mirror of
https://github.com/Microsoft/vscode
synced 2024-08-27 04:49:35 +00:00
[html] add embedded JavaScript support
This commit is contained in:
parent
ab8e320022
commit
03813455b7
|
@ -85,7 +85,8 @@ const copyrightFilter = [
|
|||
'!**/*.opts',
|
||||
'!**/*.disabled',
|
||||
'!resources/win32/bin/code.js',
|
||||
'!extensions/markdown/media/tomorrow.css'
|
||||
'!extensions/markdown/media/tomorrow.css',
|
||||
'!extensions/html/server/src/modes/typescript/*'
|
||||
];
|
||||
|
||||
const tslintFilter = [
|
||||
|
|
|
@ -33,13 +33,13 @@ export function activate(context: ExtensionContext) {
|
|||
};
|
||||
|
||||
let documentSelector = ['html', 'handlebars', 'razor'];
|
||||
let embeddedLanguages = { 'css': true };
|
||||
let embeddedLanguages = { css: true, javascript: true };
|
||||
|
||||
// Options to control the language client
|
||||
let clientOptions: LanguageClientOptions = {
|
||||
documentSelector,
|
||||
synchronize: {
|
||||
configurationSection: ['html'], // Synchronize the setting section 'html' to the server
|
||||
configurationSection: ['html', 'css', 'javascript'], // the settings to synchronize
|
||||
},
|
||||
initializationOptions: {
|
||||
embeddedLanguages,
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
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 { getLanguageModes, LanguageModes } from './modes/languageModes';
|
||||
|
||||
import * as url from 'url';
|
||||
import * as path from 'path';
|
||||
|
@ -32,22 +32,24 @@ let documents: TextDocuments = new TextDocuments();
|
|||
// for open, change and close text document events
|
||||
documents.listen(connection);
|
||||
|
||||
let languageModes = getLanguageModes({ 'css': true });
|
||||
|
||||
documents.onDidClose(e => {
|
||||
languageModes.getAllModes().forEach(m => m.onDocumentRemoved(e.document));
|
||||
});
|
||||
connection.onShutdown(() => {
|
||||
languageModes.getAllModes().forEach(m => m.dispose());
|
||||
});
|
||||
|
||||
let workspacePath: string;
|
||||
|
||||
var languageModes: LanguageModes;
|
||||
|
||||
// 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 => {
|
||||
let initializationOptions = params.initializationOptions;
|
||||
|
||||
workspacePath = params.rootPath;
|
||||
|
||||
languageModes = getLanguageModes(initializationOptions ? initializationOptions.embeddedLanguages : { css: true, javascript: true });
|
||||
documents.onDidClose(e => {
|
||||
languageModes.getAllModes().forEach(m => m.onDocumentRemoved(e.document));
|
||||
});
|
||||
connection.onShutdown(() => {
|
||||
languageModes.getAllModes().forEach(m => m.dispose());
|
||||
});
|
||||
|
||||
return {
|
||||
capabilities: {
|
||||
// Tell the client that the server works in FULL text document sync mode
|
||||
|
@ -55,8 +57,11 @@ connection.onInitialize((params: InitializeParams): InitializeResult => {
|
|||
completionProvider: { resolveProvider: false, triggerCharacters: ['.', ':', '<', '"', '=', '/'] },
|
||||
hoverProvider: true,
|
||||
documentHighlightProvider: true,
|
||||
documentRangeFormattingProvider: params.initializationOptions['format.enable'],
|
||||
documentLinkProvider: true
|
||||
documentRangeFormattingProvider: initializationOptions && initializationOptions['format.enable'],
|
||||
documentLinkProvider: true,
|
||||
definitionProvider: true,
|
||||
signatureHelpProvider: { triggerCharacters: ['('] },
|
||||
referencesProvider: true
|
||||
}
|
||||
};
|
||||
});
|
||||
|
@ -64,7 +69,12 @@ connection.onInitialize((params: InitializeParams): InitializeResult => {
|
|||
|
||||
// The settings have changed. Is send on server activation as well.
|
||||
connection.onDidChangeConfiguration((change) => {
|
||||
languageModes.configure(change.settings);
|
||||
languageModes.getAllModes().forEach(m => {
|
||||
if (m.configure) {
|
||||
m.configure(change.settings);
|
||||
}
|
||||
});
|
||||
documents.all().forEach(triggerValidation);
|
||||
});
|
||||
|
||||
let pendingValidationRequests: { [uri: string]: NodeJS.Timer } = {};
|
||||
|
@ -135,6 +145,33 @@ connection.onDocumentHighlight(documentHighlightParams => {
|
|||
return [];
|
||||
});
|
||||
|
||||
connection.onDefinition(definitionParams => {
|
||||
let document = documents.get(definitionParams.textDocument.uri);
|
||||
let mode = languageModes.getModeAtPosition(document, definitionParams.position);
|
||||
if (mode && mode.findDefinition) {
|
||||
return mode.findDefinition(document, definitionParams.position);
|
||||
}
|
||||
return [];
|
||||
});
|
||||
|
||||
connection.onReferences(referenceParams => {
|
||||
let document = documents.get(referenceParams.textDocument.uri);
|
||||
let mode = languageModes.getModeAtPosition(document, referenceParams.position);
|
||||
if (mode && mode.findReferences) {
|
||||
return mode.findReferences(document, referenceParams.position);
|
||||
}
|
||||
return [];
|
||||
});
|
||||
|
||||
connection.onSignatureHelp(signatureHelpParms => {
|
||||
let document = documents.get(signatureHelpParms.textDocument.uri);
|
||||
let mode = languageModes.getModeAtPosition(document, signatureHelpParms.position);
|
||||
if (mode && mode.doSignatureHelp) {
|
||||
return mode.doSignatureHelp(document, signatureHelpParms.position);
|
||||
}
|
||||
return null;
|
||||
});
|
||||
|
||||
connection.onDocumentRangeFormatting(formatParams => {
|
||||
let document = documents.get(formatParams.textDocument.uri);
|
||||
let startMode = languageModes.getModeAtPosition(document, formatParams.range.start);
|
||||
|
|
|
@ -1,164 +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 {
|
||||
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;
|
||||
}
|
58
extensions/html/server/src/modes/cssMode.ts
Normal file
58
extensions/html/server/src/modes/cssMode.ts
Normal file
|
@ -0,0 +1,58 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* 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 { LanguageModelCache, getLanguageModelCache } from '../languageModelCache';
|
||||
import { LanguageService as HTMLLanguageService, HTMLDocument } from 'vscode-html-languageservice';
|
||||
import { TextDocument, Position } from 'vscode-languageserver-types';
|
||||
import { getCSSLanguageService, Stylesheet } from 'vscode-css-languageservice';
|
||||
import { getEmbeddedDocument } from './embeddedSupport';
|
||||
import { LanguageMode } from './languageModes';
|
||||
|
||||
export function getCSSMode(htmlLanguageService: HTMLLanguageService, htmlDocuments: LanguageModelCache<HTMLDocument>): LanguageMode {
|
||||
let cssLanguageService = getCSSLanguageService();
|
||||
let cssStylesheets = getLanguageModelCache<Stylesheet>(10, 60, document => cssLanguageService.parseStylesheet(document));
|
||||
let getEmbeddedCSSDocument = (document: TextDocument) => getEmbeddedDocument(htmlLanguageService, document, htmlDocuments.get(document), 'css');
|
||||
|
||||
return {
|
||||
configure(options: any) {
|
||||
cssLanguageService.configure(options && options.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));
|
||||
},
|
||||
findDefinition(document: TextDocument, position: Position) {
|
||||
let embedded = getEmbeddedCSSDocument(document);
|
||||
return cssLanguageService.findDefinition(embedded, position, cssStylesheets.get(embedded));
|
||||
},
|
||||
findReferences(document: TextDocument, position: Position) {
|
||||
let embedded = getEmbeddedCSSDocument(document);
|
||||
return cssLanguageService.findReferences(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();
|
||||
}
|
||||
};
|
||||
};
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
import { TextDocument, Position, HTMLDocument, Node, LanguageService, TokenType } from 'vscode-html-languageservice';
|
||||
|
||||
export function getEmbeddedLanguageAtPosition(languageService: LanguageService, document: TextDocument, htmlDocument: HTMLDocument, position: Position): string {
|
||||
export function getLanguageAtPosition(languageService: LanguageService, document: TextDocument, htmlDocument: HTMLDocument, position: Position): string {
|
||||
let offset = document.offsetAt(position);
|
||||
let node = htmlDocument.findNodeAt(offset);
|
||||
if (node && node.children.length === 0) {
|
||||
|
@ -19,8 +19,8 @@ export function getEmbeddedLanguageAtPosition(languageService: LanguageService,
|
|||
return 'html';
|
||||
}
|
||||
|
||||
export function hasEmbeddedContent(languageService: LanguageService, document: TextDocument, htmlDocument: HTMLDocument): string[] {
|
||||
let embeddedLanguageIds: { [languageId: string]: boolean } = {};
|
||||
export function getLanguagesInContent(languageService: LanguageService, document: TextDocument, htmlDocument: HTMLDocument): string[] {
|
||||
let embeddedLanguageIds: { [languageId: string]: boolean } = { html: true };
|
||||
function collectEmbeddedLanguages(node: Node): void {
|
||||
let c = getEmbeddedContentForNode(languageService, document, node);
|
||||
if (c && !isWhitespace(document.getText().substring(c.start, c.end))) {
|
57
extensions/html/server/src/modes/htmlMode.ts
Normal file
57
extensions/html/server/src/modes/htmlMode.ts
Normal file
|
@ -0,0 +1,57 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* 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 { LanguageModelCache } from '../languageModelCache';
|
||||
import { LanguageService as HTMLLanguageService, HTMLDocument, DocumentContext, FormattingOptions } from 'vscode-html-languageservice';
|
||||
import { TextDocument, Position, Range } from 'vscode-languageserver-types';
|
||||
import { LanguageMode } from './languageModes';
|
||||
|
||||
export function getHTMLMode(htmlLanguageService: HTMLLanguageService, htmlDocuments: LanguageModelCache<HTMLDocument>): LanguageMode {
|
||||
let settings: any = {};
|
||||
|
||||
return {
|
||||
configure(options: any) {
|
||||
settings = options && options.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.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();
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
function merge(src: any, dst: any): any {
|
||||
for (var key in src) {
|
||||
if (src.hasOwnProperty(key)) {
|
||||
dst[key] = src[key];
|
||||
}
|
||||
}
|
||||
return dst;
|
||||
}
|
253
extensions/html/server/src/modes/javascriptMode.ts
Normal file
253
extensions/html/server/src/modes/javascriptMode.ts
Normal file
|
@ -0,0 +1,253 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* 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 { LanguageModelCache, getLanguageModelCache } from '../languageModelCache';
|
||||
import { LanguageService as HTMLLanguageService, HTMLDocument } from 'vscode-html-languageservice';
|
||||
import { getEmbeddedDocument } from './embeddedSupport';
|
||||
import { Location, SignatureHelp, SignatureInformation, ParameterInformation, Definition, TextEdit, TextDocument, Diagnostic, DiagnosticSeverity, Range, CompletionItemKind, Hover, MarkedString, DocumentHighlight, DocumentHighlightKind, CompletionList, Position, FormattingOptions } from 'vscode-languageserver-types';
|
||||
import { LanguageMode } from './languageModes';
|
||||
|
||||
import ts = require('./typescript/typescriptServices');
|
||||
import { contents as libdts } from './typescript/lib-ts';
|
||||
|
||||
const DEFAULT_LIB = {
|
||||
NAME: 'defaultLib:lib.d.ts',
|
||||
CONTENTS: libdts
|
||||
};
|
||||
const FILE_NAME = 'typescript://singlefile/1'; // the same 'file' is used for all contents
|
||||
|
||||
export function getJavascriptMode(htmlLanguageService: HTMLLanguageService, htmlDocuments: LanguageModelCache<HTMLDocument>): LanguageMode {
|
||||
let compilerOptions = { allowNonTsExtensions: true, allowJs: true, target: ts.ScriptTarget.Latest };
|
||||
let currentTextDocument: TextDocument;
|
||||
let host = {
|
||||
getCompilationSettings: () => compilerOptions,
|
||||
getScriptFileNames: () => [FILE_NAME],
|
||||
getScriptVersion: (fileName: string) => {
|
||||
if (fileName === FILE_NAME) {
|
||||
return String(currentTextDocument.version);
|
||||
}
|
||||
return '1'; // default lib is static
|
||||
},
|
||||
getScriptSnapshot: (fileName: string) => {
|
||||
let text = fileName === FILE_NAME ? currentTextDocument.getText() : DEFAULT_LIB.CONTENTS;
|
||||
return {
|
||||
getText: (start, end) => text.substring(start, end),
|
||||
getLength: () => text.length,
|
||||
getChangeRange: () => void 0
|
||||
};
|
||||
},
|
||||
getCurrentDirectory: () => '',
|
||||
getDefaultLibFileName: options => DEFAULT_LIB.NAME
|
||||
};
|
||||
let jsLanguageService = ts.createLanguageService(host);
|
||||
|
||||
let jsDocuments = getLanguageModelCache<TextDocument>(10, 60, document => {
|
||||
return getEmbeddedDocument(htmlLanguageService, document, htmlDocuments.get(document), 'javascript');
|
||||
});
|
||||
let settings: any = {};
|
||||
|
||||
return {
|
||||
configure(options: any) {
|
||||
settings = options && options.html;
|
||||
},
|
||||
doValidation(document: TextDocument): Diagnostic[] {
|
||||
currentTextDocument = jsDocuments.get(document);
|
||||
const diagnostics = jsLanguageService.getSyntacticDiagnostics(FILE_NAME);
|
||||
return diagnostics.map(diag => {
|
||||
return {
|
||||
range: convertRange(currentTextDocument, diag),
|
||||
severity: DiagnosticSeverity.Error,
|
||||
message: ts.flattenDiagnosticMessageText(diag.messageText, '\n')
|
||||
};
|
||||
});
|
||||
},
|
||||
doComplete(document: TextDocument, position: Position): CompletionList {
|
||||
currentTextDocument = jsDocuments.get(document);
|
||||
let completions = jsLanguageService.getCompletionsAtPosition(FILE_NAME, currentTextDocument.offsetAt(position));
|
||||
return {
|
||||
isIncomplete: false,
|
||||
items: !completions ? [] : completions.entries.map(entry => {
|
||||
return {
|
||||
uri: document.uri,
|
||||
position: position,
|
||||
label: entry.name,
|
||||
sortText: entry.sortText,
|
||||
kind: convertKind(entry.kind)
|
||||
};
|
||||
})
|
||||
};
|
||||
},
|
||||
doHover(document: TextDocument, position: Position): Hover {
|
||||
currentTextDocument = jsDocuments.get(document);
|
||||
let info = jsLanguageService.getQuickInfoAtPosition(FILE_NAME, currentTextDocument.offsetAt(position));
|
||||
if (info) {
|
||||
let contents = ts.displayPartsToString(info.displayParts);
|
||||
return {
|
||||
range: convertRange(currentTextDocument, info.textSpan),
|
||||
contents: MarkedString.fromPlainText(contents)
|
||||
};
|
||||
}
|
||||
return null;
|
||||
},
|
||||
doSignatureHelp(document: TextDocument, position: Position): SignatureHelp {
|
||||
currentTextDocument = jsDocuments.get(document);
|
||||
let signHelp = jsLanguageService.getSignatureHelpItems(FILE_NAME, currentTextDocument.offsetAt(position));
|
||||
if (signHelp) {
|
||||
let ret: SignatureHelp = {
|
||||
activeSignature: signHelp.selectedItemIndex,
|
||||
activeParameter: signHelp.argumentIndex,
|
||||
signatures: []
|
||||
};
|
||||
signHelp.items.forEach(item => {
|
||||
|
||||
let signature: SignatureInformation = {
|
||||
label: '',
|
||||
documentation: null,
|
||||
parameters: []
|
||||
};
|
||||
|
||||
signature.label += ts.displayPartsToString(item.prefixDisplayParts);
|
||||
item.parameters.forEach((p, i, a) => {
|
||||
let label = ts.displayPartsToString(p.displayParts);
|
||||
let parameter: ParameterInformation = {
|
||||
label: label,
|
||||
documentation: ts.displayPartsToString(p.documentation)
|
||||
};
|
||||
signature.label += label;
|
||||
signature.parameters.push(parameter);
|
||||
if (i < a.length - 1) {
|
||||
signature.label += ts.displayPartsToString(item.separatorDisplayParts);
|
||||
}
|
||||
});
|
||||
signature.label += ts.displayPartsToString(item.suffixDisplayParts);
|
||||
ret.signatures.push(signature);
|
||||
});
|
||||
return ret;
|
||||
};
|
||||
return null;
|
||||
},
|
||||
findDocumentHighlight(document: TextDocument, position: Position): DocumentHighlight[] {
|
||||
currentTextDocument = jsDocuments.get(document);
|
||||
let occurrences = jsLanguageService.getOccurrencesAtPosition(FILE_NAME, currentTextDocument.offsetAt(position));
|
||||
if (occurrences) {
|
||||
return occurrences.map(entry => {
|
||||
return {
|
||||
range: convertRange(currentTextDocument, entry.textSpan),
|
||||
kind: entry.isWriteAccess ? DocumentHighlightKind.Write : DocumentHighlightKind.Text
|
||||
};
|
||||
});
|
||||
};
|
||||
return null;
|
||||
},
|
||||
findDefinition(document: TextDocument, position: Position): Definition {
|
||||
currentTextDocument = jsDocuments.get(document);
|
||||
let definition = jsLanguageService.getDefinitionAtPosition(FILE_NAME, currentTextDocument.offsetAt(position));
|
||||
if (definition) {
|
||||
return definition.filter(d => d.fileName === FILE_NAME).map(d => {
|
||||
return {
|
||||
uri: document.uri,
|
||||
range: convertRange(currentTextDocument, d.textSpan)
|
||||
};
|
||||
});
|
||||
}
|
||||
return null;
|
||||
},
|
||||
findReferences(document: TextDocument, position: Position): Location[] {
|
||||
currentTextDocument = jsDocuments.get(document);
|
||||
let references = jsLanguageService.getReferencesAtPosition(FILE_NAME, currentTextDocument.offsetAt(position));
|
||||
if (references) {
|
||||
return references.filter(d => d.fileName === FILE_NAME).map(d => {
|
||||
return {
|
||||
uri: document.uri,
|
||||
range: convertRange(currentTextDocument, d.textSpan)
|
||||
};
|
||||
});
|
||||
}
|
||||
return null;
|
||||
},
|
||||
format(document: TextDocument, range: Range, formatParams: FormattingOptions): TextEdit[] {
|
||||
currentTextDocument = jsDocuments.get(document);
|
||||
let formatSettings = convertOptions(formatParams, settings && settings.format);
|
||||
let start = currentTextDocument.offsetAt(range.start);
|
||||
let end = currentTextDocument.offsetAt(range.end);
|
||||
let edits = jsLanguageService.getFormattingEditsForRange(FILE_NAME, start, end, formatSettings);
|
||||
if (edits) {
|
||||
return edits.map(e => ({
|
||||
range: convertRange(currentTextDocument, e.span),
|
||||
newText: e.newText
|
||||
}));
|
||||
}
|
||||
return null;
|
||||
},
|
||||
onDocumentRemoved(document: TextDocument) {
|
||||
jsDocuments.onDocumentRemoved(document);
|
||||
},
|
||||
dispose() {
|
||||
jsDocuments.dispose();
|
||||
jsLanguageService.dispose();
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
function convertRange(document: TextDocument, span: { start: number, length: number }): Range {
|
||||
let startPosition = document.positionAt(span.start);
|
||||
let endPosition = document.positionAt(span.start + span.length);
|
||||
return Range.create(startPosition, endPosition);
|
||||
}
|
||||
|
||||
function convertKind(kind: string): CompletionItemKind {
|
||||
switch (kind) {
|
||||
case 'primitive type':
|
||||
case 'keyword':
|
||||
return CompletionItemKind.Keyword;
|
||||
case 'var':
|
||||
case 'local var':
|
||||
return CompletionItemKind.Variable;
|
||||
case 'property':
|
||||
case 'getter':
|
||||
case 'setter':
|
||||
return CompletionItemKind.Field;
|
||||
case 'function':
|
||||
case 'method':
|
||||
case 'construct':
|
||||
case 'call':
|
||||
case 'index':
|
||||
return CompletionItemKind.Function;
|
||||
case 'enum':
|
||||
return CompletionItemKind.Enum;
|
||||
case 'module':
|
||||
return CompletionItemKind.Module;
|
||||
case 'class':
|
||||
return CompletionItemKind.Class;
|
||||
case 'interface':
|
||||
return CompletionItemKind.Interface;
|
||||
case 'warning':
|
||||
return CompletionItemKind.File;
|
||||
}
|
||||
|
||||
return CompletionItemKind.Property;
|
||||
}
|
||||
|
||||
function convertOptions(options: FormattingOptions, formatSettings?: any): ts.FormatCodeOptions {
|
||||
return {
|
||||
ConvertTabsToSpaces: options.insertSpaces,
|
||||
TabSize: options.tabSize,
|
||||
IndentSize: options.tabSize,
|
||||
IndentStyle: ts.IndentStyle.Smart,
|
||||
NewLineCharacter: '\n',
|
||||
BaseIndentSize: 1, //
|
||||
InsertSpaceAfterCommaDelimiter: !formatSettings || formatSettings.insertSpaceAfterCommaDelimiter,
|
||||
InsertSpaceAfterSemicolonInForStatements: !formatSettings || formatSettings.insertSpaceAfterSemicolonInForStatements,
|
||||
InsertSpaceBeforeAndAfterBinaryOperators: !formatSettings || formatSettings.insertSpaceBeforeAndAfterBinaryOperators,
|
||||
InsertSpaceAfterKeywordsInControlFlowStatements: !formatSettings || formatSettings.insertSpaceAfterKeywordsInControlFlowStatements,
|
||||
InsertSpaceAfterFunctionKeywordForAnonymousFunctions: !formatSettings || formatSettings.insertSpaceAfterFunctionKeywordForAnonymousFunctions,
|
||||
InsertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis: formatSettings && formatSettings.insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis,
|
||||
InsertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets: formatSettings && formatSettings.insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets,
|
||||
InsertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces: formatSettings && formatSettings.insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces,
|
||||
PlaceOpenBraceOnNewLineForControlBlocks: formatSettings && formatSettings.placeOpenBraceOnNewLineForFunctions,
|
||||
PlaceOpenBraceOnNewLineForFunctions: formatSettings && formatSettings.placeOpenBraceOnNewLineForControlBlocks
|
||||
};
|
||||
}
|
82
extensions/html/server/src/modes/languageModes.ts
Normal file
82
extensions/html/server/src/modes/languageModes.ts
Normal file
|
@ -0,0 +1,82 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* 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 { HTMLDocument, getLanguageService as getHTMLLanguageService, DocumentContext } from 'vscode-html-languageservice';
|
||||
import { Location, SignatureHelp, Definition, TextEdit, TextDocument, Diagnostic, DocumentLink, Range, Hover, DocumentHighlight, CompletionList, Position, FormattingOptions } from 'vscode-languageserver-types';
|
||||
|
||||
import { getLanguageModelCache } from '../languageModelCache';
|
||||
import { getLanguageAtPosition, getLanguagesInContent } from './embeddedSupport';
|
||||
import { getCSSMode } from './cssMode';
|
||||
import { getJavascriptMode } from './javascriptMode';
|
||||
import { getHTMLMode } from './htmlMode';
|
||||
|
||||
export interface LanguageMode {
|
||||
configure?: (options: any) => void;
|
||||
doValidation?: (document: TextDocument) => Diagnostic[];
|
||||
doComplete?: (document: TextDocument, position: Position) => CompletionList;
|
||||
doHover?: (document: TextDocument, position: Position) => Hover;
|
||||
doSignatureHelp?: (document: TextDocument, position: Position) => SignatureHelp;
|
||||
findDocumentHighlight?: (document: TextDocument, position: Position) => DocumentHighlight[];
|
||||
findDocumentLinks?: (document: TextDocument, documentContext: DocumentContext) => DocumentLink[];
|
||||
findDefinition?: (document: TextDocument, position: Position) => Definition;
|
||||
findReferences?: (document: TextDocument, position: Position) => Location[];
|
||||
format?: (document: TextDocument, range: Range, options: FormattingOptions) => TextEdit[];
|
||||
findColorSymbols?: (document: TextDocument) => Range[];
|
||||
onDocumentRemoved(document: TextDocument): void;
|
||||
dispose(): void;
|
||||
}
|
||||
|
||||
export interface LanguageModes {
|
||||
getModeAtPosition(document: TextDocument, position: Position): LanguageMode;
|
||||
getAllModesInDocument(document: TextDocument): LanguageMode[];
|
||||
getAllModes(): LanguageMode[];
|
||||
getMode(languageId: string): LanguageMode;
|
||||
}
|
||||
|
||||
export function getLanguageModes(supportedLanguages: { [languageId: string]: boolean; }): LanguageModes {
|
||||
|
||||
var htmlLanguageService = getHTMLLanguageService();
|
||||
let htmlDocuments = getLanguageModelCache<HTMLDocument>(10, 60, document => htmlLanguageService.parseHTMLDocument(document));
|
||||
|
||||
let modes = {
|
||||
'html': getHTMLMode(htmlLanguageService, htmlDocuments),
|
||||
'css': supportedLanguages['css'] && getCSSMode(htmlLanguageService, htmlDocuments),
|
||||
'javascript': supportedLanguages['javascript'] && getJavascriptMode(htmlLanguageService, htmlDocuments)
|
||||
};
|
||||
return {
|
||||
getModeAtPosition(document: TextDocument, position: Position): LanguageMode {
|
||||
let languageId = getLanguageAtPosition(htmlLanguageService, document, htmlDocuments.get(document), position);
|
||||
if (languageId) {
|
||||
return modes[languageId];
|
||||
}
|
||||
return null;
|
||||
},
|
||||
getAllModesInDocument(document: TextDocument): LanguageMode[] {
|
||||
let result = [];
|
||||
let languageIds = getLanguagesInContent(htmlLanguageService, document, htmlDocuments.get(document));
|
||||
for (let languageId of languageIds) {
|
||||
let mode = modes[languageId];
|
||||
if (mode) {
|
||||
result.push(mode);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
},
|
||||
getAllModes(): LanguageMode[] {
|
||||
let result = [];
|
||||
for (let languageId in modes) {
|
||||
let mode = modes[languageId];
|
||||
if (mode) {
|
||||
result.push(mode);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
},
|
||||
getMode(languageId: string): LanguageMode {
|
||||
return modes[languageId];
|
||||
}
|
||||
};
|
||||
}
|
6
extensions/html/server/src/modes/typescript/lib-ts.d.ts
vendored
Normal file
6
extensions/html/server/src/modes/typescript/lib-ts.d.ts
vendored
Normal file
|
@ -0,0 +1,6 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
export declare var contents: string;
|
9
extensions/html/server/src/modes/typescript/lib-ts.js
Normal file
9
extensions/html/server/src/modes/typescript/lib-ts.js
Normal file
File diff suppressed because one or more lines are too long
2615
extensions/html/server/src/modes/typescript/typescriptServices.d.ts
vendored
Normal file
2615
extensions/html/server/src/modes/typescript/typescriptServices.d.ts
vendored
Normal file
File diff suppressed because it is too large
Load diff
61638
extensions/html/server/src/modes/typescript/typescriptServices.js
Normal file
61638
extensions/html/server/src/modes/typescript/typescriptServices.js
Normal file
File diff suppressed because one or more lines are too long
|
@ -5,15 +5,15 @@
|
|||
'use strict';
|
||||
|
||||
import * as assert from 'assert';
|
||||
import * as embeddedSupport from '../embeddedSupport';
|
||||
import {TextDocument} from 'vscode-languageserver-types';
|
||||
import { getLanguageService} from 'vscode-html-languageservice';
|
||||
import * as embeddedSupport from '../modes/embeddedSupport';
|
||||
import { TextDocument } from 'vscode-languageserver-types';
|
||||
import { getLanguageService } from 'vscode-html-languageservice';
|
||||
|
||||
suite('HTML Embedded Support', () => {
|
||||
|
||||
var htmlLanguageService = getLanguageService();
|
||||
|
||||
function assertEmbeddedLanguageId(value: string, expectedLanguageId: string): void {
|
||||
function assertLanguageId(value: string, expectedLanguageId: string): void {
|
||||
let offset = value.indexOf('|');
|
||||
value = value.substr(0, offset) + value.substr(offset + 1);
|
||||
|
||||
|
@ -23,7 +23,7 @@ suite('HTML Embedded Support', () => {
|
|||
let ls = getLanguageService();
|
||||
let htmlDoc = ls.parseHTMLDocument(document);
|
||||
|
||||
let languageId = embeddedSupport.getEmbeddedLanguageAtPosition(htmlLanguageService, document, htmlDoc, position);
|
||||
let languageId = embeddedSupport.getLanguageAtPosition(htmlLanguageService, document, htmlDoc, position);
|
||||
assert.equal(languageId, expectedLanguageId);
|
||||
}
|
||||
|
||||
|
@ -39,13 +39,13 @@ suite('HTML Embedded Support', () => {
|
|||
}
|
||||
|
||||
test('Styles', function (): any {
|
||||
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>', 'html');
|
||||
assertLanguageId('|<html><style>foo { }</style></html>', 'html');
|
||||
assertLanguageId('<html|><style>foo { }</style></html>', 'html');
|
||||
assertLanguageId('<html><st|yle>foo { }</style></html>', 'html');
|
||||
assertLanguageId('<html><style>|foo { }</style></html>', 'css');
|
||||
assertLanguageId('<html><style>foo| { }</style></html>', 'css');
|
||||
assertLanguageId('<html><style>foo { }|</style></html>', 'css');
|
||||
assertLanguageId('<html><style>foo { }</sty|le></html>', 'html');
|
||||
});
|
||||
|
||||
test('Style content', function (): any {
|
||||
|
@ -57,20 +57,20 @@ suite('HTML Embedded Support', () => {
|
|||
});
|
||||
|
||||
test('Scripts', function (): any {
|
||||
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>', 'html');
|
||||
assertLanguageId('|<html><script>var i = 0;</script></html>', 'html');
|
||||
assertLanguageId('<html|><script>var i = 0;</script></html>', 'html');
|
||||
assertLanguageId('<html><scr|ipt>var i = 0;</script></html>', 'html');
|
||||
assertLanguageId('<html><script>|var i = 0;</script></html>', 'javascript');
|
||||
assertLanguageId('<html><script>var| i = 0;</script></html>', 'javascript');
|
||||
assertLanguageId('<html><script>var i = 0;|</script></html>', 'javascript');
|
||||
assertLanguageId('<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>', 'html');
|
||||
assertEmbeddedLanguageId('<script type=\'text/javascript\'>var| i = 0;</script>', 'javascript');
|
||||
assertLanguageId('<script type="text/javascript">var| i = 0;</script>', 'javascript');
|
||||
assertLanguageId('<script type="text/ecmascript">var| i = 0;</script>', 'javascript');
|
||||
assertLanguageId('<script type="application/javascript">var| i = 0;</script>', 'javascript');
|
||||
assertLanguageId('<script type="application/ecmascript">var| i = 0;</script>', 'javascript');
|
||||
assertLanguageId('<script type="application/typescript">var| i = 0;</script>', void 0);
|
||||
assertLanguageId('<script type=\'text/javascript\'>var| i = 0;</script>', 'javascript');
|
||||
});
|
||||
|
||||
test('Script content', function (): any {
|
||||
|
|
Loading…
Reference in a new issue