mirror of
https://github.com/microsoft/vscode.git
synced 2026-04-27 12:04:04 +01:00
109 lines
4.2 KiB
TypeScript
109 lines
4.2 KiB
TypeScript
/*---------------------------------------------------------------------------------------------
|
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
* Licensed under the MIT License. See License.txt in the project root for license information.
|
|
*--------------------------------------------------------------------------------------------*/
|
|
|
|
|
|
import * as vscode from 'vscode';
|
|
import { expand, createSnippetsRegistry } from '@emmetio/expand-abbreviation';
|
|
import { getSyntax, isStyleSheet } from './util';
|
|
import { expandAbbreviationHelper, ExpandAbbreviationHelperOutput } from './abbreviationActions';
|
|
|
|
const field = (index, placeholder) => `\${${index}${placeholder ? ':' + placeholder : ''}}`;
|
|
const snippetCompletionsCache = new Map<string, vscode.CompletionItem[]>();
|
|
|
|
export class EmmetCompletionItemProvider implements vscode.CompletionItemProvider {
|
|
private _mappedSyntax = false;
|
|
constructor(mappedSyntax?: boolean) {
|
|
if (mappedSyntax) {
|
|
this._mappedSyntax = true;
|
|
}
|
|
}
|
|
public provideCompletionItems(document: vscode.TextDocument, position: vscode.Position, token: vscode.CancellationToken): Thenable<vscode.CompletionList> {
|
|
|
|
if (!vscode.workspace.getConfiguration('emmet')['useNewEmmet']) {
|
|
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 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));
|
|
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) {
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function getCurrentWord(document: vscode.TextDocument, position: vscode.Position): string {
|
|
let wordAtPosition = document.getWordRangeAtPosition(position);
|
|
let currentWord = '';
|
|
if (wordAtPosition && wordAtPosition.start.character < position.character) {
|
|
let word = document.getText(wordAtPosition);
|
|
currentWord = word.substr(0, position.character - wordAtPosition.start.character);
|
|
}
|
|
|
|
return currentWord;
|
|
}
|
|
|
|
function removeTabStops(expandedWord: string): string {
|
|
return expandedWord.replace(/\$\{\d+\}/g, '').replace(/\$\{\d+:([^\}]+)\}/g, '$1');
|
|
}
|
|
|
|
|
|
|
|
|