diff --git a/clang-tools-extra/clangd/clients/clangd-vscode/.gitignore b/clang-tools-extra/clangd/clients/clangd-vscode/.gitignore --- a/clang-tools-extra/clangd/clients/clangd-vscode/.gitignore +++ b/clang-tools-extra/clangd/clients/clangd-vscode/.gitignore @@ -1,2 +1,3 @@ out node_modules +.vscode-test diff --git a/clang-tools-extra/clangd/clients/clangd-vscode/src/SemanticHighlighting.ts b/clang-tools-extra/clangd/clients/clangd-vscode/src/SemanticHighlighting.ts new file mode 100644 --- /dev/null +++ b/clang-tools-extra/clangd/clients/clangd-vscode/src/SemanticHighlighting.ts @@ -0,0 +1,36 @@ +import * as vscodelc from 'vscode-languageclient'; +import { DocumentSelector } from 'vscode-languageclient'; + +export namespace SemanticHighlighting { + interface HighlightingInformation { + textDocument: { + uri: String, + }, + lines: [{ + line: number, + tokens: string, + }], + } + + export const NotificationType = new vscodelc.NotificationType<{}, void>('textDocument/semanticHighlighting'); + + // The feature that should be registered in the vscode lsp for enabling experimental semantic highlighting. + export class Feature implements vscodelc.StaticFeature { + scopes: string[]; + fillClientCapabilities(capabilities: vscodelc.ClientCapabilities) { + const textDocumentCapabilities: vscodelc.TextDocumentClientCapabilities & { semanticHighlightingCapabilities?: { semanticHighlighting: boolean } } = capabilities.textDocument; + textDocumentCapabilities.semanticHighlightingCapabilities = { semanticHighlighting: true }; + + } + + initialize(capabilities: vscodelc.ServerCapabilities, documentSelector: DocumentSelector | undefined) { + // Use type intersection to be able to read the semanticHighlighting capability the clangd server added in the response. + const serverCapabilities: vscodelc.ServerCapabilities & { semanticHighlighting?: { scopes: string[] } } = capabilities; + if(!serverCapabilities.semanticHighlighting) + return; + this.scopes = serverCapabilities.semanticHighlighting.scopes; + } + + handleNotification(params: HighlightingInformation) { } + } +}; diff --git a/clang-tools-extra/clangd/clients/clangd-vscode/src/extension.ts b/clang-tools-extra/clangd/clients/clangd-vscode/src/extension.ts --- a/clang-tools-extra/clangd/clients/clangd-vscode/src/extension.ts +++ b/clang-tools-extra/clangd/clients/clangd-vscode/src/extension.ts @@ -1,5 +1,6 @@ import * as vscode from 'vscode'; import * as vscodelc from 'vscode-languageclient'; +import { SemanticHighlighting } from './SemanticHighlighting'; /** * Method to get workspace configuration option @@ -12,9 +13,9 @@ } namespace SwitchSourceHeaderRequest { -export const type = - new vscodelc.RequestType('textDocument/switchSourceHeader'); + export const type = + new vscodelc.RequestType('textDocument/switchSourceHeader'); } class FileStatus { @@ -32,8 +33,8 @@ const path = vscode.window.activeTextEditor.document.fileName; const status = this.statuses.get(path); if (!status) { - this.statusBarItem.hide(); - return; + this.statusBarItem.hide(); + return; } this.statusBarItem.text = `clangd: ` + status.state; this.statusBarItem.show(); @@ -73,25 +74,30 @@ // However, VSCode does not have CUDA as a supported language yet, so we // cannot add a corresponding activationEvent for CUDA files and clangd will // *not* load itself automatically on '.cu' files. - const cudaFilePattern: string = '**/*.{' +['cu'].join()+ '}'; + const cudaFilePattern: string = '**/*.{' + ['cu'].join() + '}'; const clientOptions: vscodelc.LanguageClientOptions = { // Register the server for c-family and cuda files. documentSelector: [ { scheme: 'file', language: 'c' }, { scheme: 'file', language: 'cpp' }, - { scheme: 'file', language: 'objective-c'}, - { scheme: 'file', language: 'objective-cpp'}, + { scheme: 'file', language: 'objective-c' }, + { scheme: 'file', language: 'objective-cpp' }, { scheme: 'file', pattern: cudaFilePattern }, ], synchronize: !syncFileEvents ? undefined : { - // FIXME: send sync file events when clangd provides implemenatations. + // FIXME: send sync file events when clangd provides implemenatations. }, initializationOptions: { clangdFileStatus: true }, // Do not switch to output window when clangd returns output revealOutputChannelOn: vscodelc.RevealOutputChannelOn.Never }; - const clangdClient = new vscodelc.LanguageClient('Clang Language Server',serverOptions, clientOptions); + const clangdClient = new vscodelc.LanguageClient('Clang Language Server', serverOptions, clientOptions); + const semanticHighlightingFeature = new SemanticHighlighting.Feature(); + clangdClient.registerFeature(semanticHighlightingFeature); + // The notification handler must be registered after the client is ready or the client will crash. + clangdClient.onReady().then(() => clangdClient.onNotification(SemanticHighlighting.NotificationType, semanticHighlightingFeature.handleNotification)); + console.log('Clang Language Server is now active!'); context.subscriptions.push(clangdClient.start()); context.subscriptions.push(vscode.commands.registerCommand( @@ -131,5 +137,5 @@ // An empty place holder for the activate command, otherwise we'll get an // "command is not registered" error. context.subscriptions.push(vscode.commands.registerCommand( - 'clangd-vscode.activate', async () => {})); + 'clangd-vscode.activate', async () => { })); }