diff --git a/extensions/css-language-features/server/src/cssServerMain.ts b/extensions/css-language-features/server/src/cssServerMain.ts index 75223f91b78..aba96f5ff6a 100644 --- a/extensions/css-language-features/server/src/cssServerMain.ts +++ b/extensions/css-language-features/server/src/cssServerMain.ts @@ -5,15 +5,14 @@ 'use strict'; import { - createConnection, IConnection, TextDocuments, InitializeParams, InitializeResult, ServerCapabilities, - ConfigurationRequest, WorkspaceFolder, DocumentColorRequest, ColorPresentationRequest + createConnection, IConnection, TextDocuments, InitializeParams, InitializeResult, ServerCapabilities, ConfigurationRequest, WorkspaceFolder } from 'vscode-languageserver'; import { TextDocument, CompletionList } from 'vscode-languageserver-types'; import { getCSSLanguageService, getSCSSLanguageService, getLESSLanguageService, LanguageSettings, LanguageService, Stylesheet } from 'vscode-css-languageservice'; import { getLanguageModelCache } from './languageModelCache'; -import { formatError, runSafe } from './utils/errors'; +import { formatError, runSafe } from './utils/runner'; import URI from 'vscode-uri'; import { getPathCompletionParticipant } from './pathCompletion'; import { FoldingProviderServerCapabilities, FoldingRangesRequest } from 'vscode-languageserver-protocol-foldingprovider'; @@ -182,7 +181,7 @@ function validateTextDocument(textDocument: TextDocument): void { }); } -connection.onCompletion(textDocumentPosition => { +connection.onCompletion((textDocumentPosition, token) => { return runSafe(() => { let document = documents.get(textDocumentPosition.textDocument.uri); const cssLS = getLanguageService(document); @@ -196,58 +195,58 @@ connection.onCompletion(textDocumentPosition => { isIncomplete: result.isIncomplete, items: [...pathCompletionList.items, ...result.items] }; - }, null, `Error while computing completions for ${textDocumentPosition.textDocument.uri}`); + }, null, `Error while computing completions for ${textDocumentPosition.textDocument.uri}`, token); }); -connection.onHover(textDocumentPosition => { +connection.onHover((textDocumentPosition, token) => { return runSafe(() => { let document = documents.get(textDocumentPosition.textDocument.uri); let styleSheet = stylesheets.get(document); - return getLanguageService(document).doHover(document, textDocumentPosition.position, styleSheet)!; /* TODO: remove ! once LS has null annotations */ - }, null, `Error while computing hover for ${textDocumentPosition.textDocument.uri}`); + return getLanguageService(document).doHover(document, textDocumentPosition.position, styleSheet); + }, null, `Error while computing hover for ${textDocumentPosition.textDocument.uri}`, token); }); -connection.onDocumentSymbol(documentSymbolParams => { +connection.onDocumentSymbol((documentSymbolParams, token) => { return runSafe(() => { let document = documents.get(documentSymbolParams.textDocument.uri); let stylesheet = stylesheets.get(document); return getLanguageService(document).findDocumentSymbols(document, stylesheet); - }, [], `Error while computing document symbols for ${documentSymbolParams.textDocument.uri}`); + }, [], `Error while computing document symbols for ${documentSymbolParams.textDocument.uri}`, token); }); -connection.onDefinition(documentSymbolParams => { +connection.onDefinition((documentSymbolParams, token) => { return runSafe(() => { let document = documents.get(documentSymbolParams.textDocument.uri); let stylesheet = stylesheets.get(document); return getLanguageService(document).findDefinition(document, documentSymbolParams.position, stylesheet); - }, null, `Error while computing definitions for ${documentSymbolParams.textDocument.uri}`); + }, null, `Error while computing definitions for ${documentSymbolParams.textDocument.uri}`, token); }); -connection.onDocumentHighlight(documentSymbolParams => { +connection.onDocumentHighlight((documentSymbolParams, token) => { return runSafe(() => { let document = documents.get(documentSymbolParams.textDocument.uri); let stylesheet = stylesheets.get(document); return getLanguageService(document).findDocumentHighlights(document, documentSymbolParams.position, stylesheet); - }, [], `Error while computing document highlights for ${documentSymbolParams.textDocument.uri}`); + }, [], `Error while computing document highlights for ${documentSymbolParams.textDocument.uri}`, token); }); -connection.onReferences(referenceParams => { +connection.onReferences((referenceParams, token) => { return runSafe(() => { let document = documents.get(referenceParams.textDocument.uri); let stylesheet = stylesheets.get(document); return getLanguageService(document).findReferences(document, referenceParams.position, stylesheet); - }, [], `Error while computing references for ${referenceParams.textDocument.uri}`); + }, [], `Error while computing references for ${referenceParams.textDocument.uri}`, token); }); -connection.onCodeAction(codeActionParams => { +connection.onCodeAction((codeActionParams, token) => { return runSafe(() => { let document = documents.get(codeActionParams.textDocument.uri); let stylesheet = stylesheets.get(document); return getLanguageService(document).doCodeActions(document, codeActionParams.range, codeActionParams.context, stylesheet); - }, [], `Error while computing code actions for ${codeActionParams.textDocument.uri}`); + }, [], `Error while computing code actions for ${codeActionParams.textDocument.uri}`, token); }); -connection.onRequest(DocumentColorRequest.type, params => { +connection.onDocumentColor((params, token) => { return runSafe(() => { let document = documents.get(params.textDocument.uri); if (document) { @@ -255,10 +254,10 @@ connection.onRequest(DocumentColorRequest.type, params => { return getLanguageService(document).findDocumentColors(document, stylesheet); } return []; - }, [], `Error while computing document colors for ${params.textDocument.uri}`); + }, [], `Error while computing document colors for ${params.textDocument.uri}`, token); }); -connection.onRequest(ColorPresentationRequest.type, params => { +connection.onColorPresentation((params, token) => { return runSafe(() => { let document = documents.get(params.textDocument.uri); if (document) { @@ -266,15 +265,15 @@ connection.onRequest(ColorPresentationRequest.type, params => { return getLanguageService(document).getColorPresentations(document, stylesheet, params.color, params.range); } return []; - }, [], `Error while computing color presentations for ${params.textDocument.uri}`); + }, [], `Error while computing color presentations for ${params.textDocument.uri}`, token); }); -connection.onRenameRequest(renameParameters => { +connection.onRenameRequest((renameParameters, token) => { return runSafe(() => { let document = documents.get(renameParameters.textDocument.uri); let stylesheet = stylesheets.get(document); return getLanguageService(document).doRename(document, renameParameters.position, renameParameters.newName, stylesheet); - }, null, `Error while computing renames for ${renameParameters.textDocument.uri}`); + }, null, `Error while computing renames for ${renameParameters.textDocument.uri}`, token); }); connection.onRequest(FoldingRangesRequest.type, (params, token) => { @@ -282,7 +281,7 @@ connection.onRequest(FoldingRangesRequest.type, (params, token) => { let document = documents.get(params.textDocument.uri); let stylesheet = stylesheets.get(document); return getLanguageService(document).findFoldingRegions(document, stylesheet); - }, null, `Error while computing folding ranges for ${params.textDocument.uri}`); + }, null, `Error while computing folding ranges for ${params.textDocument.uri}`, token); }); // Listen on the connection diff --git a/extensions/css-language-features/server/src/test/completion.test.ts b/extensions/css-language-features/server/src/test/completion.test.ts index 86f57ca523d..23fc5e0e3b1 100644 --- a/extensions/css-language-features/server/src/test/completion.test.ts +++ b/extensions/css-language-features/server/src/test/completion.test.ts @@ -48,7 +48,7 @@ suite('Completions', () => { cssLanguageService.setCompletionParticipants([getPathCompletionParticipant(document, workspaceFolders, participantResult)]); const stylesheet = cssLanguageService.parseStylesheet(document); - let list = cssLanguageService.doComplete!(document, position, stylesheet); + let list = cssLanguageService.doComplete(document, position, stylesheet)!; list.items = list.items.concat(participantResult.items); if (expected.count) { diff --git a/extensions/css-language-features/server/src/test/emmet.test.ts b/extensions/css-language-features/server/src/test/emmet.test.ts index 7c850fe2697..e7fe76d7be3 100644 --- a/extensions/css-language-features/server/src/test/emmet.test.ts +++ b/extensions/css-language-features/server/src/test/emmet.test.ts @@ -15,7 +15,7 @@ suite('CSS Emmet Support', () => { const cssLanguageService = getCSSLanguageService(); const scssLanguageService = getSCSSLanguageService(); - function assertCompletions(syntax: string, value: string, expectedProposal: string, expectedProposalDoc: string): void { + function assertCompletions(syntax: string, value: string, expectedProposal: string | null, expectedProposalDoc: string | null): void { const offset = value.indexOf('|'); value = value.substr(0, offset) + value.substr(offset + 1); @@ -23,12 +23,12 @@ suite('CSS Emmet Support', () => { const position = document.positionAt(offset); const emmetCompletionList: CompletionList = { isIncomplete: true, - items: undefined + items: [] }; const languageService = syntax === 'scss' ? scssLanguageService : cssLanguageService; languageService.setCompletionParticipants([getEmmetCompletionParticipants(document, position, document.languageId, {}, emmetCompletionList)]); const stylesheet = languageService.parseStylesheet(document); - const list = languageService.doComplete!(document, position, stylesheet); + const list = languageService.doComplete(document, position, stylesheet); assert.ok(list); assert.ok(emmetCompletionList); @@ -43,7 +43,7 @@ suite('CSS Emmet Support', () => { } } - test('Css Emmet Completions', function (): any { + test('Css Emmet Completions', function (this: any): any { this.skip(); // disabled again (see #29113) assertCompletions('css', '.foo { display: none; m10| }', 'margin: 10px;', 'margin: 10px;'); @@ -56,7 +56,7 @@ suite('CSS Emmet Support', () => { assertCompletions('css', '.foo { display: none; -m-m10| }', 'margin: 10px;', '-moz-margin: 10px;\nmargin: 10px;'); }); - test('Scss Emmet Completions', function (): any { + test('Scss Emmet Completions', function (this: any): any { this.skip(); // disabled again (see #29113) assertCompletions('scss', '.foo { display: none; .bar { m10| } }', 'margin: 10px;', 'margin: 10px;'); diff --git a/extensions/css-language-features/server/src/utils/errors.ts b/extensions/css-language-features/server/src/utils/errors.ts deleted file mode 100644 index d5a0c8e7d05..00000000000 --- a/extensions/css-language-features/server/src/utils/errors.ts +++ /dev/null @@ -1,33 +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'; - -export function formatError(message: string, err: any): string { - if (err instanceof Error) { - let error = err; - return `${message}: ${error.message}\n${error.stack}`; - } else if (typeof err === 'string') { - return `${message}: ${err}`; - } else if (err) { - return `${message}: ${err.toString()}`; - } - return message; -} - -export function runSafe(func: () => Thenable | T, errorVal: T, errorMessage: string): Thenable | T { - try { - let t = func(); - if (t instanceof Promise) { - return t.then(void 0, e => { - console.error(formatError(errorMessage, e)); - return errorVal; - }); - } - return t; - } catch (e) { - console.error(formatError(errorMessage, e)); - return errorVal; - } -} \ No newline at end of file diff --git a/extensions/css-language-features/server/src/utils/runner.ts b/extensions/css-language-features/server/src/utils/runner.ts new file mode 100644 index 00000000000..273194ce431 --- /dev/null +++ b/extensions/css-language-features/server/src/utils/runner.ts @@ -0,0 +1,47 @@ +/*--------------------------------------------------------------------------------------------- + * 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 { ResponseError, ErrorCodes, CancellationToken } from 'vscode-languageserver'; + +export function formatError(message: string, err: any): string { + if (err instanceof Error) { + let error = err; + return `${message}: ${error.message}\n${error.stack}`; + } else if (typeof err === 'string') { + return `${message}: ${err}`; + } else if (err) { + return `${message}: ${err.toString()}`; + } + return message; +} + +export function runSafe(func: () => T, errorVal: T, errorMessage: string, token: CancellationToken): Thenable> { + return new Promise>((resolve, reject) => { + setImmediate(() => { + if (token.isCancellationRequested) { + resolve(cancelValue()); + } else { + try { + let result = func(); + if (token.isCancellationRequested) { + resolve(cancelValue()); + return; + } else { + resolve(result); + } + + } catch (e) { + console.error(formatError(errorMessage, e)); + resolve(errorVal); + } + } + }); + }); +} + +function cancelValue() { + return new ResponseError(ErrorCodes.RequestCancelled, 'Request cancelled'); +} diff --git a/extensions/css-language-features/server/tsconfig.json b/extensions/css-language-features/server/tsconfig.json index dc12dad6cf0..7f8b647d04b 100644 --- a/extensions/css-language-features/server/tsconfig.json +++ b/extensions/css-language-features/server/tsconfig.json @@ -6,7 +6,8 @@ "noUnusedLocals": true, "lib": [ "es5", "es2015.promise" - ] + ], + "strict": true }, "include": [ "src/**/*"