Skip to content

Commit e571968

Browse files
committed
implement api commands for call hierarchy, #83274
1 parent 467079f commit e571968

File tree

8 files changed

+345
-97
lines changed

8 files changed

+345
-97
lines changed

src/vs/workbench/api/browser/mainThreadLanguageFeatures.ts

+12-16
Original file line numberDiff line numberDiff line change
@@ -498,39 +498,35 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
498498
this._registrations.set(handle, callh.CallHierarchyProviderRegistry.register(selector, {
499499

500500
prepareCallHierarchy: async (document, position, token) => {
501-
const result = await this._proxy.$prepareCallHierarchy(handle, document.uri, position, token);
502-
if (!result) {
501+
const item = await this._proxy.$prepareCallHierarchy(handle, document.uri, position, token);
502+
if (!item) {
503503
return undefined;
504504
}
505505
return {
506-
dispose: () => this._proxy.$releaseCallHierarchy(handle, result.sessionId),
507-
root: MainThreadLanguageFeatures._reviveCallHierarchyItemDto(result.root)
506+
dispose: () => this._proxy.$releaseCallHierarchy(handle, item._sessionId),
507+
root: MainThreadLanguageFeatures._reviveCallHierarchyItemDto(item)
508508
};
509509
},
510510

511511
provideOutgoingCalls: async (item, token) => {
512-
const outgoing = await this._proxy.$provideCallHierarchyOutgoingCalls(handle, item.id, token);
512+
const outgoing = await this._proxy.$provideCallHierarchyOutgoingCalls(handle, item._sessionId, item._itemId, token);
513513
if (!outgoing) {
514514
return outgoing;
515515
}
516-
return outgoing.map(([item, fromRanges]): callh.OutgoingCall => {
517-
return {
518-
to: MainThreadLanguageFeatures._reviveCallHierarchyItemDto(item),
519-
fromRanges
520-
};
516+
outgoing.forEach(value => {
517+
value.to = MainThreadLanguageFeatures._reviveCallHierarchyItemDto(value.to);
521518
});
519+
return <any>outgoing;
522520
},
523521
provideIncomingCalls: async (item, token) => {
524-
const incoming = await this._proxy.$provideCallHierarchyIncomingCalls(handle, item.id, token);
522+
const incoming = await this._proxy.$provideCallHierarchyIncomingCalls(handle, item._sessionId, item._itemId, token);
525523
if (!incoming) {
526524
return incoming;
527525
}
528-
return incoming.map(([item, fromRanges]): callh.IncomingCall => {
529-
return {
530-
from: MainThreadLanguageFeatures._reviveCallHierarchyItemDto(item),
531-
fromRanges
532-
};
526+
incoming.forEach(value => {
527+
value.from = MainThreadLanguageFeatures._reviveCallHierarchyItemDto(value.from);
533528
});
529+
return <any>incoming;
534530
}
535531
}));
536532
}

src/vs/workbench/api/common/extHost.protocol.ts

+37-26
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ export interface IStaticWorkspaceData {
7171
}
7272

7373
export interface IWorkspaceData extends IStaticWorkspaceData {
74-
folders: { uri: UriComponents, name: string, index: number }[];
74+
folders: { uri: UriComponents, name: string, index: number; }[];
7575
}
7676

7777
export interface IInitData {
@@ -97,7 +97,7 @@ export interface IConfigurationInitData extends IConfigurationData {
9797

9898
export interface IWorkspaceConfigurationChangeEventData {
9999
changedConfiguration: IConfigurationModel;
100-
changedConfigurationByResource: { [folder: string]: IConfigurationModel };
100+
changedConfigurationByResource: { [folder: string]: IConfigurationModel; };
101101
}
102102

103103
export interface IExtHostContext extends IRPCProtocol {
@@ -136,7 +136,7 @@ export type CommentThreadChanges = Partial<{
136136
label: string,
137137
contextValue: string,
138138
comments: modes.Comment[],
139-
collapseState: modes.CommentThreadCollapsibleState
139+
collapseState: modes.CommentThreadCollapsibleState;
140140
}>;
141141

142142
export interface MainThreadCommentsShape extends IDisposable {
@@ -165,13 +165,13 @@ export interface MainThreadDialogOpenOptions {
165165
canSelectFiles?: boolean;
166166
canSelectFolders?: boolean;
167167
canSelectMany?: boolean;
168-
filters?: { [name: string]: string[] };
168+
filters?: { [name: string]: string[]; };
169169
}
170170

171171
export interface MainThreadDialogSaveOptions {
172172
defaultUri?: UriComponents;
173173
saveLabel?: string;
174-
filters?: { [name: string]: string[] };
174+
filters?: { [name: string]: string[]; };
175175
}
176176

177177
export interface MainThreadDiaglogsShape extends IDisposable {
@@ -254,8 +254,8 @@ export interface MainThreadTextEditorsShape extends IDisposable {
254254
}
255255

256256
export interface MainThreadTreeViewsShape extends IDisposable {
257-
$registerTreeViewDataProvider(treeViewId: string, options: { showCollapseAll: boolean, canSelectMany: boolean }): void;
258-
$refresh(treeViewId: string, itemsToRefresh?: { [treeItemHandle: string]: ITreeItem }): Promise<void>;
257+
$registerTreeViewDataProvider(treeViewId: string, options: { showCollapseAll: boolean, canSelectMany: boolean; }): void;
258+
$refresh(treeViewId: string, itemsToRefresh?: { [treeItemHandle: string]: ITreeItem; }): Promise<void>;
259259
$reveal(treeViewId: string, treeItem: ITreeItem, parentChain: ITreeItem[], options: IRevealOptions): Promise<void>;
260260
$setMessage(treeViewId: string, message: string): void;
261261
$setTitle(treeViewId: string, title: string): void;
@@ -278,7 +278,7 @@ export interface MainThreadKeytarShape extends IDisposable {
278278
$setPassword(service: string, account: string, password: string): Promise<void>;
279279
$deletePassword(service: string, account: string): Promise<boolean>;
280280
$findPassword(service: string): Promise<string | null>;
281-
$findCredentials(service: string): Promise<Array<{ account: string, password: string }>>;
281+
$findCredentials(service: string): Promise<Array<{ account: string, password: string; }>>;
282282
}
283283

284284
export interface IRegExpDto {
@@ -321,7 +321,7 @@ export interface ILanguageConfigurationDto {
321321
};
322322
}
323323

324-
export type GlobPattern = string | { base: string; pattern: string };
324+
export type GlobPattern = string | { base: string; pattern: string; };
325325

326326
export interface IDocumentFilterDto {
327327
$serialized: true;
@@ -400,15 +400,15 @@ export interface TerminalLaunchConfig {
400400
shellPath?: string;
401401
shellArgs?: string[] | string;
402402
cwd?: string | UriComponents;
403-
env?: { [key: string]: string | null };
403+
env?: { [key: string]: string | null; };
404404
waitOnExit?: boolean;
405405
strictEnv?: boolean;
406406
hideFromUser?: boolean;
407407
isExtensionTerminal?: boolean;
408408
}
409409

410410
export interface MainThreadTerminalServiceShape extends IDisposable {
411-
$createTerminal(config: TerminalLaunchConfig): Promise<{ id: number, name: string }>;
411+
$createTerminal(config: TerminalLaunchConfig): Promise<{ id: number, name: string; }>;
412412
$dispose(terminalId: number): void;
413413
$hide(terminalId: number): void;
414414
$sendText(terminalId: number, text: string, addNewLine: boolean): void;
@@ -558,7 +558,7 @@ export interface MainThreadWebviewsShape extends IDisposable {
558558
$disposeWebview(handle: WebviewPanelHandle): void;
559559
$reveal(handle: WebviewPanelHandle, showOptions: WebviewPanelShowOptions): void;
560560
$setTitle(handle: WebviewPanelHandle, value: string): void;
561-
$setIconPath(handle: WebviewPanelHandle, value: { light: UriComponents, dark: UriComponents } | undefined): void;
561+
$setIconPath(handle: WebviewPanelHandle, value: { light: UriComponents, dark: UriComponents; } | undefined): void;
562562

563563
$setHtml(handle: WebviewPanelHandle, value: string): void;
564564
$setOptions(handle: WebviewPanelHandle, options: modes.IWebviewOptions): void;
@@ -593,7 +593,7 @@ export interface MainThreadUrlsShape extends IDisposable {
593593
$registerUriHandler(handle: number, extensionId: ExtensionIdentifier): Promise<void>;
594594
$unregisterUriHandler(handle: number): Promise<void>;
595595
$createAppUri(uri: UriComponents): Promise<UriComponents>;
596-
$proposedCreateAppUri(extensionId: ExtensionIdentifier, options?: { payload?: Partial<UriComponents> }): Promise<UriComponents>;
596+
$proposedCreateAppUri(extensionId: ExtensionIdentifier, options?: { payload?: Partial<UriComponents>; }): Promise<UriComponents>;
597597
}
598598

599599
export interface ExtHostUrlsShape {
@@ -609,7 +609,7 @@ export interface MainThreadWorkspaceShape extends IDisposable {
609609
$startTextSearch(query: search.IPatternInfo, options: ITextQueryBuilderOptions, requestId: number, token: CancellationToken): Promise<ITextSearchComplete>;
610610
$checkExists(folders: UriComponents[], includes: string[], token: CancellationToken): Promise<boolean>;
611611
$saveAll(includeUntitled?: boolean): Promise<boolean>;
612-
$updateWorkspaceFolders(extensionName: string, index: number, deleteCount: number, workspaceFoldersToAdd: { uri: UriComponents, name?: string }[]): Promise<void>;
612+
$updateWorkspaceFolders(extensionName: string, index: number, deleteCount: number, workspaceFoldersToAdd: { uri: UriComponents, name?: string; }[]): Promise<void>;
613613
$resolveProxy(url: string): Promise<string | undefined>;
614614
}
615615

@@ -764,7 +764,7 @@ export interface MainThreadWindowShape extends IDisposable {
764764

765765
export interface ExtHostCommandsShape {
766766
$executeContributedCommand<T>(id: string, ...args: any[]): Promise<T>;
767-
$getContributedCommandHandlerDescriptions(): Promise<{ [id: string]: string | ICommandHandlerDescription }>;
767+
$getContributedCommandHandlerDescriptions(): Promise<{ [id: string]: string | ICommandHandlerDescription; }>;
768768
}
769769

770770
export interface ExtHostConfigurationShape {
@@ -898,7 +898,7 @@ export interface ExtHostExtensionServiceShape {
898898
$startExtensionHost(enabledExtensionIds: ExtensionIdentifier[]): Promise<void>;
899899
$activateByEvent(activationEvent: string): Promise<void>;
900900
$activate(extensionId: ExtensionIdentifier, reason: ExtensionActivationReason): Promise<boolean>;
901-
$setRemoteEnvironment(env: { [key: string]: string | null }): Promise<void>;
901+
$setRemoteEnvironment(env: { [key: string]: string | null; }): Promise<void>;
902902

903903
$deltaExtensions(toAdd: IExtensionDescription[], toRemove: ExtensionIdentifier[]): Promise<void>;
904904

@@ -978,7 +978,7 @@ export interface ISuggestDataDto {
978978
[ISuggestDataDtoField.preselect]?: boolean;
979979
[ISuggestDataDtoField.insertText]?: string;
980980
[ISuggestDataDtoField.insertTextRules]?: modes.CompletionItemInsertTextRule;
981-
[ISuggestDataDtoField.range]?: IRange | { insert: IRange, replace: IRange };
981+
[ISuggestDataDtoField.range]?: IRange | { insert: IRange, replace: IRange; };
982982
[ISuggestDataDtoField.commitCharacters]?: string[];
983983
[ISuggestDataDtoField.additionalTextEdits]?: ISingleEditOperation[];
984984
[ISuggestDataDtoField.command]?: modes.Command;
@@ -989,7 +989,7 @@ export interface ISuggestDataDto {
989989

990990
export interface ISuggestResultDto {
991991
x?: number;
992-
a: { insert: IRange, replace: IRange };
992+
a: { insert: IRange, replace: IRange; };
993993
b: ISuggestDataDto[];
994994
c?: boolean;
995995
}
@@ -1112,7 +1112,8 @@ export interface ICodeLensDto {
11121112
}
11131113

11141114
export interface ICallHierarchyItemDto {
1115-
id: string;
1115+
_sessionId: string;
1116+
_itemId: string;
11161117
kind: modes.SymbolKind;
11171118
name: string;
11181119
detail?: string;
@@ -1121,6 +1122,16 @@ export interface ICallHierarchyItemDto {
11211122
selectionRange: IRange;
11221123
}
11231124

1125+
export interface IIncomingCallDto {
1126+
from: ICallHierarchyItemDto;
1127+
fromRanges: IRange[];
1128+
}
1129+
1130+
export interface IOutgoingCallDto {
1131+
fromRanges: IRange[];
1132+
to: ICallHierarchyItemDto;
1133+
}
1134+
11241135
export interface ExtHostLanguageFeaturesShape {
11251136
$provideDocumentSymbols(handle: number, resource: UriComponents, token: CancellationToken): Promise<modes.DocumentSymbol[] | undefined>;
11261137
$provideCodeLenses(handle: number, resource: UriComponents, token: CancellationToken): Promise<ICodeLensListDto | undefined>;
@@ -1155,9 +1166,9 @@ export interface ExtHostLanguageFeaturesShape {
11551166
$provideColorPresentations(handle: number, resource: UriComponents, colorInfo: IRawColorInfo, token: CancellationToken): Promise<modes.IColorPresentation[] | undefined>;
11561167
$provideFoldingRanges(handle: number, resource: UriComponents, context: modes.FoldingContext, token: CancellationToken): Promise<modes.FoldingRange[] | undefined>;
11571168
$provideSelectionRanges(handle: number, resource: UriComponents, positions: IPosition[], token: CancellationToken): Promise<modes.SelectionRange[][]>;
1158-
$prepareCallHierarchy(handle: number, resource: UriComponents, position: IPosition, token: CancellationToken): Promise<{ sessionId: string, root: ICallHierarchyItemDto } | undefined>;
1159-
$provideCallHierarchyIncomingCalls(handle: number, itemId: string, token: CancellationToken): Promise<[ICallHierarchyItemDto, IRange[]][] | undefined>;
1160-
$provideCallHierarchyOutgoingCalls(handle: number, itemId: string, token: CancellationToken): Promise<[ICallHierarchyItemDto, IRange[]][] | undefined>;
1169+
$prepareCallHierarchy(handle: number, resource: UriComponents, position: IPosition, token: CancellationToken): Promise<ICallHierarchyItemDto | undefined>;
1170+
$provideCallHierarchyIncomingCalls(handle: number, sessionId: string, itemId: string, token: CancellationToken): Promise<IIncomingCallDto[] | undefined>;
1171+
$provideCallHierarchyOutgoingCalls(handle: number, sessionId: string, itemId: string, token: CancellationToken): Promise<IOutgoingCallDto[] | undefined>;
11611172
$releaseCallHierarchy(handle: number, sessionId: string): void;
11621173
}
11631174

@@ -1177,7 +1188,7 @@ export interface IShellLaunchConfigDto {
11771188
executable?: string;
11781189
args?: string[] | string;
11791190
cwd?: string | UriComponents;
1180-
env?: { [key: string]: string | null };
1191+
env?: { [key: string]: string | null; };
11811192
}
11821193

11831194
export interface IShellDefinitionDto {
@@ -1232,8 +1243,8 @@ export interface ExtHostTaskShape {
12321243
$onDidStartTaskProcess(value: tasks.TaskProcessStartedDTO): void;
12331244
$onDidEndTaskProcess(value: tasks.TaskProcessEndedDTO): void;
12341245
$OnDidEndTask(execution: tasks.TaskExecutionDTO): void;
1235-
$resolveVariables(workspaceFolder: UriComponents, toResolve: { process?: { name: string; cwd?: string }, variables: string[] }): Promise<{ process?: string; variables: { [key: string]: string } }>;
1236-
$getDefaultShellAndArgs(): Thenable<{ shell: string, args: string[] | string | undefined }>;
1246+
$resolveVariables(workspaceFolder: UriComponents, toResolve: { process?: { name: string; cwd?: string; }, variables: string[]; }): Promise<{ process?: string; variables: { [key: string]: string; }; }>;
1247+
$getDefaultShellAndArgs(): Thenable<{ shell: string, args: string[] | string | undefined; }>;
12371248
$jsonTasksSupported(): Thenable<boolean>;
12381249
}
12391250

@@ -1321,7 +1332,7 @@ export interface DecorationRequest {
13211332
}
13221333

13231334
export type DecorationData = [number, boolean, string, string, ThemeColor];
1324-
export type DecorationReply = { [id: number]: DecorationData };
1335+
export type DecorationReply = { [id: number]: DecorationData; };
13251336

13261337
export interface ExtHostDecorationsShape {
13271338
$provideDecorations(requests: DecorationRequest[], token: CancellationToken): Promise<DecorationReply>;

src/vs/workbench/api/common/extHostApiCommands.ts

+90-3
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,11 @@
44
*--------------------------------------------------------------------------------------------*/
55

66
import { URI } from 'vs/base/common/uri';
7-
import { DisposableStore } from 'vs/base/common/lifecycle';
7+
import { DisposableStore, IDisposable } from 'vs/base/common/lifecycle';
88
import * as vscode from 'vscode';
99
import * as typeConverters from 'vs/workbench/api/common/extHostTypeConverters';
1010
import * as types from 'vs/workbench/api/common/extHostTypes';
11-
import { IRawColorInfo, IWorkspaceEditDto } from 'vs/workbench/api/common/extHost.protocol';
11+
import { IRawColorInfo, IWorkspaceEditDto, ICallHierarchyItemDto, IIncomingCallDto, IOutgoingCallDto } from 'vs/workbench/api/common/extHost.protocol';
1212
import { ISingleEditOperation } from 'vs/editor/common/model';
1313
import * as modes from 'vs/editor/common/modes';
1414
import * as search from 'vs/workbench/contrib/search/common/search';
@@ -19,10 +19,97 @@ import { ICommandsExecutor, OpenFolderAPICommand, DiffAPICommand, OpenAPICommand
1919
import { EditorGroupLayout } from 'vs/workbench/services/editor/common/editorGroupsService';
2020
import { isFalsyOrEmpty } from 'vs/base/common/arrays';
2121
import { IRange } from 'vs/editor/common/core/range';
22+
import { IPosition } from 'vs/editor/common/core/position';
23+
24+
//#region --- NEW world
25+
26+
export class ApiCommandArgument<V, O = V> {
27+
28+
static readonly Uri = new ApiCommandArgument<URI>('uri', 'Uri of a text document', v => URI.isUri(v), v => v);
29+
static readonly Position = new ApiCommandArgument<types.Position, IPosition>('position', 'A position in a text document', v => types.Position.isPosition(v), typeConverters.Position.from);
30+
31+
static readonly CallHierarchyItem = new ApiCommandArgument('item', 'A call hierarchy item', v => v instanceof types.CallHierarchyItem, typeConverters.CallHierarchyItem.to);
32+
33+
constructor(
34+
readonly name: string,
35+
readonly description: string,
36+
readonly validate: (v: V) => boolean,
37+
readonly convert: (v: V) => O
38+
) { }
39+
}
40+
41+
export class ApiCommandResult<V, O = V> {
42+
43+
constructor(
44+
readonly description: string,
45+
readonly convert: (v: V) => O
46+
) { }
47+
}
48+
49+
export class ApiCommand {
50+
51+
constructor(
52+
readonly id: string,
53+
readonly internalId: string,
54+
readonly description: string,
55+
readonly args: ApiCommandArgument<any, any>[],
56+
readonly result: ApiCommandResult<any, any>
57+
) { }
58+
59+
register(commands: ExtHostCommands): IDisposable {
60+
61+
return commands.registerCommand(false, this.id, async (...apiArgs) => {
62+
63+
const internalArgs = this.args.map((arg, i) => {
64+
if (!arg.validate(apiArgs[i])) {
65+
throw new Error(`Invalid argument '${arg.name}' when running '${this.id}', receieved: ${apiArgs[i]}`);
66+
}
67+
return arg.convert(apiArgs[i]);
68+
});
69+
70+
const internalResult = await commands.executeCommand(this.internalId, ...internalArgs);
71+
return this.result.convert(internalResult);
72+
}, undefined, this._getCommandHandlerDesc());
73+
}
74+
75+
private _getCommandHandlerDesc(): ICommandHandlerDescription {
76+
return {
77+
description: this.description,
78+
args: this.args,
79+
returns: this.result.description
80+
};
81+
}
82+
}
83+
84+
85+
const newCommands: ApiCommand[] = [
86+
new ApiCommand(
87+
'vscode.prepareCallHierarchy', '_executePrepareCallHierarchy', 'Prepare call hierarchy at a position inside a document',
88+
[ApiCommandArgument.Uri, ApiCommandArgument.Position],
89+
new ApiCommandResult<ICallHierarchyItemDto, types.CallHierarchyItem>('A CallHierarchyItem or undefined', v => typeConverters.CallHierarchyItem.to(v))
90+
),
91+
new ApiCommand(
92+
'vscode.provideIncomingCalls', '_executeProvideIncomingCalls', 'Compute incoming calls for an item',
93+
[ApiCommandArgument.CallHierarchyItem],
94+
new ApiCommandResult<IIncomingCallDto[], types.CallHierarchyIncomingCall[]>('A CallHierarchyItem or undefined', v => v.map(typeConverters.CallHierarchyIncomingCall.to))
95+
),
96+
new ApiCommand(
97+
'vscode.provideOutgoingCalls', '_executeProvideOutgoingCalls', 'Compute outgoing calls for an item',
98+
[ApiCommandArgument.CallHierarchyItem],
99+
new ApiCommandResult<IOutgoingCallDto[], types.CallHierarchyOutgoingCall[]>('A CallHierarchyItem or undefined', v => v.map(typeConverters.CallHierarchyOutgoingCall.to))
100+
),
101+
];
102+
103+
104+
//#endregion
105+
106+
107+
//#region OLD world
22108

23109
export class ExtHostApiCommands {
24110

25111
static register(commands: ExtHostCommands) {
112+
newCommands.forEach(command => command.register(commands));
26113
return new ExtHostApiCommands(commands).registerCommands();
27114
}
28115

@@ -433,7 +520,7 @@ export class ExtHostApiCommands {
433520
});
434521
}
435522

436-
private _executeColorPresentationProvider(color: types.Color, context: { uri: URI, range: types.Range }): Promise<types.ColorPresentation[]> {
523+
private _executeColorPresentationProvider(color: types.Color, context: { uri: URI, range: types.Range; }): Promise<types.ColorPresentation[]> {
437524
const args = {
438525
resource: context.uri,
439526
color: typeConverters.Color.from(color),

0 commit comments

Comments
 (0)