Skip to content

Commit

Permalink
API supports disabled extension
Browse files Browse the repository at this point in the history
  • Loading branch information
thegecko committed Nov 13, 2024
1 parent 0bf5af2 commit e18c97a
Show file tree
Hide file tree
Showing 12 changed files with 126 additions and 60 deletions.
7 changes: 6 additions & 1 deletion api/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ 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 CLANGD_API_VERSION = 2;

const ASTRequestMethod = 'textDocument/ast';

Expand All @@ -17,6 +17,11 @@ const provideHover = async (document: vscode.TextDocument, position: vscode.Posi

if (clangdExtension) {
const api = (await clangdExtension.activate()).getApi(CLANGD_API_VERSION);

// Extension may be disabled
if (!api.languageClient) {
return undefined;
}

const textDocument = api.languageClient.code2ProtocolConverter.asTextDocumentIdentifier(document);
const range = api.languageClient.code2ProtocolConverter.asRange(new vscode.Range(position, position));
Expand Down
13 changes: 12 additions & 1 deletion api/vscode-clangd.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,22 @@ export interface ClangdApiV1 {
// https://microsoft.github.io/language-server-protocol/specifications/specification-current
// clangd custom requests:
// https://clangd.llvm.org/extensions
languageClient: BaseLanguageClient
languageClient: BaseLanguageClient;
}

export interface ClangdApiV2 {
// 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 | undefined;
}

export interface ClangdExtension {
getApi(version: 1): ClangdApiV1;
getApi(version: 2): ClangdApiV2;
}

// clangd custom request types
Expand Down
11 changes: 8 additions & 3 deletions src/api.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,19 @@
import {BaseLanguageClient} from 'vscode-languageclient';

import {ClangdApiV1, ClangdExtension} from '../api/vscode-clangd';
import {ClangdApiV1, ClangdApiV2, ClangdExtension} from '../api/vscode-clangd';

export class ClangdExtensionImpl implements ClangdExtension {
constructor(public client: BaseLanguageClient) {}
constructor(public client: BaseLanguageClient|undefined) {}

public getApi(version: 1): ClangdApiV1;
public getApi(version: 2): ClangdApiV2;
public getApi(version: number): unknown {
if (version === 1) {
switch (version) {
case 1:
case 2: {
return {languageClient: this.client};
break;
}
}

throw new Error(`No API version ${version} found`);
Expand Down
22 changes: 13 additions & 9 deletions src/ast.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,10 @@ import type {ASTParams, ASTNode} from '../api/vscode-clangd';
const ASTRequestMethod = 'textDocument/ast';

export function activate(context: ClangdContext) {
const feature = new ASTFeature(context);
context.client.registerFeature(feature);
if (context.client) {
const feature = new ASTFeature(context);
context.client.registerFeature(feature);
}
}

const ASTRequestType =
Expand Down Expand Up @@ -42,13 +44,15 @@ class ASTFeature implements vscodelc.StaticFeature {
vscode.commands.registerTextEditorCommand(
'clangd.ast',
async (editor, _edit) => {
const converter = this.context.client.code2ProtocolConverter;
const item =
await this.context.client.sendRequest(ASTRequestType, {
textDocument:
converter.asTextDocumentIdentifier(editor.document),
range: converter.asRange(editor.selection),
});
let item: ASTNode|null = null;
if (this.context.client) {
const converter = this.context.client.code2ProtocolConverter;
item = await this.context.client.sendRequest(ASTRequestType, {
textDocument:
converter.asTextDocumentIdentifier(editor.document),
range: converter.asRange(editor.selection),
});
}
if (!item)
vscode.window.showInformationMessage(
'No AST node at selection');
Expand Down
4 changes: 2 additions & 2 deletions src/clangd-context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ export function isClangdDocument(document: vscode.TextDocument) {
return vscode.languages.match(clangdDocumentSelector, document);
}

class ClangdLanguageClient extends vscodelc.LanguageClient {
export class ClangdLanguageClient extends vscodelc.LanguageClient {
// Override the default implementation for failed requests. The default
// behavior is just to log failures in the output panel, however output panel
// is designed for extension debugging purpose, normal users will not open it,
Expand Down Expand Up @@ -58,7 +58,7 @@ class EnableEditsNearCursorFeature implements vscodelc.StaticFeature {

export class ClangdContext implements vscode.Disposable {
subscriptions: vscode.Disposable[] = [];
client!: ClangdLanguageClient;
client: ClangdLanguageClient|undefined;

async activate(globalStoragePath: string,
outputChannel: vscode.OutputChannel) {
Expand Down
4 changes: 3 additions & 1 deletion src/config-file-watcher.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ import * as config from './config';

export function activate(context: ClangdContext) {
if (config.get<string>('onConfigChanged') !== 'ignore') {
context.client.registerFeature(new ConfigFileWatcherFeature(context));
if (context.client) {
context.client.registerFeature(new ConfigFileWatcherFeature(context));
}
}
}

Expand Down
34 changes: 21 additions & 13 deletions src/file-status.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,23 +4,31 @@ import * as vscodelc from 'vscode-languageclient/node';
import {ClangdContext} from './clangd-context';

export function activate(context: ClangdContext) {
context.subscriptions.push(vscode.commands.registerCommand(
'clangd.openOutputPanel', () => context.client.outputChannel.show()));
context.subscriptions.push(
vscode.commands.registerCommand('clangd.openOutputPanel', () => {
if (context.client) {
context.client.outputChannel.show();
}
}));
const status = new FileStatus('clangd.openOutputPanel');
context.subscriptions.push(vscode.Disposable.from(status));
context.subscriptions.push(vscode.window.onDidChangeActiveTextEditor(
() => { status.updateStatus(); }));
context.subscriptions.push(context.client.onDidChangeState(({newState}) => {
if (newState === vscodelc.State.Running) {
// clangd starts or restarts after crash.
context.client.onNotification(
'textDocument/clangd.fileStatus',
(fileStatus) => { status.onFileUpdated(fileStatus); });
} else if (newState === vscodelc.State.Stopped) {
// Clear all cached statuses when clangd crashes.
status.clear();
}
}));
if (context.client) {
context.subscriptions.push(context.client.onDidChangeState(({newState}) => {
if (newState === vscodelc.State.Running) {
// clangd starts or restarts after crash.
if (context.client) {
context.client.onNotification(
'textDocument/clangd.fileStatus',
(fileStatus) => { status.onFileUpdated(fileStatus); });
}
} else if (newState === vscodelc.State.Stopped) {
// Clear all cached statuses when clangd crashes.
status.clear();
}
}));
}
}

class FileStatus {
Expand Down
13 changes: 9 additions & 4 deletions src/inactive-regions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,11 @@ export const NotificationType =

export function activate(context: ClangdContext) {
const feature = new InactiveRegionsFeature(context);
context.client.registerFeature(feature);
context.client.onNotification(NotificationType,
feature.handleNotification.bind(feature));
if (context.client) {
context.client.registerFeature(feature);
context.client.onNotification(NotificationType,
feature.handleNotification.bind(feature));
}
}

export class InactiveRegionsFeature implements vscodelc.StaticFeature {
Expand Down Expand Up @@ -80,9 +82,12 @@ export class InactiveRegionsFeature implements vscodelc.StaticFeature {
}

handleNotification(params: InactiveRegionsParams) {
if (!this.context.client) {
return;
}
const filePath = vscode.Uri.parse(params.textDocument.uri, true).fsPath;
const ranges: vscode.Range[] = params.regions.map(
(r) => this.context.client.protocol2CodeConverter.asRange(r));
(r) => this.context.client!.protocol2CodeConverter.asRange(r));
this.files.set(filePath, ranges);
this.applyHighlights(filePath);
}
Expand Down
23 changes: 16 additions & 7 deletions src/inlay-hints.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,17 @@
import * as vscode from 'vscode';
import * as vscodelc from 'vscode-languageclient/node';

import {ClangdContext, clangdDocumentSelector} from './clangd-context';
import {
ClangdContext,
clangdDocumentSelector,
ClangdLanguageClient
} from './clangd-context';

export function activate(context: ClangdContext) {
const feature = new InlayHintsFeature(context);
context.client.registerFeature(feature);
if (context.client) {
const feature = new InlayHintsFeature(context);
context.client.registerFeature(feature);
}
}

namespace protocol {
Expand Down Expand Up @@ -107,10 +113,10 @@ class Provider implements vscode.InlayHintsProvider {
return undefined;
}

decode(hint: protocol.InlayHint): vscode.InlayHint {
decode(hint: protocol.InlayHint,
client: ClangdLanguageClient): vscode.InlayHint {
return {
position:
this.context.client.protocol2CodeConverter.asPosition(hint.position!),
position: client.protocol2CodeConverter.asPosition(hint.position!),
kind: this.decodeKind(hint.kind),
label: hint.label.trim(),
paddingLeft: hint.label.startsWith(' '),
Expand All @@ -121,13 +127,16 @@ class Provider implements vscode.InlayHintsProvider {
async provideInlayHints(document: vscode.TextDocument, range: vscode.Range,
token: vscode.CancellationToken):
Promise<vscode.InlayHint[]> {
if (!this.context.client) {
return [];
}
const request: protocol.InlayHintsParams = {
textDocument: {uri: document.uri.toString()},
range: this.context.client.code2ProtocolConverter.asRange(range),
};

const result = await this.context.client.sendRequest(
protocol.InlayHintsRequest.type, request, token);
return result.map(this.decode, this);
return result.map(hint => this.decode(hint, this.context.client!));
}
}
14 changes: 9 additions & 5 deletions src/memory-usage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,10 @@ import * as vscodelc from 'vscode-languageclient/node';
import {ClangdContext} from './clangd-context';

export function activate(context: ClangdContext) {
const feature = new MemoryUsageFeature(context);
context.client.registerFeature(feature);
if (context.client) {
const feature = new MemoryUsageFeature(context);
context.client.registerFeature(feature);
}
}

// LSP wire format for this clangd feature.
Expand Down Expand Up @@ -58,9 +60,11 @@ class MemoryUsageFeature implements vscodelc.StaticFeature {
vscode.window.registerTreeDataProvider('clangd.memoryUsage', adapter));
this.context.subscriptions.push(
vscode.commands.registerCommand('clangd.memoryUsage', async () => {
const usage =
await this.context.client.sendRequest(MemoryUsageRequest, {});
adapter.root = convert(usage, '<root>');
if (this.context.client) {
const usage =
await this.context.client.sendRequest(MemoryUsageRequest, {});
adapter.root = convert(usage, '<root>');
}
}));
this.context.subscriptions.push(vscode.commands.registerCommand(
'clangd.memoryUsage.close', () => adapter.root = undefined));
Expand Down
6 changes: 3 additions & 3 deletions src/switch-source-header.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@ export const type =
'textDocument/switchSourceHeader');
}

async function switchSourceHeader(client: vscodelc.LanguageClient):
Promise<void> {
if (!vscode.window.activeTextEditor)
async function switchSourceHeader(client
?: vscodelc.LanguageClient): Promise<void> {
if (!client || !vscode.window.activeTextEditor)
return;
const uri = vscode.Uri.file(vscode.window.activeTextEditor.document.fileName);

Expand Down
35 changes: 24 additions & 11 deletions src/type-hierarchy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,10 @@ import * as vscodelc from 'vscode-languageclient/node';
import {ClangdContext} from './clangd-context';

export function activate(context: ClangdContext) {
const feature = new TypeHierarchyFeature(context);
context.client.registerFeature(feature);
if (context.client) {
const feature = new TypeHierarchyFeature(context);
context.client.registerFeature(feature);
}
}

export namespace TypeHierarchyDirection {
Expand Down Expand Up @@ -106,10 +108,13 @@ class TypeHierarchyFeature implements vscodelc.StaticFeature {
constructor(context: ClangdContext) {
this.context = context;
new TypeHierarchyProvider(context);
context.subscriptions.push(context.client.onDidChangeState(stateChange => {
this.state = stateChange.newState;
this.recomputeEnableTypeHierarchy();
}));
if (context.client) {
context.subscriptions.push(
context.client.onDidChangeState(stateChange => {
this.state = stateChange.newState;
this.recomputeEnableTypeHierarchy();
}));
}
}

fillClientCapabilities(capabilities: vscodelc.ClientCapabilities) {}
Expand All @@ -125,9 +130,11 @@ class TypeHierarchyFeature implements vscodelc.StaticFeature {
// incompatible protocol.
if (serverCapabilities.typeHierarchyProvider &&
!serverCapabilities.standardTypeHierarchyProvider) {
// Disable mis-guided support for standard type-hierarchy feature.
this.context.client.getFeature('textDocument/prepareTypeHierarchy')
.dispose();
if (this.context.client) {
// Disable mis-guided support for standard type-hierarchy feature.
this.context.client.getFeature('textDocument/prepareTypeHierarchy')
.dispose();
}
this.serverSupportsTypeHierarchy = true;
this.recomputeEnableTypeHierarchy();
} else {
Expand All @@ -152,7 +159,7 @@ class TypeHierarchyFeature implements vscodelc.StaticFeature {
class TypeHierarchyProvider implements
vscode.TreeDataProvider<TypeHierarchyItem> {

private client: vscodelc.LanguageClient;
private client: vscodelc.LanguageClient|undefined;

private _onDidChangeTreeData =
new vscode.EventEmitter<TypeHierarchyItem|null>();
Expand Down Expand Up @@ -190,6 +197,9 @@ class TypeHierarchyProvider implements
}

public async gotoItem(item: TypeHierarchyItem) {
if (!this.client) {
return;
}
const uri = vscode.Uri.parse(item.uri);
const range =
this.client.protocol2CodeConverter.asRange(item.selectionRange);
Expand Down Expand Up @@ -251,7 +261,7 @@ class TypeHierarchyProvider implements
return element.parents ?? [];
}
// Otherwise, this.direction === Children.
if (!element.children) {
if (!element.children && this.client) {
// Children are not resolved yet, resolve them now.
const resolved =
await this.client.sendRequest(ResolveTypeHierarchyRequest.type, {
Expand Down Expand Up @@ -291,6 +301,9 @@ class TypeHierarchyProvider implements
}

private async reveal(editor: vscode.TextEditor) {
if (!this.client) {
return;
}
// This makes the type hierarchy view visible by causing the condition
// "when": "extension.vscode-clangd.typeHierarchyVisible" from
// package.json to evaluate to true.
Expand Down

0 comments on commit e18c97a

Please sign in to comment.