mirror of
https://github.com/Microsoft/vscode
synced 2024-08-27 21:09:43 +00:00
[html] add css support to html extension as library
This commit is contained in:
parent
332fd57d3f
commit
8a85fc0399
|
@ -5,7 +5,6 @@
|
|||
'use strict';
|
||||
|
||||
import { window, workspace, DecorationOptions, DecorationRenderOptions, Disposable, Range, TextDocument, TextEditor } from 'vscode';
|
||||
import { isEmbeddedContentUri, getHostDocumentUri } from './embeddedContentUri';
|
||||
|
||||
const MAX_DECORATORS = 500;
|
||||
|
||||
|
@ -64,9 +63,8 @@ export function activateColorDecorations(decoratorProvider: (uri: string) => The
|
|||
if (triggerUpdate) {
|
||||
pendingUpdateRequests[documentUriStr] = setTimeout(() => {
|
||||
// check if the document is in use by an active editor
|
||||
let contentHostUri = isEmbeddedContentUri(documentUri) ? getHostDocumentUri(documentUri) : documentUriStr;
|
||||
window.visibleTextEditors.forEach(editor => {
|
||||
if (editor.document && contentHostUri === editor.document.uri.toString()) {
|
||||
if (editor.document && documentUriStr === editor.document.uri.toString()) {
|
||||
updateDecorationForEditor(editor, documentUriStr);
|
||||
}
|
||||
});
|
||||
|
|
|
@ -1,27 +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 { Uri } from 'vscode';
|
||||
|
||||
export const EMBEDDED_CONTENT_SCHEME = 'embedded-content';
|
||||
|
||||
export function isEmbeddedContentUri(virtualDocumentUri: Uri): boolean {
|
||||
return virtualDocumentUri.scheme === EMBEDDED_CONTENT_SCHEME;
|
||||
}
|
||||
|
||||
export function getEmbeddedContentUri(parentDocumentUri: string, embeddedLanguageId: string): Uri {
|
||||
return new Uri().with({ scheme: EMBEDDED_CONTENT_SCHEME, authority: embeddedLanguageId, path: '/' + encodeURIComponent(parentDocumentUri) + '.' + embeddedLanguageId });
|
||||
};
|
||||
|
||||
export function getHostDocumentUri(virtualDocumentUri: Uri): string {
|
||||
let languageId = virtualDocumentUri.authority;
|
||||
let path = virtualDocumentUri.path.substring(1, virtualDocumentUri.path.length - languageId.length - 1); // remove leading '/' and new file extension
|
||||
return decodeURIComponent(path);
|
||||
};
|
||||
|
||||
export function getEmbeddedLanguageId(virtualDocumentUri: Uri): string {
|
||||
return virtualDocumentUri.authority;
|
||||
}
|
|
@ -9,8 +9,7 @@
|
|||
},
|
||||
"dependencies": {
|
||||
"vscode-css-languageservice": "^1.1.0",
|
||||
"vscode-languageserver": "^2.4.0-next.12",
|
||||
"vscode-uri": "^1.0.0"
|
||||
"vscode-languageserver": "^2.4.0-next.12"
|
||||
},
|
||||
"scripts": {
|
||||
"compile": "gulp compile-extension:css-server",
|
||||
|
|
|
@ -11,8 +11,6 @@ import {
|
|||
|
||||
import { getCSSLanguageService, getSCSSLanguageService, getLESSLanguageService, LanguageSettings, LanguageService, Stylesheet } from 'vscode-css-languageservice';
|
||||
import { getLanguageModelCache } from './languageModelCache';
|
||||
import Uri from 'vscode-uri';
|
||||
import { isEmbeddedContentUri, getHostDocumentUri } from './embeddedContentUri';
|
||||
|
||||
namespace ColorSymbolRequest {
|
||||
export const type: RequestType<string, Range[], any> = { get method() { return 'css/colorSymbols'; } };
|
||||
|
@ -127,9 +125,7 @@ function validateTextDocument(textDocument: TextDocument): void {
|
|||
let stylesheet = stylesheets.get(textDocument);
|
||||
let diagnostics = getLanguageService(textDocument).doValidation(textDocument, stylesheet);
|
||||
// Send the computed diagnostics to VSCode.
|
||||
let uri = Uri.parse(textDocument.uri);
|
||||
let diagnosticsTarget = isEmbeddedContentUri(uri) ? getHostDocumentUri(uri) : textDocument.uri;
|
||||
connection.sendDiagnostics({ uri: diagnosticsTarget, diagnostics });
|
||||
connection.sendDiagnostics({ uri: textDocument.uri, diagnostics });
|
||||
}
|
||||
|
||||
connection.onCompletion(textDocumentPosition => {
|
||||
|
|
|
@ -1,27 +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 Uri from 'vscode-uri';
|
||||
|
||||
export const EMBEDDED_CONTENT_SCHEME = 'embedded-content';
|
||||
|
||||
export function isEmbeddedContentUri(virtualDocumentUri: Uri): boolean {
|
||||
return virtualDocumentUri.scheme === EMBEDDED_CONTENT_SCHEME;
|
||||
}
|
||||
|
||||
export function getEmbeddedContentUri(parentDocumentUri: string, embeddedLanguageId: string): Uri {
|
||||
return Uri.from({ scheme: EMBEDDED_CONTENT_SCHEME, authority: embeddedLanguageId, path: '/' + encodeURIComponent(parentDocumentUri) + '.' + embeddedLanguageId });
|
||||
};
|
||||
|
||||
export function getHostDocumentUri(virtualDocumentUri: Uri): string {
|
||||
let languageId = virtualDocumentUri.authority;
|
||||
let path = virtualDocumentUri.path.substring(1, virtualDocumentUri.path.length - languageId.length - 1); // remove leading '/' and new file extension
|
||||
return decodeURIComponent(path);
|
||||
};
|
||||
|
||||
export function getEmbeddedLanguageId(virtualDocumentUri: Uri): string {
|
||||
return virtualDocumentUri.authority;
|
||||
}
|
95
extensions/html/client/src/colorDecorators.ts
Normal file
95
extensions/html/client/src/colorDecorators.ts
Normal file
|
@ -0,0 +1,95 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* 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 { window, workspace, DecorationOptions, DecorationRenderOptions, Disposable, Range, TextDocument, TextEditor } from 'vscode';
|
||||
|
||||
const MAX_DECORATORS = 500;
|
||||
|
||||
let decorationType: DecorationRenderOptions = {
|
||||
before: {
|
||||
contentText: ' ',
|
||||
border: 'solid 0.1em #000',
|
||||
margin: '0.1em 0.2em 0 0.2em',
|
||||
width: '0.8em',
|
||||
height: '0.8em'
|
||||
},
|
||||
dark: {
|
||||
before: {
|
||||
border: 'solid 0.1em #eee'
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export function activateColorDecorations(decoratorProvider: (uri: string) => Thenable<Range[]>, supportedLanguages: { [id: string]: boolean }): Disposable {
|
||||
|
||||
let disposables: Disposable[] = [];
|
||||
|
||||
let colorsDecorationType = window.createTextEditorDecorationType(decorationType);
|
||||
disposables.push(colorsDecorationType);
|
||||
|
||||
let pendingUpdateRequests: { [key: string]: NodeJS.Timer; } = {};
|
||||
|
||||
// we care about all visible editors
|
||||
window.visibleTextEditors.forEach(editor => {
|
||||
if (editor.document) {
|
||||
triggerUpdateDecorations(editor.document);
|
||||
}
|
||||
});
|
||||
// to get visible one has to become active
|
||||
window.onDidChangeActiveTextEditor(editor => {
|
||||
if (editor) {
|
||||
triggerUpdateDecorations(editor.document);
|
||||
}
|
||||
}, null, disposables);
|
||||
|
||||
workspace.onDidChangeTextDocument(event => triggerUpdateDecorations(event.document), null, disposables);
|
||||
workspace.onDidOpenTextDocument(triggerUpdateDecorations, null, disposables);
|
||||
workspace.onDidCloseTextDocument(triggerUpdateDecorations, null, disposables);
|
||||
|
||||
workspace.textDocuments.forEach(triggerUpdateDecorations);
|
||||
|
||||
function triggerUpdateDecorations(document: TextDocument) {
|
||||
let triggerUpdate = supportedLanguages[document.languageId];
|
||||
let documentUri = document.uri;
|
||||
let documentUriStr = documentUri.toString();
|
||||
let timeout = pendingUpdateRequests[documentUriStr];
|
||||
if (typeof timeout !== 'undefined') {
|
||||
clearTimeout(timeout);
|
||||
triggerUpdate = true; // force update, even if languageId is not supported (anymore)
|
||||
}
|
||||
if (triggerUpdate) {
|
||||
pendingUpdateRequests[documentUriStr] = setTimeout(() => {
|
||||
// check if the document is in use by an active editor
|
||||
window.visibleTextEditors.forEach(editor => {
|
||||
if (editor.document && documentUriStr === editor.document.uri.toString()) {
|
||||
updateDecorationForEditor(editor, documentUriStr);
|
||||
}
|
||||
});
|
||||
delete pendingUpdateRequests[documentUriStr];
|
||||
}, 500);
|
||||
}
|
||||
}
|
||||
|
||||
function updateDecorationForEditor(editor: TextEditor, contentUri: string) {
|
||||
let document = editor.document;
|
||||
decoratorProvider(contentUri).then(ranges => {
|
||||
let decorations = ranges.slice(0, MAX_DECORATORS).map(range => {
|
||||
let color = document.getText(range);
|
||||
return <DecorationOptions>{
|
||||
range: range,
|
||||
renderOptions: {
|
||||
before: {
|
||||
backgroundColor: color
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
editor.setDecorations(colorsDecorationType, decorations);
|
||||
});
|
||||
}
|
||||
|
||||
return Disposable.from(...disposables);
|
||||
}
|
|
@ -1,124 +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 { workspace, Uri, EventEmitter, Disposable, TextDocument } from 'vscode';
|
||||
import { LanguageClient, RequestType, NotificationType } from 'vscode-languageclient';
|
||||
import { getEmbeddedContentUri, getEmbeddedLanguageId, getHostDocumentUri, isEmbeddedContentUri, EMBEDDED_CONTENT_SCHEME } from './embeddedContentUri';
|
||||
|
||||
interface EmbeddedContentParams {
|
||||
uri: string;
|
||||
embeddedLanguageId: string;
|
||||
}
|
||||
|
||||
interface EmbeddedContent {
|
||||
content: string;
|
||||
version: number;
|
||||
}
|
||||
|
||||
namespace EmbeddedContentRequest {
|
||||
export const type: RequestType<EmbeddedContentParams, EmbeddedContent, any> = { get method() { return 'embedded/content'; } };
|
||||
}
|
||||
|
||||
export interface EmbeddedDocuments extends Disposable {
|
||||
getEmbeddedContentUri: (parentDocumentUri: string, embeddedLanguageId: string) => Uri;
|
||||
openEmbeddedContentDocument: (embeddedContentUri: Uri, expectedVersion: number) => Thenable<TextDocument>;
|
||||
}
|
||||
|
||||
interface EmbeddedContentChangedParams {
|
||||
uri: string;
|
||||
version: number;
|
||||
embeddedLanguageIds: string[];
|
||||
}
|
||||
|
||||
namespace EmbeddedContentChangedNotification {
|
||||
export const type: NotificationType<EmbeddedContentChangedParams> = { get method() { return 'embedded/contentchanged'; } };
|
||||
}
|
||||
|
||||
export function initializeEmbeddedContentDocuments(parentDocumentSelector: string[], embeddedLanguages: { [languageId: string]: boolean }, client: LanguageClient): EmbeddedDocuments {
|
||||
let toDispose: Disposable[] = [];
|
||||
|
||||
let embeddedContentChanged = new EventEmitter<Uri>();
|
||||
|
||||
// remember all open virtual documents with the version of the content
|
||||
let openVirtualDocuments: { [uri: string]: number } = {};
|
||||
|
||||
// documents are closed after a time out or when collected.
|
||||
toDispose.push(workspace.onDidCloseTextDocument(d => {
|
||||
if (isEmbeddedContentUri(d.uri)) {
|
||||
delete openVirtualDocuments[d.uri.toString()];
|
||||
}
|
||||
}));
|
||||
|
||||
// virtual document provider
|
||||
toDispose.push(workspace.registerTextDocumentContentProvider(EMBEDDED_CONTENT_SCHEME, {
|
||||
provideTextDocumentContent: uri => {
|
||||
if (isEmbeddedContentUri(uri)) {
|
||||
let contentRequestParms = { uri: getHostDocumentUri(uri), embeddedLanguageId: getEmbeddedLanguageId(uri) };
|
||||
return client.sendRequest(EmbeddedContentRequest.type, contentRequestParms).then(content => {
|
||||
if (content) {
|
||||
openVirtualDocuments[uri.toString()] = content.version;
|
||||
return content.content;
|
||||
} else {
|
||||
delete openVirtualDocuments[uri.toString()];
|
||||
return '';
|
||||
}
|
||||
});
|
||||
}
|
||||
return '';
|
||||
},
|
||||
onDidChange: embeddedContentChanged.event
|
||||
}));
|
||||
|
||||
// diagnostics for embedded contents
|
||||
client.onNotification(EmbeddedContentChangedNotification.type, p => {
|
||||
for (let languageId in embeddedLanguages) {
|
||||
if (p.embeddedLanguageIds.indexOf(languageId) !== -1) {
|
||||
// open the document so that validation is triggered in the embedded mode
|
||||
let virtualUri = getEmbeddedContentUri(p.uri, languageId);
|
||||
openEmbeddedContentDocument(virtualUri, p.version);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
function ensureContentUpdated(virtualURI: Uri, expectedVersion: number) {
|
||||
let virtualURIString = virtualURI.toString();
|
||||
let virtualDocVersion = openVirtualDocuments[virtualURIString];
|
||||
if (isDefined(virtualDocVersion) && virtualDocVersion !== expectedVersion) {
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
let subscription = workspace.onDidChangeTextDocument(d => {
|
||||
if (d.document.uri.toString() === virtualURIString) {
|
||||
subscription.dispose();
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
embeddedContentChanged.fire(virtualURI);
|
||||
});
|
||||
}
|
||||
return Promise.resolve();
|
||||
};
|
||||
|
||||
function openEmbeddedContentDocument(virtualURI: Uri, expectedVersion: number): Thenable<TextDocument> {
|
||||
return ensureContentUpdated(virtualURI, expectedVersion).then(_ => {
|
||||
return workspace.openTextDocument(virtualURI).then(document => {
|
||||
if (expectedVersion === openVirtualDocuments[virtualURI.toString()]) {
|
||||
return document;
|
||||
}
|
||||
return void 0;
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
return {
|
||||
getEmbeddedContentUri,
|
||||
openEmbeddedContentDocument,
|
||||
dispose: Disposable.from(...toDispose).dispose
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
function isDefined(o: any) {
|
||||
return typeof o !== 'undefined';
|
||||
}
|
|
@ -1,27 +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 { Uri } from 'vscode';
|
||||
|
||||
export const EMBEDDED_CONTENT_SCHEME = 'embedded-content';
|
||||
|
||||
export function isEmbeddedContentUri(virtualDocumentUri: Uri): boolean {
|
||||
return virtualDocumentUri.scheme === EMBEDDED_CONTENT_SCHEME;
|
||||
}
|
||||
|
||||
export function getEmbeddedContentUri(parentDocumentUri: string, embeddedLanguageId: string): Uri {
|
||||
return new Uri().with({ scheme: EMBEDDED_CONTENT_SCHEME, authority: embeddedLanguageId, path: '/' + encodeURIComponent(parentDocumentUri) + '.' + embeddedLanguageId });
|
||||
};
|
||||
|
||||
export function getHostDocumentUri(virtualDocumentUri: Uri): string {
|
||||
let languageId = virtualDocumentUri.authority;
|
||||
let path = virtualDocumentUri.path.substring(1, virtualDocumentUri.path.length - languageId.length - 1); // remove leading '/' and new file extension
|
||||
return decodeURIComponent(path);
|
||||
};
|
||||
|
||||
export function getEmbeddedLanguageId(virtualDocumentUri: Uri): string {
|
||||
return virtualDocumentUri.authority;
|
||||
}
|
|
@ -6,35 +6,16 @@
|
|||
|
||||
import * as path from 'path';
|
||||
|
||||
import { languages, workspace, ExtensionContext, IndentAction, commands, CompletionList, Hover } from 'vscode';
|
||||
import { LanguageClient, LanguageClientOptions, ServerOptions, TransportKind, Position, RequestType, Protocol2Code, Code2Protocol } from 'vscode-languageclient';
|
||||
import { CompletionList as LSCompletionList, Hover as LSHover } from 'vscode-languageserver-types';
|
||||
import { languages, workspace, ExtensionContext, IndentAction } from 'vscode';
|
||||
import { LanguageClient, LanguageClientOptions, ServerOptions, TransportKind, Range, RequestType, Protocol2Code } from 'vscode-languageclient';
|
||||
import { EMPTY_ELEMENTS } from './htmlEmptyTagsShared';
|
||||
import { initializeEmbeddedContentDocuments } from './embeddedContentDocuments';
|
||||
import { activateColorDecorations } from './colorDecorators';
|
||||
|
||||
import * as nls from 'vscode-nls';
|
||||
let localize = nls.loadMessageBundle();
|
||||
|
||||
interface EmbeddedCompletionParams {
|
||||
uri: string;
|
||||
version: number;
|
||||
embeddedLanguageId: string;
|
||||
position: Position;
|
||||
}
|
||||
|
||||
namespace EmbeddedCompletionRequest {
|
||||
export const type: RequestType<EmbeddedCompletionParams, LSCompletionList, any> = { get method() { return 'embedded/completion'; } };
|
||||
}
|
||||
|
||||
interface EmbeddedHoverParams {
|
||||
uri: string;
|
||||
version: number;
|
||||
embeddedLanguageId: string;
|
||||
position: Position;
|
||||
}
|
||||
|
||||
namespace EmbeddedHoverRequest {
|
||||
export const type: RequestType<EmbeddedHoverParams, LSHover, any> = { get method() { return 'embedded/hover'; } };
|
||||
namespace ColorSymbolRequest {
|
||||
export const type: RequestType<string, Range[], any> = { get method() { return 'css/colorSymbols'; } };
|
||||
}
|
||||
|
||||
export function activate(context: ExtensionContext) {
|
||||
|
@ -67,56 +48,20 @@ export function activate(context: ExtensionContext) {
|
|||
};
|
||||
|
||||
// Create the language client and start the client.
|
||||
let client = new LanguageClient('html', localize('htmlserver.name', 'HTML Language Server'), serverOptions, clientOptions);
|
||||
|
||||
let embeddedDocuments = initializeEmbeddedContentDocuments(documentSelector, embeddedLanguages, client);
|
||||
context.subscriptions.push(embeddedDocuments);
|
||||
|
||||
client.onRequest(EmbeddedCompletionRequest.type, params => {
|
||||
let position = Protocol2Code.asPosition(params.position);
|
||||
let virtualDocumentURI = embeddedDocuments.getEmbeddedContentUri(params.uri, params.embeddedLanguageId);
|
||||
|
||||
return embeddedDocuments.openEmbeddedContentDocument(virtualDocumentURI, params.version).then(document => {
|
||||
if (document) {
|
||||
return commands.executeCommand<CompletionList>('vscode.executeCompletionItemProvider', virtualDocumentURI, position).then(completionList => {
|
||||
if (completionList) {
|
||||
return {
|
||||
isIncomplete: completionList.isIncomplete,
|
||||
items: completionList.items.map(Code2Protocol.asCompletionItem)
|
||||
};
|
||||
}
|
||||
return { isIncomplete: true, items: [] };
|
||||
});
|
||||
}
|
||||
return { isIncomplete: true, items: [] };
|
||||
});
|
||||
});
|
||||
|
||||
client.onRequest(EmbeddedHoverRequest.type, params => {
|
||||
let position = Protocol2Code.asPosition(params.position);
|
||||
let virtualDocumentURI = embeddedDocuments.getEmbeddedContentUri(params.uri, params.embeddedLanguageId);
|
||||
return embeddedDocuments.openEmbeddedContentDocument(virtualDocumentURI, params.version).then(document => {
|
||||
if (document) {
|
||||
return commands.executeCommand<Hover[]>('vscode.executeHoverProvider', virtualDocumentURI, position).then(hover => {
|
||||
if (hover && hover.length > 0) {
|
||||
return <LSHover>{
|
||||
contents: hover[0].contents,
|
||||
range: Code2Protocol.asRange(hover[0].range)
|
||||
};
|
||||
}
|
||||
return void 0;
|
||||
});
|
||||
}
|
||||
return void 0;
|
||||
});
|
||||
});
|
||||
|
||||
let client = new LanguageClient('html', localize('htmlserver.name', 'HTML Language Server'), serverOptions, clientOptions, true);
|
||||
let disposable = client.start();
|
||||
|
||||
// Push the disposable to the context's subscriptions so that the
|
||||
// client can be deactivated on extension deactivation
|
||||
context.subscriptions.push(disposable);
|
||||
|
||||
let colorRequestor = (uri: string) => {
|
||||
return client.sendRequest(ColorSymbolRequest.type, uri).then(ranges => ranges.map(Protocol2Code.asRange));
|
||||
};
|
||||
disposable = activateColorDecorations(colorRequestor, { html: true, handlebars: true, razor: true });
|
||||
context.subscriptions.push(disposable);
|
||||
|
||||
|
||||
languages.setLanguageConfiguration('html', {
|
||||
wordPattern: /(-?\d*\.\d\w*)|([^\`\~\!\@\$\^\&\*\(\)\=\+\[\{\]\}\\\|\;\:\'\"\,\.\<\>\/\s]+)/g,
|
||||
onEnterRules: [
|
||||
|
|
|
@ -143,7 +143,7 @@
|
|||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"vscode-languageclient": "^2.6.0-next.1",
|
||||
"vscode-languageclient": "^2.6.2",
|
||||
"vscode-languageserver-types": "^1.0.4",
|
||||
"vscode-nls": "^1.0.7"
|
||||
}
|
||||
|
|
|
@ -8,8 +8,9 @@
|
|||
"node": "*"
|
||||
},
|
||||
"dependencies": {
|
||||
"vscode-html-languageservice": "^1.0.0-next.9",
|
||||
"vscode-languageserver": "^2.6.0-next.3",
|
||||
"vscode-html-languageservice": "^1.0.0",
|
||||
"vscode-languageserver": "^2.6.1",
|
||||
"vscode-css-languageservice": "^1.1.0",
|
||||
"vscode-nls": "^1.0.4",
|
||||
"vscode-uri": "^1.0.0"
|
||||
},
|
||||
|
@ -19,6 +20,7 @@
|
|||
"install-service-next": "npm install vscode-html-languageservice@next -f -S",
|
||||
"install-service-local": "npm install ../../../../vscode-html-languageservice -f -S",
|
||||
"install-server-next": "npm install vscode-languageserver@next -f -S",
|
||||
"install-server-local": "npm install ../../../../vscode-languageserver-node/server -f -S"
|
||||
"install-server-local": "npm install ../../../../vscode-languageserver-node/server -f -S",
|
||||
"test": "mocha"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,14 +16,14 @@ export function getEmbeddedLanguageAtPosition(languageService: LanguageService,
|
|||
return embeddedContent.languageId;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
return 'html';
|
||||
}
|
||||
|
||||
export function hasEmbeddedContent(languageService: LanguageService, document: TextDocument, htmlDocument: HTMLDocument, embeddedLanguages: { [languageId: string]: boolean }): string[] {
|
||||
export function hasEmbeddedContent(languageService: LanguageService, document: TextDocument, htmlDocument: HTMLDocument): string[] {
|
||||
let embeddedLanguageIds: { [languageId: string]: boolean } = {};
|
||||
function collectEmbeddedLanguages(node: Node): void {
|
||||
let c = getEmbeddedContentForNode(languageService, document, node);
|
||||
if (c && embeddedLanguages[c.languageId] && !isWhitespace(document.getText().substring(c.start, c.end))) {
|
||||
if (c && !isWhitespace(document.getText().substring(c.start, c.end))) {
|
||||
embeddedLanguageIds[c.languageId] = true;
|
||||
}
|
||||
node.children.forEach(collectEmbeddedLanguages);
|
||||
|
@ -33,7 +33,7 @@ export function hasEmbeddedContent(languageService: LanguageService, document: T
|
|||
return Object.keys(embeddedLanguageIds);
|
||||
}
|
||||
|
||||
export function getEmbeddedContent(languageService: LanguageService, document: TextDocument, htmlDocument: HTMLDocument, languageId: string): string {
|
||||
export function getEmbeddedDocument(languageService: LanguageService, document: TextDocument, htmlDocument: HTMLDocument, languageId: string): TextDocument {
|
||||
let contents = [];
|
||||
function collectEmbeddedNodes(node: Node): void {
|
||||
let c = getEmbeddedContentForNode(languageService, document, node);
|
||||
|
@ -54,7 +54,7 @@ export function getEmbeddedContent(languageService: LanguageService, document: T
|
|||
currentPos = c.end;
|
||||
}
|
||||
result = substituteWithWhitespace(result, currentPos, oldContent.length, oldContent);
|
||||
return result;
|
||||
return TextDocument.create(document.uri, languageId, document.version, result);
|
||||
}
|
||||
|
||||
function substituteWithWhitespace(result, start, end, oldContent) {
|
||||
|
|
|
@ -4,14 +4,10 @@
|
|||
*--------------------------------------------------------------------------------------------*/
|
||||
'use strict';
|
||||
|
||||
import {
|
||||
createConnection, IConnection, TextDocuments, InitializeParams, InitializeResult, FormattingOptions, RequestType, NotificationType,
|
||||
CompletionList, Position, Hover
|
||||
} from 'vscode-languageserver';
|
||||
import { createConnection, IConnection, TextDocuments, InitializeParams, InitializeResult, RequestType } from 'vscode-languageserver';
|
||||
import { DocumentContext, TextDocument, Diagnostic, DocumentLink, Range } from 'vscode-html-languageservice';
|
||||
import { getLanguageModes } from './languageModes';
|
||||
|
||||
import { HTMLDocument, getLanguageService, CompletionConfiguration, HTMLFormatConfiguration, DocumentContext, TextDocument } from 'vscode-html-languageservice';
|
||||
import { getLanguageModelCache } from './languageModelCache';
|
||||
import { getEmbeddedContent, getEmbeddedLanguageAtPosition, hasEmbeddedContent } from './embeddedSupport';
|
||||
import * as url from 'url';
|
||||
import * as path from 'path';
|
||||
import uri from 'vscode-uri';
|
||||
|
@ -19,50 +15,8 @@ import uri from 'vscode-uri';
|
|||
import * as nls from 'vscode-nls';
|
||||
nls.config(process.env['VSCODE_NLS_CONFIG']);
|
||||
|
||||
interface EmbeddedCompletionParams {
|
||||
uri: string;
|
||||
version: number;
|
||||
embeddedLanguageId: string;
|
||||
position: Position;
|
||||
}
|
||||
|
||||
namespace EmbeddedCompletionRequest {
|
||||
export const type: RequestType<EmbeddedCompletionParams, CompletionList, any> = { get method() { return 'embedded/completion'; } };
|
||||
}
|
||||
|
||||
interface EmbeddedHoverParams {
|
||||
uri: string;
|
||||
version: number;
|
||||
embeddedLanguageId: string;
|
||||
position: Position;
|
||||
}
|
||||
|
||||
namespace EmbeddedHoverRequest {
|
||||
export const type: RequestType<EmbeddedCompletionParams, Hover, any> = { get method() { return 'embedded/hover'; } };
|
||||
}
|
||||
|
||||
interface EmbeddedContentParams {
|
||||
uri: string;
|
||||
embeddedLanguageId: string;
|
||||
}
|
||||
|
||||
interface EmbeddedContent {
|
||||
content: string;
|
||||
version: number;
|
||||
}
|
||||
|
||||
namespace EmbeddedContentRequest {
|
||||
export const type: RequestType<EmbeddedContentParams, EmbeddedContent, any> = { get method() { return 'embedded/content'; } };
|
||||
}
|
||||
|
||||
interface EmbeddedContentChangedParams {
|
||||
uri: string;
|
||||
version: number;
|
||||
embeddedLanguageIds: string[];
|
||||
}
|
||||
|
||||
namespace EmbeddedContentChangedNotification {
|
||||
export const type: NotificationType<EmbeddedContentChangedParams> = { get method() { return 'embedded/contentchanged'; } };
|
||||
namespace ColorSymbolRequest {
|
||||
export const type: RequestType<string, Range[], any> = { get method() { return 'css/colorSymbols'; } };
|
||||
}
|
||||
|
||||
// Create a connection for the server
|
||||
|
@ -78,22 +32,22 @@ let documents: TextDocuments = new TextDocuments();
|
|||
// for open, change and close text document events
|
||||
documents.listen(connection);
|
||||
|
||||
let htmlDocuments = getLanguageModelCache<HTMLDocument>(10, 60, document => getLanguageService().parseHTMLDocument(document));
|
||||
let languageModes = getLanguageModes({ 'css': true });
|
||||
|
||||
documents.onDidClose(e => {
|
||||
htmlDocuments.onDocumentRemoved(e.document);
|
||||
languageModes.getAllModes().forEach(m => m.onDocumentRemoved(e.document));
|
||||
});
|
||||
connection.onShutdown(() => {
|
||||
htmlDocuments.dispose();
|
||||
languageModes.getAllModes().forEach(m => m.dispose());
|
||||
});
|
||||
|
||||
let workspacePath: string;
|
||||
let embeddedLanguages: { [languageId: string]: boolean };
|
||||
|
||||
|
||||
// After the server has started the client sends an initilize request. The server receives
|
||||
// in the passed params the rootPath of the workspace plus the client capabilites
|
||||
connection.onInitialize((params: InitializeParams): InitializeResult => {
|
||||
workspacePath = params.rootPath;
|
||||
embeddedLanguages = params.initializationOptions.embeddedLanguages;
|
||||
return {
|
||||
capabilities: {
|
||||
// Tell the client that the server works in FULL text document sync mode
|
||||
|
@ -107,25 +61,10 @@ connection.onInitialize((params: InitializeParams): InitializeResult => {
|
|||
};
|
||||
});
|
||||
|
||||
// create the JSON language service
|
||||
var languageService = getLanguageService();
|
||||
|
||||
// The settings interface describes the server relevant settings part
|
||||
interface Settings {
|
||||
html: LanguageSettings;
|
||||
}
|
||||
|
||||
interface LanguageSettings {
|
||||
suggest: CompletionConfiguration;
|
||||
format: HTMLFormatConfiguration;
|
||||
}
|
||||
|
||||
let languageSettings: LanguageSettings;
|
||||
|
||||
// The settings have changed. Is send on server activation as well.
|
||||
connection.onDidChangeConfiguration((change) => {
|
||||
var settings = <Settings>change.settings;
|
||||
languageSettings = settings.html;
|
||||
languageModes.configure(change.settings);
|
||||
});
|
||||
|
||||
let pendingValidationRequests: { [uri: string]: NodeJS.Timer } = {};
|
||||
|
@ -140,10 +79,7 @@ documents.onDidChangeContent(change => {
|
|||
// a document has closed: clear all diagnostics
|
||||
documents.onDidClose(event => {
|
||||
cleanPendingValidation(event.document);
|
||||
//connection.sendDiagnostics({ uri: event.document.uri, diagnostics: [] });
|
||||
if (embeddedLanguages) {
|
||||
connection.sendNotification(EmbeddedContentChangedNotification.type, { uri: event.document.uri, version: event.document.version, embeddedLanguageIds: [] });
|
||||
}
|
||||
connection.sendDiagnostics({ uri: event.document.uri, diagnostics: [] });
|
||||
});
|
||||
|
||||
function cleanPendingValidation(textDocument: TextDocument): void {
|
||||
|
@ -163,79 +99,50 @@ function triggerValidation(textDocument: TextDocument): void {
|
|||
}
|
||||
|
||||
function validateTextDocument(textDocument: TextDocument): void {
|
||||
let htmlDocument = htmlDocuments.get(textDocument);
|
||||
//let diagnostics = languageService.doValidation(textDocument, htmlDocument);
|
||||
// Send the computed diagnostics to VSCode.
|
||||
//connection.sendDiagnostics({ uri: textDocument.uri, diagnostics });
|
||||
if (embeddedLanguages) {
|
||||
let embeddedLanguageIds = hasEmbeddedContent(languageService, textDocument, htmlDocument, embeddedLanguages);
|
||||
let p = { uri: textDocument.uri, version: textDocument.version, embeddedLanguageIds };
|
||||
connection.sendNotification(EmbeddedContentChangedNotification.type, p);
|
||||
}
|
||||
let diagnostics: Diagnostic[] = [];
|
||||
languageModes.getAllModesInDocument(textDocument).forEach(mode => {
|
||||
if (mode.doValidation) {
|
||||
diagnostics = diagnostics.concat(mode.doValidation(textDocument));
|
||||
}
|
||||
});
|
||||
connection.sendDiagnostics({ uri: textDocument.uri, diagnostics });
|
||||
}
|
||||
|
||||
connection.onCompletion(textDocumentPosition => {
|
||||
let document = documents.get(textDocumentPosition.textDocument.uri);
|
||||
let htmlDocument = htmlDocuments.get(document);
|
||||
let options = languageSettings && languageSettings.suggest;
|
||||
let list = languageService.doComplete(document, textDocumentPosition.position, htmlDocument, options);
|
||||
if (list.items.length === 0 && embeddedLanguages) {
|
||||
let embeddedLanguageId = getEmbeddedLanguageAtPosition(languageService, document, htmlDocument, textDocumentPosition.position);
|
||||
if (embeddedLanguageId && embeddedLanguages[embeddedLanguageId]) {
|
||||
return connection.sendRequest(EmbeddedCompletionRequest.type, { uri: document.uri, version: document.version, embeddedLanguageId, position: textDocumentPosition.position });
|
||||
}
|
||||
let mode = languageModes.getModeAtPosition(document, textDocumentPosition.position);
|
||||
if (mode && mode.doComplete) {
|
||||
return mode.doComplete(document, textDocumentPosition.position);
|
||||
}
|
||||
return list;
|
||||
return { isIncomplete: true, items: [] };
|
||||
});
|
||||
|
||||
connection.onHover(textDocumentPosition => {
|
||||
let document = documents.get(textDocumentPosition.textDocument.uri);
|
||||
let htmlDocument = htmlDocuments.get(document);
|
||||
let hover = languageService.doHover(document, textDocumentPosition.position, htmlDocument);
|
||||
if (!hover && embeddedLanguages) {
|
||||
let embeddedLanguageId = getEmbeddedLanguageAtPosition(languageService, document, htmlDocument, textDocumentPosition.position);
|
||||
if (embeddedLanguageId && embeddedLanguages[embeddedLanguageId]) {
|
||||
return connection.sendRequest(EmbeddedHoverRequest.type, { uri: document.uri, version: document.version, embeddedLanguageId, position: textDocumentPosition.position });
|
||||
}
|
||||
let mode = languageModes.getModeAtPosition(document, textDocumentPosition.position);
|
||||
if (mode && mode.doHover) {
|
||||
return mode.doHover(document, textDocumentPosition.position);
|
||||
}
|
||||
return hover;
|
||||
});
|
||||
|
||||
connection.onRequest(EmbeddedContentRequest.type, parms => {
|
||||
let document = documents.get(parms.uri);
|
||||
if (document) {
|
||||
let htmlDocument = htmlDocuments.get(document);
|
||||
return { content: getEmbeddedContent(languageService, document, htmlDocument, parms.embeddedLanguageId), version: document.version };
|
||||
}
|
||||
return void 0;
|
||||
return null;
|
||||
});
|
||||
|
||||
connection.onDocumentHighlight(documentHighlightParams => {
|
||||
let document = documents.get(documentHighlightParams.textDocument.uri);
|
||||
let htmlDocument = htmlDocuments.get(document);
|
||||
return languageService.findDocumentHighlights(document, documentHighlightParams.position, htmlDocument);
|
||||
let mode = languageModes.getModeAtPosition(document, documentHighlightParams.position);
|
||||
if (mode && mode.findDocumentHighlight) {
|
||||
return mode.findDocumentHighlight(document, documentHighlightParams.position);
|
||||
}
|
||||
return [];
|
||||
});
|
||||
|
||||
function merge(src: any, dst: any): any {
|
||||
for (var key in src) {
|
||||
if (src.hasOwnProperty(key)) {
|
||||
dst[key] = src[key];
|
||||
}
|
||||
}
|
||||
return dst;
|
||||
}
|
||||
|
||||
function getFormattingOptions(formatParams: FormattingOptions) {
|
||||
let formatSettings = languageSettings && languageSettings.format;
|
||||
if (!formatSettings) {
|
||||
return formatParams;
|
||||
}
|
||||
return merge(formatParams, merge(formatSettings, {}));
|
||||
}
|
||||
|
||||
connection.onDocumentRangeFormatting(formatParams => {
|
||||
let document = documents.get(formatParams.textDocument.uri);
|
||||
return languageService.format(document, formatParams.range, getFormattingOptions(formatParams.options));
|
||||
let startMode = languageModes.getModeAtPosition(document, formatParams.range.start);
|
||||
let endMode = languageModes.getModeAtPosition(document, formatParams.range.end);
|
||||
if (startMode && startMode === endMode && startMode.format) {
|
||||
return startMode.format(document, formatParams.range, formatParams.options);
|
||||
}
|
||||
return null;
|
||||
});
|
||||
|
||||
connection.onDocumentLinks(documentLinkParam => {
|
||||
|
@ -248,9 +155,27 @@ connection.onDocumentLinks(documentLinkParam => {
|
|||
return url.resolve(document.uri, ref);
|
||||
}
|
||||
};
|
||||
return languageService.findDocumentLinks(document, documentContext);
|
||||
let links: DocumentLink[] = [];
|
||||
languageModes.getAllModesInDocument(document).forEach(m => {
|
||||
if (m.findDocumentLinks) {
|
||||
links = links.concat(m.findDocumentLinks(document, documentContext));
|
||||
}
|
||||
});
|
||||
return links;
|
||||
});
|
||||
|
||||
connection.onRequest(ColorSymbolRequest.type, uri => {
|
||||
let ranges: Range[] = [];
|
||||
let document = documents.get(uri);
|
||||
if (document) {
|
||||
languageModes.getAllModesInDocument(document).forEach(m => {
|
||||
if (m.findColorSymbols) {
|
||||
ranges = ranges.concat(m.findColorSymbols(document));
|
||||
}
|
||||
});
|
||||
}
|
||||
return ranges;
|
||||
});
|
||||
|
||||
// Listen on the connection
|
||||
connection.listen();
|
164
extensions/html/server/src/languageModes.ts
Normal file
164
extensions/html/server/src/languageModes.ts
Normal file
|
@ -0,0 +1,164 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* 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 {
|
||||
TextDocument, Position, HTMLDocument, Diagnostic, CompletionList, Hover, getLanguageService as getHTMLLanguageService,
|
||||
DocumentHighlight, DocumentLink, DocumentContext, Range, TextEdit, FormattingOptions, CompletionConfiguration, HTMLFormatConfiguration
|
||||
} from 'vscode-html-languageservice';
|
||||
import { getCSSLanguageService, Stylesheet } from 'vscode-css-languageservice';
|
||||
|
||||
import { getLanguageModelCache } from './languageModelCache';
|
||||
import { getEmbeddedDocument, getEmbeddedLanguageAtPosition, hasEmbeddedContent } from './embeddedSupport';
|
||||
|
||||
export interface LanguageMode {
|
||||
doValidation?: (document: TextDocument) => Diagnostic[];
|
||||
doComplete?: (document: TextDocument, position: Position) => CompletionList;
|
||||
doHover?: (document: TextDocument, position: Position) => Hover;
|
||||
findDocumentHighlight?: (document: TextDocument, position: Position) => DocumentHighlight[];
|
||||
findDocumentLinks?: (document: TextDocument, documentContext: DocumentContext) => DocumentLink[];
|
||||
format?: (document: TextDocument, range: Range, options: FormattingOptions) => TextEdit[];
|
||||
findColorSymbols?: (document: TextDocument) => Range[];
|
||||
onDocumentRemoved(document: TextDocument): void;
|
||||
dispose(): void;
|
||||
}
|
||||
|
||||
// The settings interface describes the server relevant settings part
|
||||
export interface Settings {
|
||||
html: HTMLLanguageSettings;
|
||||
css: any;
|
||||
}
|
||||
|
||||
export interface HTMLLanguageSettings {
|
||||
suggest: CompletionConfiguration;
|
||||
format: HTMLFormatConfiguration;
|
||||
}
|
||||
|
||||
export interface LanguageModes {
|
||||
getModeAtPosition(document: TextDocument, position: Position): LanguageMode;
|
||||
getAllModesInDocument(document: TextDocument): LanguageMode[];
|
||||
getAllModes(): LanguageMode[];
|
||||
getMode(languageId: string): LanguageMode;
|
||||
configure(options: Settings): void;
|
||||
}
|
||||
|
||||
export function getLanguageModes(supportedLanguages: { [languageId: string]: boolean; }): LanguageModes {
|
||||
|
||||
var htmlLanguageService = getHTMLLanguageService();
|
||||
let htmlDocuments = getLanguageModelCache<HTMLDocument>(10, 60, document => htmlLanguageService.parseHTMLDocument(document));
|
||||
|
||||
let modes: { [id: string]: LanguageMode } = {};
|
||||
let settings: any = {};
|
||||
|
||||
supportedLanguages['html'] = true;
|
||||
modes['html'] = {
|
||||
doComplete(document: TextDocument, position: Position) {
|
||||
let options = settings && settings.html && settings.html.suggest;
|
||||
return htmlLanguageService.doComplete(document, position, htmlDocuments.get(document), options);
|
||||
},
|
||||
doHover(document: TextDocument, position: Position) {
|
||||
return htmlLanguageService.doHover(document, position, htmlDocuments.get(document));
|
||||
},
|
||||
findDocumentHighlight(document: TextDocument, position: Position) {
|
||||
return htmlLanguageService.findDocumentHighlights(document, position, htmlDocuments.get(document));
|
||||
},
|
||||
findDocumentLinks(document: TextDocument, documentContext: DocumentContext) {
|
||||
return htmlLanguageService.findDocumentLinks(document, documentContext);
|
||||
},
|
||||
format(document: TextDocument, range: Range, formatParams: FormattingOptions) {
|
||||
let formatSettings = settings && settings.html && settings.html.format;
|
||||
if (!formatSettings) {
|
||||
formatSettings = formatParams;
|
||||
} else {
|
||||
formatSettings = merge(formatParams, merge(formatSettings, {}));
|
||||
}
|
||||
return htmlLanguageService.format(document, range, formatSettings);
|
||||
},
|
||||
onDocumentRemoved(document: TextDocument) {
|
||||
htmlDocuments.onDocumentRemoved(document);
|
||||
},
|
||||
dispose() {
|
||||
htmlDocuments.dispose();
|
||||
}
|
||||
};
|
||||
if (supportedLanguages['css']) {
|
||||
let cssLanguageService = getCSSLanguageService();
|
||||
let cssStylesheets = getLanguageModelCache<Stylesheet>(10, 60, document => cssLanguageService.parseStylesheet(document));
|
||||
let getEmbeddedCSSDocument = (document: TextDocument) => getEmbeddedDocument(htmlLanguageService, document, htmlDocuments.get(document), 'css');
|
||||
|
||||
modes['css'] = {
|
||||
doValidation(document: TextDocument) {
|
||||
let embedded = getEmbeddedCSSDocument(document);
|
||||
return cssLanguageService.doValidation(embedded, cssStylesheets.get(embedded));
|
||||
},
|
||||
doComplete(document: TextDocument, position: Position) {
|
||||
let embedded = getEmbeddedCSSDocument(document);
|
||||
return cssLanguageService.doComplete(embedded, position, cssStylesheets.get(embedded));
|
||||
},
|
||||
doHover(document: TextDocument, position: Position) {
|
||||
let embedded = getEmbeddedCSSDocument(document);
|
||||
return cssLanguageService.doHover(embedded, position, cssStylesheets.get(embedded));
|
||||
},
|
||||
findDocumentHighlight(document: TextDocument, position: Position) {
|
||||
let embedded = getEmbeddedCSSDocument(document);
|
||||
return cssLanguageService.findDocumentHighlights(embedded, position, cssStylesheets.get(embedded));
|
||||
},
|
||||
findColorSymbols(document: TextDocument) {
|
||||
let embedded = getEmbeddedCSSDocument(document);
|
||||
return cssLanguageService.findColorSymbols(embedded, cssStylesheets.get(embedded));
|
||||
},
|
||||
onDocumentRemoved(document: TextDocument) {
|
||||
cssStylesheets.onDocumentRemoved(document);
|
||||
},
|
||||
dispose() {
|
||||
cssStylesheets.dispose();
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
return {
|
||||
getModeAtPosition(document: TextDocument, position: Position): LanguageMode {
|
||||
let languageId = getEmbeddedLanguageAtPosition(htmlLanguageService, document, htmlDocuments.get(document), position);
|
||||
if (supportedLanguages[languageId]) {
|
||||
return modes[languageId];
|
||||
}
|
||||
return null;
|
||||
},
|
||||
getAllModesInDocument(document: TextDocument): LanguageMode[] {
|
||||
let result = [modes['html']];
|
||||
let embeddedLanguageIds = hasEmbeddedContent(htmlLanguageService, document, htmlDocuments.get(document));
|
||||
for (let languageId of embeddedLanguageIds) {
|
||||
if (supportedLanguages[languageId]) {
|
||||
result.push(modes[languageId]);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
},
|
||||
getAllModes(): LanguageMode[] {
|
||||
let result = [];
|
||||
for (let languageId in modes) {
|
||||
if (supportedLanguages[languageId]) {
|
||||
result.push(modes[languageId]);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
},
|
||||
getMode(languageId: string): LanguageMode {
|
||||
return modes[languageId];
|
||||
},
|
||||
configure(options: any): void {
|
||||
settings = options;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function merge(src: any, dst: any): any {
|
||||
for (var key in src) {
|
||||
if (src.hasOwnProperty(key)) {
|
||||
dst[key] = src[key];
|
||||
}
|
||||
}
|
||||
return dst;
|
||||
}
|
|
@ -7,11 +7,11 @@
|
|||
import * as assert from 'assert';
|
||||
import * as embeddedSupport from '../embeddedSupport';
|
||||
import {TextDocument} from 'vscode-languageserver-types';
|
||||
|
||||
import { getLanguageService } from 'vscode-html-languageservice';
|
||||
import { getLanguageService} from 'vscode-html-languageservice';
|
||||
|
||||
suite('HTML Embedded Support', () => {
|
||||
|
||||
var htmlLanguageService = getLanguageService();
|
||||
|
||||
function assertEmbeddedLanguageId(value: string, expectedLanguageId: string): void {
|
||||
let offset = value.indexOf('|');
|
||||
|
@ -23,7 +23,7 @@ suite('HTML Embedded Support', () => {
|
|||
let ls = getLanguageService();
|
||||
let htmlDoc = ls.parseHTMLDocument(document);
|
||||
|
||||
let languageId = embeddedSupport.getEmbeddedLanguageAtPosition(ls, document, htmlDoc, position);
|
||||
let languageId = embeddedSupport.getEmbeddedLanguageAtPosition(htmlLanguageService, document, htmlDoc, position);
|
||||
assert.equal(languageId, expectedLanguageId);
|
||||
}
|
||||
|
||||
|
@ -34,18 +34,18 @@ suite('HTML Embedded Support', () => {
|
|||
let ls = getLanguageService();
|
||||
let htmlDoc = ls.parseHTMLDocument(document);
|
||||
|
||||
let content = embeddedSupport.getEmbeddedContent(ls, document, htmlDoc, languageId);
|
||||
assert.equal(content, expectedContent);
|
||||
let content = embeddedSupport.getEmbeddedDocument(ls, document, htmlDoc, languageId);
|
||||
assert.equal(content.getText(), expectedContent);
|
||||
}
|
||||
|
||||
test('Styles', function (): any {
|
||||
assertEmbeddedLanguageId('|<html><style>foo { }</style></html>', void 0);
|
||||
assertEmbeddedLanguageId('<html|><style>foo { }</style></html>', void 0);
|
||||
assertEmbeddedLanguageId('<html><st|yle>foo { }</style></html>', void 0);
|
||||
assertEmbeddedLanguageId('|<html><style>foo { }</style></html>', 'html');
|
||||
assertEmbeddedLanguageId('<html|><style>foo { }</style></html>', 'html');
|
||||
assertEmbeddedLanguageId('<html><st|yle>foo { }</style></html>', 'html');
|
||||
assertEmbeddedLanguageId('<html><style>|foo { }</style></html>', 'css');
|
||||
assertEmbeddedLanguageId('<html><style>foo| { }</style></html>', 'css');
|
||||
assertEmbeddedLanguageId('<html><style>foo { }|</style></html>', 'css');
|
||||
assertEmbeddedLanguageId('<html><style>foo { }</sty|le></html>', void 0);
|
||||
assertEmbeddedLanguageId('<html><style>foo { }</sty|le></html>', 'html');
|
||||
});
|
||||
|
||||
test('Style content', function (): any {
|
||||
|
@ -57,19 +57,19 @@ suite('HTML Embedded Support', () => {
|
|||
});
|
||||
|
||||
test('Scripts', function (): any {
|
||||
assertEmbeddedLanguageId('|<html><script>var i = 0;</script></html>', void 0);
|
||||
assertEmbeddedLanguageId('<html|><script>var i = 0;</script></html>', void 0);
|
||||
assertEmbeddedLanguageId('<html><scr|ipt>var i = 0;</script></html>', void 0);
|
||||
assertEmbeddedLanguageId('|<html><script>var i = 0;</script></html>', 'html');
|
||||
assertEmbeddedLanguageId('<html|><script>var i = 0;</script></html>', 'html');
|
||||
assertEmbeddedLanguageId('<html><scr|ipt>var i = 0;</script></html>', 'html');
|
||||
assertEmbeddedLanguageId('<html><script>|var i = 0;</script></html>', 'javascript');
|
||||
assertEmbeddedLanguageId('<html><script>var| i = 0;</script></html>', 'javascript');
|
||||
assertEmbeddedLanguageId('<html><script>var i = 0;|</script></html>', 'javascript');
|
||||
assertEmbeddedLanguageId('<html><script>var i = 0;</scr|ipt></html>', void 0);
|
||||
assertEmbeddedLanguageId('<html><script>var i = 0;</scr|ipt></html>', 'html');
|
||||
|
||||
assertEmbeddedLanguageId('<script type="text/javascript">var| i = 0;</script>', 'javascript');
|
||||
assertEmbeddedLanguageId('<script type="text/ecmascript">var| i = 0;</script>', 'javascript');
|
||||
assertEmbeddedLanguageId('<script type="application/javascript">var| i = 0;</script>', 'javascript');
|
||||
assertEmbeddedLanguageId('<script type="application/ecmascript">var| i = 0;</script>', 'javascript');
|
||||
assertEmbeddedLanguageId('<script type="application/typescript">var| i = 0;</script>', void 0);
|
||||
assertEmbeddedLanguageId('<script type="application/typescript">var| i = 0;</script>', 'html');
|
||||
assertEmbeddedLanguageId('<script type=\'text/javascript\'>var| i = 0;</script>', 'javascript');
|
||||
});
|
||||
|
||||
|
|
|
@ -1,27 +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 * as assert from 'assert';
|
||||
import {getEmbeddedContentUri, getEmbeddedLanguageId, getHostDocumentUri, isEmbeddedContentUri} from './embeddedContentUri';
|
||||
|
||||
suite('Embedded URI', () => {
|
||||
|
||||
test('URI', function (): any {
|
||||
let resourceUri1 = 'file:///c%3A/workspaces/samples/foo.html';
|
||||
let resourceUri2 = 'file://Users/joe/samples/foo.html';
|
||||
|
||||
let uri = getEmbeddedContentUri(resourceUri1, 'css');
|
||||
assert(isEmbeddedContentUri(uri));
|
||||
assert.equal(getEmbeddedLanguageId(uri), 'css');
|
||||
assert.equal(getHostDocumentUri(uri), resourceUri1);
|
||||
|
||||
let uri2 = getEmbeddedContentUri(resourceUri2, 'css');
|
||||
assert(isEmbeddedContentUri(uri2));
|
||||
assert.equal(getEmbeddedLanguageId(uri2), 'css');
|
||||
assert.equal(getHostDocumentUri(uri2), resourceUri2);
|
||||
});
|
||||
|
||||
});
|
|
@ -1,27 +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 Uri from 'vscode-uri';
|
||||
|
||||
export const EMBEDDED_CONTENT_SCHEME = 'embedded-content';
|
||||
|
||||
export function isEmbeddedContentUri(virtualDocumentUri: Uri): boolean {
|
||||
return virtualDocumentUri.scheme === EMBEDDED_CONTENT_SCHEME;
|
||||
}
|
||||
|
||||
export function getEmbeddedContentUri(parentDocumentUri: string, embeddedLanguageId: string): Uri {
|
||||
return Uri.from({ scheme: EMBEDDED_CONTENT_SCHEME, authority: embeddedLanguageId, path: '/' + encodeURIComponent(parentDocumentUri) + '.' + embeddedLanguageId });
|
||||
};
|
||||
|
||||
export function getHostDocumentUri(virtualDocumentUri: Uri): string {
|
||||
let languageId = virtualDocumentUri.authority;
|
||||
let path = virtualDocumentUri.path.substring(1, virtualDocumentUri.path.length - languageId.length - 1); // remove leading '/' and new file extension
|
||||
return decodeURIComponent(path);
|
||||
};
|
||||
|
||||
export function getEmbeddedLanguageId(virtualDocumentUri: Uri): string {
|
||||
return virtualDocumentUri.authority;
|
||||
}
|
Loading…
Reference in a new issue