mirror of
https://github.com/microsoft/vscode.git
synced 2026-05-01 22:12:26 +01:00
Move emmet from html extenstion to emmet extension
This commit is contained in:
@@ -9,7 +9,6 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"vscode-css-languageservice": "^3.0.9-next.10",
|
||||
"vscode-emmet-helper": "1.2.6",
|
||||
"vscode-html-languageservice": "^2.1.3-next.3",
|
||||
"vscode-languageserver": "^4.0.0",
|
||||
"vscode-languageserver-protocol-foldingprovider": "^2.0.0-next.2",
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;');
|
||||
});
|
||||
});
|
||||
@@ -2,10 +2,6 @@
|
||||
# yarn lockfile v1
|
||||
|
||||
|
||||
"@emmetio/extract-abbreviation@0.1.6":
|
||||
version "0.1.6"
|
||||
resolved "https://registry.yarnpkg.com/@emmetio/extract-abbreviation/-/extract-abbreviation-0.1.6.tgz#e4a9856c1057f0aff7d443b8536477c243abe28c"
|
||||
|
||||
"@types/mocha@2.2.33":
|
||||
version "2.2.33"
|
||||
resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-2.2.33.tgz#d79a0061ec270379f4d9e225f4096fb436669def"
|
||||
@@ -14,10 +10,6 @@
|
||||
version "7.0.43"
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-7.0.43.tgz#a187e08495a075f200ca946079c914e1a5fe962c"
|
||||
|
||||
jsonc-parser@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/jsonc-parser/-/jsonc-parser-1.0.0.tgz#ddcc864ae708e60a7a6dd36daea00172fa8d9272"
|
||||
|
||||
vscode-css-languageservice@^3.0.9-next.10:
|
||||
version "3.0.9-next.10"
|
||||
resolved "https://registry.yarnpkg.com/vscode-css-languageservice/-/vscode-css-languageservice-3.0.9-next.10.tgz#be73d571221176b43d2c398a4a27f7d38206952d"
|
||||
@@ -25,14 +17,6 @@ vscode-css-languageservice@^3.0.9-next.10:
|
||||
vscode-languageserver-types "^3.6.1"
|
||||
vscode-nls "^3.2.1"
|
||||
|
||||
vscode-emmet-helper@1.2.6:
|
||||
version "1.2.6"
|
||||
resolved "https://registry.yarnpkg.com/vscode-emmet-helper/-/vscode-emmet-helper-1.2.6.tgz#6cc7293765af7136d409d0d62ef17c66e8b9cf45"
|
||||
dependencies:
|
||||
"@emmetio/extract-abbreviation" "0.1.6"
|
||||
jsonc-parser "^1.0.0"
|
||||
vscode-languageserver-types "^3.6.0-next.1"
|
||||
|
||||
vscode-html-languageservice@^2.1.3-next.3:
|
||||
version "2.1.3-next.3"
|
||||
resolved "https://registry.yarnpkg.com/vscode-html-languageservice/-/vscode-html-languageservice-2.1.3-next.3.tgz#20c4a0ae673815b598a7e132b5ef03a6920fa7af"
|
||||
@@ -63,10 +47,6 @@ vscode-languageserver-types@^3.6.0, vscode-languageserver-types@^3.6.1:
|
||||
version "3.6.1"
|
||||
resolved "https://registry.yarnpkg.com/vscode-languageserver-types/-/vscode-languageserver-types-3.6.1.tgz#4bc06a48dff653495f12f94b8b1e228988a1748d"
|
||||
|
||||
vscode-languageserver-types@^3.6.0-next.1:
|
||||
version "3.6.0-next.1"
|
||||
resolved "https://registry.yarnpkg.com/vscode-languageserver-types/-/vscode-languageserver-types-3.6.0-next.1.tgz#98e488d3f87b666b4ee1a3d89f0023e246d358f3"
|
||||
|
||||
vscode-languageserver@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/vscode-languageserver/-/vscode-languageserver-4.0.0.tgz#8b792f0d6d10acfe363d02371ed4ce53d08af88a"
|
||||
|
||||
Reference in New Issue
Block a user