Skip to content

Commit 97fc588

Browse files
committed
use Action2 for call hierarchy title commands
1 parent 1ca18ed commit 97fc588

6 files changed

Lines changed: 153 additions & 81 deletions

File tree

src/vs/editor/browser/editorExtensions.ts

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import { IEditorContribution, IDiffEditorContribution } from 'vs/editor/common/e
1414
import { ITextModel } from 'vs/editor/common/model';
1515
import { IModelService } from 'vs/editor/common/services/modelService';
1616
import { ITextModelService } from 'vs/editor/common/services/resolverService';
17-
import { MenuId, MenuRegistry } from 'vs/platform/actions/common/actions';
17+
import { MenuId, MenuRegistry, Action2 } from 'vs/platform/actions/common/actions';
1818
import { CommandsRegistry, ICommandHandlerDescription } from 'vs/platform/commands/common/commands';
1919
import { ContextKeyExpr, IContextKeyService, ContextKeyExpression } from 'vs/platform/contextkey/common/contextkey';
2020
import { IConstructorSignature1, ServicesAccessor as InstantiationServicesAccessor, BrandedService } from 'vs/platform/instantiation/common/instantiation';
@@ -339,6 +339,32 @@ export abstract class EditorAction extends EditorCommand {
339339

340340
//#endregion EditorAction
341341

342+
//#region EditorAction2
343+
344+
export abstract class EditorAction2 extends Action2 {
345+
346+
run(accessor: ServicesAccessor, ...args: any[]) {
347+
// Find the editor with text focus or active
348+
const codeEditorService = accessor.get(ICodeEditorService);
349+
const editor = codeEditorService.getFocusedCodeEditor() || codeEditorService.getActiveCodeEditor();
350+
if (!editor) {
351+
// well, at least we tried...
352+
return;
353+
}
354+
// precondition does hold
355+
return editor.invokeWithinContext((editorAccessor) => {
356+
const kbService = editorAccessor.get(IContextKeyService);
357+
if (kbService.contextMatchesRules(withNullAsUndefined(this.desc.precondition))) {
358+
return this.runEditorCommand(editorAccessor, editor!, args);
359+
}
360+
});
361+
}
362+
363+
abstract runEditorCommand(accessor: ServicesAccessor, editor: ICodeEditor, ...args: any[]): any;
364+
}
365+
366+
//#endregion
367+
342368
// --- Registration of commands and actions
343369

344370
export function registerLanguageCommand<Args extends { [n: string]: any; }>(id: string, handler: (accessor: ServicesAccessor, args: Args) => any) {

src/vs/editor/contrib/peekView/peekView.ts

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@ export abstract class PeekViewWidget extends ZoneWidget {
169169
container.appendChild(this._bodyElement);
170170
}
171171

172-
protected _fillHead(container: HTMLElement): void {
172+
protected _fillHead(container: HTMLElement, noCloseAction?: boolean): void {
173173
const titleElement = dom.$('.peekview-title');
174174
dom.append(this._headElement!, titleElement);
175175
dom.addStandardDisposableListener(titleElement, 'click', event => this._onTitleClick(event));
@@ -187,10 +187,12 @@ export abstract class PeekViewWidget extends ZoneWidget {
187187
this._actionbarWidget = new ActionBar(actionsContainer, actionBarOptions);
188188
this._disposables.add(this._actionbarWidget);
189189

190-
this._actionbarWidget.push(new Action('peekview.close', nls.localize('label.close', "Close"), Codicon.close.classNames, true, () => {
191-
this.dispose();
192-
return Promise.resolve();
193-
}), { label: false, icon: true });
190+
if (!noCloseAction) {
191+
this._actionbarWidget.push(new Action('peekview.close', nls.localize('label.close', "Close"), Codicon.close.classNames, true, () => {
192+
this.dispose();
193+
return Promise.resolve();
194+
}), { label: false, icon: true });
195+
}
194196
}
195197

196198
protected _fillTitleIcon(container: HTMLElement): void {

src/vs/platform/keybinding/common/keybindingsRegistry.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ export interface IKeybindingRule extends IKeybindings {
3939
id: string;
4040
weight: number;
4141
args?: any;
42-
when: ContextKeyExpression | null | undefined;
42+
when?: ContextKeyExpression | null | undefined;
4343
}
4444

4545
export interface IKeybindingRule2 {

src/vs/workbench/contrib/callHierarchy/browser/callHierarchy.contribution.ts

Lines changed: 89 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import { CancellationTokenSource } from 'vs/base/common/cancellation';
99
import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
1010
import { CallHierarchyTreePeekWidget } from 'vs/workbench/contrib/callHierarchy/browser/callHierarchyPeek';
1111
import { Event } from 'vs/base/common/event';
12-
import { registerEditorContribution, registerEditorAction, EditorAction, registerEditorCommand, EditorCommand } from 'vs/editor/browser/editorExtensions';
12+
import { registerEditorContribution, EditorAction2 } from 'vs/editor/browser/editorExtensions';
1313
import { IEditorContribution } from 'vs/editor/common/editorCommon';
1414
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
1515
import { IContextKeyService, RawContextKey, IContextKey, ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
@@ -22,10 +22,18 @@ import { IStorageService, StorageScope } from 'vs/platform/storage/common/storag
2222
import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService';
2323
import { Range } from 'vs/editor/common/core/range';
2424
import { IPosition } from 'vs/editor/common/core/position';
25-
import { MenuId } from 'vs/platform/actions/common/actions';
25+
import { MenuId, registerAction2 } from 'vs/platform/actions/common/actions';
26+
import { registerIcon, Codicon } from 'vs/base/common/codicons';
2627

2728
const _ctxHasCallHierarchyProvider = new RawContextKey<boolean>('editorHasCallHierarchyProvider', false);
2829
const _ctxCallHierarchyVisible = new RawContextKey<boolean>('callHierarchyVisible', false);
30+
const _ctxCallHierarchyDirection = new RawContextKey<string>('callHierarchyDirection', undefined);
31+
32+
function sanitizedDirection(candidate: string): CallHierarchyDirection {
33+
return candidate === CallHierarchyDirection.CallsFrom || candidate === CallHierarchyDirection.CallsTo
34+
? candidate
35+
: CallHierarchyDirection.CallsTo;
36+
}
2937

3038
class CallHierarchyController implements IEditorContribution {
3139

@@ -39,6 +47,7 @@ class CallHierarchyController implements IEditorContribution {
3947

4048
private readonly _ctxHasProvider: IContextKey<boolean>;
4149
private readonly _ctxIsVisible: IContextKey<boolean>;
50+
private readonly _ctxDirection: IContextKey<string>;
4251
private readonly _dispoables = new DisposableStore();
4352
private readonly _sessionDisposables = new DisposableStore();
4453

@@ -53,6 +62,7 @@ class CallHierarchyController implements IEditorContribution {
5362
) {
5463
this._ctxIsVisible = _ctxCallHierarchyVisible.bindTo(this._contextKeyService);
5564
this._ctxHasProvider = _ctxHasCallHierarchyProvider.bindTo(this._contextKeyService);
65+
this._ctxDirection = _ctxCallHierarchyDirection.bindTo(this._contextKeyService);
5666
this._dispoables.add(Event.any<any>(_editor.onDidChangeModel, _editor.onDidChangeModelLanguage, CallHierarchyProviderRegistry.onDidChange)(() => {
5767
this._ctxHasProvider.set(_editor.hasModel() && CallHierarchyProviderRegistry.has(_editor.getModel()));
5868
}));
@@ -80,7 +90,7 @@ class CallHierarchyController implements IEditorContribution {
8090

8191
const cts = new CancellationTokenSource();
8292
const model = CallHierarchyModel.create(document, position, cts.token);
83-
const direction = this._storageService.getNumber(CallHierarchyController._StorageDirection, StorageScope.GLOBAL, <number>CallHierarchyDirection.CallsFrom);
93+
const direction = sanitizedDirection(this._storageService.get(CallHierarchyController._StorageDirection, StorageScope.GLOBAL, CallHierarchyDirection.CallsTo));
8494

8595
this._showCallHierarchyWidget(position, direction, model, cts);
8696
}
@@ -109,12 +119,13 @@ class CallHierarchyController implements IEditorContribution {
109119
);
110120
}
111121

112-
private _showCallHierarchyWidget(position: IPosition, direction: number, model: Promise<CallHierarchyModel | undefined>, cts: CancellationTokenSource) {
122+
private _showCallHierarchyWidget(position: IPosition, direction: CallHierarchyDirection, model: Promise<CallHierarchyModel | undefined>, cts: CancellationTokenSource) {
113123

124+
this._ctxIsVisible.set(true);
125+
this._ctxDirection.set(direction);
114126
Event.any<any>(this._editor.onDidChangeModel, this._editor.onDidChangeModelLanguage)(this.endCallHierarchy, this, this._sessionDisposables);
115127
this._widget = this._instantiationService.createInstance(CallHierarchyTreePeekWidget, this._editor, position, direction);
116128
this._widget.showLoading();
117-
this._ctxIsVisible.set(true);
118129
this._sessionDisposables.add(this._widget.onDidClose(() => {
119130
this.endCallHierarchy();
120131
this._storageService.store(CallHierarchyController._StorageDirection, this._widget!.direction, StorageScope.GLOBAL);
@@ -139,10 +150,14 @@ class CallHierarchyController implements IEditorContribution {
139150
});
140151
}
141152

142-
toggleCallHierarchyDirection(): void {
143-
if (this._widget) {
144-
this._widget.toggleDirection();
145-
}
153+
showOutgoingCalls(): void {
154+
this._widget?.updateDirection(CallHierarchyDirection.CallsFrom);
155+
this._ctxDirection.set(CallHierarchyDirection.CallsFrom);
156+
}
157+
158+
showIncomingCalls(): void {
159+
this._widget?.updateDirection(CallHierarchyDirection.CallsTo);
160+
this._ctxDirection.set(CallHierarchyDirection.CallsTo);
146161
}
147162

148163
endCallHierarchy(): void {
@@ -154,20 +169,19 @@ class CallHierarchyController implements IEditorContribution {
154169

155170
registerEditorContribution(CallHierarchyController.Id, CallHierarchyController);
156171

157-
registerEditorAction(class extends EditorAction {
172+
registerAction2(class extends EditorAction2 {
158173

159174
constructor() {
160175
super({
161176
id: 'editor.showCallHierarchy',
162-
label: localize('title', "Peek Call Hierarchy"),
163-
alias: 'Peek Call Hierarchy',
164-
contextMenuOpts: {
165-
menuId: MenuId.EditorContextPeek,
177+
title: { value: localize('title', "Peek Call Hierarchy"), original: 'Peek Call Hierarchy' },
178+
menu: {
179+
id: MenuId.EditorContextPeek,
166180
group: 'navigation',
167181
order: 1000
168182
},
169-
kbOpts: {
170-
kbExpr: EditorContextKeys.editorTextFocus,
183+
keybinding: {
184+
when: EditorContextKeys.editorTextFocus,
171185
weight: KeybindingWeight.WorkbenchContrib,
172186
primary: KeyMod.Shift + KeyMod.Alt + KeyCode.KEY_H
173187
},
@@ -178,65 +192,101 @@ registerEditorAction(class extends EditorAction {
178192
});
179193
}
180194

181-
async run(_accessor: ServicesAccessor, editor: ICodeEditor): Promise<void> {
195+
async runEditorCommand(_accessor: ServicesAccessor, editor: ICodeEditor): Promise<void> {
182196
return CallHierarchyController.get(editor).startCallHierarchyFromEditor();
183197
}
184198
});
185199

186-
registerEditorAction(class extends EditorAction {
200+
registerAction2(class extends EditorAction2 {
187201

188202
constructor() {
189203
super({
190-
id: 'editor.toggleCallHierarchy',
191-
label: localize('title.toggle', "Toggle Call Hierarchy"),
192-
alias: 'Toggle Call Hierarchy',
193-
kbOpts: {
204+
id: 'editor.showIncomingCalls',
205+
title: { value: localize('title.incoming', "Show Incoming Calls"), original: 'Show Incoming Calls' },
206+
icon: registerIcon('callhierarchy-incoming', Codicon.callIncoming),
207+
precondition: ContextKeyExpr.and(_ctxCallHierarchyVisible, _ctxCallHierarchyDirection.isEqualTo(CallHierarchyDirection.CallsFrom)),
208+
keybinding: {
194209
weight: KeybindingWeight.WorkbenchContrib,
195-
primary: KeyMod.Shift + KeyMod.Alt + KeyCode.KEY_H
210+
primary: KeyMod.Shift + KeyMod.Alt + KeyCode.KEY_H,
196211
},
197-
precondition: _ctxCallHierarchyVisible
212+
menu: {
213+
id: CallHierarchyTreePeekWidget.TitleMenu,
214+
when: _ctxCallHierarchyDirection.isEqualTo(CallHierarchyDirection.CallsFrom),
215+
order: 1,
216+
}
198217
});
199218
}
200219

201-
async run(_accessor: ServicesAccessor, editor: ICodeEditor): Promise<void> {
202-
return CallHierarchyController.get(editor).toggleCallHierarchyDirection();
220+
runEditorCommand(_accessor: ServicesAccessor, editor: ICodeEditor) {
221+
return CallHierarchyController.get(editor).showIncomingCalls();
203222
}
204223
});
205224

206-
registerEditorAction(class extends EditorAction {
225+
registerAction2(class extends EditorAction2 {
226+
227+
constructor() {
228+
super({
229+
id: 'editor.showOutgoingCalls',
230+
title: { value: localize('title.outgoing', "Show Outgoing Calls"), original: 'Show Outgoing Calls' },
231+
icon: registerIcon('callhierarchy-outgoing', Codicon.callOutgoing),
232+
precondition: ContextKeyExpr.and(_ctxCallHierarchyVisible, _ctxCallHierarchyDirection.isEqualTo(CallHierarchyDirection.CallsTo)),
233+
keybinding: {
234+
weight: KeybindingWeight.WorkbenchContrib,
235+
primary: KeyMod.Shift + KeyMod.Alt + KeyCode.KEY_H,
236+
},
237+
menu: {
238+
id: CallHierarchyTreePeekWidget.TitleMenu,
239+
when: _ctxCallHierarchyDirection.isEqualTo(CallHierarchyDirection.CallsTo),
240+
order: 1
241+
}
242+
});
243+
}
244+
245+
runEditorCommand(_accessor: ServicesAccessor, editor: ICodeEditor) {
246+
return CallHierarchyController.get(editor).showOutgoingCalls();
247+
}
248+
});
249+
250+
251+
registerAction2(class extends EditorAction2 {
207252

208253
constructor() {
209254
super({
210255
id: 'editor.refocusCallHierarchy',
211-
label: localize('title.refocus', "Refocus Call Hierarchy"),
212-
alias: 'Refocus Call Hierarchy',
213-
kbOpts: {
256+
title: { value: localize('title.refocus', "Refocus Call Hierarchy"), original: 'Refocus Call Hierarchy' },
257+
precondition: _ctxCallHierarchyVisible,
258+
keybinding: {
214259
weight: KeybindingWeight.WorkbenchContrib,
215260
primary: KeyMod.Shift + KeyCode.Enter
216-
},
217-
precondition: _ctxCallHierarchyVisible
261+
}
218262
});
219263
}
220264

221-
async run(_accessor: ServicesAccessor, editor: ICodeEditor): Promise<void> {
265+
async runEditorCommand(_accessor: ServicesAccessor, editor: ICodeEditor): Promise<void> {
222266
return CallHierarchyController.get(editor).startCallHierarchyFromCallHierarchy();
223267
}
224268
});
225269

226270

227-
registerEditorCommand(new class extends EditorCommand {
271+
registerAction2(class extends EditorAction2 {
228272

229273
constructor() {
230274
super({
231275
id: 'editor.closeCallHierarchy',
232-
kbOpts: {
233-
weight: KeybindingWeight.WorkbenchContrib + 10,
234-
primary: KeyCode.Escape
235-
},
276+
title: localize('close', 'Close'),
277+
icon: Codicon.close,
236278
precondition: ContextKeyExpr.and(
237279
_ctxCallHierarchyVisible,
238280
ContextKeyExpr.not('config.editor.stablePeek')
239-
)
281+
),
282+
keybinding: {
283+
weight: KeybindingWeight.WorkbenchContrib + 10,
284+
primary: KeyCode.Escape
285+
},
286+
menu: {
287+
id: CallHierarchyTreePeekWidget.TitleMenu,
288+
order: 1000
289+
}
240290
});
241291
}
242292

0 commit comments

Comments
 (0)