From ef715cf8c5ec206e01791892eb0d045d7d4b3683 Mon Sep 17 00:00:00 2001 From: Martin Aeschlimann Date: Thu, 9 Apr 2020 18:25:12 +0200 Subject: [PATCH] TypeScript semantic tokens: use range provider --- .../src/features/semanticTokens.ts | 12 ++++++------ .../inspectEditorTokens/inspectEditorTokens.ts | 18 ++++++++++++++---- 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/extensions/typescript-language-features/src/features/semanticTokens.ts b/extensions/typescript-language-features/src/features/semanticTokens.ts index 373275a6356..92b6e479330 100644 --- a/extensions/typescript-language-features/src/features/semanticTokens.ts +++ b/extensions/typescript-language-features/src/features/semanticTokens.ts @@ -14,20 +14,19 @@ import { TokenType, TokenModifier, TokenEncodingConsts, VersionRequirement } fro const minTypeScriptVersion = API.fromVersionString(`${VersionRequirement.major}.${VersionRequirement.minor}`); +// as we don't do deltas, for performance reasons, don't compute semantic tokens for documents above that limit +const CONTENT_LENGTH_LIMIT = 100000; + export function register(selector: vscode.DocumentSelector, client: ITypeScriptServiceClient) { return new VersionDependentRegistration(client, minTypeScriptVersion, () => { const provider = new DocumentSemanticTokensProvider(client); return vscode.Disposable.from( - vscode.languages.registerDocumentSemanticTokensProvider(selector, provider, provider.getLegend()), + // register only as a range provider vscode.languages.registerDocumentRangeSemanticTokensProvider(selector, provider, provider.getLegend()), ); }); } - -// as we don't do deltas, for performance reasons, don't compute semantic tokens for documents above that limit -const CONTENT_LENGTH_LIMIT = 100000; - /** * Prototype of a DocumentSemanticTokensProvider, relying on the experimental `encodedSemanticClassifications-full` request from the TypeScript server. * As the results retured by the TypeScript server are limited, we also add a Typescript plugin (typescript-vscode-sh-plugin) to enrich the returned token. @@ -52,9 +51,10 @@ class DocumentSemanticTokensProvider implements vscode.DocumentSemanticTokensPro async provideDocumentRangeSemanticTokens(document: vscode.TextDocument, range: vscode.Range, token: vscode.CancellationToken): Promise { const file = this.client.toOpenedFilePath(document); - if (!file || document.getText().length > CONTENT_LENGTH_LIMIT) { + if (!file || (document.offsetAt(range.end) - document.offsetAt(range.start) > CONTENT_LENGTH_LIMIT)) { return null; } + const start = document.offsetAt(range.start); const length = document.offsetAt(range.end) - start; return this._provideSemanticTokens(document, { file, start, length }, token); diff --git a/src/vs/workbench/contrib/codeEditor/browser/inspectEditorTokens/inspectEditorTokens.ts b/src/vs/workbench/contrib/codeEditor/browser/inspectEditorTokens/inspectEditorTokens.ts index cda6157b97c..a8810e4b0cf 100644 --- a/src/vs/workbench/contrib/codeEditor/browser/inspectEditorTokens/inspectEditorTokens.ts +++ b/src/vs/workbench/contrib/codeEditor/browser/inspectEditorTokens/inspectEditorTokens.ts @@ -17,7 +17,7 @@ import { Position } from 'vs/editor/common/core/position'; import { Range } from 'vs/editor/common/core/range'; import { IEditorContribution } from 'vs/editor/common/editorCommon'; import { ITextModel } from 'vs/editor/common/model'; -import { FontStyle, LanguageIdentifier, StandardTokenType, TokenMetadata, DocumentSemanticTokensProviderRegistry, SemanticTokensLegend, SemanticTokens, LanguageId, ColorId } from 'vs/editor/common/modes'; +import { FontStyle, LanguageIdentifier, StandardTokenType, TokenMetadata, DocumentSemanticTokensProviderRegistry, SemanticTokensLegend, SemanticTokens, LanguageId, ColorId, DocumentRangeSemanticTokensProviderRegistry } from 'vs/editor/common/modes'; import { IModeService } from 'vs/editor/common/services/modeService'; import { INotificationService } from 'vs/platform/notification/common/notification'; import { editorHoverBackground, editorHoverBorder } from 'vs/platform/theme/common/colorRegistry'; @@ -240,7 +240,7 @@ class InspectEditorTokensWidget extends Disposable implements IContentWidget { private _beginCompute(position: Position): void { const grammar = this._textMateService.createGrammar(this._model.getLanguageIdentifier().language); - const semanticTokens = this._computeSemanticTokens(); + const semanticTokens = this._computeSemanticTokens(position); dom.clearNode(this._domNode); this._domNode.appendChild(document.createTextNode(nls.localize('inspectTMScopesWidget.loading', "Loading..."))); @@ -307,7 +307,7 @@ class InspectEditorTokensWidget extends Disposable implements IContentWidget { const properties: (keyof TokenStyleData)[] = ['foreground', 'bold', 'italic', 'underline']; const propertiesByDefValue: { [rule: string]: string[] } = {}; const allDefValues = []; // remember the order - // first collect to detect when the same rule is used fro multiple properties + // first collect to detect when the same rule is used for multiple properties for (let property of properties) { if (semanticTokenInfo.metadata[property] !== undefined) { const definition = semanticTokenInfo.definitions[property]; @@ -476,7 +476,7 @@ class InspectEditorTokensWidget extends Disposable implements IContentWidget { return token && token.data; } - private async _computeSemanticTokens(): Promise { + private async _computeSemanticTokens(position: Position): Promise { if (!this._isSemanticColoringEnabled()) { return null; } @@ -489,6 +489,16 @@ class InspectEditorTokensWidget extends Disposable implements IContentWidget { return { tokens, legend: provider.getLegend() }; } } + const rangeTokenProviders = DocumentRangeSemanticTokensProviderRegistry.ordered(this._model); + if (rangeTokenProviders.length) { + const provider = rangeTokenProviders[0]; + const lineNumber = position.lineNumber; + const range = new Range(lineNumber, 1, lineNumber, this._model.getLineMaxColumn(lineNumber)); + const tokens = await Promise.resolve(provider.provideDocumentRangeSemanticTokens(this._model, range, this._currentRequestCancellationTokenSource.token)); + if (this.isSemanticTokens(tokens)) { + return { tokens, legend: provider.getLegend() }; + } + } return null; } -- GitLab