-
Notifications
You must be signed in to change notification settings - Fork 147
Export client from activation as API for use in other extensions #575
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
8b118f4
163c9cb
3f00701
1c1de54
be45460
716647e
8b870d6
094f473
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,38 @@ | ||
| # VS Code clangd Extension API | ||
|
|
||
| The VS Code clangd extension exposes an API that other extensions can consume: | ||
|
|
||
| ```typescript | ||
| import * as vscode from 'vscode'; | ||
| import type { ClangdExtension, ASTParams, ASTNode } from '@clangd/vscode-clangd'; | ||
|
|
||
| const CLANGD_EXTENSION = 'llvm-vs-code-extensions.vscode-clangd'; | ||
| const CLANGD_API_VERSION = 1; | ||
|
|
||
| const ASTRequestMethod = 'textDocument/ast'; | ||
|
|
||
| const provideHover = async (document: vscode.TextDocument, position: vscode.Position, _token: vscode.CancellationToken): Promise<vscode.Hover | undefined> => { | ||
|
|
||
| const clangdExtension = vscode.extensions.getExtension<ClangdExtension>(CLANGD_EXTENSION); | ||
|
|
||
| if (clangdExtension) { | ||
| const api = (await clangdExtension.activate()).getApi(CLANGD_API_VERSION); | ||
|
|
||
| const textDocument = api.languageClient.code2ProtocolConverter.asTextDocumentIdentifier(document); | ||
| const range = api.languageClient.code2ProtocolConverter.asRange(new vscode.Range(position, position)); | ||
| const params: ASTParams = { textDocument, range }; | ||
|
|
||
| const ast: ASTNode | undefined = await api.languageClient.sendRequest(ASTRequestMethod, params); | ||
|
|
||
| if (!ast) { | ||
| return undefined; | ||
| } | ||
|
|
||
| return { | ||
| contents: [ast.kind] | ||
| }; | ||
| } | ||
| }; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. can we show the
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Added |
||
|
|
||
| vscode.languages.registerHoverProvider(['c', 'cpp'], { provideHover }); | ||
| ``` | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| { | ||
| "name": "@clangd/vscode-clangd", | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please add a Also, maybe a
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Both added |
||
| "version": "0.0.0", | ||
| "description": "API for the llvm-vs-code-extensions.vscode-clangd VS Code extension", | ||
| "types": "vscode-clangd.d.ts", | ||
| "publishConfig": { | ||
| "registry": "https://npm.pkg.github.com" | ||
| }, | ||
| "repository": "https://github.com/clangd/vscode-clangd", | ||
| "license": "MIT", | ||
| "homepage": "https://github.com/clangd/vscode-clangd/blob/master/api/README.md", | ||
| "dependencies": { | ||
| "vscode-languageclient": "8.0.2" | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,36 @@ | ||
| import {BaseLanguageClient} from 'vscode-languageclient'; | ||
| import * as vscodelc from 'vscode-languageclient/node'; | ||
|
|
||
| export interface ClangdApiV1 { | ||
| // vscode-clangd's language client which can be used to send requests to the | ||
| // clangd language server | ||
| // Standard requests: | ||
| // https://microsoft.github.io/language-server-protocol/specifications/specification-current | ||
| // clangd custom requests: | ||
| // https://clangd.llvm.org/extensions | ||
| languageClient: BaseLanguageClient | ||
| } | ||
|
|
||
| export interface ClangdExtension { | ||
| getApi(version: 1): ClangdApiV1; | ||
| } | ||
|
|
||
| // clangd custom request types | ||
| // (type declarations for other requests may be added later) | ||
|
|
||
| // textDocument/ast wire format | ||
| // Send: position | ||
| export interface ASTParams { | ||
| textDocument: vscodelc.TextDocumentIdentifier; | ||
| range: vscodelc.Range; | ||
| } | ||
|
|
||
| // Receive: tree of ASTNode | ||
| export interface ASTNode { | ||
| role: string; // e.g. expression | ||
| kind: string; // e.g. BinaryOperator | ||
| detail?: string; // e.g. || | ||
| arcana?: string; // e.g. BinaryOperator <0x12345> <col:12, col:1> 'bool' '||' | ||
| children?: Array<ASTNode>; | ||
| range?: vscodelc.Range; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,16 @@ | ||
| import {BaseLanguageClient} from 'vscode-languageclient'; | ||
|
|
||
| import {ClangdApiV1, ClangdExtension} from '../api/vscode-clangd'; | ||
|
|
||
| export class ClangdExtensionImpl implements ClangdExtension { | ||
| constructor(private readonly client: BaseLanguageClient) {} | ||
|
|
||
| public getApi(version: 1): ClangdApiV1; | ||
| public getApi(version: number): unknown { | ||
| if (version === 1) { | ||
| return {languageClient: this.client}; | ||
| } | ||
|
|
||
| throw new Error(`No API version ${version} found`); | ||
| } | ||
| } |
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should probably discourage consumers unconditionally calling
activate(), since the clangd extension may already be activated and it doesn't expectactivate()to be called again in that state.I believe the right pattern here is for consuming code to:
clangdExtension.exportsto access theClangdExtensionobject.exportswith aclangdExtension.isActivecheckactivate()at that pointThis is what I've done in my example plugin, and I'd prefer the README does the same. (Sorry to be picky on this point, I worry that users who may not have much familiarity with VSCode extensions may look to this README for how to use the API and assume that what it shows is a good way to do things.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
vscode.Extension.activate()is designed to be called multiple times and only calls into the extension'sactivate()method once. Subsequent calls return the resolved extension. This is a common pattern and (just to be sure) I tested this scenario by activating it multiple times with logging in the extensionactivate()function. It worked as expected and only activates once.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for checking on this, I think this is fine then.