From 8f5fc228a7a535c034781019e615a4c8d9b45e21 Mon Sep 17 00:00:00 2001 From: Ramya Achutha Rao Date: Tue, 20 Jun 2017 17:39:00 -0700 Subject: [PATCH] Refactoring to support #28556 eventually --- extensions/emmet/src/abbreviationActions.ts | 43 ++++++---- .../emmet/src/emmetCompletionProvider.ts | 85 ++++++++++--------- 2 files changed, 72 insertions(+), 56 deletions(-) diff --git a/extensions/emmet/src/abbreviationActions.ts b/extensions/emmet/src/abbreviationActions.ts index f3ffe745f46..aeb64582f25 100644 --- a/extensions/emmet/src/abbreviationActions.ts +++ b/extensions/emmet/src/abbreviationActions.ts @@ -51,7 +51,13 @@ export function expandAbbreviation() { mappedSyntax = true; } } - let output = expandAbbreviationHelper(syntax, editor.document, editor.selection, mappedSyntax); + if (!mappedSyntax) { + syntax = syntaxHelper(syntax, editor.document, editor.selection.end); + } + if (!syntax) { + return; + } + let output = expandAbbreviationHelper(syntax, editor.document, editor.selection); if (output) { editor.insertSnippet(new vscode.SnippetString(output.expandedText), output.abbreviationRange); } @@ -69,21 +75,8 @@ export interface ExpandAbbreviationHelperOutput { * @param syntax string syntax to be used for expanding abbreviations * @param document vscode.TextDocument * @param abbreviationRange vscode.Range range of the abbreviation that needs to be expanded - * @param mappedSyntax Boolean Pass true if given document language was mapped to given syntax to get emmet abbreviation expansions. * */ -export function expandAbbreviationHelper(syntax: string, document: vscode.TextDocument, abbreviationRange: vscode.Range, mappedSyntax: boolean): ExpandAbbreviationHelperOutput { - if (!mappedSyntax) { - let parseContent = isStyleSheet(syntax) ? parseStylesheet : parse; - let rootNode: Node = parseContent(new DocumentStreamReader(document)); - let currentNode = getNode(rootNode, abbreviationRange.end); - - if (forceCssSyntax(syntax, currentNode, abbreviationRange.end)) { - syntax = 'css'; - } else if (!isValidLocationForEmmetAbbreviation(currentNode, syntax, abbreviationRange.end)) { - return; - } - } - +export function expandAbbreviationHelper(syntax: string, document: vscode.TextDocument, abbreviationRange: vscode.Range): ExpandAbbreviationHelperOutput { let abbreviation = document.getText(abbreviationRange); if (abbreviationRange.isEmpty) { [abbreviationRange, abbreviation] = extractAbbreviation(document, abbreviationRange.start); @@ -93,6 +86,24 @@ export function expandAbbreviationHelper(syntax: string, document: vscode.TextDo return { expandedText, abbreviationRange, abbreviation, syntax }; } +/** + * Checks whether given position is valid for emmet abbreviation and returns appropriate syntax + * @param syntax string language mode of current document + * @param document vscode.Textdocument + * @param position vscode.Position position of the abbreviation that needs to be expanded + */ +export function syntaxHelper(syntax: string, document: vscode.TextDocument, position: vscode.Position): string { + let parseContent = isStyleSheet(syntax) ? parseStylesheet : parse; + let rootNode: Node = parseContent(new DocumentStreamReader(document)); + let currentNode = getNode(rootNode, position); + + if (forceCssSyntax(syntax, currentNode, position)) { + return 'css'; + } else if (!isValidLocationForEmmetAbbreviation(currentNode, syntax, position)) { + return; + } +} + /** * Extracts abbreviation from the given position in the given document */ @@ -141,7 +152,7 @@ function isValidLocationForEmmetAbbreviation(currentNode: Node, syntax: string, return false; } -function getExpandOptions(syntax: string, textToReplace?: string) { +export function getExpandOptions(syntax: string, textToReplace?: string) { return { field: field, syntax: syntax, diff --git a/extensions/emmet/src/emmetCompletionProvider.ts b/extensions/emmet/src/emmetCompletionProvider.ts index 3a0a0c35396..d807be74992 100644 --- a/extensions/emmet/src/emmetCompletionProvider.ts +++ b/extensions/emmet/src/emmetCompletionProvider.ts @@ -7,10 +7,9 @@ import * as vscode from 'vscode'; import { expand, createSnippetsRegistry } from '@emmetio/expand-abbreviation'; import { getSyntax, isStyleSheet } from './util'; -import { expandAbbreviationHelper, ExpandAbbreviationHelperOutput } from './abbreviationActions'; +import { syntaxHelper, expandAbbreviationHelper, ExpandAbbreviationHelperOutput, getExpandOptions } from './abbreviationActions'; -const field = (index, placeholder) => `\${${index}${placeholder ? ':' + placeholder : ''}}`; -const snippetCompletionsCache = new Map(); +const snippetKeyCache = new Map(); export class EmmetCompletionItemProvider implements vscode.CompletionItemProvider { private _mappedSyntax = false; @@ -21,64 +20,70 @@ export class EmmetCompletionItemProvider implements vscode.CompletionItemProvide } public provideCompletionItems(document: vscode.TextDocument, position: vscode.Position, token: vscode.CancellationToken): Thenable { - if (!vscode.workspace.getConfiguration('emmet')['useNewEmmet']) { + let emmetConfig = vscode.workspace.getConfiguration('emmet'); + if (!emmetConfig['useNewEmmet'] || !emmetConfig['showExpandedAbbreviation']) { return Promise.resolve(null); } let syntax = getSyntax(document); - let expandedAbbr: vscode.CompletionItem; - if (vscode.workspace.getConfiguration('emmet')['showExpandedAbbreviation']) { - let output: ExpandAbbreviationHelperOutput = expandAbbreviationHelper(syntax, document, new vscode.Range(position, position), this._mappedSyntax); - if (output) { - expandedAbbr = new vscode.CompletionItem(output.abbreviation); - expandedAbbr.insertText = new vscode.SnippetString(output.expandedText); - expandedAbbr.documentation = removeTabStops(output.expandedText); - expandedAbbr.range = output.abbreviationRange; - expandedAbbr.detail = 'Expand Emmet Abbreviation'; - syntax = output.syntax; - } + let abbreviationRange = new vscode.Range(position, position); + if (!this._mappedSyntax) { + syntax = syntaxHelper(syntax, document, position); + } + + let output: ExpandAbbreviationHelperOutput = expandAbbreviationHelper(syntax, document, abbreviationRange); + if (!output) { + return; } + let expandedAbbr = new vscode.CompletionItem(output.abbreviation); + expandedAbbr.insertText = new vscode.SnippetString(output.expandedText); + expandedAbbr.documentation = removeTabStops(output.expandedText); + expandedAbbr.range = output.abbreviationRange; + expandedAbbr.detail = 'Expand Emmet Abbreviation'; + syntax = output.syntax; + let completionItems: vscode.CompletionItem[] = expandedAbbr ? [expandedAbbr] : []; if (!isStyleSheet(syntax)) { - if (expandedAbbr) { - // 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 - expandedAbbr.kind = vscode.CompletionItemKind.Value; - } let currentWord = getCurrentWord(document, position); - - let abbreviationSuggestions = this.getAbbreviationSuggestions(syntax, currentWord, (expandedAbbr && currentWord === expandedAbbr.label)); + let abbreviationSuggestions = this.getAbbreviationSuggestions(syntax, currentWord, output.abbreviation, output.abbreviationRange); completionItems = completionItems.concat(abbreviationSuggestions); } - return Promise.resolve(new vscode.CompletionList(completionItems, true)); + + } - getAbbreviationSuggestions(syntax: string, prefix: string, skipExactMatch: boolean) { - if (!vscode.workspace.getConfiguration('emmet')['showAbbreviationSuggestions'] || !prefix) { + getAbbreviationSuggestions(syntax: string, prefix: string, abbreviation: string, abbreviationRange: vscode.Range): vscode.CompletionItem[] { + if (!vscode.workspace.getConfiguration('emmet')['showAbbreviationSuggestions'] || !prefix || !abbreviation) { return []; } - if (!snippetCompletionsCache.has(syntax)) { + if (!snippetKeyCache.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; + let snippetKeys: string[] = registry.all({ type: 'string' }).map(snippet => { + return snippet.key; }); - snippetCompletionsCache.set(syntax, completions); + snippetKeyCache.set(syntax, snippetKeys); } - let snippetCompletions = snippetCompletionsCache.get(syntax); + let skipExactMatch = prefix === abbreviation; + let snippetKeys = snippetKeyCache.get(syntax); + let snippetCompletions = []; + snippetKeys.forEach(snippetKey => { + if (!snippetKey.startsWith(prefix) || (snippetKey === prefix) || (skipExactMatch && snippetKey === prefix)) { + return; + } + + let currentAbbr = snippetKey; // For #28556: abbreviation + snippetKey.substr(prefix.length); + let expandedAbbr = expand(currentAbbr, getExpandOptions(syntax)); + + let item = new vscode.CompletionItem(snippetKey); + item.documentation = removeTabStops(expandedAbbr); + item.detail = 'Complete Emmet Abbreviation'; + item.insertText = snippetKey; // For #28556: new vscode.SnippetString(expandedAbbr); - snippetCompletions = snippetCompletions.filter(x => x.label.startsWith(prefix) && (!skipExactMatch || x.label !== prefix)); + snippetCompletions.push(item); + }); return snippetCompletions; -- GitLab