diff --git a/extensions/emmet/src/emmetCompletionProvider.ts b/extensions/emmet/src/emmetCompletionProvider.ts index 9a84da40c31..5f1a641eef2 100644 --- a/extensions/emmet/src/emmetCompletionProvider.ts +++ b/extensions/emmet/src/emmetCompletionProvider.ts @@ -6,12 +6,12 @@ import * as vscode from 'vscode'; import { expand, createSnippetsRegistry } from '@emmetio/expand-abbreviation'; -import { getSyntax, isStyleSheet, getProfile, extractAbbreviation } from './util'; +import { getSyntax, getProfile, extractAbbreviation } from './util'; const field = (index, placeholder) => `\${${index}${placeholder ? ':' + placeholder : ''}}`; const snippetCompletionsCache = new Map(); -export class EmmetCompletionItemProvider implements vscode.CompletionItemProvider { +abstract class EmmetCompletionItemProviderBase implements vscode.CompletionItemProvider { public provideCompletionItems(document: vscode.TextDocument, position: vscode.Position, token: vscode.CancellationToken): Thenable { @@ -20,42 +20,97 @@ export class EmmetCompletionItemProvider implements vscode.CompletionItemProvide } let currentWord = getCurrentWord(document, position); - let expandedAbbr = getExpandedAbbreviation(document, position); - let abbreviationSuggestions = getAbbreviationSuggestions(getSyntax(document), currentWord, (expandedAbbr && currentWord === expandedAbbr.label)); + let expandedAbbr = this.getExpandedAbbreviation(document, position); + let abbreviationSuggestions = this.getAbbreviationSuggestions(getSyntax(document), currentWord, (expandedAbbr && currentWord === expandedAbbr.label)); let completionItems = expandedAbbr ? [expandedAbbr, ...abbreviationSuggestions] : abbreviationSuggestions; return Promise.resolve(new vscode.CompletionList(completionItems, true)); } + + protected getExpandedAbbreviation(document: vscode.TextDocument, position: vscode.Position): vscode.CompletionItem { + if (!vscode.workspace.getConfiguration('emmet')['showExpandedAbbreviation']) { + return; + } + let [rangeToReplace, wordToExpand] = extractAbbreviation(position); + if (!rangeToReplace || !wordToExpand) { + return; + } + let syntax = getSyntax(document); + let expandedWord = expand(wordToExpand, { + field: field, + syntax: syntax, + profile: getProfile(syntax), + addons: syntax === 'jsx' ? { 'jsx': true } : null + }); + + let completionitem = new vscode.CompletionItem(wordToExpand); + completionitem.insertText = new vscode.SnippetString(expandedWord); + completionitem.documentation = removeTabStops(expandedWord); + completionitem.range = rangeToReplace; + completionitem.detail = 'Expand Emmet Abbreviation'; + + + return completionitem; + } + + abstract getAbbreviationSuggestions(syntax: string, prefix: string, skipExactMatch: boolean): vscode.CompletionItem[]; + } -function getExpandedAbbreviation(document: vscode.TextDocument, position: vscode.Position): vscode.CompletionItem { - if (!vscode.workspace.getConfiguration('emmet')['showExpandedAbbreviation']) { - return; - } - let [rangeToReplace, wordToExpand] = extractAbbreviation(position); - if (!rangeToReplace || !wordToExpand) { - return; - } - let syntax = getSyntax(document); - let expandedWord = expand(wordToExpand, { - field: field, - syntax: syntax, - profile: getProfile(syntax), - addons: syntax === 'jsx' ? { 'jsx': true } : null - }); +export class EmmetCompletionItemProviderHtml extends EmmetCompletionItemProviderBase { - let completionitem = new vscode.CompletionItem(wordToExpand); - completionitem.insertText = new vscode.SnippetString(expandedWord); - completionitem.documentation = removeTabStops(expandedWord); - completionitem.range = rangeToReplace; - completionitem.detail = 'Expand Emmet Abbreviation'; + protected getExpandedAbbreviation(document: vscode.TextDocument, position: vscode.Position): vscode.CompletionItem { + let completionItem = super.getExpandedAbbreviation(document, position); - // In non stylesheet like syntax, this extension returns expanded abbr plus posssible abbr completions - // To differentiate between the 2, the former is given CompletionItemKind.Value so that it gets a different icon - if (!isStyleSheet(syntax)) { - completionitem.kind = vscode.CompletionItemKind.Value; + // In non stylesheet like syntax, this extension returns expanded abbr plus posssible abbr completions + // To differentiate between the 2, the former is given CompletionItemKind.Value so that it gets a different icon + completionItem.kind = vscode.CompletionItemKind.Value; + + return completionItem; } - return completionitem; + + getAbbreviationSuggestions(syntax: string, prefix: string, skipExactMatch: boolean) { + if (!vscode.workspace.getConfiguration('emmet')['showAbbreviationSuggestions'] || !prefix) { + return []; + } + + if (!snippetCompletionsCache.has(syntax)) { + let registry = createSnippetsRegistry(syntax); + let completions: vscode.CompletionItem[] = registry.all({ type: 'string' }).map(snippet => { + let expandedWord = expand(snippet.value, { + field: field, + syntax: syntax + }); + + let item = new vscode.CompletionItem(snippet.key); + item.documentation = removeTabStops(expandedWord); + item.detail = 'Complete Emmet Abbreviation'; + item.insertText = snippet.key; + return item; + }); + snippetCompletionsCache.set(syntax, completions); + } + + let snippetCompletions = snippetCompletionsCache.get(syntax); + + snippetCompletions = snippetCompletions.filter(x => x.label.startsWith(prefix) && (!skipExactMatch || x.label !== prefix)); + + return snippetCompletions; + + } + + +} + +export class EmmetCompletionItemProviderCss extends EmmetCompletionItemProviderBase { + public provideCompletionItems(document: vscode.TextDocument, position: vscode.Position, token: vscode.CancellationToken): Thenable { + return super.provideCompletionItems(document, position, token); + } + + getAbbreviationSuggestions(syntax: string, prefix: string, skipExactMatch: boolean) { + return []; + } + } function getCurrentWord(document: vscode.TextDocument, position: vscode.Position): string { @@ -72,35 +127,7 @@ function getCurrentWord(document: vscode.TextDocument, position: vscode.Position function removeTabStops(expandedWord: string): string { return expandedWord.replace(/\$\{\d+\}/g, '').replace(/\$\{\d+:([^\}]+)\}/g, '$1'); } -function getAbbreviationSuggestions(syntax: string, prefix: string, skipExactMatch: boolean) { - if (!vscode.workspace.getConfiguration('emmet')['showAbbreviationSuggestions'] || !prefix || isStyleSheet(syntax)) { - return []; - } - - if (!snippetCompletionsCache.has(syntax)) { - let registry = createSnippetsRegistry(syntax); - let completions: vscode.CompletionItem[] = registry.all({ type: 'string' }).map(snippet => { - let expandedWord = expand(snippet.value, { - field: field, - syntax: syntax - }); - - let item = new vscode.CompletionItem(snippet.key); - item.documentation = removeTabStops(expandedWord); - item.detail = 'Complete Emmet Abbreviation'; - item.insertText = snippet.key; - return item; - }); - snippetCompletionsCache.set(syntax, completions); - } - - let snippetCompletions = snippetCompletionsCache.get(syntax); - - snippetCompletions = snippetCompletions.filter(x => x.label.startsWith(prefix) && (!skipExactMatch || x.label !== prefix)); - - return snippetCompletions; - -} + diff --git a/extensions/emmet/src/extension.ts b/extensions/emmet/src/extension.ts index 620df18dc32..23f9190743d 100644 --- a/extensions/emmet/src/extension.ts +++ b/extensions/emmet/src/extension.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import * as vscode from 'vscode'; -import { EmmetCompletionItemProvider } from './emmetCompletionProvider'; +import { EmmetCompletionItemProviderHtml, EmmetCompletionItemProviderCss } from './emmetCompletionProvider'; import { expandAbbreviation, wrapWithAbbreviation } from './abbreviationActions'; import { removeTag } from './removeTag'; import { updateTag } from './updateTag'; @@ -21,7 +21,7 @@ interface ISupportedLanguageMode { triggerCharacters: string[]; } -const SUPPORTED_LANGUAGE_MODES: ISupportedLanguageMode[] = [ +const HTML_LANGUAGE_MODES: ISupportedLanguageMode[] = [ { id: 'html', triggerCharacters: ['!', '.', '}'] }, { id: 'jade', triggerCharacters: ['!', '.', '}'] }, { id: 'slim', triggerCharacters: ['!', '.', '}'] }, @@ -29,23 +29,29 @@ const SUPPORTED_LANGUAGE_MODES: ISupportedLanguageMode[] = [ { id: 'xml', triggerCharacters: ['.', '}'] }, { id: 'xsl', triggerCharacters: ['.', '}'] }, - { id: 'css', triggerCharacters: [':'] }, - { id: 'scss', triggerCharacters: [':'] }, - { id: 'sass', triggerCharacters: [':'] }, - { id: 'less', triggerCharacters: [':'] }, - { id: 'stylus', triggerCharacters: [':'] }, - { id: 'javascriptreact', triggerCharacters: ['.'] }, { id: 'typescriptreact', triggerCharacters: ['.'] } ]; +const CSS_LANGUAGE_MODES: ISupportedLanguageMode[] = [ + { id: 'css', triggerCharacters: [':'] }, + { id: 'scss', triggerCharacters: [':'] }, + { id: 'sass', triggerCharacters: [':'] }, + { id: 'less', triggerCharacters: [':'] }, + { id: 'stylus', triggerCharacters: [':'] } +]; + export function activate(context: vscode.ExtensionContext) { - let completionProvider = new EmmetCompletionItemProvider(); + let completionProviderHtml = new EmmetCompletionItemProviderHtml(); + let completionProviderCss = new EmmetCompletionItemProviderCss(); - for (let language of SUPPORTED_LANGUAGE_MODES) { - const selector: vscode.DocumentFilter = { language: language.id }; - const provider = vscode.languages.registerCompletionItemProvider(selector, completionProvider, ...language.triggerCharacters); + for (let language of HTML_LANGUAGE_MODES) { + const provider = vscode.languages.registerCompletionItemProvider({ language: language.id }, completionProviderHtml, ...language.triggerCharacters); + context.subscriptions.push(provider); + } + for (let language of CSS_LANGUAGE_MODES) { + const provider = vscode.languages.registerCompletionItemProvider({ language: language.id }, completionProviderCss, ...language.triggerCharacters); context.subscriptions.push(provider); }