Move emmet from html extenstion to emmet extension

This commit is contained in:
Ramya Achutha Rao
2018-04-22 12:29:13 -07:00
parent 147ca542e6
commit c314388da2
12 changed files with 17 additions and 174 deletions

View File

@@ -7,10 +7,10 @@
import {
createConnection, IConnection, TextDocuments, InitializeParams, InitializeResult, RequestType,
DocumentRangeFormattingRequest, Disposable, DocumentSelector, TextDocumentPositionParams, ServerCapabilities,
Position, CompletionTriggerKind, ConfigurationRequest, ConfigurationParams, DidChangeWorkspaceFoldersNotification,
Position, ConfigurationRequest, ConfigurationParams, DidChangeWorkspaceFoldersNotification,
WorkspaceFolder, DocumentColorRequest, ColorInformation, ColorPresentationRequest
} from 'vscode-languageserver';
import { TextDocument, Diagnostic, DocumentLink, SymbolInformation, CompletionList } from 'vscode-languageserver-types';
import { TextDocument, Diagnostic, DocumentLink, SymbolInformation } from 'vscode-languageserver-types';
import { getLanguageModes, LanguageModes, Settings } from './modes/languageModes';
import { format } from './modes/formatting';
@@ -18,7 +18,6 @@ import { pushAll } from './utils/arrays';
import { getDocumentContext } from './utils/documentContext';
import uri from 'vscode-uri';
import { formatError, runSafe, runSafeAsync } from './utils/runner';
import { doComplete as emmetDoComplete, updateExtensionsPath as updateEmmetExtensionsPath, getEmmetCompletionParticipants } from 'vscode-emmet-helper';
import { FoldingRangeRequest, FoldingRangeServerCapabilities } from 'vscode-languageserver-protocol-foldingprovider';
import { getFoldingRanges } from './modes/htmlFolding';
@@ -78,10 +77,6 @@ function getDocumentSettings(textDocument: TextDocument, needsDocumentSettings:
return Promise.resolve(void 0);
}
let emmetSettings: any = {};
let currentEmmetExtensionsPath: string;
const emmetTriggerCharacters = ['!', '.', '}', ':', '*', '$', ']', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'];
// After the server has started the client sends an initialize request. The server receives
// in the passed params the rootPath of the workspace plus the client capabilities
connection.onInitialize((params: InitializeParams): InitializeResult => {
@@ -127,7 +122,7 @@ connection.onInitialize((params: InitializeParams): InitializeResult => {
let capabilities: ServerCapabilities & FoldingRangeServerCapabilities = {
// Tell the client that the server works in FULL text document sync mode
textDocumentSync: documents.syncKind,
completionProvider: clientSnippetSupport ? { resolveProvider: true, triggerCharacters: [...emmetTriggerCharacters, '.', ':', '<', '"', '=', '/'] } : undefined,
completionProvider: clientSnippetSupport ? { resolveProvider: true, triggerCharacters: ['.', ':', '<', '"', '=', '/'] } : undefined,
hoverProvider: true,
documentHighlightProvider: true,
documentRangeFormattingProvider: false,
@@ -184,13 +179,6 @@ connection.onDidChangeConfiguration((change) => {
formatterRegistration = null;
}
}
emmetSettings = globalSettings.emmet || {};
if (currentEmmetExtensionsPath !== emmetSettings['extensionsPath']) {
currentEmmetExtensionsPath = emmetSettings['extensionsPath'];
const workspaceUri = (workspaceFolders && workspaceFolders.length === 1) ? uri.parse(workspaceFolders[0].uri) : null;
updateEmmetExtensionsPath(currentEmmetExtensionsPath, workspaceUri ? workspaceUri.fsPath : undefined);
}
});
const pendingValidationRequests: { [uri: string]: NodeJS.Timer } = {};
@@ -254,8 +242,6 @@ async function validateTextDocument(textDocument: TextDocument) {
}
}
let cachedCompletionList: CompletionList | null;
const hexColorRegex = /^#[\d,a-f,A-F]{1,6}$/;
connection.onCompletion(async (textDocumentPosition, token) => {
return runSafeAsync(async () => {
const document = documents.get(textDocumentPosition.textDocument.uri);
@@ -265,22 +251,6 @@ connection.onCompletion(async (textDocumentPosition, token) => {
}
const doComplete = mode.doComplete!;
if (cachedCompletionList
&& !cachedCompletionList.isIncomplete
&& (mode.getId() === 'html' || mode.getId() === 'css')
&& textDocumentPosition.context
&& textDocumentPosition.context.triggerKind === CompletionTriggerKind.TriggerForIncompleteCompletions
) {
let result: CompletionList = emmetDoComplete(document, textDocumentPosition.position, mode.getId(), emmetSettings);
if (result && result.items) {
result.items.push(...cachedCompletionList.items);
} else {
result = cachedCompletionList;
cachedCompletionList = null;
}
return result;
}
if (mode.getId() !== 'html') {
/* __GDPR__
"html.embbedded.complete" : {
@@ -290,22 +260,8 @@ connection.onCompletion(async (textDocumentPosition, token) => {
connection.telemetry.logEvent({ key: 'html.embbedded.complete', value: { languageId: mode.getId() } });
}
cachedCompletionList = null;
const emmetCompletionList = CompletionList.create([], false);
const emmetCompletionParticipant = getEmmetCompletionParticipants(document, textDocumentPosition.position, mode.getId(), emmetSettings, emmetCompletionList);
const completionParticipants = [emmetCompletionParticipant];
let settings = await getDocumentSettings(document, () => doComplete.length > 2);
let result = doComplete(document, textDocumentPosition.position, settings, completionParticipants);
if (emmetCompletionList.isIncomplete) {
emmetCompletionList.items = emmetCompletionList.items || [];
cachedCompletionList = result;
if (emmetCompletionList.items.length && hexColorRegex.test(emmetCompletionList.items[0].label) && result.items.some(x => x.label === emmetCompletionList.items[0].label)) {
emmetCompletionList.items.shift();
}
return CompletionList.create([...emmetCompletionList.items, ...result.items], emmetCompletionList.isIncomplete || result.isIncomplete);
}
let result = doComplete(document, textDocumentPosition.position, settings);
return result;
}, null, `Error while computing completions for ${textDocumentPosition.textDocument.uri}`, token);

View File

@@ -6,11 +6,10 @@
import { LanguageModelCache, getLanguageModelCache } from '../languageModelCache';
import { TextDocument, Position, Range, CompletionList } from 'vscode-languageserver-types';
import { getCSSLanguageService, Stylesheet, ICompletionParticipant, FoldingRange } from 'vscode-css-languageservice';
import { getCSSLanguageService, Stylesheet, FoldingRange } from 'vscode-css-languageservice';
import { LanguageMode, Workspace } from './languageModes';
import { HTMLDocumentRegions, CSS_STYLE_RULE } from './embeddedSupport';
import { Color } from 'vscode-languageserver';
import { extractAbbreviation } from 'vscode-emmet-helper';
export function getCSSMode(documentRegions: LanguageModelCache<HTMLDocumentRegions>, workspace: Workspace): LanguageMode {
let cssLanguageService = getCSSLanguageService();
@@ -25,26 +24,9 @@ export function getCSSMode(documentRegions: LanguageModelCache<HTMLDocumentRegio
let embedded = embeddedCSSDocuments.get(document);
return cssLanguageService.doValidation(embedded, cssStylesheets.get(embedded), settings && settings.css);
},
doComplete(document: TextDocument, position: Position, settings = workspace.settings, registeredCompletionParticipants?: ICompletionParticipant[]) {
doComplete(document: TextDocument, position: Position, settings = workspace.settings) {
let embedded = embeddedCSSDocuments.get(document);
const stylesheet = cssStylesheets.get(embedded);
const nonEmmetCompletionParticipants = [];
if (registeredCompletionParticipants) {
// Css Emmet completions in html files are provided no matter where the cursor is inside the embedded css document
// Mimic the same here, until we solve the issue of css language service not able to parse complete embedded documents when there are errors
for (let i = 0; i < registeredCompletionParticipants.length; i++) {
if (typeof (<any>registeredCompletionParticipants[i]).getId === 'function' && (<any>registeredCompletionParticipants[i]).getId() === 'emmet') {
const extractedResults = extractAbbreviation(document, position, { lookAhead: false, syntax: 'css' });
if (extractedResults && extractedResults.abbreviation) {
registeredCompletionParticipants[i].onCssProperty!({ propertyName: extractedResults.abbreviation, range: extractedResults.abbreviationRange });
}
} else {
nonEmmetCompletionParticipants.push(registeredCompletionParticipants[i]);
}
}
}
cssLanguageService.setCompletionParticipants(nonEmmetCompletionParticipants);
return cssLanguageService.doComplete(embedded, position, stylesheet) || CompletionList.create();
},
doHover(document: TextDocument, position: Position) {

View File

@@ -5,7 +5,7 @@
'use strict';
import { getLanguageModelCache } from '../languageModelCache';
import { LanguageService as HTMLLanguageService, HTMLDocument, DocumentContext, FormattingOptions, HTMLFormatConfiguration, ICompletionParticipant } from 'vscode-html-languageservice';
import { LanguageService as HTMLLanguageService, HTMLDocument, DocumentContext, FormattingOptions, HTMLFormatConfiguration } from 'vscode-html-languageservice';
import { TextDocument, Position, Range, CompletionItem } from 'vscode-languageserver-types';
import { LanguageMode, Workspace } from './languageModes';
@@ -18,7 +18,7 @@ export function getHTMLMode(htmlLanguageService: HTMLLanguageService, workspace:
getId() {
return 'html';
},
doComplete(document: TextDocument, position: Position, settings = workspace.settings, completionParticipants?: ICompletionParticipant[]) {
doComplete(document: TextDocument, position: Position, settings = workspace.settings) {
let options = settings && settings.html && settings.html.suggest;
let doAutoComplete = settings && settings.html && settings.html.autoClosingTags;
if (doAutoComplete) {
@@ -26,9 +26,6 @@ export function getHTMLMode(htmlLanguageService: HTMLLanguageService, workspace:
}
let pathCompletionProposals: CompletionItem[] = [];
let participants = [getPathCompletionParticipant(document, workspace.folders, pathCompletionProposals)];
if (completionParticipants) {
participants.push(...completionParticipants);
}
htmlLanguageService.setCompletionParticipants(participants);
const htmlDocument = htmlDocuments.get(document);

View File

@@ -24,7 +24,6 @@ export interface Settings {
css?: any;
html?: any;
javascript?: any;
emmet?: { [key: string]: any };
}
export interface Workspace {
@@ -35,7 +34,7 @@ export interface Workspace {
export interface LanguageMode {
getId(): string;
doValidation?: (document: TextDocument, settings?: Settings) => Diagnostic[];
doComplete?: (document: TextDocument, position: Position, settings?: Settings, registeredCompletionParticipants?: any[]) => CompletionList;
doComplete?: (document: TextDocument, position: Position, settings?: Settings) => CompletionList;
doResolve?: (document: TextDocument, item: CompletionItem) => CompletionItem;
doHover?: (document: TextDocument, position: Position) => Hover | null;
doSignatureHelp?: (document: TextDocument, position: Position) => SignatureHelp | null;

View File

@@ -1,72 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import 'mocha';
import * as assert from 'assert';
import { getHTMLMode } from '../modes/htmlMode';
import { TextDocument, CompletionList } from 'vscode-languageserver-types';
import { getLanguageModelCache } from '../languageModelCache';
import { getLanguageService } from 'vscode-html-languageservice';
import * as embeddedSupport from '../modes/embeddedSupport';
import { getEmmetCompletionParticipants } from 'vscode-emmet-helper';
import { getCSSMode } from '../modes/cssMode';
suite('HTML Emmet Support', () => {
const htmlLanguageService = getLanguageService();
function assertCompletions(syntax: string, value: string, expectedProposal: string | null, expectedProposalDoc: string | null): void {
const offset = value.indexOf('|');
value = value.substr(0, offset) + value.substr(offset + 1);
const workspace = {
settings: {},
folders: [{ name: 'test', uri: 'test://test' }]
};
const document = TextDocument.create('test://test/test.' + syntax, syntax, 0, value);
const position = document.positionAt(offset);
const documentRegions = getLanguageModelCache<embeddedSupport.HTMLDocumentRegions>(10, 60, document => embeddedSupport.getDocumentRegions(htmlLanguageService, document));
const mode = syntax === 'html' ? getHTMLMode(htmlLanguageService, workspace) : getCSSMode(documentRegions, workspace);
const emmetCompletionList = CompletionList.create([], false);
const emmetParticipant = getEmmetCompletionParticipants(document, position, document.languageId, {}, emmetCompletionList);
const list = mode.doComplete!(document, position, {}, [emmetParticipant]);
assert.ok(list);
assert.ok(emmetCompletionList);
let actualLabels = emmetCompletionList.items.map(c => c.label).sort();
let actualDocs = emmetCompletionList.items.map(c => c.documentation).sort();
if (expectedProposal && expectedProposalDoc) {
assert.ok(actualLabels.indexOf(expectedProposal) !== -1, value + ': Not found:' + expectedProposal + ' is ' + actualLabels.join(', '));
assert.ok(actualDocs.indexOf(expectedProposalDoc) !== -1, value + ': Not found:' + expectedProposalDoc + ' is ' + actualDocs.join(', '));
} else {
assert.ok(!emmetCompletionList.items.length && !emmetCompletionList.isIncomplete, value + ': No proposals expected, but was ' + actualLabels.join(', '));
}
}
test('Html Emmet Completions', function (): any {
assertCompletions('html', 'ul|', 'ul', '<ul>|</ul>');
assertCompletions('html', '<ul|', null, null);
assertCompletions('html', '<html>ul|</html>', 'ul', '<ul>|</ul>');
assertCompletions('html', '<img src=|', null, null);
assertCompletions('html', '<div class=|/>', null, null);
});
test('Css Emmet Completions', function (): any {
assertCompletions('css', '<style>.foo { display: none; m10| }</style>', 'margin: 10px;', 'margin: 10px;');
assertCompletions('css', '<style>foo { display: none; pos:f| }</style>', 'position: fixed;', 'position: fixed;');
// assertCompletions('css', '<style>foo { display: none; margin: a| }</style>', null, null); // disabled for #29113
// assertCompletions('css', '<style>foo| { display: none; }</style>', null, null); // disabled for #29113
assertCompletions('css', '<style>foo {| display: none; }</style>', null, null);
assertCompletions('css', '<style>foo { display: none;| }</style>', null, null);
assertCompletions('css', '<style>foo { display: none|; }</style>', null, null);
assertCompletions('css', '<style>.foo { display: none; -m-m10| }</style>', 'margin: 10px;', '-moz-margin: 10px;\nmargin: 10px;');
});
});