diff --git a/extensions/html-language-features/server/src/htmlServer.ts b/extensions/html-language-features/server/src/htmlServer.ts index 29aa041746c..22ab2e18076 100644 --- a/extensions/html-language-features/server/src/htmlServer.ts +++ b/extensions/html-language-features/server/src/htmlServer.ts @@ -7,11 +7,12 @@ import { Connection, TextDocuments, InitializeParams, InitializeResult, RequestType, DocumentRangeFormattingRequest, Disposable, ServerCapabilities, ConfigurationRequest, ConfigurationParams, DidChangeWorkspaceFoldersNotification, - DocumentColorRequest, ColorPresentationRequest, TextDocumentSyncKind, NotificationType, RequestType0, DocumentFormattingRequest, FormattingOptions, TextEdit + DocumentColorRequest, ColorPresentationRequest, TextDocumentSyncKind, NotificationType, RequestType0, DocumentFormattingRequest, FormattingOptions, TextEdit, + TextDocumentContentRequest } from 'vscode-languageserver'; import { getLanguageModes, LanguageModes, Settings, TextDocument, Position, Diagnostic, WorkspaceFolder, ColorInformation, - Range, DocumentLink, SymbolInformation, TextDocumentIdentifier, isCompletionItemData + Range, DocumentLink, SymbolInformation, TextDocumentIdentifier, isCompletionItemData, FILE_PROTOCOL } from './modes/languageModes'; import { format } from './modes/formatting'; @@ -213,6 +214,9 @@ export function startServer(connection: Connection, runtime: RuntimeEnvironment) documentSelector: null, interFileDependencies: false, workspaceDiagnostics: false + }, + workspace: { + textDocumentContent: { schemes: [FILE_PROTOCOL] } } }; return { capabilities }; @@ -584,6 +588,18 @@ export function startServer(connection: Connection, runtime: RuntimeEnvironment) }); }); + connection.onRequest(TextDocumentContentRequest.type, (params, token) => { + return runSafe(runtime, async () => { + for (const languageMode of languageModes.getAllModes()) { + const content = await languageMode.getTextDocumentContent?.(params.uri); + if (content) { + return { text: content }; + } + } + return null; + }, null, `Error while computing text document content for ${params.uri}`, token); + }); + // Listen on the connection connection.listen(); } diff --git a/extensions/html-language-features/server/src/modes/javascriptMode.ts b/extensions/html-language-features/server/src/modes/javascriptMode.ts index d820810c920..aafb54a64b5 100644 --- a/extensions/html-language-features/server/src/modes/javascriptMode.ts +++ b/extensions/html-language-features/server/src/modes/javascriptMode.ts @@ -8,7 +8,7 @@ import { SymbolInformation, SymbolKind, CompletionItem, Location, SignatureHelp, SignatureInformation, ParameterInformation, Definition, TextEdit, TextDocument, Diagnostic, DiagnosticSeverity, Range, CompletionItemKind, Hover, DocumentHighlight, DocumentHighlightKind, CompletionList, Position, FormattingOptions, FoldingRange, FoldingRangeKind, SelectionRange, - LanguageMode, Settings, SemanticTokenData, Workspace, DocumentContext, CompletionItemData, isCompletionItemData + LanguageMode, Settings, SemanticTokenData, Workspace, DocumentContext, CompletionItemData, isCompletionItemData, FILE_PROTOCOL, DocumentUri } from './languageModes'; import { getWordAtText, isWhitespaceOnly, repeat } from '../utils/strings'; import { HTMLDocumentRegions } from './embeddedSupport'; @@ -77,18 +77,24 @@ function getLanguageServiceHost(scriptKind: ts.ScriptKind) { } }; - return ts.createLanguageService(host); + return { + service: ts.createLanguageService(host), + loadLibrary: libs.loadLibrary, + }; }); return { async getLanguageService(jsDocument: TextDocument): Promise { currentTextDocument = jsDocument; - return jsLanguageService; + return (await jsLanguageService).service; }, getCompilationSettings() { return compilerOptions; }, + async loadLibrary(fileName: string) { + return (await jsLanguageService).loadLibrary(fileName); + }, dispose() { - jsLanguageService.then(s => s.dispose()); + jsLanguageService.then(s => s.service.dispose()); } }; } @@ -104,6 +110,8 @@ export function getJavaScriptMode(documentRegions: LanguageModelCache d.fileName === jsDocument.uri).map(d => { - return { - uri: document.uri, - range: convertRange(jsDocument, d.textSpan) - }; - }); + return (await Promise.all(definition.map(async d => { + if (d.fileName === jsDocument.uri) { + return { + uri: document.uri, + range: convertRange(jsDocument, d.textSpan) + }; + } else { + const libUri = libParentUri + d.fileName; + const content = await host.loadLibrary(d.fileName); + if (!content) { + return undefined; + } + const libDocument = TextDocument.create(libUri, languageId, 1, content); + return { + uri: libUri, + range: convertRange(libDocument, d.textSpan) + }; + } + }))).filter(d => !!d); } return null; }, @@ -402,6 +423,12 @@ export function getJavaScriptMode(documentRegions: LanguageModelCache { + if (documentUri.startsWith(libParentUri)) { + return host.loadLibrary(documentUri.substring(libParentUri.length)); + } + return undefined; + }, dispose() { host.dispose(); jsDocuments.dispose(); diff --git a/extensions/html-language-features/server/src/modes/languageModes.ts b/extensions/html-language-features/server/src/modes/languageModes.ts index 803fa6c1c87..45d0b8fabe7 100644 --- a/extensions/html-language-features/server/src/modes/languageModes.ts +++ b/extensions/html-language-features/server/src/modes/languageModes.ts @@ -14,7 +14,7 @@ import { Color, ColorInformation, ColorPresentation, WorkspaceEdit, WorkspaceFolder } from 'vscode-languageserver'; -import { TextDocument } from 'vscode-languageserver-textdocument'; +import { DocumentUri, TextDocument } from 'vscode-languageserver-textdocument'; import { getLanguageModelCache, LanguageModelCache } from '../languageModelCache'; import { getCSSMode } from './cssMode'; @@ -34,7 +34,7 @@ export { export { ClientCapabilities, DocumentContext, LanguageService, HTMLDocument, HTMLFormatConfiguration, TokenType } from 'vscode-html-languageservice'; -export { TextDocument } from 'vscode-languageserver-textdocument'; +export { TextDocument, DocumentUri } from 'vscode-languageserver-textdocument'; export interface Settings { readonly css?: any; @@ -89,6 +89,7 @@ export interface LanguageMode { onDocumentRemoved(document: TextDocument): void; getSemanticTokens?(document: TextDocument): Promise; getSemanticTokenLegend?(): { types: string[]; modifiers: string[] }; + getTextDocumentContent?(uri: DocumentUri): Promise; dispose(): void; } @@ -108,6 +109,8 @@ export interface LanguageModeRange extends Range { attributeValue?: boolean; } +export const FILE_PROTOCOL = 'html-server'; + export function getLanguageModes(supportedLanguages: { [languageId: string]: boolean }, workspace: Workspace, clientCapabilities: ClientCapabilities, requestService: FileSystemProvider): LanguageModes { const htmlLanguageService = getHTMLLanguageService({ clientCapabilities, fileSystemProvider: requestService }); const cssLanguageService = getCSSLanguageService({ clientCapabilities, fileSystemProvider: requestService });