[folding] hook up cancellation

This commit is contained in:
Martin Aeschlimann
2018-03-13 09:48:50 +01:00
parent 060a4aa3fc
commit e647a097e6
9 changed files with 127 additions and 69 deletions

View File

@@ -4,17 +4,20 @@
*--------------------------------------------------------------------------------------------*/
'use strict';
import { TextDocument, Position } from 'vscode-languageserver';
import { TextDocument, Position, CancellationToken } from 'vscode-languageserver';
import { createScanner, SyntaxKind, ScanError } from 'jsonc-parser';
import { FoldingRangeType, FoldingRange, FoldingRangeList } from './protocol/foldingProvider.proposed';
export function getFoldingRegions(document: TextDocument) {
export function getFoldingRegions(document: TextDocument, cancellationToken: CancellationToken | null) {
let ranges: FoldingRange[] = [];
let stack: FoldingRange[] = [];
let prevStart = -1;
let scanner = createScanner(document.getText(), false);
let token = scanner.scan();
while (token !== SyntaxKind.EOF) {
if (cancellationToken && cancellationToken.isCancellationRequested) {
return null;
}
switch (token) {
case SyntaxKind.OpenBraceToken:
case SyntaxKind.OpenBracketToken: {

View File

@@ -18,7 +18,7 @@ import { startsWith } from './utils/strings';
import { formatError, runSafe, runSafeAsync } from './utils/errors';
import { JSONDocument, JSONSchema, getLanguageService, DocumentLanguageSettings, SchemaConfiguration } from 'vscode-json-languageservice';
import { getLanguageModelCache } from './languageModelCache';
import { getFoldingRegions } from './folding';
import { getFoldingRegions } from './jsonFolding';
import { FoldingRangesRequest, FoldingProviderServerCapabilities } from './protocol/foldingProvider.proposed';
@@ -260,17 +260,21 @@ function validateTextDocument(textDocument: TextDocument): void {
connection.sendDiagnostics({ uri: textDocument.uri, diagnostics: [] });
return;
}
try {
let jsonDocument = getJSONDocument(textDocument);
let jsonDocument = getJSONDocument(textDocument);
let version = textDocument.version;
let documentSettings: DocumentLanguageSettings = textDocument.languageId === 'jsonc' ? { comments: 'ignore', trailingCommas: 'ignore' } : { comments: 'error', trailingCommas: 'error' };
languageService.doValidation(textDocument, jsonDocument, documentSettings).then(diagnostics => {
// Send the computed diagnostics to VSCode.
connection.sendDiagnostics({ uri: textDocument.uri, diagnostics });
});
} catch (e) {
connection.console.error(formatError(`Error while validating ${textDocument.uri}`, e));
}
let documentSettings: DocumentLanguageSettings = textDocument.languageId === 'jsonc' ? { comments: 'ignore', trailingCommas: 'ignore' } : { comments: 'error', trailingCommas: 'error' };
languageService.doValidation(textDocument, jsonDocument, documentSettings).then(diagnostics => {
setTimeout(() => {
let currDocument = documents.get(textDocument.uri);
if (currDocument && currDocument.version === version) {
// Send the computed diagnostics to VSCode.
connection.sendDiagnostics({ uri: textDocument.uri, diagnostics });
}
}, 100);
}, error => {
connection.console.error(formatError(`Error while validating ${textDocument.uri}`, error));
});
}
connection.onDidChangeWatchedFiles((change) => {
@@ -282,7 +286,7 @@ connection.onDidChangeWatchedFiles((change) => {
}
});
if (hasChanges) {
documents.all().forEach(validateTextDocument);
documents.all().forEach(triggerValidation);
}
});
@@ -320,19 +324,19 @@ connection.onHover(textDocumentPositionParams => {
}, null, `Error while computing hover for ${textDocumentPositionParams.textDocument.uri}`);
});
connection.onDocumentSymbol(documentSymbolParams => {
connection.onDocumentSymbol((documentSymbolParams, token) => {
return runSafe(() => {
let document = documents.get(documentSymbolParams.textDocument.uri);
let jsonDocument = getJSONDocument(document);
return languageService.findDocumentSymbols(document, jsonDocument);
}, [], `Error while computing document symbols for ${documentSymbolParams.textDocument.uri}`);
}, [], `Error while computing document symbols for ${documentSymbolParams.textDocument.uri}`, token);
});
connection.onDocumentRangeFormatting(formatParams => {
connection.onDocumentRangeFormatting((formatParams, token) => {
return runSafe(() => {
let document = documents.get(formatParams.textDocument.uri);
return languageService.format(document, formatParams.range, formatParams.options);
}, [], `Error while formatting range for ${formatParams.textDocument.uri}`);
}, [], `Error while formatting range for ${formatParams.textDocument.uri}`, token);
});
connection.onRequest(DocumentColorRequest.type, params => {
@@ -346,7 +350,7 @@ connection.onRequest(DocumentColorRequest.type, params => {
}, [], `Error while computing document colors for ${params.textDocument.uri}`);
});
connection.onRequest(ColorPresentationRequest.type, params => {
connection.onRequest(ColorPresentationRequest.type, (params, token) => {
return runSafe(() => {
let document = documents.get(params.textDocument.uri);
if (document) {
@@ -354,17 +358,17 @@ connection.onRequest(ColorPresentationRequest.type, params => {
return languageService.getColorPresentations(document, jsonDocument, 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.onRequest(FoldingRangesRequest.type, params => {
connection.onRequest(FoldingRangesRequest.type, (params, token) => {
return runSafe(() => {
let document = documents.get(params.textDocument.uri);
if (document) {
return getFoldingRegions(document);
return getFoldingRegions(document, token);
}
return null;
}, 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

View File

@@ -8,7 +8,7 @@
import 'mocha';
import * as assert from 'assert';
import { TextDocument } from 'vscode-languageserver';
import { getFoldingRegions } from '../folding';
import { getFoldingRegions } from '../jsonFolding';
interface ExpectedIndentRange {
startLine: number;
@@ -18,8 +18,7 @@ interface ExpectedIndentRange {
function assertRanges(lines: string[], expected: ExpectedIndentRange[]): void {
let document = TextDocument.create('test://foo/bar.json', 'json', 1, lines.join('\n'));
let actual = getFoldingRegions(document).ranges;
let actual = getFoldingRegions(document, null)!.ranges;
let actualRanges = [];
for (let i = 0; i < actual.length; i++) {

View File

@@ -4,6 +4,8 @@
*--------------------------------------------------------------------------------------------*/
'use strict';
import { CancellationToken, ResponseError, ErrorCodes } from 'vscode-languageserver';
export function formatError(message: string, err: any): string {
if (err instanceof Error) {
let error = <Error>err;
@@ -23,11 +25,31 @@ export function runSafeAsync<T>(func: () => Thenable<T>, errorVal: T, errorMessa
return errorVal;
});
}
export function runSafe<T>(func: () => T, errorVal: T, errorMessage: string): T {
try {
return func();
} catch (e) {
console.error(formatError(errorMessage, e));
return errorVal;
}
}
export function runSafe<T, E>(func: () => T, errorVal: T, errorMessage: string, token: CancellationToken): Thenable<T | ResponseError<E>> {
return new Promise<T | ResponseError<E>>((resolve, reject) => {
setTimeout(() => {
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);
}
}
}, 100);
});
}
function cancelValue<E>() {
console.log('cancelled');
return new ResponseError<E>(ErrorCodes.RequestCancelled, 'Request cancelled');
}