From a6aa50a86bd6c2a1dd4517a23a3d67d94e5dfdec Mon Sep 17 00:00:00 2001 From: Colen Garoutte-Carson Date: Wed, 22 Apr 2020 18:27:17 -0700 Subject: [PATCH 01/14] Work in progress --- Extension/package.json | 2 +- Extension/src/LanguageServer/client.ts | 32 ++++++++++++++++++++++++++ Extension/yarn.lock | 8 +++---- 3 files changed, 37 insertions(+), 5 deletions(-) diff --git a/Extension/package.json b/Extension/package.json index 325cafe4b4..fd665ba50a 100644 --- a/Extension/package.json +++ b/Extension/package.json @@ -1499,7 +1499,7 @@ "@types/plist": "^3.0.2", "@types/semver": "^7.1.0", "@types/tmp": "^0.1.0", - "@types/vscode": "1.43.0", + "@types/vscode": "1.44.0", "@types/webpack": "^4.39.0", "@types/which": "^1.3.2", "@types/yauzl": "^2.9.1", diff --git a/Extension/src/LanguageServer/client.ts b/Extension/src/LanguageServer/client.ts index d27799cbc2..82a25055ed 100644 --- a/Extension/src/LanguageServer/client.ts +++ b/Extension/src/LanguageServer/client.ts @@ -964,6 +964,16 @@ export class DefaultClient implements Client { } } + class SemanticTokensProvider implements vscode.DocumentSemanticTokensProvider { + private client: DefaultClient; + constructor(client: DefaultClient) { + this.client = client; + } + + public async provideDocumentSemanticTokens(document: vscode.TextDocument, token: vscode.CancellationToken): Promise { + } + } + this.registerFileWatcher(); if (firstClient) { @@ -973,6 +983,28 @@ export class DefaultClient implements Client { this.disposables.push(vscode.languages.registerDocumentSymbolProvider(documentSelector, new DocumentSymbolProvider(this), undefined)); this.disposables.push(vscode.languages.registerCodeActionsProvider(documentSelector, new CodeActionProvider(this), undefined)); + const tokenTypes: Map = new Map(); + const tokenModifiers: Map = new Map(); + + const legend: vscode.SemanticTokensLegend = (() => { + const tokenTypesLegend: string[] = [ + 'templateClass', 'enummember', 'event', 'function', 'templateFunction', 'genericClass', + 'variable', 'label', 'property', 'member', 'namespace', 'newOperator', 'operatorOverload', + 'memberOperatorOverload', 'parameter', 'cliProperty', 'referenceClass', 'class', + 'numberLiteral', 'customLiteral', 'stringLiteral', 'valueClass' + ]; + tokenTypesLegend.forEach((tokenType, index) => tokenTypes.set(tokenType, index)); + + const tokenModifiersLegend: string[] = [ + 'global', 'local', 'static' + ]; + tokenModifiersLegend.forEach((tokenModifier, index) => tokenModifiers.set(tokenModifier, index)); + + return new vscode.SemanticTokensLegend(tokenTypesLegend, tokenModifiersLegend); + })(); + + this.disposables.push(vscode.languages.registerDocumentSemanticTokensProvider(documentSelector, new SemanticTokensProvider(this), legend)); + // Listen for messages from the language server. this.registerNotifications(); diff --git a/Extension/yarn.lock b/Extension/yarn.lock index 765cdc3136..928978bb54 100644 --- a/Extension/yarn.lock +++ b/Extension/yarn.lock @@ -204,10 +204,10 @@ dependencies: source-map "^0.6.1" -"@types/vscode@1.43.0": - version "1.43.0" - resolved "https://registry.yarnpkg.com/@types/vscode/-/vscode-1.43.0.tgz#22276e60034c693b33117f1068ffaac0e89522db" - integrity sha512-kIaR9qzd80rJOxePKpCB/mdy00mz8Apt2QA5Y6rdrKFn13QNFNeP3Hzmsf37Bwh/3cS7QjtAeGSK7wSqAU0sYQ== +"@types/vscode@1.44.0": + version "1.44.0" + resolved "https://registry.yarnpkg.com/@types/vscode/-/vscode-1.44.0.tgz#62ecfe3d0e38942fce556574da54ee1013c775b7" + integrity sha512-WJZtZlinE3meRdH+I7wTsIhpz/GLhqEQwmPGeh4s1irWLwMzCeTV8WZ+pgPTwrDXoafVUWwo1LiZ9HJVHFlJSQ== "@types/webpack-sources@*": version "0.1.6" From 949759b55835a5913641f6664582756b366c90b8 Mon Sep 17 00:00:00 2001 From: Colen Garoutte-Carson Date: Thu, 23 Apr 2020 16:01:22 -0700 Subject: [PATCH 02/14] Work in progress --- Extension/package.json | 74 +++++++++++++++++++++- Extension/src/LanguageServer/client.ts | 87 +++++++++++++++++--------- 2 files changed, 130 insertions(+), 31 deletions(-) diff --git a/Extension/package.json b/Extension/package.json index 6ea9243aec..dc38f1e0d5 100644 --- a/Extension/package.json +++ b/Extension/package.json @@ -1468,7 +1468,79 @@ "[Log]": { "editor.wordWrap": "off" } - } + }, + "semanticTokenTypes": [ + { + "id": "referenceType", + "superType": "type", + "description": "A C++/CLI reference type." + }, + { + "id": "cliProperty", + "superType": "property", + "description": "A C++/CLI property." + }, + { + "id": "genericType", + "superType": "type", + "description": "A C++/CLI generic type." + }, + { + "id": "valueType", + "superType": "type", + "description": "A C++/CLI value type." + }, + { + "id": "templateFunction", + "superType": "function", + "description": "A template function." + }, + { + "id": "templateType", + "superType": "type", + "description": "A template type." + }, + { + "id": "operatorOverload", + "superType": "operator", + "description": "An overloaded operator." + }, + { + "id": "memberOperatorOverload", + "superType": "operator", + "description": "An overloaded operator member function." + }, + { + "id": "newOperator", + "superType": "operator", + "description": "A C++ new or delete operator." + }, + { + "id": "customLiteral", + "superType": "number", + "description": "A user-defined literal." + }, + { + "id": "numberLiteral", + "superType": "number", + "description": "A user-defined literal number." + }, + { + "id": "stringLiteral", + "superType": "string", + "description": "A user-defined literal string." + } + ], + "semanticTokenModifiers": [ + { + "id": "global", + "description": "Annotates a symbol that is declared in global scope." + }, + { + "id": "local", + "description": "Annotates a symbol that is declared in local scope." + } + ] }, "scripts": { "vscode:prepublish": "yarn run compile", diff --git a/Extension/src/LanguageServer/client.ts b/Extension/src/LanguageServer/client.ts index ffc6708ab2..eaaa010893 100644 --- a/Extension/src/LanguageServer/client.ts +++ b/Extension/src/LanguageServer/client.ts @@ -551,6 +551,8 @@ export class DefaultClient implements Client { private visibleRanges = new Map(); private settingsTracker: SettingsTracker; private configurationProvider?: string; + private tokenTypes: Map = new Map(); + private tokenModifiers: Map = new Map(); // The "model" that is displayed via the UI (status bar). private model: ClientModel = new ClientModel(); @@ -1043,18 +1045,64 @@ export class DefaultClient implements Client { } } + const legend: vscode.SemanticTokensLegend = (() => { + const tokenTypesLegend: string[] = [ + 'macro', 'enumMember', 'variable', 'parameter', 'type', 'referenceType', 'valueType', 'function', + 'member', 'property', 'cliProperty', 'event', 'genericType', 'templateFunction', 'templateType', + 'namespace', 'label', 'customLiteral', 'numberLiteral', 'stringLiteral', 'operatorOverload', + 'memberOperatorOverload', 'newOperator' + ]; + tokenTypesLegend.forEach((tokenType, index) => this.tokenTypes.set(tokenType, index)); + + const tokenModifiersLegend: string[] = [ + 'static', 'global', 'local' + ]; + tokenModifiersLegend.forEach((tokenModifier, index) => this.tokenModifiers.set(tokenModifier, index)); + + return new vscode.SemanticTokensLegend(tokenTypesLegend, tokenModifiersLegend); + })(); + class SemanticTokensProvider implements vscode.DocumentSemanticTokensProvider { - private client: DefaultClient; - constructor(client: DefaultClient) { - this.client = client; + private client: DefaultClient; + constructor(client: DefaultClient) { + this.client = client; + } + + private _encodeTokenType(tokenType: string): number { + let type: number | undefined = this.client.tokenTypes.get(tokenType); + return type ? type : 0; + } + + private _encodeTokenModifiers(strTokenModifiers: string[]): number { + let result: number = 0; + for (let i: number = 0; i < strTokenModifiers.length; i++) { + const tokenModifier: string = strTokenModifiers[i]; + if (this.client.tokenModifiers.has(tokenModifier)) { + const shift: number | undefined = this.client.tokenModifiers.get(tokenModifier); + if (shift) { + // eslint-disable-next-line no-bitwise + result = result | (1 << shift); + } + } } - public async provideDocumentSemanticTokens(document: vscode.TextDocument, token: vscode.CancellationToken): Promise { - return new Promise((resolve, reject) => { - this.client.notifyWhenReady(() => { - reject(); - }); + return result; + } + + public async provideDocumentSemanticTokens(document: vscode.TextDocument, token: vscode.CancellationToken): Promise { + return new Promise((resolve, reject) => { + this.client.notifyWhenReady(() => { + + // const builder: vscode.SemanticTokensBuilder = new vscode.SemanticTokensBuilder(); + // allTokens.forEach((token) => { + // builder.push(token.line, token.startCharacter, token.length, + // this._encodeTokenType(token.tokenType), + // this._encodeTokenModifiers(token.tokenModifiers)); + // }); + // return builder.build(); + + reject(); }); - } + }); } } @@ -1067,27 +1115,6 @@ export class DefaultClient implements Client { this.disposables.push(vscode.languages.registerDocumentSymbolProvider(documentSelector, new DocumentSymbolProvider(this), undefined)); this.disposables.push(vscode.languages.registerCodeActionsProvider(documentSelector, new CodeActionProvider(this), undefined)); this.disposables.push(vscode.languages.registerFoldingRangeProvider(documentSelector, new FoldingRangeProvider(this))); - - const tokenTypes: Map = new Map(); - const tokenModifiers: Map = new Map(); - - const legend: vscode.SemanticTokensLegend = (() => { - const tokenTypesLegend: string[] = [ - 'templateClass', 'enummember', 'event', 'function', 'templateFunction', 'genericClass', - 'variable', 'label', 'property', 'member', 'namespace', 'newOperator', 'operatorOverload', - 'memberOperatorOverload', 'parameter', 'cliProperty', 'referenceClass', 'class', - 'numberLiteral', 'customLiteral', 'stringLiteral', 'valueClass' - ]; - tokenTypesLegend.forEach((tokenType, index) => tokenTypes.set(tokenType, index)); - - const tokenModifiersLegend: string[] = [ - 'global', 'local', 'static' - ]; - tokenModifiersLegend.forEach((tokenModifier, index) => tokenModifiers.set(tokenModifier, index)); - - return new vscode.SemanticTokensLegend(tokenTypesLegend, tokenModifiersLegend); - })(); - this.disposables.push(vscode.languages.registerDocumentSemanticTokensProvider(documentSelector, new SemanticTokensProvider(this), legend)); // Listen for messages from the language server. From 747ec857fe122d7e4269c98932c46127f87d58cb Mon Sep 17 00:00:00 2001 From: Colen Garoutte-Carson Date: Tue, 28 Apr 2020 16:50:35 -0700 Subject: [PATCH 03/14] Work in progress --- Extension/src/LanguageServer/client.ts | 161 +++++++++++++++++-------- 1 file changed, 111 insertions(+), 50 deletions(-) diff --git a/Extension/src/LanguageServer/client.ts b/Extension/src/LanguageServer/client.ts index eaaa010893..16e433d7f2 100644 --- a/Extension/src/LanguageServer/client.ts +++ b/Extension/src/LanguageServer/client.ts @@ -342,7 +342,7 @@ interface GetFoldingRangesParams { id: number; } -export enum FoldingRangeKind { +enum FoldingRangeKind { None = 0, Comment = 1, Imports = 2, @@ -352,7 +352,7 @@ export enum FoldingRangeKind { interface FoldingRange { kind: FoldingRangeKind; range: Range; -}; +} interface GetFoldingRangesResult { canceled: boolean; @@ -363,6 +363,58 @@ interface AbortRequestParams { id: number; } +interface GetSemanticTokensParams { + uri: string; + id: number; +} + +interface SemanticToken { + line: number; + character: number; + length: number; + type: number; + modifiers?: number; +} + +interface GetSemanticTokensResult { + canceled: boolean; + tokens: SemanticToken[]; +} + +enum SemanticTokenTypes { + // These are camelCase as the enum names are used directly as strings in our legend. + macro = 0, + enumMember = 1, + variable = 2, + parameter = 3, + type = 4, + referenceType = 5, + valueType = 6, + function = 7, + member = 8, + property = 9, + cliProperty = 10, + event = 11, + genericType = 12, + templateFunction = 13, + templateType = 14, + namespace = 15, + label = 16, + customLiteral = 17, + numberLiteral = 18, + stringLiteral = 19, + operatorOverload = 20, + memberOperatorOverload = 21, + newOperator = 22 +} + +enum SemanticTokenModifiers { + // These are camelCase as the enum names are used directly as strings in our legend. + static = (1 << 0), + global = (1 << 1), + local = (1 << 2) +} + // Requests const QueryCompilerDefaultsRequest: RequestType = new RequestType('cpptools/queryCompilerDefaults'); const QueryTranslationUnitSourceRequest: RequestType = new RequestType('cpptools/queryTranslationUnitSource'); @@ -372,6 +424,7 @@ const GetCodeActionsRequest: RequestType = new RequestType('cpptools/getDocumentSymbols'); const GetSymbolInfoRequest: RequestType = new RequestType('cpptools/getWorkspaceSymbols'); const GetFoldingRangesRequest: RequestType = new RequestType('cpptools/getFoldingRanges'); +const GetSemanticTokensRequest: RequestType = new RequestType('cpptools/getSemanticTokens'); // Notifications to the server const DidOpenNotification: NotificationType = new NotificationType('textDocument/didOpen'); @@ -551,8 +604,8 @@ export class DefaultClient implements Client { private visibleRanges = new Map(); private settingsTracker: SettingsTracker; private configurationProvider?: string; - private tokenTypes: Map = new Map(); - private tokenModifiers: Map = new Map(); + // private tokenTypes: Map = new Map(); + // private tokenModifiers: Map = new Map(); // The "model" that is displayed via the UI (status bar). private model: ClientModel = new ClientModel(); @@ -1045,22 +1098,42 @@ export class DefaultClient implements Client { } } - const legend: vscode.SemanticTokensLegend = (() => { - const tokenTypesLegend: string[] = [ - 'macro', 'enumMember', 'variable', 'parameter', 'type', 'referenceType', 'valueType', 'function', - 'member', 'property', 'cliProperty', 'event', 'genericType', 'templateFunction', 'templateType', - 'namespace', 'label', 'customLiteral', 'numberLiteral', 'stringLiteral', 'operatorOverload', - 'memberOperatorOverload', 'newOperator' - ]; - tokenTypesLegend.forEach((tokenType, index) => this.tokenTypes.set(tokenType, index)); - - const tokenModifiersLegend: string[] = [ - 'static', 'global', 'local' - ]; - tokenModifiersLegend.forEach((tokenModifier, index) => this.tokenModifiers.set(tokenModifier, index)); - - return new vscode.SemanticTokensLegend(tokenTypesLegend, tokenModifiersLegend); - })(); + // Semantic token types are identified by indexes in this list of types, in the legend. + let tokenTypesLegend: string[] = []; + for (let e in SemanticTokenTypes) { + // An enum is actually a set of mappings from key <=> value. Enumerate over only the names. + // This allow us to represent the constants using an enum, which we can match in native code. + if (isNaN(Number(e))) { + tokenTypesLegend.push(e); + } + } + // Semantic token modifiers are bit indexes corresponding to the indexes in this list of modifiers in the legend. + let tokenModifiersLegend: string[] = []; + for (let e in SemanticTokenModifiers) { + if (isNaN(Number(e))) { + tokenModifiersLegend.push(e); + } + } + const legend: vscode.SemanticTokensLegend = new vscode.SemanticTokensLegend(tokenTypesLegend, tokenModifiersLegend); + + // // Semantic token types are identified by indexes in this list of types, in the legend. + // const legend: vscode.SemanticTokensLegend = (() => { + // const tokenTypesLegend: string[] = [ + // 'macro', 'enumMember', 'variable', 'parameter', 'type', 'referenceType', 'valueType', 'function', + // 'member', 'property', 'cliProperty', 'event', 'genericType', 'templateFunction', 'templateType', + // 'namespace', 'label', 'customLiteral', 'numberLiteral', 'stringLiteral', 'operatorOverload', + // 'memberOperatorOverload', 'newOperator' + // ]; + // //tokenTypesLegend.forEach((tokenType, index) => this.tokenTypes.set(tokenType, index)); + // + // // Semantic token modifiers are bit indexes corresponding to the indexes in this list of modifiers in the legend. + // const tokenModifiersLegend: string[] = [ + // 'static', 'global', 'local' + // ]; + // //tokenModifiersLegend.forEach((tokenModifier, index) => this.tokenModifiers.set(tokenModifier, index)); + // + // return new vscode.SemanticTokensLegend(tokenTypesLegend, tokenModifiersLegend); + // })(); class SemanticTokensProvider implements vscode.DocumentSemanticTokensProvider { private client: DefaultClient; @@ -1068,39 +1141,27 @@ export class DefaultClient implements Client { this.client = client; } - private _encodeTokenType(tokenType: string): number { - let type: number | undefined = this.client.tokenTypes.get(tokenType); - return type ? type : 0; - } - - private _encodeTokenModifiers(strTokenModifiers: string[]): number { - let result: number = 0; - for (let i: number = 0; i < strTokenModifiers.length; i++) { - const tokenModifier: string = strTokenModifiers[i]; - if (this.client.tokenModifiers.has(tokenModifier)) { - const shift: number | undefined = this.client.tokenModifiers.get(tokenModifier); - if (shift) { - // eslint-disable-next-line no-bitwise - result = result | (1 << shift); - } - } - } - return result; - } - public async provideDocumentSemanticTokens(document: vscode.TextDocument, token: vscode.CancellationToken): Promise { return new Promise((resolve, reject) => { this.client.notifyWhenReady(() => { - - // const builder: vscode.SemanticTokensBuilder = new vscode.SemanticTokensBuilder(); - // allTokens.forEach((token) => { - // builder.push(token.line, token.startCharacter, token.length, - // this._encodeTokenType(token.tokenType), - // this._encodeTokenModifiers(token.tokenModifiers)); - // }); - // return builder.build(); - - reject(); + let id: number = ++abortRequestId; + let params: GetSemanticTokensParams = { + id: id, + uri: document.uri.toString() + }; + this.client.languageClient.sendRequest(GetSemanticTokensRequest, params) + .then((tokensResult) => { + if (tokensResult.canceled) { + reject(); + } else { + let builder: vscode.SemanticTokensBuilder = new vscode.SemanticTokensBuilder(legend); + tokensResult.tokens.forEach((token) => { + builder.push(token.line, token.character, token.length, token.type, token.modifiers); + }); + resolve(builder.build()); + } + }); + token.onCancellationRequested(e => this.client.abortRequest(id)); }); }); } From 0ddb1b95dc880baffd4f7331e23a50d0ca9125bd Mon Sep 17 00:00:00 2001 From: Colen Garoutte-Carson Date: Thu, 30 Apr 2020 02:02:05 -0700 Subject: [PATCH 04/14] Work in progress --- Extension/package.nls.json | 2 +- Extension/src/LanguageServer/client.ts | 323 +++------ Extension/src/LanguageServer/colorization.ts | 671 ------------------ Extension/src/LanguageServer/extension.ts | 28 - .../src/LanguageServer/protocolFilter.ts | 4 +- 5 files changed, 96 insertions(+), 932 deletions(-) delete mode 100644 Extension/src/LanguageServer/colorization.ts diff --git a/Extension/package.nls.json b/Extension/package.nls.json index f79d7b5c96..9f949789b1 100644 --- a/Extension/package.nls.json +++ b/Extension/package.nls.json @@ -63,7 +63,7 @@ "c_cpp.configuration.updateChannel.description": "Set to \"Insiders\" to automatically download and install the latest Insiders builds of the extension, which include upcoming features and bug fixes.", "c_cpp.configuration.experimentalFeatures.description": "Controls whether \"experimental\" features are usable.", "c_cpp.configuration.suggestSnippets.description": "If true, snippets are provided by the language server.", - "c_cpp.configuration.enhancedColorization.description": "If enabled, code is colorized based on IntelliSense. This setting has no effect if IntelliSense is disabled or if using the Default High Contrast theme.", + "c_cpp.configuration.enhancedColorization.description": "If enabled, code is colorized based on IntelliSense. This setting only applies if intelliSenseEngine is set to \"Default\".", "c_cpp.configuration.vcpkg.enabled.markdownDescription": "Enable integration services for the [vcpkg dependency manager](https://aka.ms/vcpkg/).", "c_cpp.configuration.renameRequiresIdentifier.description": "If true, 'Rename Symbol' will require a valid C/C++ identifier.", "c_cpp.configuration.debugger.useBacktickCommandSubstitution.description": "If true, debugger shell command substitution will use obsolete backtick (`)", diff --git a/Extension/src/LanguageServer/client.ts b/Extension/src/LanguageServer/client.ts index 16e433d7f2..e4545d8406 100644 --- a/Extension/src/LanguageServer/client.ts +++ b/Extension/src/LanguageServer/client.ts @@ -30,7 +30,6 @@ import { getCustomConfigProviders, CustomConfigurationProvider1, isSameProviderE import { ABTestSettings, getABTestSettings } from '../abTesting'; import * as fs from 'fs'; import * as os from 'os'; -import { TokenKind, ColorizationSettings, ColorizationState } from './colorization'; import * as refs from './references'; import * as nls from 'vscode-nls'; @@ -53,17 +52,12 @@ let diagnosticsChannel: vscode.OutputChannel; let outputChannel: vscode.OutputChannel; let debugChannel: vscode.OutputChannel; let diagnosticsCollection: vscode.DiagnosticCollection; -let workspaceColorizationState: Map = new Map(); let workspaceDisposables: vscode.Disposable[] = []; let workspaceReferences: refs.ReferencesManager; export function disposeWorkspaceData(): void { workspaceDisposables.forEach((d) => d.dispose()); workspaceDisposables = []; - - workspaceColorizationState.forEach(colorizationState => { - colorizationState.dispose(); - }); } function logTelemetry(notificationBody: TelemetryPayload): void { @@ -140,28 +134,6 @@ function publishDiagnostics(params: PublishDiagnosticsParams): void { diagnosticsCollection.set(realUri, diagnostics); } -function updateSemanticColorizationRegions(params: SemanticColorizationRegionsParams): void { - let colorizationState: ColorizationState | undefined = workspaceColorizationState.get(params.uri); - if (colorizationState) { - // Convert the params to vscode.Range's before passing to colorizationState.updateSemantic() - let semanticRanges: vscode.Range[][] = new Array(TokenKind.Count); - for (let i: number = 0; i < TokenKind.Count; i++) { - semanticRanges[i] = []; - } - params.regions.forEach(element => { - let newRange: vscode.Range = new vscode.Range(element.range.start.line, element.range.start.character, element.range.end.line, element.range.end.character); - semanticRanges[element.kind].push(newRange); - }); - let inactiveRanges: vscode.Range[] = []; - params.inactiveRegions.forEach(element => { - let newRange: vscode.Range = new vscode.Range(element.startLine, 0, element.endLine, 0); - inactiveRanges.push(newRange); - }); - colorizationState.updateSemantic(params.uri, semanticRanges, inactiveRanges, params.editVersion); - languageClient.sendNotification(SemanticColorizationRegionsReceiptNotification, { uri: params.uri }); - } -} - interface WorkspaceFolderParams { workspaceFolderUri?: string; } @@ -203,21 +175,20 @@ interface FileChangedParams extends WorkspaceFolderParams { uri: string; } -interface SemanticColorizationRegionsParams { - uri: string; - regions: InputColorizationRegion[]; - inactiveRegions: InputRegion[]; - editVersion: number; -} - interface InputRegion { startLine: number; endLine: number; } -interface InputColorizationRegion { - range: Range; - kind: number; +interface DecorationRangesPair { + decoration: vscode.TextEditorDecorationType; + ranges: vscode.Range[]; +} + +interface InactiveRegionParams { + uri: string; + fileVersion: number; + regions: InputRegion[]; } // Need to convert vscode.Uri to a string before sending it to the language server. @@ -250,19 +221,6 @@ interface GetDiagnosticsResult { diagnostics: string; } -interface DidChangeVisibleRangesParams { - uri: string; - ranges: Range[]; -} - -interface SemanticColorizationRegionsReceiptParams { - uri: string; -} - -interface ColorThemeChangedParams { - name: string; -} - interface Diagnostic { range: Range; code?: number | string; @@ -377,6 +335,7 @@ interface SemanticToken { } interface GetSemanticTokensResult { + fileVersion: number; canceled: boolean; tokens: SemanticToken[]; } @@ -410,8 +369,11 @@ enum SemanticTokenTypes { enum SemanticTokenModifiers { // These are camelCase as the enum names are used directly as strings in our legend. + // eslint-disable-next-line no-bitwise static = (1 << 0), + // eslint-disable-next-line no-bitwise global = (1 << 1), + // eslint-disable-next-line no-bitwise local = (1 << 2) } @@ -445,9 +407,6 @@ const CustomBrowseConfigurationNotification: NotificationType = new NotificationType('cpptools/clearCustomConfigurations'); const ClearCustomBrowseConfigurationNotification: NotificationType = new NotificationType('cpptools/clearCustomBrowseConfiguration'); const RescanFolderNotification: NotificationType = new NotificationType('cpptools/rescanFolder'); -const DidChangeVisibleRangesNotification: NotificationType = new NotificationType('cpptools/didChangeVisibleRanges'); -const SemanticColorizationRegionsReceiptNotification: NotificationType = new NotificationType('cpptools/semanticColorizationRegionsReceipt'); -const ColorThemeChangedNotification: NotificationType = new NotificationType('cpptools/colorThemeChanged'); const RequestReferencesNotification: NotificationType = new NotificationType('cpptools/requestReferences'); const CancelReferencesNotification: NotificationType = new NotificationType('cpptools/cancelReferences'); const FinishedRequestCustomConfig: NotificationType = new NotificationType('cpptools/finishedRequestCustomConfig'); @@ -463,7 +422,7 @@ const ReportTagParseStatusNotification: NotificationType = new NotificationType('cpptools/reportStatus'); const DebugProtocolNotification: NotificationType = new NotificationType('cpptools/debugProtocol'); const DebugLogNotification: NotificationType = new NotificationType('cpptools/debugLog'); -const SemanticColorizationRegionsNotification: NotificationType = new NotificationType('cpptools/semanticColorizationRegions'); +const InactiveRegionNotification: NotificationType = new NotificationType('cpptools/inactiveRegions'); const CompileCommandsPathsNotification: NotificationType = new NotificationType('cpptools/compileCommandsPaths'); const ReferencesNotification: NotificationType = new NotificationType('cpptools/references'); const ReportReferencesProgressNotification: NotificationType = new NotificationType('cpptools/reportReferencesProgress'); @@ -539,11 +498,8 @@ export interface Client { Name: string; TrackedDocuments: Set; onDidChangeSettings(event: vscode.ConfigurationChangeEvent, isFirstClient: boolean): { [key: string]: string }; - onDidOpenTextDocument(document: vscode.TextDocument): void; - onDidCloseTextDocument(document: vscode.TextDocument): void; onDidChangeVisibleTextEditors(editors: vscode.TextEditor[]): void; onDidChangeTextDocument(textDocumentChangeEvent: vscode.TextDocumentChangeEvent): void; - onDidChangeTextEditorVisibleRanges(textEditorVisibleRangesChangeEvent: vscode.TextEditorVisibleRangesChangeEvent): void; onRegisterCustomConfigurationProvider(provider: CustomConfigurationProvider1): Thenable; updateCustomConfigurations(requestingProvider?: CustomConfigurationProvider1): Thenable; updateCustomBrowseConfiguration(requestingProvider?: CustomConfigurationProvider1): Thenable; @@ -599,13 +555,9 @@ export class DefaultClient implements Client { private storagePath: string; private trackedDocuments = new Set(); private isSupported: boolean = true; - private colorizationSettings: ColorizationSettings; - private openFileVersions = new Map(); - private visibleRanges = new Map(); + private inactiveRegionsDecorations = new Map(); private settingsTracker: SettingsTracker; private configurationProvider?: string; - // private tokenTypes: Map = new Map(); - // private tokenModifiers: Map = new Map(); // The "model" that is displayed via the UI (status bar). private model: ClientModel = new ClientModel(); @@ -689,7 +641,6 @@ export class DefaultClient implements Client { this.storagePath = storagePath; const rootUri: vscode.Uri | undefined = this.RootUri; this.settingsTracker = getTracker(rootUri); - this.colorizationSettings = new ColorizationSettings(rootUri); try { let firstClient: boolean = false; if (!languageClient || languageClientCrashedNeedsRestart) { @@ -1116,25 +1067,6 @@ export class DefaultClient implements Client { } const legend: vscode.SemanticTokensLegend = new vscode.SemanticTokensLegend(tokenTypesLegend, tokenModifiersLegend); - // // Semantic token types are identified by indexes in this list of types, in the legend. - // const legend: vscode.SemanticTokensLegend = (() => { - // const tokenTypesLegend: string[] = [ - // 'macro', 'enumMember', 'variable', 'parameter', 'type', 'referenceType', 'valueType', 'function', - // 'member', 'property', 'cliProperty', 'event', 'genericType', 'templateFunction', 'templateType', - // 'namespace', 'label', 'customLiteral', 'numberLiteral', 'stringLiteral', 'operatorOverload', - // 'memberOperatorOverload', 'newOperator' - // ]; - // //tokenTypesLegend.forEach((tokenType, index) => this.tokenTypes.set(tokenType, index)); - // - // // Semantic token modifiers are bit indexes corresponding to the indexes in this list of modifiers in the legend. - // const tokenModifiersLegend: string[] = [ - // 'static', 'global', 'local' - // ]; - // //tokenModifiersLegend.forEach((tokenModifier, index) => this.tokenModifiers.set(tokenModifier, index)); - // - // return new vscode.SemanticTokensLegend(tokenTypesLegend, tokenModifiersLegend); - // })(); - class SemanticTokensProvider implements vscode.DocumentSemanticTokensProvider { private client: DefaultClient; constructor(client: DefaultClient) { @@ -1144,21 +1076,27 @@ export class DefaultClient implements Client { public async provideDocumentSemanticTokens(document: vscode.TextDocument, token: vscode.CancellationToken): Promise { return new Promise((resolve, reject) => { this.client.notifyWhenReady(() => { + let uri: vscode.Uri = document.uri; let id: number = ++abortRequestId; let params: GetSemanticTokensParams = { id: id, - uri: document.uri.toString() + uri: uri.toString() }; this.client.languageClient.sendRequest(GetSemanticTokensRequest, params) .then((tokensResult) => { if (tokensResult.canceled) { reject(); } else { - let builder: vscode.SemanticTokensBuilder = new vscode.SemanticTokensBuilder(legend); - tokensResult.tokens.forEach((token) => { - builder.push(token.line, token.character, token.length, token.type, token.modifiers); - }); - resolve(builder.build()); + let editor: vscode.TextEditor | undefined = vscode.window.visibleTextEditors.find(e => e.document.uri === uri); + if (!editor || editor.document.version !== tokensResult.fileVersion) { + reject(); + } else { + let builder: vscode.SemanticTokensBuilder = new vscode.SemanticTokensBuilder(legend); + tokensResult.tokens.forEach((token) => { + builder.push(token.line, token.character, token.length, token.type, token.modifiers); + }); + resolve(builder.build()); + } } }); token.onCancellationRequested(e => this.client.abortRequest(id)); @@ -1204,7 +1142,6 @@ export class DefaultClient implements Client { vscode.window.showErrorMessage(localize("unable.to.start", "Unable to start the C/C++ language server. IntelliSense features will be disabled. Error: {0}", String(err))); } })); - this.colorizationSettings.reload(); } catch (err) { this.isSupported = false; // Running on an OS we don't support yet. if (!failureMessageShown) { @@ -1432,44 +1369,6 @@ export class DefaultClient implements Client { let changedSettings: { [key: string]: string }; changedSettings = this.settingsTracker.getChangedSettings(); this.notifyWhenReady(() => { - let colorizationNeedsReload: boolean = isFirstClient && (event.affectsConfiguration("workbench.colorTheme") - || event.affectsConfiguration("editor.tokenColorCustomizations")); - - let colorizationNeedsRefresh: boolean = colorizationNeedsReload - || event.affectsConfiguration("C_Cpp.enhancedColorization", this.RootUri) - || event.affectsConfiguration("C_Cpp.dimInactiveRegions", this.RootUri) - || event.affectsConfiguration("C_Cpp.inactiveRegionOpacity", this.RootUri) - || event.affectsConfiguration("C_Cpp.inactiveRegionForegroundColor", this.RootUri) - || event.affectsConfiguration("C_Cpp.inactiveRegionBackgroundColor", this.RootUri); - - if (isFirstClient) { - let colorThemeChanged: boolean = event.affectsConfiguration("workbench.colorTheme"); - if (colorThemeChanged) { - let otherSettings: OtherSettings = new OtherSettings(); - this.languageClient.sendNotification(ColorThemeChangedNotification, { name: otherSettings.colorTheme }); - } - } - - if (colorizationNeedsReload) { - this.colorizationSettings.reload(); - } - if (colorizationNeedsRefresh) { - let processedUris: vscode.Uri[] = []; - for (let e of vscode.window.visibleTextEditors) { - let uri: vscode.Uri = e.document.uri; - - // Make sure we don't process the same file multiple times. - // colorizationState.onSettingsChanged ensures all visible text editors for that file get - // refreshed, after it creates a set of decorators to be shared by all visible instances of the file. - if (!processedUris.find(e => e === uri)) { - processedUris.push(uri); - let colorizationState: ColorizationState | undefined = workspaceColorizationState.get(uri.toString()); - if (colorizationState) { - colorizationState.onSettingsChanged(uri); - } - } - } - } if (Object.keys(changedSettings).length > 0) { if (changedSettings["commentContinuationPatterns"]) { updateLanguageConfigurations(); @@ -1481,115 +1380,30 @@ export class DefaultClient implements Client { return changedSettings; } - private editVersion: number = 0; + public onDidChangeVisibleTextEditors(editors: vscode.TextEditor[]): void { + let settings: CppSettings = new CppSettings(this.RootUri); + if (settings.dimInactiveRegions) { + // Apply text decorations to inactive regions + for (let e of editors) { + let valuePair: DecorationRangesPair | undefined = this.inactiveRegionsDecorations.get(e.document.uri.toString()); + if (valuePair) { + e.setDecorations(valuePair.decoration, valuePair.ranges); // VSCode clears the decorations when the text editor becomes invisible + } + } + } + } public onDidChangeTextDocument(textDocumentChangeEvent: vscode.TextDocumentChangeEvent): void { - // Increment editVersion for every call to onDidChangeTextDocument, regardless of whether the file is handled - this.editVersion++; if (textDocumentChangeEvent.document.uri.scheme === "file") { if (textDocumentChangeEvent.document.languageId === "cpp" || textDocumentChangeEvent.document.languageId === "c") { - // If any file has changed, we need to abort the current rename operation if (renamePending) { this.cancelReferences(); } - - let oldVersion: number | undefined = this.openFileVersions.get(textDocumentChangeEvent.document.uri.toString()); - let newVersion: number = textDocumentChangeEvent.document.version; - if (oldVersion === undefined || newVersion > oldVersion) { - this.openFileVersions.set(textDocumentChangeEvent.document.uri.toString(), newVersion); - try { - let colorizationState: ColorizationState | undefined = workspaceColorizationState.get(textDocumentChangeEvent.document.uri.toString()); - if (colorizationState) { - // Adjust colorization ranges after this edit. (i.e. if a line was added, push decorations after it down one line) - colorizationState.addEdits(textDocumentChangeEvent.contentChanges, this.editVersion); - } - } catch (e) { - // Ensure an exception does not prevent pass-through to native handler, or editVersion could become inconsistent - console.log(e.toString()); - } - } - } - } - } - - public onDidOpenTextDocument(document: vscode.TextDocument): void { - if (document.uri.scheme === "file") { - this.openFileVersions.set(document.uri.toString(), document.version); - workspaceColorizationState.set(document.uri.toString(), new ColorizationState(document.uri, this.colorizationSettings)); - this.sendVisibleRanges(document.uri); - } - } - - public onDidCloseTextDocument(document: vscode.TextDocument): void { - workspaceColorizationState.delete(document.uri.toString()); - this.openFileVersions.delete(document.uri.toString()); - } - - public onDidChangeVisibleTextEditors(editors: vscode.TextEditor[]): void { - let processedUris: vscode.Uri[] = []; - editors.forEach(editor => { - if (editor.document.uri.scheme === "file") { - let colorizationState: ColorizationState | undefined = workspaceColorizationState.get(editor.document.uri.toString()); - if (colorizationState) { - colorizationState.refresh(editor); - if (!processedUris.find(uri => uri === editor.document.uri)) { - processedUris.push(editor.document.uri); - this.sendVisibleRanges(editor.document.uri); - } - } - } - }); - } - - public sendVisibleRanges(uri: vscode.Uri): void { - let ranges: Range[] = []; - // Get ranges from all editors matching this URI - let editors: vscode.TextEditor[] = vscode.window.visibleTextEditors.filter(e => e.document.uri === uri); - for (let e of editors) { - e.visibleRanges.forEach(range => ranges.push(Range.create(range.start.line, range.start.character, range.end.line, range.end.character))); - } - - // Only send ranges if they have actually changed. - let isSame: boolean = false; - let savedRanges: Range[] | undefined = this.visibleRanges.get(uri.toString()); - if (savedRanges) { - if (ranges.length === savedRanges.length) { - isSame = true; - for (let i: number = 0; i < ranges.length; i++) { - if (ranges[i] !== savedRanges[i]) { - isSame = false; - break; - } - } } - } else { - isSame = ranges.length === 0; - } - if (!isSame) { - this.visibleRanges.set(uri.toString(), ranges); - let params: DidChangeVisibleRangesParams = { - uri: uri.toString(), - ranges: ranges - }; - this.notifyWhenReady(() => this.languageClient.sendNotification(DidChangeVisibleRangesNotification, params)); } } - public onDidChangeTextEditorVisibleRanges(textEditorVisibleRangesChangeEvent: vscode.TextEditorVisibleRangesChangeEvent): void { - this.notifyWhenReady(() => { - if (textEditorVisibleRangesChangeEvent.textEditor.document.uri.scheme === "file") { - if (vscode.window.activeTextEditor === textEditorVisibleRangesChangeEvent.textEditor) { - if (textEditorVisibleRangesChangeEvent.visibleRanges.length === 1) { - let visibleRangesLength: number = textEditorVisibleRangesChangeEvent.visibleRanges[0].end.line - textEditorVisibleRangesChangeEvent.visibleRanges[0].start.line; - workspaceReferences.updateVisibleRange(visibleRangesLength); - } - } - this.sendVisibleRanges(textEditorVisibleRangesChangeEvent.textEditor.document.uri); - } - }); - } - private registeredProviders: CustomConfigurationProvider1[] = []; public onRegisterCustomConfigurationProvider(provider: CustomConfigurationProvider1): Thenable { let onRegistered: () => void = () => { @@ -2032,7 +1846,7 @@ export class DefaultClient implements Client { this.languageClient.onNotification(LogTelemetryNotification, logTelemetry); this.languageClient.onNotification(ReportStatusNotification, (e) => this.updateStatus(e)); this.languageClient.onNotification(ReportTagParseStatusNotification, (e) => this.updateTagParseStatus(e)); - this.languageClient.onNotification(SemanticColorizationRegionsNotification, updateSemanticColorizationRegions); + this.languageClient.onNotification(InactiveRegionNotification, (e) => this.updateInactiveRegions(e)); this.languageClient.onNotification(CompileCommandsPathsNotification, (e) => this.promptCompileCommands(e)); this.languageClient.onNotification(ReferencesNotification, (e) => this.processReferencesResult(e.referencesResult)); this.languageClient.onNotification(ReportReferencesProgressNotification, (e) => this.handleReferencesProgress(e)); @@ -2244,6 +2058,60 @@ export class DefaultClient implements Client { this.model.tagParserStatus.Value = util.getLocalizedString(notificationBody); } + private updateInactiveRegions(params: InactiveRegionParams): void { + let settings: CppSettings = new CppSettings(this.RootUri); + let opacity: number | undefined = settings.inactiveRegionOpacity; + if (opacity !== null && opacity !== undefined) { + let backgroundColor: string | undefined = settings.inactiveRegionBackgroundColor; + if (backgroundColor === "") { + backgroundColor = undefined; + } + let color: string | undefined = settings.inactiveRegionForegroundColor; + if (color === "") { + color = undefined; + } + let decoration: vscode.TextEditorDecorationType = vscode.window.createTextEditorDecorationType({ + opacity: opacity.toString(), + backgroundColor: backgroundColor, + color: color, + rangeBehavior: vscode.DecorationRangeBehavior.OpenOpen + }); + // We must convert to vscode.Ranges in order to make use of the API's + let ranges: vscode.Range[] = []; + params.regions.forEach(element => { + let newRange: vscode.Range = new vscode.Range(element.startLine, 0, element.endLine, 0); + ranges.push(newRange); + }); + // Find entry for cached file and act accordingly + let valuePair: DecorationRangesPair | undefined = this.inactiveRegionsDecorations.get(params.uri); + if (valuePair) { + // Disposing of and resetting the decoration will undo previously applied text decorations + valuePair.decoration.dispose(); + valuePair.decoration = decoration; + // As vscode.TextEditor.setDecorations only applies to visible editors, we must cache the range for when another editor becomes visible + valuePair.ranges = ranges; + } else { // The entry does not exist. Make a new one + let toInsert: DecorationRangesPair = { + decoration: decoration, + ranges: ranges + }; + this.inactiveRegionsDecorations.set(params.uri, toInsert); + } + if (settings.dimInactiveRegions) { + // Apply the decorations to all *visible* text editors + let editors: vscode.TextEditor[] = vscode.window.visibleTextEditors.filter(e => e.document.uri.toString() === params.uri); + if (editors.length > 0) { + // Check one of the editors to ensure the file version matches + if (editors[0].document.version === params.fileVersion) { + for (let e of editors) { + e.setDecorations(decoration, ranges); + } + } + } + } + } + } + private promptCompileCommands(params: CompileCommandsPaths): void { if (!params.workspaceFolderUri) { return; @@ -2752,11 +2620,8 @@ class NullClient implements Client { Name: string = "(empty)"; TrackedDocuments = new Set(); onDidChangeSettings(event: vscode.ConfigurationChangeEvent, isFirstClient: boolean): { [key: string]: string } { return {}; } - onDidOpenTextDocument(document: vscode.TextDocument): void {} - onDidCloseTextDocument(document: vscode.TextDocument): void {} onDidChangeVisibleTextEditors(editors: vscode.TextEditor[]): void {} onDidChangeTextDocument(textDocumentChangeEvent: vscode.TextDocumentChangeEvent): void {} - onDidChangeTextEditorVisibleRanges(textEditorVisibleRangesChangeEvent: vscode.TextEditorVisibleRangesChangeEvent): void {} onRegisterCustomConfigurationProvider(provider: CustomConfigurationProvider1): Thenable { return Promise.resolve(); } updateCustomConfigurations(requestingProvider?: CustomConfigurationProvider1): Thenable { return Promise.resolve(); } updateCustomBrowseConfiguration(requestingProvider?: CustomConfigurationProvider1): Thenable { return Promise.resolve(); } diff --git a/Extension/src/LanguageServer/colorization.ts b/Extension/src/LanguageServer/colorization.ts deleted file mode 100644 index 2c5367825a..0000000000 --- a/Extension/src/LanguageServer/colorization.ts +++ /dev/null @@ -1,671 +0,0 @@ -/* -------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All Rights Reserved. - * See 'LICENSE' in the project root for license information. - * ------------------------------------------------------------------------------------------ */ -'use strict'; - -import * as path from 'path'; -import * as vscode from 'vscode'; -import * as util from '../common'; -import { CppSettings, OtherSettings, TextMateRule, TextMateRuleSettings } from './settings'; -import * as jsonc from 'jsonc-parser'; -import * as plist from 'plist'; - -export enum TokenKind { - // These need to match the token_kind enum in the server - - // Semantic tokens - Macro, - Enumerator, - GlobalVariable, - LocalVariable, - Parameter, - Type, - RefType, - ValueType, - Function, - MemberFunction, - MemberField, - StaticMemberFunction, - StaticMemberField, - Property, - Event, - ClassTemplate, - GenericType, - FunctionTemplate, - Namespace, - Label, - UdlRaw, - UdlNumber, - UdlString, - OperatorFunction, - MemberOperator, - NewDelete, - - Count -} - -interface VersionedEdits { - editVersion: number; - changes: readonly vscode.TextDocumentContentChangeEvent[]; -} - -class ThemeStyle { - foreground?: string; - background?: string; - fontStyle?: string; -} - -export class ColorizationSettings { - private uri: vscode.Uri | undefined; - private pendingTask?: util.BlockingTask; - private editorBackground?: string; - - public themeStyleCMap: ThemeStyle[] = []; - public themeStyleCppMap: ThemeStyle[] = []; - - private static readonly scopeToTokenColorNameMap = new Map([ - ["comment", "comments"], - ["string", "strings"], - ["keyword.operator", "keywords"], - ["keyword.control", "keywords"], - ["constant.numeric", "numbers"], - ["entity.name.type", "types"], - ["entity.name.class", "types"], - ["entity.name.function", "functions"], - ["variable", "variables"] - ]); - - constructor(uri: vscode.Uri | undefined) { - this.uri = uri; - } - - // Given a TextMate rule 'settings' node, update a ThemeStyle to include any color or style information - private updateStyleFromTextMateRuleSettings(baseStyle: ThemeStyle, textMateRuleSettings: TextMateRuleSettings): void { - if (textMateRuleSettings.foreground) { - baseStyle.foreground = textMateRuleSettings.foreground; - } - if (!this.editorBackground || textMateRuleSettings.background && textMateRuleSettings.background.toUpperCase() !== this.editorBackground.toUpperCase()) { - baseStyle.background = textMateRuleSettings.background; - } - // Any (even empty) string for fontStyle removes inherited value - if (textMateRuleSettings.fontStyle) { - baseStyle.fontStyle = textMateRuleSettings.fontStyle; - } else if (textMateRuleSettings.fontStyle === "") { - baseStyle.fontStyle = undefined; - } - } - - // If the scope can be found in a set of TextMate rules, apply it to both C and Cpp ThemeStyle's - private findThemeStyleForScope(baseCStyle: ThemeStyle | undefined, baseCppStyle: ThemeStyle | undefined, scope: string, textMateRules: TextMateRule[] | undefined): void { - if (textMateRules) { - let match: TextMateRule | undefined = textMateRules.find(e => e.settings && (e.scope === scope || ((e.scope instanceof Array) && e.scope.indexOf(scope) > -1))); - if (match) { - if (baseCStyle) { - this.updateStyleFromTextMateRuleSettings(baseCStyle, match.settings); - } - if (baseCppStyle) { - this.updateStyleFromTextMateRuleSettings(baseCppStyle, match.settings); - } - } - - match = textMateRules.find(e => e.settings && (e.scope === "source " + scope || ((e.scope instanceof Array) && e.scope.indexOf("source " + scope) > -1))); - if (match) { - if (baseCStyle) { - this.updateStyleFromTextMateRuleSettings(baseCStyle, match.settings); - } - if (baseCppStyle) { - this.updateStyleFromTextMateRuleSettings(baseCppStyle, match.settings); - } - } - - if (baseCStyle) { - match = textMateRules.find(e => e.settings && (e.scope === "source.c " + scope || ((e.scope instanceof Array) && e.scope.indexOf("source.c " + scope) > -1))); - if (match) { - this.updateStyleFromTextMateRuleSettings(baseCStyle, match.settings); - } - } - - if (baseCppStyle) { - match = textMateRules.find(e => e.settings && (e.scope === "source.cpp " + scope || ((e.scope instanceof Array) && e.scope.indexOf("source.cpp " + scope) > -1))); - if (match) { - this.updateStyleFromTextMateRuleSettings(baseCppStyle, match.settings); - } - } - } - } - - // For a specific scope cascase all potential sources of style information to create a final ThemeStyle - private calculateThemeStyleForScope(baseCStyle: ThemeStyle | undefined, baseCppStyle: ThemeStyle | undefined, scope: string, themeName: string, themeTextMateRules: TextMateRule[][]): void { - // Search for settings with this scope in current theme - themeTextMateRules.forEach((rules) => { - this.findThemeStyleForScope(baseCStyle, baseCppStyle, scope, rules); - }); - - let otherSettings: OtherSettings = new OtherSettings(this.uri); - - // Next in priority would be a global user override of token color of the equivilent scope - let colorTokenName: string | undefined = ColorizationSettings.scopeToTokenColorNameMap.get(scope); - if (colorTokenName) { - let settingValue: string | undefined = otherSettings.getCustomColorToken(colorTokenName); - if (settingValue) { - if (baseCStyle) { - baseCStyle.foreground = settingValue; - } - if (baseCppStyle) { - baseCppStyle.foreground = settingValue; - } - } - } - - // Next in priority would be a global user override of this scope in textMateRules - this.findThemeStyleForScope(baseCStyle, baseCppStyle, scope, otherSettings.customTextMateRules); - - // Next in priority would be a theme-specific user override of token color of the equivilent scope - if (colorTokenName) { - let settingValue: string | undefined = otherSettings.getCustomThemeSpecificColorToken(colorTokenName, themeName); - if (settingValue) { - if (baseCStyle) { - baseCStyle.foreground = settingValue; - } - if (baseCppStyle) { - baseCppStyle.foreground = settingValue; - } - } - } - - // Next in priority would be a theme-specific user override of this scope in textMateRules - let textMateRules: TextMateRule[] | undefined = otherSettings.getCustomThemeSpecificTextMateRules(themeName); - this.findThemeStyleForScope(baseCStyle, baseCppStyle, scope, textMateRules); - } - - // For each level of the scope, look of style information - private calculateStyleForToken(tokenKind: TokenKind, scope: string, themeName: string, themeTextMateRules: TextMateRule[][]): void { - // Try scopes, from most general to most specific, apply style in cascading manner - let parts: string[] = scope.split("."); - let accumulatedScope: string = ""; - for (let i: number = 0; i < parts.length; i++) { - accumulatedScope += parts[i]; - this.calculateThemeStyleForScope(this.themeStyleCMap[tokenKind], this.themeStyleCppMap[tokenKind], accumulatedScope, themeName, themeTextMateRules); - this.calculateThemeStyleForScope(this.themeStyleCMap[tokenKind], undefined, accumulatedScope + ".c", themeName, themeTextMateRules); - this.calculateThemeStyleForScope(undefined, this.themeStyleCppMap[tokenKind], accumulatedScope + ".cpp", themeName, themeTextMateRules); - accumulatedScope += "."; - } - } - - public syncWithLoadingSettings(f: () => any): void { - this.pendingTask = new util.BlockingTask(f, this.pendingTask); - } - - public updateStyles(themeName: string, defaultStyle: ThemeStyle, textMateRules: TextMateRule[][]): void { - this.themeStyleCMap = new Array(TokenKind.Count); - this.themeStyleCppMap = new Array(TokenKind.Count); - - // Populate with unique objects, as they will be individual modified in place - for (let i: number = 0; i < TokenKind.Count; i++) { - this.themeStyleCMap[i] = {...defaultStyle}; - this.themeStyleCppMap[i] = {...defaultStyle}; - } - - this.calculateStyleForToken(TokenKind.Macro, "entity.name.function.preprocessor", themeName, textMateRules); - this.calculateStyleForToken(TokenKind.Enumerator, "variable.other.enummember", themeName, textMateRules); - this.calculateStyleForToken(TokenKind.GlobalVariable, "variable.other.global", themeName, textMateRules); - this.calculateStyleForToken(TokenKind.LocalVariable, "variable.other.local", themeName, textMateRules); - this.calculateStyleForToken(TokenKind.Parameter, "variable.parameter", themeName, textMateRules); - this.calculateStyleForToken(TokenKind.Type, "entity.name.type.class", themeName, textMateRules); - this.calculateStyleForToken(TokenKind.RefType, "entity.name.type.class.reference", themeName, textMateRules); - this.calculateStyleForToken(TokenKind.ValueType, "entity.name.type.class.value", themeName, textMateRules); - this.calculateStyleForToken(TokenKind.Function, "entity.name.function", themeName, textMateRules); - this.calculateStyleForToken(TokenKind.MemberFunction, "entity.name.function.member", themeName, textMateRules); - this.calculateStyleForToken(TokenKind.MemberField, "variable.other.property", themeName, textMateRules); - this.calculateStyleForToken(TokenKind.StaticMemberFunction, "entity.name.function.member.static", themeName, textMateRules); - this.calculateStyleForToken(TokenKind.StaticMemberField, "variable.other.property.static", themeName, textMateRules); - this.calculateStyleForToken(TokenKind.Property, "variable.other.property.cli", themeName, textMateRules); - this.calculateStyleForToken(TokenKind.Event, "variable.other.event", themeName, textMateRules); - this.calculateStyleForToken(TokenKind.ClassTemplate, "entity.name.type.class.templated", themeName, textMateRules); - this.calculateStyleForToken(TokenKind.GenericType, "entity.name.type.class.generic", themeName, textMateRules); - this.calculateStyleForToken(TokenKind.FunctionTemplate, "entity.name.function.templated", themeName, textMateRules); - this.calculateStyleForToken(TokenKind.Namespace, "entity.name.namespace", themeName, textMateRules); - this.calculateStyleForToken(TokenKind.Label, "entity.name.label", themeName, textMateRules); - this.calculateStyleForToken(TokenKind.UdlRaw, "entity.name.operator.custom-literal", themeName, textMateRules); - this.calculateStyleForToken(TokenKind.UdlNumber, "entity.name.operator.custom-literal.number", themeName, textMateRules); - this.calculateStyleForToken(TokenKind.UdlString, "entity.name.operator.custom-literal.string", themeName, textMateRules); - this.calculateStyleForToken(TokenKind.OperatorFunction, "entity.name.function.operator", themeName, textMateRules); - this.calculateStyleForToken(TokenKind.MemberOperator, "entity.name.function.operator.member", themeName, textMateRules); - this.calculateStyleForToken(TokenKind.NewDelete, "keyword.operator.new", themeName, textMateRules); - } - - public async loadTheme(themePath: string, defaultStyle: ThemeStyle): Promise { - let rules: TextMateRule[][] = []; - if (await util.checkFileExists(themePath)) { - let themeContentText: string = await util.readFileText(themePath); - let themeContent: any; - let textMateRules: TextMateRule[] | undefined; - if (themePath.endsWith("tmTheme")) { - themeContent = plist.parse(themeContentText); - if (themeContent) { - textMateRules = themeContent.settings; - } - } else { - themeContent = jsonc.parse(themeContentText); - if (themeContent) { - textMateRules = themeContent.tokenColors; - if (themeContent.include) { - // parse included theme file - let includedThemePath: string = path.join(path.dirname(themePath), themeContent.include); - rules = await this.loadTheme(includedThemePath, defaultStyle); - } - - if (themeContent.colors && themeContent.colors["editor.background"]) { - this.editorBackground = themeContent.colors["editor.background"]; - } - } - } - - if (textMateRules) { - // Convert comma delimited scopes into an array - textMateRules.forEach(e => { - if (e.scope && e.scope.includes(',')) { - e.scope = e.scope.split(',').map((s: string) => s.trim()); - } - }); - - let scopelessSetting: any = textMateRules.find(e => e.settings && !e.scope); - if (scopelessSetting) { - if (scopelessSetting.settings.background) { - this.editorBackground = scopelessSetting.settings.background; - } - this.updateStyleFromTextMateRuleSettings(defaultStyle, scopelessSetting.settings); - } - rules.push(textMateRules); - } - } - - return rules; - } - - public reload(): void { - let f: () => void = async () => { - let otherSettings: OtherSettings = new OtherSettings(this.uri); - let themeName: string | undefined = otherSettings.colorTheme; - if (themeName) { - // Enumerate through all extensions, looking for this theme. (Themes are implemented as extensions - even the default ones) - // Open each package.json to check for a theme path - for (let i: number = 0; i < vscode.extensions.all.length; i++) { - let extensionPath: string = vscode.extensions.all[i].extensionPath; - let extensionPackageJsonPath: string = path.join(extensionPath, "package.json"); - if (!await util.checkFileExists(extensionPackageJsonPath)) { - continue; - } - let packageJsonText: string = await util.readFileText(extensionPackageJsonPath); - let packageJson: any = jsonc.parse(packageJsonText); - if (packageJson.contributes && packageJson.contributes.themes) { - let foundTheme: any = packageJson.contributes.themes.find((e: any) => e.id === themeName || e.label === themeName); - if (foundTheme) { - let themeRelativePath: string = foundTheme.path; - let themeFullPath: string = path.join(extensionPath, themeRelativePath); - let defaultStyle: ThemeStyle = new ThemeStyle(); - let rulesSet: TextMateRule[][] = await this.loadTheme(themeFullPath, defaultStyle); - this.updateStyles(themeName, defaultStyle, rulesSet); - return; - } - } - } - } - }; - this.syncWithLoadingSettings(f); - } - - public static createDecorationFromThemeStyle(themeStyle: ThemeStyle): vscode.TextEditorDecorationType | undefined { - if (themeStyle && (themeStyle.foreground || themeStyle.background || themeStyle.fontStyle)) { - let options: vscode.DecorationRenderOptions = {}; - options.rangeBehavior = vscode.DecorationRangeBehavior.OpenOpen; - if (themeStyle.foreground) { - options.color = themeStyle.foreground; - } - if (themeStyle.background) { - options.backgroundColor = themeStyle.background; - } - if (themeStyle.fontStyle) { - let parts: string[] = themeStyle.fontStyle.split(" "); - parts.forEach((part) => { - switch (part) { - case "italic": - options.fontStyle = "italic"; - break; - case "bold": - options.fontWeight = "bold"; - break; - case "underline": - options.textDecoration = "underline"; - break; - default: - break; - } - }); - } - return vscode.window.createTextEditorDecorationType(options); - } - - return undefined; - } -} - -export class ColorizationState { - private uri: vscode.Uri; - private colorizationSettings: ColorizationSettings; - private decorations: (vscode.TextEditorDecorationType | undefined)[] = new Array(TokenKind.Count); - private semanticRanges: vscode.Range[][] = new Array(TokenKind.Count); - private inactiveDecoration: vscode.TextEditorDecorationType | undefined; - private inactiveRanges: vscode.Range[] = []; - private versionedEdits: VersionedEdits[] = []; - private currentSemanticVersion: number = 0; - private lastReceivedSemanticVersion: number = 0; - - public constructor(uri: vscode.Uri, colorizationSettings: ColorizationSettings) { - this.uri = uri; - this.colorizationSettings = colorizationSettings; - } - - private createColorizationDecorations(isCpp: boolean): void { - let settings: CppSettings = new CppSettings(this.uri); - if (settings.enhancedColorization) { - // Create new decorators - // The first decorator created takes precedence, so these need to be created in reverse order - for (let i: number = TokenKind.Count; i > 0;) { - i--; - let themeStyleMap: any; - if (isCpp) { - themeStyleMap = this.colorizationSettings.themeStyleCppMap; - } else { - themeStyleMap = this.colorizationSettings.themeStyleCMap; - } - this.decorations[i] = ColorizationSettings.createDecorationFromThemeStyle(themeStyleMap[i]); - } - } - if (settings.dimInactiveRegions) { - let opacity: number | undefined = settings.inactiveRegionOpacity; - if (opacity !== null && opacity !== undefined) { - let backgroundColor: string | undefined = settings.inactiveRegionBackgroundColor; - if (backgroundColor === "") { - backgroundColor = undefined; - } - let color: string | undefined = settings.inactiveRegionForegroundColor; - if (color === "") { - color = undefined; - } - this.inactiveDecoration = vscode.window.createTextEditorDecorationType({ - opacity: opacity.toString(), - backgroundColor: backgroundColor, - color: color, - rangeBehavior: vscode.DecorationRangeBehavior.OpenOpen - }); - } - } - } - - private disposeColorizationDecorations(): void { - // Dispose of all old decorations - if (this.inactiveDecoration) { - this.inactiveDecoration.dispose(); - this.inactiveDecoration = undefined; - } - for (let i: number = 0; i < TokenKind.Count; i++) { - let decoration: vscode.TextEditorDecorationType | undefined = this.decorations[i]; - if (decoration) { - decoration.dispose(); - this.decorations[i] = undefined; - } - } - } - - public dispose(): void { - this.disposeColorizationDecorations(); - } - - private refreshInner(e: vscode.TextEditor): void { - let settings: CppSettings = new CppSettings(this.uri); - if (settings.enhancedColorization) { - for (let i: number = 0; i < TokenKind.Count; i++) { - let decoration: vscode.TextEditorDecorationType | undefined = this.decorations[i]; - if (decoration) { - let ranges: vscode.Range[] = this.semanticRanges[i]; - if (ranges && ranges.length > 0) { - e.setDecorations(decoration, ranges); - } - } - } - } - - // Normally, decorators are honored in the order in which they were created, not the - // order in which they were applied. Decorators with opacity appear to be handled - // differently, in that the opacity is applied to overlapping decorators even if - // created afterwards. - if (settings.dimInactiveRegions && this.inactiveDecoration && this.inactiveRanges) { - e.setDecorations(this.inactiveDecoration, this.inactiveRanges); - } - } - - public refresh(e: vscode.TextEditor): void { - this.applyEdits(); - let f: () => void = async () => { - this.refreshInner(e); - }; - this.colorizationSettings.syncWithLoadingSettings(f); - } - - public onSettingsChanged(uri: vscode.Uri): void { - let f: () => void = async () => { - this.applyEdits(); - this.disposeColorizationDecorations(); - let isCpp: boolean = util.isEditorFileCpp(uri.toString()); - this.createColorizationDecorations(isCpp); - let editors: vscode.TextEditor[] = vscode.window.visibleTextEditors.filter(e => e.document.uri === uri); - for (let e of editors) { - this.refreshInner(e); - } - }; - this.colorizationSettings.syncWithLoadingSettings(f); - } - - // Utility function to convert a string and a start Position into a Range - private textToRange(text: string, startPosition: vscode.Position): vscode.Range { - let parts: string[] = text.split("\n"); - let addedLines: number = parts.length - 1; - let newStartLine: number = startPosition.line; - let newStartCharacter: number = startPosition.character; - let newEndLine: number = newStartLine + addedLines; - let newEndCharacter: number = parts[parts.length - 1].length; - if (newStartLine === newEndLine) { - newEndCharacter += newStartCharacter; - } - return new vscode.Range(newStartLine, newStartCharacter, newEndLine, newEndCharacter); - } - - // Utility function to shift a range back after removing content before it - private shiftRangeAfterRemove(range: vscode.Range, removeStartPosition: vscode.Position, removeEndPosition: vscode.Position): vscode.Range { - let lineDelta: number = removeStartPosition.line - removeEndPosition.line; - let startCharacterDelta: number = 0; - let endCharacterDelta: number = 0; - if (range.start.line === removeEndPosition.line) { - startCharacterDelta = removeStartPosition.character - removeEndPosition.character; - if (range.end.line === removeEndPosition.line) { - endCharacterDelta = startCharacterDelta; - } - } - let newStart: vscode.Position = range.start.translate(lineDelta, startCharacterDelta); - let newEnd: vscode.Position = range.end.translate(lineDelta, endCharacterDelta); - return new vscode.Range(newStart, newEnd); - } - - // Utility function to shift a range forward after inserting content before it - private shiftRangeAfterInsert(range: vscode.Range, insertStartPosition: vscode.Position, insertEndPosition: vscode.Position): vscode.Range { - let addedLines: number = insertEndPosition.line - insertStartPosition.line; - let newStartLine: number = range.start.line + addedLines; - let newEndLine: number = range.end.line + addedLines; - let newStartCharacter: number = range.start.character; - let newEndCharacter: number = range.end.character; - // If starts on the same line as replacement ended - if (insertEndPosition.line === newStartLine) { - let endOffsetLength: number = insertEndPosition.character; - // If insertRange starts and ends on the same line, only offset by it's length - if (insertEndPosition.line === insertStartPosition.line) { - endOffsetLength -= insertStartPosition.character; - } - newStartCharacter += endOffsetLength; - if (insertEndPosition.line === newEndLine) { - newEndCharacter += endOffsetLength; - } - } - return new vscode.Range(newStartLine, newStartCharacter, newEndLine, newEndCharacter); - } - - // Utility function to adjust a range to account for an insert and/or replace - private fixRange(range: vscode.Range, removeInsertStartPosition: vscode.Position, removeEndPosition: vscode.Position, insertEndPosition: vscode.Position): vscode.Range | undefined { - // If the replace/insert starts after this range ends, no adjustment is needed. - if (removeInsertStartPosition.isAfterOrEqual(range.end)) { - return range; - } - // Else, replace/insert range starts before this range ends. - - // If replace/insert starts before/where this range starts, we don't need to extend the existing range, but need to shift it - if (removeInsertStartPosition.isBeforeOrEqual(range.start)) { - - // If replace consumes the entire range, remove it - if (removeEndPosition.isAfterOrEqual(range.end)) { - return undefined; - } - - // If replace ends within this range, we need to trim it before we shift it - let newRange: vscode.Range; - if (removeEndPosition.isAfterOrEqual(range.start)) { - newRange = new vscode.Range(removeEndPosition, range.end); - } else { - newRange = range; - } - // Else, if replace ends before this range starts, we just need to shift it. - - newRange = this.shiftRangeAfterRemove(newRange, removeInsertStartPosition, removeEndPosition); - return this.shiftRangeAfterInsert(newRange, removeInsertStartPosition, insertEndPosition); - } - // Else, if replace/insert starts within (not before or after) range, extend it. - - // If there replace/insert overlaps past the end of the original range, just extend existing range to the insert end position - if (removeEndPosition.isAfterOrEqual(range.end)) { - return new vscode.Range(range.start.line, range.start.character, insertEndPosition.line, insertEndPosition.character); - } - // Else, range has some left over at the end, which needs to be shifted after insertEndPosition. - - // If the trailing segment is on the last line replace, we just need to extend by the remaining number of characters - if (removeEndPosition.line === range.end.line) { - return new vscode.Range(range.start.line, range.start.character, insertEndPosition.line, insertEndPosition.character + (range.end.character - removeEndPosition.character)); - } - // Else, the trailing segment ends on another line, so the character position should remain the same. Just adjust based on added/removed lined. - let removedLines: number = removeEndPosition.line - removeInsertStartPosition.line; - let addedLines: number = insertEndPosition.line - removeInsertStartPosition.line; - let deltaLines: number = addedLines - removedLines; - return new vscode.Range(range.start.line, range.start.character, range.end.line + deltaLines, range.end.character); - } - - private fixRanges(originalRanges: vscode.Range[], changes: readonly vscode.TextDocumentContentChangeEvent[]): vscode.Range[] { - // outer loop needs to be the versioned edits, then changes within that edit, then ranges - let ranges: vscode.Range[] = originalRanges; - if (ranges && ranges.length > 0) { - changes.forEach((change) => { - let newRanges: vscode.Range[] = []; - let insertRange: vscode.Range = this.textToRange(change.text, change.range.start); - for (let i: number = 0; i < ranges.length; i++) { - let newRange: vscode.Range | undefined = this.fixRange(ranges[i], change.range.start, change.range.end, insertRange.end); - if (newRange) { - newRanges.push(newRange); - } - } - ranges = newRanges; - }); - } - return ranges; - } - - // Add edits to be applied when/if cached tokens need to be reapplied. - public addEdits(changes: readonly vscode.TextDocumentContentChangeEvent[], editVersion: number): void { - let edits: VersionedEdits = { - editVersion: editVersion, - changes: changes - }; - this.versionedEdits.push(edits); - } - - // Apply any pending edits to the currently cached tokens - private applyEdits(): void { - this.versionedEdits.forEach((edit) => { - if (edit.editVersion > this.currentSemanticVersion) { - for (let i: number = 0; i < TokenKind.Count; i++) { - this.semanticRanges[i] = this.fixRanges(this.semanticRanges[i], edit.changes); - } - this.inactiveRanges = this.fixRanges(this.inactiveRanges, edit.changes); - this.currentSemanticVersion = edit.editVersion; - } - }); - } - - // Remove any edits from the list if we will never receive tokens that old. - private purgeOldVersionedEdits(): void { - let minVersion: number = this.lastReceivedSemanticVersion; - let index: number = this.versionedEdits.findIndex((edit) => edit.editVersion > minVersion); - if (index === -1) { - this.versionedEdits = []; - } else if (index > 0) { - this.versionedEdits = this.versionedEdits.slice(index); - } - } - - private updateColorizationRanges(uri: string): void { - let f: () => void = async () => { - this.applyEdits(); - this.purgeOldVersionedEdits(); - - // The only way to un-apply decorators is to dispose them. - // If we dispose old decorators before applying new decorators, we see a flicker on Mac, - // likely due to a race with UI updates. Here we set aside the existing decorators to be - // disposed of after the new decorators have been applied, so there is not a gap - // in which decorators are not applied. - let oldInactiveDecoration: vscode.TextEditorDecorationType | undefined = this.inactiveDecoration; - let oldDecorations: (vscode.TextEditorDecorationType | undefined)[] = this.decorations; - this.inactiveDecoration = undefined; - this.decorations = new Array(TokenKind.Count); - - let isCpp: boolean = util.isEditorFileCpp(uri); - this.createColorizationDecorations(isCpp); - - // Apply the decorations to all *visible* text editors - let editors: vscode.TextEditor[] = vscode.window.visibleTextEditors.filter(e => e.document.uri.toString() === uri); - for (let e of editors) { - this.refreshInner(e); - } - - // Dispose of the old decorators only after the new ones have been applied. - if (oldInactiveDecoration) { - oldInactiveDecoration.dispose(); - } - if (oldDecorations) { - for (let i: number = 0; i < TokenKind.Count; i++) { - let oldDecoration: vscode.TextEditorDecorationType | undefined = oldDecorations[i]; - if (oldDecoration) { - oldDecoration.dispose(); - } - } - } - }; - this.colorizationSettings.syncWithLoadingSettings(f); - } - - public updateSemantic(uri: string, semanticRanges: vscode.Range[][], inactiveRanges: vscode.Range[], editVersion: number): void { - this.inactiveRanges = inactiveRanges; - for (let i: number = 0; i < TokenKind.Count; i++) { - this.semanticRanges[i] = semanticRanges[i]; - } - this.currentSemanticVersion = editVersion; - this.lastReceivedSemanticVersion = editVersion; - this.updateColorizationRanges(uri); - } -} diff --git a/Extension/src/LanguageServer/extension.ts b/Extension/src/LanguageServer/extension.ts index 29c138fc57..35c6222c3b 100644 --- a/Extension/src/LanguageServer/extension.ts +++ b/Extension/src/LanguageServer/extension.ts @@ -452,7 +452,6 @@ function realActivation(): void { disposables.push(vscode.window.onDidChangeActiveTextEditor(onDidChangeActiveTextEditor)); disposables.push(vscode.window.onDidChangeTextEditorSelection(onDidChangeTextEditorSelection)); disposables.push(vscode.window.onDidChangeVisibleTextEditors(onDidChangeVisibleTextEditors)); - disposables.push(vscode.window.onDidChangeTextEditorVisibleRanges(onDidChangeTextEditorVisibleRanges)); updateLanguageConfigurations(); @@ -560,7 +559,6 @@ export function processDelayedDidOpen(document: vscode.TextDocument): void { client.provideCustomConfiguration(document.uri, undefined); client.notifyWhenReady(() => { client.takeOwnership(document); - client.onDidOpenTextDocument(document); }); } } @@ -574,32 +572,6 @@ function onDidChangeVisibleTextEditors(editors: vscode.TextEditor[]): void { processDelayedDidOpen(editor.document); } }); - - clients.forEach(client => { - let editorsForThisClient: vscode.TextEditor[] = []; - editors.forEach(editor => { - if (editor.document.languageId === "c" || editor.document.languageId === "cpp" - || editor.document.languageId === "json" && editor.document.uri.fsPath.endsWith("c_cpp_properties.json")) { - if (clients.checkOwnership(client, editor.document)) { - editorsForThisClient.push(editor); - } - } - }); - if (editorsForThisClient.length > 0) { - client.onDidChangeVisibleTextEditors(editorsForThisClient); - } - }); -} - -function onDidChangeTextEditorVisibleRanges(textEditorVisibleRangesChangeEvent: vscode.TextEditorVisibleRangesChangeEvent): void { - let languageId: String = textEditorVisibleRangesChangeEvent.textEditor.document.languageId; - if (languageId === "c" || languageId === "cpp") { - clients.forEach(client => { - if (clients.checkOwnership(client, textEditorVisibleRangesChangeEvent.textEditor.document)) { - client.onDidChangeTextEditorVisibleRanges(textEditorVisibleRangesChangeEvent); - } - }); - } } function onInterval(): void { diff --git a/Extension/src/LanguageServer/protocolFilter.ts b/Extension/src/LanguageServer/protocolFilter.ts index 5aa1b10dde..b04d0e5395 100644 --- a/Extension/src/LanguageServer/protocolFilter.ts +++ b/Extension/src/LanguageServer/protocolFilter.ts @@ -43,7 +43,6 @@ export function createProtocolFilter(clients: ClientCollection): Middleware { me.provideCustomConfiguration(document.uri, undefined); me.notifyWhenReady(() => { sendMessage(document); - me.onDidOpenTextDocument(document); if (editor && editor === vscode.window.activeTextEditor) { onDidChangeActiveTextEditor(editor); } @@ -53,7 +52,7 @@ export function createProtocolFilter(clients: ClientCollection): Middleware { // NO-OP // If the file is not opened into an editor (such as in response for a control-hover), // we do not actually load a translation unit for it. When we receive a didOpen, the file - // may not yet be visible. So, we defer creation of the translation until we receive a + // may not yet be visible. So, we defer creation of the translation until we receive a // call to onDidChangeVisibleTextEditors(), in extension.ts. A file is only loaded when // it is actually opened in the editor (not in response to control-hover, which sends a // didOpen), and first becomes visible. @@ -79,7 +78,6 @@ export function createProtocolFilter(clients: ClientCollection): Middleware { didClose: (document, sendMessage) => { let me: Client = clients.getClientFor(document.uri); if (me.TrackedDocuments.has(document)) { - me.onDidCloseTextDocument(document); me.TrackedDocuments.delete(document); me.notifyWhenReady(() => sendMessage(document)); } From 258eb4869f550e3945a0ce1ca8bf7ca8b2a95246 Mon Sep 17 00:00:00 2001 From: Colen Garoutte-Carson Date: Thu, 30 Apr 2020 02:33:30 -0700 Subject: [PATCH 05/14] Restore some code that shouldn't have been removed --- Extension/src/LanguageServer/client.ts | 39 +++++++++++++------ Extension/src/LanguageServer/extension.ts | 1 + .../src/LanguageServer/protocolFilter.ts | 2 + 3 files changed, 30 insertions(+), 12 deletions(-) diff --git a/Extension/src/LanguageServer/client.ts b/Extension/src/LanguageServer/client.ts index e4545d8406..046f01159a 100644 --- a/Extension/src/LanguageServer/client.ts +++ b/Extension/src/LanguageServer/client.ts @@ -498,6 +498,8 @@ export interface Client { Name: string; TrackedDocuments: Set; onDidChangeSettings(event: vscode.ConfigurationChangeEvent, isFirstClient: boolean): { [key: string]: string }; + onDidOpenTextDocument(document: vscode.TextDocument): void; + onDidCloseTextDocument(document: vscode.TextDocument): void; onDidChangeVisibleTextEditors(editors: vscode.TextEditor[]): void; onDidChangeTextDocument(textDocumentChangeEvent: vscode.TextDocumentChangeEvent): void; onRegisterCustomConfigurationProvider(provider: CustomConfigurationProvider1): Thenable; @@ -556,6 +558,7 @@ export class DefaultClient implements Client { private trackedDocuments = new Set(); private isSupported: boolean = true; private inactiveRegionsDecorations = new Map(); + private openFileVersions = new Map(); private settingsTracker: SettingsTracker; private configurationProvider?: string; @@ -1076,19 +1079,18 @@ export class DefaultClient implements Client { public async provideDocumentSemanticTokens(document: vscode.TextDocument, token: vscode.CancellationToken): Promise { return new Promise((resolve, reject) => { this.client.notifyWhenReady(() => { - let uri: vscode.Uri = document.uri; + let uriString: string = document.uri.toString(); let id: number = ++abortRequestId; let params: GetSemanticTokensParams = { id: id, - uri: uri.toString() + uri: uriString }; this.client.languageClient.sendRequest(GetSemanticTokensRequest, params) .then((tokensResult) => { if (tokensResult.canceled) { reject(); } else { - let editor: vscode.TextEditor | undefined = vscode.window.visibleTextEditors.find(e => e.document.uri === uri); - if (!editor || editor.document.version !== tokensResult.fileVersion) { + if (tokensResult.fileVersion !== this.client.openFileVersions.get(uriString)) { reject(); } else { let builder: vscode.SemanticTokensBuilder = new vscode.SemanticTokensBuilder(legend); @@ -1400,10 +1402,26 @@ export class DefaultClient implements Client { if (renamePending) { this.cancelReferences(); } + + let oldVersion: number | undefined = this.openFileVersions.get(textDocumentChangeEvent.document.uri.toString()); + let newVersion: number = textDocumentChangeEvent.document.version; + if (oldVersion === undefined || newVersion > oldVersion) { + this.openFileVersions.set(textDocumentChangeEvent.document.uri.toString(), newVersion); + } } } } + public onDidOpenTextDocument(document: vscode.TextDocument): void { + if (document.uri.scheme === "file") { + this.openFileVersions.set(document.uri.toString(), document.version); + } + } + + public onDidCloseTextDocument(document: vscode.TextDocument): void { + this.openFileVersions.delete(document.uri.toString()); + } + private registeredProviders: CustomConfigurationProvider1[] = []; public onRegisterCustomConfigurationProvider(provider: CustomConfigurationProvider1): Thenable { let onRegistered: () => void = () => { @@ -2097,16 +2115,11 @@ export class DefaultClient implements Client { }; this.inactiveRegionsDecorations.set(params.uri, toInsert); } - if (settings.dimInactiveRegions) { + if (settings.dimInactiveRegions && params.fileVersion === this.openFileVersions.get(params.uri)) { // Apply the decorations to all *visible* text editors let editors: vscode.TextEditor[] = vscode.window.visibleTextEditors.filter(e => e.document.uri.toString() === params.uri); - if (editors.length > 0) { - // Check one of the editors to ensure the file version matches - if (editors[0].document.version === params.fileVersion) { - for (let e of editors) { - e.setDecorations(decoration, ranges); - } - } + for (let e of editors) { + e.setDecorations(decoration, ranges); } } } @@ -2620,6 +2633,8 @@ class NullClient implements Client { Name: string = "(empty)"; TrackedDocuments = new Set(); onDidChangeSettings(event: vscode.ConfigurationChangeEvent, isFirstClient: boolean): { [key: string]: string } { return {}; } + onDidOpenTextDocument(document: vscode.TextDocument): void {} + onDidCloseTextDocument(document: vscode.TextDocument): void {} onDidChangeVisibleTextEditors(editors: vscode.TextEditor[]): void {} onDidChangeTextDocument(textDocumentChangeEvent: vscode.TextDocumentChangeEvent): void {} onRegisterCustomConfigurationProvider(provider: CustomConfigurationProvider1): Thenable { return Promise.resolve(); } diff --git a/Extension/src/LanguageServer/extension.ts b/Extension/src/LanguageServer/extension.ts index 35c6222c3b..8330acb5be 100644 --- a/Extension/src/LanguageServer/extension.ts +++ b/Extension/src/LanguageServer/extension.ts @@ -559,6 +559,7 @@ export function processDelayedDidOpen(document: vscode.TextDocument): void { client.provideCustomConfiguration(document.uri, undefined); client.notifyWhenReady(() => { client.takeOwnership(document); + client.onDidOpenTextDocument(document); }); } } diff --git a/Extension/src/LanguageServer/protocolFilter.ts b/Extension/src/LanguageServer/protocolFilter.ts index b04d0e5395..46aed2a679 100644 --- a/Extension/src/LanguageServer/protocolFilter.ts +++ b/Extension/src/LanguageServer/protocolFilter.ts @@ -43,6 +43,7 @@ export function createProtocolFilter(clients: ClientCollection): Middleware { me.provideCustomConfiguration(document.uri, undefined); me.notifyWhenReady(() => { sendMessage(document); + me.onDidOpenTextDocument(document); if (editor && editor === vscode.window.activeTextEditor) { onDidChangeActiveTextEditor(editor); } @@ -78,6 +79,7 @@ export function createProtocolFilter(clients: ClientCollection): Middleware { didClose: (document, sendMessage) => { let me: Client = clients.getClientFor(document.uri); if (me.TrackedDocuments.has(document)) { + me.onDidCloseTextDocument(document); me.TrackedDocuments.delete(document); me.notifyWhenReady(() => sendMessage(document)); } From f652775fb8f39aefdb34276753fe113001fad133 Mon Sep 17 00:00:00 2001 From: Colen Garoutte-Carson Date: Thu, 7 May 2020 18:50:37 -0700 Subject: [PATCH 06/14] Increase minimum VS Code version requirement to 1.44.0 --- Extension/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Extension/package.json b/Extension/package.json index 74ec1328f2..0e76f0ffa3 100644 --- a/Extension/package.json +++ b/Extension/package.json @@ -12,7 +12,7 @@ }, "license": "SEE LICENSE IN LICENSE.txt", "engines": { - "vscode": "^1.43.0" + "vscode": "^1.44.0" }, "bugs": { "url": "https://github.com/Microsoft/vscode-cpptools/issues", From 4d85817e10910f3ef03cab4321b8497a7e149f5f Mon Sep 17 00:00:00 2001 From: Colen Garoutte-Carson Date: Mon, 8 Jun 2020 11:50:10 -0700 Subject: [PATCH 07/14] Update themes --- Themes/README.md | 4 +++- Themes/themes/cpptools_dark_vs.json | 33 ++++++++++++++++++++++++++++ Themes/themes/cpptools_light_vs.json | 23 +++++++++++++++++++ 3 files changed, 59 insertions(+), 1 deletion(-) diff --git a/Themes/README.md b/Themes/README.md index 9f80ac2fcf..ecaf1a815b 100644 --- a/Themes/README.md +++ b/Themes/README.md @@ -1,9 +1,11 @@ # C/C++ Extension UI Themes -[Semantic colorization was added to the C/C++ Extension in version 0.24.0](https://devblogs.microsoft.com/cppblog/visual-studio-code-c-c-extension-july-2019-update/). By default, colorization in VS Code is syntactic/lexical and leverages TextMate grammar to associate named 'scopes' with syntactic elements. Themes and settings can be used to apply the colors associated with those scopes. Our implementation of semantic colorization leverages the same system of associating colors with named scopes. But, some tokens that can be colored by semantic colorization in C/C++ do not have existing analogs in VS Code's TextMate grammar. So, new named scopes are required. Information about these new scopes can be found [here](https://code.visualstudio.com/docs/cpp/colorization-cpp). Because these scopes are new, existing themes do not include colors for them either. +[Semantic colorization was added to the C/C++ Extension in version 0.24.0](https://devblogs.microsoft.com/cppblog/visual-studio-code-c-c-extension-july-2019-update/). At the time, colorization in VS Code was purely syntactic/lexical and leveraged TextMate grammar to associate named 'scopes' with syntactic elements. Themes and settings can be used to associate colors with these scopes. Our original implementation of semantic colorization leveraged the same system of associating colors with named scopes. But, some tokens that can be colored by semantic colorization in C/C++ did not have existing analogs in VS Code's TextMate grammar. So, new named scopes are required. Because these scopes were new, existing themes did not include colors for them either. We created C/C++ Extension UI Themes to closely match Visual Studio themes, and include colors for many of the new scopes. +VS Code has since provided an API for semantic colorization. The C/C++ Extension has transitioned from it's own implementation to this new API. These themes now include colors for some of the new semantic token scopes. + ## Example Light Theme diff --git a/Themes/themes/cpptools_dark_vs.json b/Themes/themes/cpptools_dark_vs.json index a0394b6d67..d2d7daaa77 100644 --- a/Themes/themes/cpptools_dark_vs.json +++ b/Themes/themes/cpptools_dark_vs.json @@ -20,6 +20,7 @@ "statusBarItem.remoteForeground": "#FFF", "statusBarItem.remoteBackground": "#16825D" }, + "semanticHighlighting": true, "tokenColors": [ { "scope": [ @@ -466,5 +467,37 @@ "foreground": "#7F7F7F" } } + ], + "semanticTokenColors": [ + { + "operatorOverload": { + "foreground": "#B4B4B4" + } + }, + { + "operatorOverloadMember": { + "foreground": "#B4B4B4" + } + }, + { + "newOperator": { + "foreground": "#569CD6" + } + }, + { + "numberLiteral": { + "foreground": "#B5CEA8" + } + }, + { + "customLiteral": { + "foreground": "#DADADA" + } + }, + { + "stringLiteral": { + "foreground": "#D69D85" + } + } ] } \ No newline at end of file diff --git a/Themes/themes/cpptools_light_vs.json b/Themes/themes/cpptools_light_vs.json index 4901df8c77..b1f5e6fd18 100644 --- a/Themes/themes/cpptools_light_vs.json +++ b/Themes/themes/cpptools_light_vs.json @@ -19,6 +19,7 @@ "statusBarItem.remoteForeground": "#FFF", "statusBarItem.remoteBackground": "#16825D" }, + "semanticHighlighting": true, "tokenColors": [ { "scope": ["meta.embedded", "source.groovy.embedded"], @@ -455,5 +456,27 @@ "foreground": "#808080" } } + ], + "semanticTokenColors": [ + { + "operatorOverload": { + "foreground": "#008080" + } + }, + { + "operatorOverloadMember": { + "foreground": "#008080" + } + }, + { + "newOperator": { + "foreground": "#0000FF" + } + }, + { + "stringLiteral": { + "foreground": "#A31515" + } + } ] } \ No newline at end of file From 49f8d171f99c59f48d0cb19461310439bf4b22e8 Mon Sep 17 00:00:00 2001 From: Sean McManus Date: Mon, 15 Jun 2020 15:09:31 -0700 Subject: [PATCH 08/14] Edit ReadMe. --- Themes/README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Themes/README.md b/Themes/README.md index ecaf1a815b..a65d6ba55b 100644 --- a/Themes/README.md +++ b/Themes/README.md @@ -1,10 +1,10 @@ # C/C++ Extension UI Themes -[Semantic colorization was added to the C/C++ Extension in version 0.24.0](https://devblogs.microsoft.com/cppblog/visual-studio-code-c-c-extension-july-2019-update/). At the time, colorization in VS Code was purely syntactic/lexical and leveraged TextMate grammar to associate named 'scopes' with syntactic elements. Themes and settings can be used to associate colors with these scopes. Our original implementation of semantic colorization leveraged the same system of associating colors with named scopes. But, some tokens that can be colored by semantic colorization in C/C++ did not have existing analogs in VS Code's TextMate grammar. So, new named scopes are required. Because these scopes were new, existing themes did not include colors for them either. +[Semantic colorization was added to the C/C++ Extension in version 0.24.0](https://devblogs.microsoft.com/cppblog/visual-studio-code-c-c-extension-july-2019-update/). At the time, colorization in VS Code was purely syntactic/lexical and leveraged TextMate grammar to associate named 'scopes' with syntactic elements. Themes and settings can be used to associate colors with these scopes. Our original implementation of semantic colorization leveraged the same system of associating colors with named scopes. But, some tokens that can be colored by semantic colorization in C/C++ did not have existing analogs in VS Code's TextMate grammar. So, new named scopes are required. Because these scopes were new, existing themes did not include colors for them either. -We created C/C++ Extension UI Themes to closely match Visual Studio themes, and include colors for many of the new scopes. +We created C/C++ Extension UI Themes to closely match Visual Studio themes and include colors for many of the new scopes. -VS Code has since provided an API for semantic colorization. The C/C++ Extension has transitioned from it's own implementation to this new API. These themes now include colors for some of the new semantic token scopes. +VS Code has since provided an API for semantic colorization. The C/C++ Extension has transitioned from its own implementation to this new API. These themes now include colors for some of the new semantic token scopes. ## Example @@ -18,7 +18,7 @@ Dark Theme ## Contributing -This project welcomes contributions and suggestions. Most contributions require you to agree to a +This project welcomes contributions and suggestions. Most contributions require you to agree to a Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us the rights to use your contribution. For details, visit https://cla.opensource.microsoft.com. From 54314a9f00b478f7f6e39524c4fe5c35d0ca09df Mon Sep 17 00:00:00 2001 From: Sean McManus Date: Mon, 15 Jun 2020 15:12:25 -0700 Subject: [PATCH 09/14] Fix missed spaces. --- Themes/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Themes/README.md b/Themes/README.md index a65d6ba55b..b34aee95f9 100644 --- a/Themes/README.md +++ b/Themes/README.md @@ -4,7 +4,7 @@ We created C/C++ Extension UI Themes to closely match Visual Studio themes and include colors for many of the new scopes. -VS Code has since provided an API for semantic colorization. The C/C++ Extension has transitioned from its own implementation to this new API. These themes now include colors for some of the new semantic token scopes. +VS Code has since provided an API for semantic colorization. The C/C++ Extension has transitioned from its own implementation to this new API. These themes now include colors for some of the new semantic token scopes. ## Example From c98970df16ddc8596834acdf1efea30e6984c3f1 Mon Sep 17 00:00:00 2001 From: Sean McManus Date: Mon, 15 Jun 2020 15:39:58 -0700 Subject: [PATCH 10/14] Fix linter errors. --- Extension/src/LanguageServer/client.ts | 42 +++++++++++++------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/Extension/src/LanguageServer/client.ts b/Extension/src/LanguageServer/client.ts index 3b8f2dc22b..89650bc721 100644 --- a/Extension/src/LanguageServer/client.ts +++ b/Extension/src/LanguageServer/client.ts @@ -607,9 +607,9 @@ class SemanticTokensProvider implements vscode.DocumentSemanticTokensProvider { public async provideDocumentSemanticTokens(document: vscode.TextDocument, token: vscode.CancellationToken): Promise { return new Promise((resolve, reject) => { this.client.notifyWhenReady(() => { - let uriString: string = document.uri.toString(); - let id: number = ++abortRequestId; - let params: GetSemanticTokensParams = { + const uriString: string = document.uri.toString(); + const id: number = ++abortRequestId; + const params: GetSemanticTokensParams = { id: id, uri: uriString }; @@ -621,7 +621,7 @@ class SemanticTokensProvider implements vscode.DocumentSemanticTokensProvider { if (tokensResult.fileVersion !== this.client.openFileVersions.get(uriString)) { reject(); } else { - let builder: vscode.SemanticTokensBuilder = new vscode.SemanticTokensBuilder(this.client.semanticTokensLegend); + const builder: vscode.SemanticTokensBuilder = new vscode.SemanticTokensBuilder(this.client.semanticTokensLegend); tokensResult.tokens.forEach((token) => { builder.push(token.line, token.character, token.length, token.type, token.modifiers); }); @@ -1093,8 +1093,8 @@ export class DefaultClient implements Client { } // Semantic token types are identified by indexes in this list of types, in the legend. - let tokenTypesLegend: string[] = []; - for (let e in SemanticTokenTypes) { + const tokenTypesLegend: string[] = []; + for (const e in SemanticTokenTypes) { // An enum is actually a set of mappings from key <=> value. Enumerate over only the names. // This allow us to represent the constants using an enum, which we can match in native code. if (isNaN(Number(e))) { @@ -1102,8 +1102,8 @@ export class DefaultClient implements Client { } } // Semantic token modifiers are bit indexes corresponding to the indexes in this list of modifiers in the legend. - let tokenModifiersLegend: string[] = []; - for (let e in SemanticTokenModifiers) { + const tokenModifiersLegend: string[] = []; + for (const e in SemanticTokenModifiers) { if (isNaN(Number(e))) { tokenModifiersLegend.push(e); } @@ -1398,7 +1398,7 @@ export class DefaultClient implements Client { } } if (changedSettings["enhancedColorization"]) { - let settings: CppSettings = new CppSettings(); + const settings: CppSettings = new CppSettings(); if (settings.enhancedColorization && this.semanticTokensLegend) { this.semanticTokensProviderDisposable = vscode.languages.registerDocumentSemanticTokensProvider(this.documentSelector, new SemanticTokensProvider(this), this.semanticTokensLegend); ; } else if (this.semanticTokensProviderDisposable) { @@ -1414,11 +1414,11 @@ export class DefaultClient implements Client { } public onDidChangeVisibleTextEditors(editors: vscode.TextEditor[]): void { - let settings: CppSettings = new CppSettings(this.RootUri); + const settings: CppSettings = new CppSettings(this.RootUri); if (settings.dimInactiveRegions) { // Apply text decorations to inactive regions - for (let e of editors) { - let valuePair: DecorationRangesPair | undefined = this.inactiveRegionsDecorations.get(e.document.uri.toString()); + for (const e of editors) { + const valuePair: DecorationRangesPair | undefined = this.inactiveRegionsDecorations.get(e.document.uri.toString()); if (valuePair) { e.setDecorations(valuePair.decoration, valuePair.ranges); // VSCode clears the decorations when the text editor becomes invisible } @@ -2107,8 +2107,8 @@ export class DefaultClient implements Client { } private updateInactiveRegions(params: InactiveRegionParams): void { - let settings: CppSettings = new CppSettings(this.RootUri); - let opacity: number | undefined = settings.inactiveRegionOpacity; + const settings: CppSettings = new CppSettings(this.RootUri); + const opacity: number | undefined = settings.inactiveRegionOpacity; if (opacity !== null && opacity !== undefined) { let backgroundColor: string | undefined = settings.inactiveRegionBackgroundColor; if (backgroundColor === "") { @@ -2118,20 +2118,20 @@ export class DefaultClient implements Client { if (color === "") { color = undefined; } - let decoration: vscode.TextEditorDecorationType = vscode.window.createTextEditorDecorationType({ + const decoration: vscode.TextEditorDecorationType = vscode.window.createTextEditorDecorationType({ opacity: opacity.toString(), backgroundColor: backgroundColor, color: color, rangeBehavior: vscode.DecorationRangeBehavior.OpenOpen }); // We must convert to vscode.Ranges in order to make use of the API's - let ranges: vscode.Range[] = []; + const ranges: vscode.Range[] = []; params.regions.forEach(element => { - let newRange: vscode.Range = new vscode.Range(element.startLine, 0, element.endLine, 0); + const newRange: vscode.Range = new vscode.Range(element.startLine, 0, element.endLine, 0); ranges.push(newRange); }); // Find entry for cached file and act accordingly - let valuePair: DecorationRangesPair | undefined = this.inactiveRegionsDecorations.get(params.uri); + const valuePair: DecorationRangesPair | undefined = this.inactiveRegionsDecorations.get(params.uri); if (valuePair) { // Disposing of and resetting the decoration will undo previously applied text decorations valuePair.decoration.dispose(); @@ -2139,7 +2139,7 @@ export class DefaultClient implements Client { // As vscode.TextEditor.setDecorations only applies to visible editors, we must cache the range for when another editor becomes visible valuePair.ranges = ranges; } else { // The entry does not exist. Make a new one - let toInsert: DecorationRangesPair = { + const toInsert: DecorationRangesPair = { decoration: decoration, ranges: ranges }; @@ -2147,8 +2147,8 @@ export class DefaultClient implements Client { } if (settings.dimInactiveRegions && params.fileVersion === this.openFileVersions.get(params.uri)) { // Apply the decorations to all *visible* text editors - let editors: vscode.TextEditor[] = vscode.window.visibleTextEditors.filter(e => e.document.uri.toString() === params.uri); - for (let e of editors) { + const editors: vscode.TextEditor[] = vscode.window.visibleTextEditors.filter(e => e.document.uri.toString() === params.uri); + for (const e of editors) { e.setDecorations(decoration, ranges); } } From e37b5f475d21bec3d4fd298a21f091f765c7977e Mon Sep 17 00:00:00 2001 From: Colen Garoutte-Carson Date: Mon, 29 Jun 2020 12:21:04 -0700 Subject: [PATCH 11/14] Enable semantic highlighing by default for C and CPP files --- Extension/package.json | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Extension/package.json b/Extension/package.json index 684d587fe8..ce1b6f3768 100644 --- a/Extension/package.json +++ b/Extension/package.json @@ -1529,11 +1529,13 @@ "configurationDefaults": { "[cpp]": { "editor.wordBasedSuggestions": false, - "editor.suggest.insertMode": "replace" + "editor.suggest.insertMode": "replace", + "editor.semanticHighlighting.enabled": true }, "[c]": { "editor.wordBasedSuggestions": false, - "editor.suggest.insertMode": "replace" + "editor.suggest.insertMode": "replace", + "editor.semanticHighlighting.enabled": true }, "[Log]": { "editor.wordWrap": "off" From 60861c86ce33a514a7259ea354ca8568a81d12a2 Mon Sep 17 00:00:00 2001 From: Colen Garoutte-Carson Date: Tue, 30 Jun 2020 13:57:28 -0700 Subject: [PATCH 12/14] Swtich from using 'type' to 'class' for fallback colors --- Extension/package.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Extension/package.json b/Extension/package.json index 8396a775c1..ebc963352e 100644 --- a/Extension/package.json +++ b/Extension/package.json @@ -1554,7 +1554,7 @@ "semanticTokenTypes": [ { "id": "referenceType", - "superType": "type", + "superType": "class", "description": "A C++/CLI reference type." }, { @@ -1564,12 +1564,12 @@ }, { "id": "genericType", - "superType": "type", + "superType": "class", "description": "A C++/CLI generic type." }, { "id": "valueType", - "superType": "type", + "superType": "class", "description": "A C++/CLI value type." }, { @@ -1579,7 +1579,7 @@ }, { "id": "templateType", - "superType": "type", + "superType": "class", "description": "A template type." }, { From a51c80f74d262cace9c9440fc2f69a74ff476690 Mon Sep 17 00:00:00 2001 From: Colen Garoutte-Carson Date: Tue, 30 Jun 2020 15:00:13 -0700 Subject: [PATCH 13/14] Add our old custom scopes as fallbacks --- Extension/package.json | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/Extension/package.json b/Extension/package.json index ebc963352e..9e0f201c7d 100644 --- a/Extension/package.json +++ b/Extension/package.json @@ -1622,7 +1622,25 @@ "id": "local", "description": "Annotates a symbol that is declared in local scope." } - ] + ], + "semanticTokenScopes": [ + { + "scopes": { + "referenceType": [ "entity.name.type.class.reference" ], + "cliProperty": [ "variable.other.property.cli" ], + "genericType": [ "entity.name.type.class.generic" ], + "valueType": [ "entity.name.type.class.value" ], + "templateFunction": [ "entity.name.function.templated" ], + "templateType": [ "entity.name.type.class.templated" ], + "operatorOverload": [ "entity.name.function.operator" ], + "memberOperatorOverload": [ "entity.name.function.operator.member" ], + "newOperator": [ "keyword.operator.new" ], + "numberLiteral": [ "entity.name.operator.custom-literal.number" ], + "customLiteral": [ "entity.name.operator.custom-literal" ], + "stringLiteral": [ "entity.name.operator.custom-literal.string" ] + } + } + ], }, "scripts": { "vscode:prepublish": "yarn run compile", From 282d01f5c044dd351b19c680cecb10c17087ab54 Mon Sep 17 00:00:00 2001 From: Colen Garoutte-Carson Date: Tue, 30 Jun 2020 15:10:12 -0700 Subject: [PATCH 14/14] Fix issue with json validation --- Extension/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Extension/package.json b/Extension/package.json index 9e0f201c7d..f69f9662b8 100644 --- a/Extension/package.json +++ b/Extension/package.json @@ -1640,7 +1640,7 @@ "stringLiteral": [ "entity.name.operator.custom-literal.string" ] } } - ], + ] }, "scripts": { "vscode:prepublish": "yarn run compile",