Fix language-specific tab expansion and polish (#157035)

* Fix language-specific tab expansion and polish

Fixes #156075

* Add back check
This commit is contained in:
Raymond Zhao
2022-08-03 16:31:19 -07:00
committed by GitHub
parent 357d14621c
commit 9f80085795
5 changed files with 42 additions and 36 deletions
+1 -1
View File
@@ -65,7 +65,7 @@
"emmet.showAbbreviationSuggestions": {
"type": "boolean",
"default": true,
"scope": "language-overridable",
"scope": "resource",
"markdownDescription": "%emmetShowAbbreviationSuggestions%"
},
"emmet.includeLanguages": {
+30 -30
View File
@@ -264,47 +264,47 @@ export async function wrapWithAbbreviation(args: any): Promise<boolean> {
}
export function expandEmmetAbbreviation(args: any): Thenable<boolean | undefined> {
if (!validate() || !vscode.window.activeTextEditor) {
return fallbackTab();
if (!validate()) {
return Promise.resolve(undefined);
}
const editor = vscode.window.activeTextEditor!;
args = args || {};
if (!args['language']) {
args['language'] = editor.document.languageId;
} else {
const excludedLanguages = vscode.workspace.getConfiguration('emmet')['excludeLanguages'] ?? [];
if (excludedLanguages.includes(args['language'])) {
return fallbackTab(args['language']);
}
}
const languageId: string = args['language'];
/**
* Short circuit the parsing. If previous character is space, do not expand.
*/
if (vscode.window.activeTextEditor.selections.length === 1 &&
vscode.window.activeTextEditor.selection.isEmpty
if (editor.selections.length === 1 && editor.selection.isEmpty
) {
const anchor = vscode.window.activeTextEditor.selection.anchor;
const anchor = editor.selection.anchor;
if (anchor.character === 0) {
return fallbackTab();
return fallbackTab(languageId);
}
const prevPositionAnchor = anchor.translate(0, -1);
const prevText = vscode.window.activeTextEditor.document.getText(new vscode.Range(prevPositionAnchor, anchor));
const prevText = editor.document.getText(new vscode.Range(prevPositionAnchor, anchor));
if (prevText === ' ' || prevText === '\t') {
return fallbackTab();
return fallbackTab(languageId);
}
}
args = args || {};
if (!args['language']) {
args['language'] = vscode.window.activeTextEditor.document.languageId;
} else {
const excludedLanguages = vscode.workspace.getConfiguration('emmet')['excludeLanguages'] ? vscode.workspace.getConfiguration('emmet')['excludeLanguages'] : [];
if (excludedLanguages.indexOf(vscode.window.activeTextEditor.document.languageId) > -1) {
return fallbackTab();
}
}
const syntax = getSyntaxFromArgs(args);
if (!syntax) {
return fallbackTab();
return fallbackTab(languageId);
}
const editor = vscode.window.activeTextEditor;
// When tabbed on a non empty selection, do not treat it as an emmet abbreviation, and fallback to tab instead
if (vscode.workspace.getConfiguration('emmet')['triggerExpansionOnTab'] === true && editor.selections.find(x => !x.isEmpty)) {
return fallbackTab();
if (vscode.workspace.getConfiguration('emmet', { languageId })['triggerExpansionOnTab'] === true && editor.selections.find(x => !x.isEmpty)) {
return fallbackTab(languageId);
}
const abbreviationList: ExpandAbbreviationInput[] = [];
@@ -325,7 +325,7 @@ export function expandEmmetAbbreviation(args: any): Thenable<boolean | undefined
}
const currentLine = editor.document.lineAt(position.line).text;
const textTillPosition = currentLine.substr(0, position.character);
const textTillPosition = currentLine.substring(0, position.character);
// Expand cases like <div to <div></div> explicitly
// else we will end up with <<div></div>
@@ -415,12 +415,12 @@ export function expandEmmetAbbreviation(args: any): Thenable<boolean | undefined
});
return expandAbbreviationInRange(editor, abbreviationList, allAbbreviationsSame).then(success => {
return success ? Promise.resolve(undefined) : fallbackTab();
return success ? Promise.resolve(undefined) : fallbackTab(languageId);
});
}
function fallbackTab(): Thenable<boolean | undefined> {
if (vscode.workspace.getConfiguration('emmet')['triggerExpansionOnTab'] === true) {
function fallbackTab(languageId: string): Thenable<boolean | undefined> {
if (vscode.workspace.getConfiguration('emmet', { languageId })['triggerExpansionOnTab'] === true) {
return vscode.commands.executeCommand('tab');
}
return Promise.resolve(true);
@@ -470,13 +470,13 @@ export function isValidLocationForEmmetAbbreviation(document: vscode.TextDocumen
&& propertyNode.separator
&& offset >= propertyNode.separatorToken.end
&& offset <= propertyNode.terminatorToken.start
&& abbreviation.indexOf(':') === -1) {
&& !abbreviation.includes(':')) {
return hexColorRegex.test(abbreviation) || abbreviation === '!';
}
if (!propertyNode.terminatorToken
&& propertyNode.separator
&& offset >= propertyNode.separatorToken.end
&& abbreviation.indexOf(':') === -1) {
&& !abbreviation.includes(':')) {
return hexColorRegex.test(abbreviation) || abbreviation === '!';
}
if (hexColorRegex.test(abbreviation) || abbreviation === '!') {
@@ -529,7 +529,7 @@ export function isValidLocationForEmmetAbbreviation(document: vscode.TextDocumen
const typeAttribute = (currentHtmlNode.attributes || []).filter(x => x.name.toString() === 'type')[0];
const typeValue = typeAttribute ? typeAttribute.value.toString() : '';
if (allowedMimeTypesInScriptTag.indexOf(typeValue) > -1) {
if (allowedMimeTypesInScriptTag.includes(typeValue)) {
return true;
}
@@ -31,7 +31,7 @@ export class DefaultCompletionItemProvider implements vscode.CompletionItemProvi
if (expandedText.startsWith('<')) {
this.lastCompletionType = 'html';
} else if (expandedText.indexOf(':') > 0 && expandedText.endsWith(';')) {
} else if (expandedText.includes(':') && expandedText.endsWith(';')) {
this.lastCompletionType = 'css';
} else {
this.lastCompletionType = undefined;
@@ -43,7 +43,7 @@ export class DefaultCompletionItemProvider implements vscode.CompletionItemProvi
private provideCompletionItemsInternal(document: vscode.TextDocument, position: vscode.Position, context: vscode.CompletionContext): Thenable<vscode.CompletionList | undefined> | undefined {
const emmetConfig = vscode.workspace.getConfiguration('emmet');
const excludedLanguages = emmetConfig['excludeLanguages'] ? emmetConfig['excludeLanguages'] : [];
if (excludedLanguages.indexOf(document.languageId) > -1) {
if (excludedLanguages.includes(document.languageId)) {
return;
}
+1 -1
View File
@@ -140,7 +140,7 @@ function getNextAttribute(document: vscode.TextDocument, selectionStart: number,
}
// Fetch the next word in the attr value
if (attr.value.toString().indexOf(' ') === -1) {
if (!attr.value.toString().includes(' ')) {
// attr value does not have space, so no next word to find
continue;
}
@@ -8,6 +8,7 @@ import { grammarsExtPoint, ITMSyntaxExtensionPoint } from 'vs/workbench/services
import { IExtensionService, ExtensionPointContribution } from 'vs/workbench/services/extensions/common/extensions';
import { ICommandService } from 'vs/platform/commands/common/commands';
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
interface ModeScopeMap {
[key: string]: string;
@@ -70,13 +71,18 @@ export abstract class EmmetEditorAction extends EditorAction {
}
public run(accessor: ServicesAccessor, editor: ICodeEditor): Promise<void> {
const extensionService = accessor.get(IExtensionService);
const commandService = accessor.get(ICommandService);
const configurationService = accessor.get(IConfigurationService);
const extensionService = accessor.get(IExtensionService);
return this._withGrammarContributions(extensionService).then((grammarContributions) => {
if (this.id === 'editor.emmet.action.expandAbbreviation' && grammarContributions) {
return commandService.executeCommand<void>('emmet.expandAbbreviation', EmmetEditorAction.getLanguage(editor, grammarContributions));
const languageInfo = EmmetEditorAction.getLanguage(editor, grammarContributions);
const languageId = languageInfo?.language;
if (configurationService.getValue('emmet.triggerExpansionOnTab', { overrideIdentifier: languageId }) === true) {
return commandService.executeCommand<void>('emmet.expandAbbreviation', languageInfo);
}
}
return undefined;