Skip to content

Commit 9348727

Browse files
authoredFeb 27, 2024··
Add a few vscode menu contribution points (#13226)
* Added extension/context contribuiton point Signed-off-by: Jonah Iden <jonah.iden@typefox.io> * implemented terminal/context and terminal/title/context menu contribution points Signed-off-by: Jonah Iden <jonah.iden@typefox.io> * fixed command execution for new menus Signed-off-by: Jonah Iden <jonah.iden@typefox.io> * fixed terminal contribution menu and execution of vsx contributed commands Signed-off-by: Jonah Iden <jonah.iden@typefox.io> * fix spelling and user terminalId getter instead _terminal id property Signed-off-by: Jonah Iden <jonah.iden@typefox.io> --------- Signed-off-by: Jonah Iden <jonah.iden@typefox.io>
1 parent df6341a commit 9348727

11 files changed

+95
-8
lines changed
 

‎packages/core/src/browser/frontend-application-module.ts

+3-1
Original file line numberDiff line numberDiff line change
@@ -200,7 +200,9 @@ export const frontendApplicationModule = new ContainerModule((bind, _unbind, _is
200200
const commandService = container.get<CommandService>(CommandService);
201201
const corePreferences = container.get<CorePreferences>(CorePreferences);
202202
const hoverService = container.get(HoverService);
203-
return new TabBarRenderer(contextMenuRenderer, tabBarDecoratorService, iconThemeService, selectionService, commandService, corePreferences, hoverService);
203+
const contextKeyService: ContextKeyService = container.get(ContextKeyService);
204+
return new TabBarRenderer(contextMenuRenderer, tabBarDecoratorService, iconThemeService,
205+
selectionService, commandService, corePreferences, hoverService, contextKeyService);
204206
});
205207
bind(TheiaDockPanel.Factory).toFactory(({ container }) => (options?: DockPanel.IOptions) => {
206208
const corePreferences = container.get<CorePreferences>(CorePreferences);

‎packages/core/src/browser/shell/tab-bars.ts

+5-1
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ import { SelectComponent } from '../widgets/select-component';
3939
import { createElement } from 'react';
4040
import { PreviewableWidget } from '../widgets/previewable-widget';
4141
import { EnhancedPreviewWidget } from '../widgets/enhanced-preview-widget';
42+
import { ContextKeyService } from '../context-key-service';
4243

4344
/** The class name added to hidden content nodes, which are required to render vertical side bars. */
4445
const HIDDEN_CONTENT_CLASS = 'theia-TabBar-hidden-content';
@@ -102,7 +103,8 @@ export class TabBarRenderer extends TabBar.Renderer {
102103
protected readonly selectionService?: SelectionService,
103104
protected readonly commandService?: CommandService,
104105
protected readonly corePreferences?: CorePreferences,
105-
protected readonly hoverService?: HoverService
106+
protected readonly hoverService?: HoverService,
107+
protected readonly contextKeyService?: ContextKeyService,
106108
) {
107109
super();
108110
if (this.decoratorService) {
@@ -646,10 +648,12 @@ export class TabBarRenderer extends TabBar.Renderer {
646648
this.selectionService.selection = NavigatableWidget.is(widget) ? { uri: widget.getResourceUri() } : widget;
647649
}
648650

651+
const contextKeyServiceOverlay = this.contextKeyService?.createOverlay([['isTerminalTab', widget && 'terminalId' in widget]]);
649652
this.contextMenuRenderer.render({
650653
menuPath: this.contextMenuPath!,
651654
anchor: event,
652655
args: [event],
656+
contextKeyService: contextKeyServiceOverlay,
653657
// We'd like to wait until the command triggered by the context menu has been run, but this should let it get through the preamble, at least.
654658
onHide: () => setTimeout(() => { if (this.selectionService) { this.selectionService.selection = oldSelection; } })
655659
});

‎packages/plugin-ext/src/main/browser/command-registry-main.ts

+7
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@ import { RPCProtocol } from '../../common/rpc-protocol';
2323
import { KeybindingRegistry } from '@theia/core/lib/browser';
2424
import { PluginContributionHandler } from './plugin-contribution-handler';
2525
import { ArgumentProcessor } from '../../common/commands';
26+
import { ContributionProvider } from '@theia/core';
27+
28+
export const ArgumentProcessorContribution = Symbol('ArgumentProcessorContribution');
2629

2730
export class CommandRegistryMainImpl implements CommandRegistryMain, Disposable {
2831
private readonly proxy: CommandRegistryExt;
@@ -41,6 +44,10 @@ export class CommandRegistryMainImpl implements CommandRegistryMain, Disposable
4144
this.delegate = container.get(CommandRegistry);
4245
this.keyBinding = container.get(KeybindingRegistry);
4346
this.contributions = container.get(PluginContributionHandler);
47+
48+
container.getNamed<ContributionProvider<ArgumentProcessor>>(ContributionProvider, ArgumentProcessorContribution).getContributions().forEach(processor => {
49+
this.registerArgumentProcessor(processor);
50+
});
4451
}
4552

4653
dispose(): void {

‎packages/plugin-ext/src/main/browser/menus/plugin-menu-command-adapter.ts

+4-1
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,10 @@ export class PluginMenuCommandAdapter implements MenuCommandAdapter {
108108
['timeline/item/context', (...args) => this.toTimelineArgs(...args)],
109109
['view/item/context', (...args) => this.toTreeArgs(...args)],
110110
['view/title', noArgs],
111-
['webview/context', firstArgOnly]
111+
['webview/context', firstArgOnly],
112+
['extension/context', noArgs],
113+
['terminal/context', noArgs],
114+
['terminal/title/context', noArgs],
112115
]).forEach(([contributionPoint, adapter]) => {
113116
if (adapter) {
114117
const paths = codeToTheiaMappings.get(contributionPoint);

‎packages/plugin-ext/src/main/browser/menus/vscode-theia-menu-mappings.ts

+10-2
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ import { WEBVIEW_CONTEXT_MENU, WebviewWidget } from '../webview/webview';
3333
import { EDITOR_LINENUMBER_CONTEXT_MENU } from '@theia/editor/lib/browser/editor-linenumber-contribution';
3434
import { TEST_VIEW_CONTEXT_MENU } from '@theia/test/lib/browser/view/test-view-contribution';
3535
import { TEST_RUNS_CONTEXT_MENU } from '@theia/test/lib/browser/view/test-run-view-contribution';
36+
import { TerminalMenus } from '@theia/terminal/lib/browser/terminal-frontend-contribution';
3637

3738
export const PLUGIN_EDITOR_TITLE_MENU = ['plugin_editor/title'];
3839
export const PLUGIN_EDITOR_TITLE_RUN_MENU = ['plugin_editor/title/run'];
@@ -61,7 +62,10 @@ export const implementedVSCodeContributionPoints = [
6162
'testing/message/context',
6263
'view/item/context',
6364
'view/title',
64-
'webview/context'
65+
'webview/context',
66+
'extension/context',
67+
'terminal/context',
68+
'terminal/title/context'
6569
] as const;
6670

6771
export type ContributionPoint = (typeof implementedVSCodeContributionPoints)[number];
@@ -89,7 +93,11 @@ export const codeToTheiaMappings = new Map<ContributionPoint, MenuPath[]>([
8993
['timeline/item/context', [TIMELINE_ITEM_CONTEXT_MENU]],
9094
['view/item/context', [VIEW_ITEM_CONTEXT_MENU]],
9195
['view/title', [PLUGIN_VIEW_TITLE_MENU]],
92-
['webview/context', [WEBVIEW_CONTEXT_MENU]]
96+
['webview/context', [WEBVIEW_CONTEXT_MENU]],
97+
['extension/context', [['extensions_context_menu', '3_contribution']]],
98+
['terminal/context', [TerminalMenus.TERMINAL_CONTRIBUTIONS]],
99+
['terminal/title/context', [TerminalMenus.TERMINAL_TITLE_CONTRIBUTIONS]]
100+
93101
]);
94102

95103
type CodeEditorWidget = EditorWidget | WebviewWidget;

‎packages/plugin-ext/src/main/browser/plugin-ext-frontend-module.ts

+3
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ import { CellOutputWebviewFactory } from '@theia/notebook/lib/browser';
8989
import { CellOutputWebviewImpl, createCellOutputWebviewContainer } from './notebooks/renderers/cell-output-webview';
9090
import { NotebookCellModel } from '@theia/notebook/lib/browser/view-model/notebook-cell-model';
9191
import { NotebookModel } from '@theia/notebook/lib/browser/view-model/notebook-model';
92+
import { ArgumentProcessorContribution } from './command-registry-main';
9293

9394
export default new ContainerModule((bind, unbind, isBound, rebind) => {
9495

@@ -266,4 +267,6 @@ export default new ContainerModule((bind, unbind, isBound, rebind) => {
266267
bind(CellOutputWebviewFactory).toFactory(ctx => async (cell: NotebookCellModel, notebook: NotebookModel) =>
267268
createCellOutputWebviewContainer(ctx.container, cell, notebook).getAsync(CellOutputWebviewImpl)
268269
);
270+
271+
bindContributionProvider(bind, ArgumentProcessorContribution);
269272
});

‎packages/terminal/src/browser/terminal-frontend-contribution.ts

+15-2
Original file line numberDiff line numberDiff line change
@@ -27,12 +27,13 @@ import {
2727
Emitter,
2828
Event,
2929
ViewColumn,
30-
OS
30+
OS,
31+
CompoundMenuNodeRole
3132
} from '@theia/core/lib/common';
3233
import {
3334
ApplicationShell, KeybindingContribution, KeyCode, Key, WidgetManager, PreferenceService,
3435
KeybindingRegistry, LabelProvider, WidgetOpenerOptions, StorageService, QuickInputService,
35-
codicon, CommonCommands, FrontendApplicationContribution, OnWillStopAction, Dialog, ConfirmDialog, FrontendApplication, PreferenceScope, Widget
36+
codicon, CommonCommands, FrontendApplicationContribution, OnWillStopAction, Dialog, ConfirmDialog, FrontendApplication, PreferenceScope, Widget, SHELL_TABBAR_CONTEXT_MENU
3637
} from '@theia/core/lib/browser';
3738
import { TabBarToolbarContribution, TabBarToolbarRegistry } from '@theia/core/lib/browser/shell/tab-bar-toolbar';
3839
import { TERMINAL_WIDGET_FACTORY_ID, TerminalWidgetFactoryOptions, TerminalWidgetImpl } from './terminal-widget-impl';
@@ -68,6 +69,9 @@ export namespace TerminalMenus {
6869
export const TERMINAL_OPEN_EDITORS_CONTEXT_MENU = ['open-editors-context-menu', 'navigation'];
6970

7071
export const TERMINAL_CONTEXT_MENU = ['terminal-context-menu'];
72+
export const TERMINAL_CONTRIBUTIONS = [...TERMINAL_CONTEXT_MENU, '5_terminal_contributions'];
73+
74+
export const TERMINAL_TITLE_CONTRIBUTIONS = [...SHELL_TABBAR_CONTEXT_MENU, 'terminal_title_contributions'];
7175
}
7276

7377
export namespace TerminalCommands {
@@ -732,6 +736,15 @@ export class TerminalFrontendContribution implements FrontendApplicationContribu
732736
menus.registerMenuAction([...TerminalMenus.TERMINAL_CONTEXT_MENU, '_4'], {
733737
commandId: TerminalCommands.KILL_TERMINAL.id
734738
});
739+
740+
menus.registerSubmenu(TerminalMenus.TERMINAL_CONTRIBUTIONS, '', {
741+
role: CompoundMenuNodeRole.Group
742+
});
743+
744+
menus.registerSubmenu(TerminalMenus.TERMINAL_TITLE_CONTRIBUTIONS, '', {
745+
role: CompoundMenuNodeRole.Group,
746+
when: 'isTerminalTab'
747+
});
735748
}
736749

737750
registerToolbarItems(toolbar: TabBarToolbarRegistry): void {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// *****************************************************************************
2+
// Copyright (C) 2024 TypeFox and others.
3+
//
4+
// This program and the accompanying materials are made available under the
5+
// terms of the Eclipse Public License v. 2.0 which is available at
6+
// http://www.eclipse.org/legal/epl-2.0.
7+
//
8+
// This Source Code may also be made available under the following Secondary
9+
// Licenses when the conditions for such availability set forth in the Eclipse
10+
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
11+
// with the GNU Classpath Exception which is available at
12+
// https://www.gnu.org/software/classpath/license.html.
13+
//
14+
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
15+
// *****************************************************************************
16+
17+
import { injectable } from '@theia/core/shared/inversify';
18+
import { ArgumentProcessor } from '@theia/plugin-ext/lib/common/commands';
19+
import { VSXExtension } from './vsx-extension';
20+
21+
@injectable()
22+
export class VsxExtensionArgumentProcessor implements ArgumentProcessor {
23+
24+
processArgument(arg: unknown): unknown {
25+
if (arg instanceof VSXExtension) {
26+
return arg.id;
27+
}
28+
29+
return arg;
30+
}
31+
32+
}

‎packages/vsx-registry/src/browser/vsx-extension.tsx

+6
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ export const EXTENSIONS_CONTEXT_MENU: MenuPath = ['extensions_context_menu'];
3838
export namespace VSXExtensionsContextMenu {
3939
export const INSTALL = [...EXTENSIONS_CONTEXT_MENU, '1_install'];
4040
export const COPY = [...EXTENSIONS_CONTEXT_MENU, '2_copy'];
41+
export const CONTRIBUTION = [...EXTENSIONS_CONTEXT_MENU, '3_contribution'];
4142
}
4243

4344
@injectable()
@@ -495,6 +496,11 @@ export class VSXExtensionComponent<Props extends VSXExtensionComponent.Props = V
495496
position: 'right'
496497
});
497498
}}
499+
onMouseUp={event => {
500+
if (event.button === 2) {
501+
this.manage(event);
502+
}
503+
}}
498504
>
499505
{iconUrl ?
500506
<img className='theia-vsx-extension-icon' src={iconUrl} /> :

‎packages/vsx-registry/src/browser/vsx-extensions-contribution.ts

+5-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ import { ColorRegistry } from '@theia/core/lib/browser/color-registry';
2121
import { FrontendApplication } from '@theia/core/lib/browser/frontend-application';
2222
import { FrontendApplicationContribution } from '@theia/core/lib/browser/frontend-application-contribution';
2323
import { AbstractViewContribution } from '@theia/core/lib/browser/shell/view-contribution';
24-
import { MenuModelRegistry, MessageService, SelectionService, nls } from '@theia/core/lib/common';
24+
import { CompoundMenuNodeRole, MenuModelRegistry, MessageService, SelectionService, nls } from '@theia/core/lib/common';
2525
import { Color } from '@theia/core/lib/common/color';
2626
import { Command, CommandRegistry } from '@theia/core/lib/common/command';
2727
import URI from '@theia/core/lib/common/uri';
@@ -159,6 +159,10 @@ export class VSXExtensionsContribution extends AbstractViewContribution<VSXExten
159159
label: VSXExtensionsCommands.INSTALL_VSIX_FILE.label,
160160
when: 'resourceScheme == file && resourceExtname == .vsix'
161161
});
162+
163+
menus.registerSubmenu(VSXExtensionsContextMenu.CONTRIBUTION, '', {
164+
role: CompoundMenuNodeRole.Group,
165+
});
162166
}
163167

164168
registerColors(colors: ColorRegistry): void {

‎packages/vsx-registry/src/browser/vsx-registry-frontend-module.ts

+5
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ import { bindVsxExtensionsPreferences } from './vsx-extensions-preferences';
3737
import { VSXEnvironment, VSX_ENVIRONMENT_PATH } from '../common/vsx-environment';
3838
import { LanguageQuickPickService } from '@theia/core/lib/browser/i18n/language-quick-pick-service';
3939
import { VSXLanguageQuickPickService } from './vsx-language-quick-pick-service';
40+
import { VsxExtensionArgumentProcessor } from './vsx-extension-argument-processor';
41+
import { ArgumentProcessorContribution } from '@theia/plugin-ext/lib/main/browser/command-registry-main';
4042

4143
export default new ContainerModule((bind, unbind, isBound, rebind) => {
4244
bind(VSXEnvironment)
@@ -105,4 +107,7 @@ export default new ContainerModule((bind, unbind, isBound, rebind) => {
105107
bindExtensionPreferences(bind);
106108
bindPreferenceProviderOverrides(bind, unbind);
107109
bindVsxExtensionsPreferences(bind);
110+
111+
bind(VsxExtensionArgumentProcessor).toSelf().inSingletonScope();
112+
bind(ArgumentProcessorContribution).toService(VsxExtensionArgumentProcessor);
108113
});

0 commit comments

Comments
 (0)
Please sign in to comment.