diff --git a/extensions/emmet/package.json b/extensions/emmet/package.json
index 659be1e0fce..c256b4fa64f 100644
--- a/extensions/emmet/package.json
+++ b/extensions/emmet/package.json
@@ -16,6 +16,9 @@
"type": "git",
"url": "https://github.com/microsoft/vscode.git"
},
+ "enabledApiProposals": [
+ "inlineCompletionsNew"
+ ],
"activationEvents": [
"onCommand:emmet.expandAbbreviation",
"onCommand:editor.emmet.action.wrapWithAbbreviation",
@@ -127,6 +130,11 @@
"default": false,
"markdownDescription": "%emmetTriggerExpansionOnTab%"
},
+ "emmet.useInlineCompletions": {
+ "type": "boolean",
+ "default": true,
+ "markdownDescription": "%emmetUseInlineCompletions%"
+ },
"emmet.preferences": {
"type": "object",
"default": {},
diff --git a/extensions/emmet/package.nls.json b/extensions/emmet/package.nls.json
index 1cac53a6081..3de8f3205c1 100644
--- a/extensions/emmet/package.nls.json
+++ b/extensions/emmet/package.nls.json
@@ -59,5 +59,6 @@
"emmetPreferencesOutputInlineBreak": "The number of sibling inline elements needed for line breaks to be placed between those elements. If `0`, inline elements are always expanded onto a single line.",
"emmetPreferencesOutputReverseAttributes": "If `true`, reverses attribute merging directions when resolving snippets.",
"emmetPreferencesOutputSelfClosingStyle": "Style of self-closing tags: html (`
`), xml (`
`) or xhtml (`
`).",
- "emmetPreferencesCssColorShort": "If `true`, color values like `#f` will be expanded to `#fff` instead of `#ffffff`."
+ "emmetPreferencesCssColorShort": "If `true`, color values like `#f` will be expanded to `#fff` instead of `#ffffff`.",
+ "emmetUseInlineCompletions": "If `true`, Emmet will use inline completions to suggest expansions."
}
diff --git a/extensions/emmet/src/emmetCommon.ts b/extensions/emmet/src/emmetCommon.ts
index 5a5e0d872c3..82a32ac9b4e 100644
--- a/extensions/emmet/src/emmetCommon.ts
+++ b/extensions/emmet/src/emmetCommon.ts
@@ -23,7 +23,7 @@ import { addFileToParseCache, clearParseCache, removeFileFromParseCache } from '
export function activateEmmetExtension(context: vscode.ExtensionContext) {
migrateEmmetExtensionsPath();
- registerCompletionProviders(context);
+ refreshCompletionProviders(context);
updateEmmetExtensionsPath();
context.subscriptions.push(vscode.commands.registerCommand('editor.emmet.action.wrapWithAbbreviation', (args) => {
@@ -122,8 +122,8 @@ export function activateEmmetExtension(context: vscode.ExtensionContext) {
}));
context.subscriptions.push(vscode.workspace.onDidChangeConfiguration((e) => {
- if (e.affectsConfiguration('emmet.includeLanguages')) {
- registerCompletionProviders(context);
+ if (e.affectsConfiguration('emmet.includeLanguages') || e.affectsConfiguration('emmet.useInlineCompletions')) {
+ refreshCompletionProviders(context);
}
if (e.affectsConfiguration('emmet.extensionsPath')) {
updateEmmetExtensionsPath();
@@ -159,11 +159,42 @@ export function activateEmmetExtension(context: vscode.ExtensionContext) {
*/
const languageMappingForCompletionProviders: Map = new Map();
const completionProvidersMapping: Map = new Map();
+const completionProviderDisposables: vscode.Disposable[] = [];
-function registerCompletionProviders(context: vscode.ExtensionContext) {
- let completionProvider = new DefaultCompletionItemProvider();
- let includedLanguages = getMappingForIncludedLanguages();
+function refreshCompletionProviders(_: vscode.ExtensionContext) {
+ clearCompletionProviderInfo();
+ const completionProvider = new DefaultCompletionItemProvider();
+ const inlineCompletionProvider: vscode.InlineCompletionItemProviderNew = {
+ async provideInlineCompletionItems(document: vscode.TextDocument, position: vscode.Position, _: vscode.InlineCompletionContextNew, token: vscode.CancellationToken) {
+ const items = await completionProvider.provideCompletionItems(document, position, token, { triggerCharacter: undefined, triggerKind: vscode.CompletionTriggerKind.Invoke });
+ if (!items) {
+ return undefined;
+ }
+ const item = items.items[0];
+ if (!item) {
+ return undefined;
+ }
+ const range = item.range as vscode.Range;
+
+ if (document.getText(range) !== item.label) {
+ // We only want to show an inline completion if we are really sure the user meant emmet.
+ // If the user types `d`, we don't want to suggest ``.
+ return undefined;
+ }
+
+ return [
+ {
+ insertText: item.insertText as any,
+ filterText: item.label as any,
+ range
+ }
+ ];
+ }
+ };
+
+ const useInlineCompletionProvider = vscode.workspace.getConfiguration('emmet').get('useInlineCompletions');
+ const includedLanguages = getMappingForIncludedLanguages();
Object.keys(includedLanguages).forEach(language => {
if (languageMappingForCompletionProviders.has(language) && languageMappingForCompletionProviders.get(language) === includedLanguages[language]) {
return;
@@ -178,8 +209,13 @@ function registerCompletionProviders(context: vscode.ExtensionContext) {
completionProvidersMapping.delete(language);
}
- const provider = vscode.languages.registerCompletionItemProvider({ language, scheme: '*' }, completionProvider, ...LANGUAGE_MODES[includedLanguages[language]]);
- context.subscriptions.push(provider);
+ let provider;
+ if (useInlineCompletionProvider) {
+ provider = vscode.languages.registerInlineCompletionItemProviderNew({ language, scheme: '*' }, inlineCompletionProvider);
+ } else {
+ provider = vscode.languages.registerCompletionItemProvider({ language, scheme: '*' }, completionProvider, ...LANGUAGE_MODES[includedLanguages[language]]);
+ }
+ completionProviderDisposables.push(provider);
languageMappingForCompletionProviders.set(language, includedLanguages[language]);
completionProvidersMapping.set(language, provider);
@@ -187,8 +223,13 @@ function registerCompletionProviders(context: vscode.ExtensionContext) {
Object.keys(LANGUAGE_MODES).forEach(language => {
if (!languageMappingForCompletionProviders.has(language)) {
- const provider = vscode.languages.registerCompletionItemProvider({ language, scheme: '*' }, completionProvider, ...LANGUAGE_MODES[language]);
- context.subscriptions.push(provider);
+ let provider;
+ if (useInlineCompletionProvider) {
+ provider = vscode.languages.registerInlineCompletionItemProviderNew({ language, scheme: '*' }, inlineCompletionProvider);
+ } else {
+ provider = vscode.languages.registerCompletionItemProvider({ language, scheme: '*' }, completionProvider, ...LANGUAGE_MODES[language]);
+ }
+ completionProviderDisposables.push(provider);
languageMappingForCompletionProviders.set(language, language);
completionProvidersMapping.set(language, provider);
@@ -196,7 +237,16 @@ function registerCompletionProviders(context: vscode.ExtensionContext) {
});
}
-export function deactivate() {
+function clearCompletionProviderInfo() {
+ languageMappingForCompletionProviders.clear();
completionProvidersMapping.clear();
+ let disposable: vscode.Disposable | undefined;
+ while (disposable = completionProviderDisposables.pop()) {
+ disposable.dispose();
+ }
+}
+
+export function deactivate() {
+ clearCompletionProviderInfo();
clearParseCache();
}
diff --git a/extensions/emmet/tsconfig.json b/extensions/emmet/tsconfig.json
index 994fa239537..ad07467f4ea 100644
--- a/extensions/emmet/tsconfig.json
+++ b/extensions/emmet/tsconfig.json
@@ -9,6 +9,7 @@
],
"include": [
"src/**/*",
- "../../src/vscode-dts/vscode.d.ts"
+ "../../src/vscode-dts/vscode.d.ts",
+ "../../src/vscode-dts/vscode.proposed.inlineCompletionsNew.d.ts",
]
}