Skip to content
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

Refactor menu nodes #14676

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 1 addition & 5 deletions examples/api-samples/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,6 @@
"frontend": "lib/browser/api-samples-frontend-module",
"backend": "lib/node/api-samples-backend-module"
},
{
"frontend": "lib/browser/menu/sample-browser-menu-module",
"frontendElectron": "lib/electron-browser/menu/sample-electron-menu-module"
},
{
"electronMain": "lib/electron-main/update/sample-updater-main-module",
"frontendElectron": "lib/electron-browser/updater/sample-updater-frontend-module"
Expand Down Expand Up @@ -62,4 +58,4 @@
"devDependencies": {
"@theia/ext-scripts": "1.57.0"
}
}
}

This file was deleted.

39 changes: 26 additions & 13 deletions examples/api-samples/src/browser/menu/sample-menu-contribution.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ import { ConfirmDialog, Dialog, QuickInputService } from '@theia/core/lib/browse
import { ReactDialog } from '@theia/core/lib/browser/dialogs/react-dialog';
import { SelectComponent } from '@theia/core/lib/browser/widgets/select-component';
import {
Command, CommandContribution, CommandRegistry, MAIN_MENU_BAR,
MenuContribution, MenuModelRegistry, MenuNode, MessageService, SubMenuOptions
Command, CommandContribution, CommandMenu, CommandRegistry, ContextExpressionMatcher, MAIN_MENU_BAR,
MenuContribution, MenuModelRegistry, MenuPath, MessageService
} from '@theia/core/lib/common';
import { inject, injectable, interfaces } from '@theia/core/shared/inversify';
import * as React from '@theia/core/shared/react';
Expand Down Expand Up @@ -226,9 +226,8 @@ export class SampleCommandContribution implements CommandContribution {
export class SampleMenuContribution implements MenuContribution {
registerMenus(menus: MenuModelRegistry): void {
const subMenuPath = [...MAIN_MENU_BAR, 'sample-menu'];
menus.registerSubmenu(subMenuPath, 'Sample Menu', {
order: '2' // that should put the menu right next to the File menu
});
menus.registerSubmenu(subMenuPath, 'Sample Menu', '2'); // that should put the menu right next to the File menu

menus.registerMenuAction(subMenuPath, {
commandId: SampleCommand.id,
order: '0'
Expand All @@ -238,7 +237,7 @@ export class SampleMenuContribution implements MenuContribution {
order: '2'
});
const subSubMenuPath = [...subMenuPath, 'sample-sub-menu'];
menus.registerSubmenu(subSubMenuPath, 'Sample sub menu', { order: '2' });
menus.registerSubmenu(subSubMenuPath, 'Sample sub menu', '2');
menus.registerMenuAction(subSubMenuPath, {
commandId: SampleCommand.id,
order: '1'
Expand All @@ -247,8 +246,8 @@ export class SampleMenuContribution implements MenuContribution {
commandId: SampleCommand2.id,
order: '3'
});
const placeholder = new PlaceholderMenuNode([...subSubMenuPath, 'placeholder'].join('-'), 'Placeholder', { order: '0' });
menus.registerMenuNode(subSubMenuPath, placeholder);
const placeholder = new PlaceholderMenuNode([...subSubMenuPath, 'placeholder'].join('-'), 'Placeholder', '0');
menus.registerCommandMenu(subSubMenuPath, placeholder);

/**
* Register an action menu with an invalid command (un-registered and without a label) in order
Expand All @@ -262,16 +261,30 @@ export class SampleMenuContribution implements MenuContribution {
/**
* Special menu node that is not backed by any commands and is always disabled.
*/
export class PlaceholderMenuNode implements MenuNode {
export class PlaceholderMenuNode implements CommandMenu {

constructor(readonly id: string, public readonly label: string, protected options?: SubMenuOptions) { }
constructor(readonly id: string, public readonly label: string, readonly order?: string, readonly icon?: string) { }

isEnabled(effectiveMenuPath: MenuPath, ...args: any[]): boolean {
return false;
}

get icon(): string | undefined {
return this.options?.iconClass;
isToggled(effectiveMenuPath: MenuPath): boolean {
return false;
}
run(effectiveMenuPath: MenuPath, ...args: any[]): Promise<void> {
throw new Error('Should never happen');
}
getAccelerator(context: HTMLElement | undefined): string[] {
return [];
}

get sortString(): string {
return this.options?.order || this.label;
return this.order || this.label;
}

isVisible<T>(effectiveMenuPath: MenuPath, contextMatcher: ContextExpressionMatcher<T>, context: T | undefined, ...args: any[]): boolean {
return true;
}

}
Expand Down

This file was deleted.

28 changes: 14 additions & 14 deletions packages/core/src/browser/common-frontend-contribution.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@

import debounce = require('lodash.debounce');
import { injectable, inject, optional } from 'inversify';
import { MAIN_MENU_BAR, MANAGE_MENU, MenuContribution, MenuModelRegistry, ACCOUNTS_MENU } from '../common/menu';
import { MAIN_MENU_BAR, MANAGE_MENU, MenuContribution, MenuModelRegistry, ACCOUNTS_MENU, CompoundMenuNode, CommandMenu, Group, Submenu } from '../common/menu';
import { KeybindingContribution, KeybindingRegistry } from './keybinding';
import { FrontendApplication } from './frontend-application';
import { FrontendApplicationContribution, OnWillStopAction } from './frontend-application-contribution';
Expand Down Expand Up @@ -83,7 +83,7 @@ export namespace CommonMenus {
export const FILE_SETTINGS_SUBMENU_THEME = [...FILE_SETTINGS_SUBMENU, '2_settings_submenu_theme'];
export const FILE_CLOSE = [...FILE, '6_close'];

export const FILE_NEW_CONTRIBUTIONS = 'file/newFile';
export const FILE_NEW_CONTRIBUTIONS = ['file', 'newFile'];

export const EDIT = [...MAIN_MENU_BAR, '2_edit'];
export const EDIT_UNDO = [...EDIT, '1_undo'];
Expand Down Expand Up @@ -606,7 +606,7 @@ export class CommonFrontendContribution implements FrontendApplicationContributi
registry.registerSubmenu(CommonMenus.HELP, nls.localizeByDefault('Help'));

// For plugins contributing create new file commands/menu-actions
registry.registerIndependentSubmenu(CommonMenus.FILE_NEW_CONTRIBUTIONS, nls.localizeByDefault('New File...'));
registry.registerSubmenu(CommonMenus.FILE_NEW_CONTRIBUTIONS, nls.localizeByDefault('New File...'));

registry.registerMenuAction(CommonMenus.FILE_SAVE, {
commandId: CommonCommands.SAVE.id
Expand Down Expand Up @@ -747,7 +747,7 @@ export class CommonFrontendContribution implements FrontendApplicationContributi
commandId: CommonCommands.SELECT_ICON_THEME.id
});

registry.registerSubmenu(CommonMenus.MANAGE_SETTINGS_THEMES, nls.localizeByDefault('Themes'), { order: 'a50' });
registry.registerSubmenu(CommonMenus.MANAGE_SETTINGS_THEMES, nls.localizeByDefault('Themes'), 'a50');
registry.registerMenuAction(CommonMenus.MANAGE_SETTINGS_THEMES, {
commandId: CommonCommands.SELECT_COLOR_THEME.id,
order: '0'
Expand Down Expand Up @@ -1458,7 +1458,7 @@ export class CommonFrontendContribution implements FrontendApplicationContributi
* @todo https://github.com/eclipse-theia/theia/issues/12824
*/
protected async showNewFilePicker(): Promise<void> {
const newFileContributions = this.menuRegistry.getMenuNode(CommonMenus.FILE_NEW_CONTRIBUTIONS); // Add menus
const newFileContributions = this.menuRegistry.getMenuNode(CommonMenus.FILE_NEW_CONTRIBUTIONS) as Submenu; // Add menus
const items: QuickPickItemOrSeparator[] = [
{
label: nls.localizeByDefault('New Text File'),
Expand All @@ -1467,22 +1467,22 @@ export class CommonFrontendContribution implements FrontendApplicationContributi
},
...newFileContributions.children
.flatMap(node => {
if (node.children && node.children.length > 0) {
if (CompoundMenuNode.is(node) && node.children.length > 0) {
return node.children;
}
return node;
})
.filter(node => node.role || node.command)
.filter(node => Group.is(node) || CommandMenu.is(node))
.map(node => {
if (node.role) {
if (Group.is(node)) {
return { type: 'separator' } as QuickPickSeparator;
} else {
const item = node as CommandMenu;
return {
label: item.label,
execute: () => item.run(CommonMenus.FILE_NEW_CONTRIBUTIONS)
};
}
const command = this.commandRegistry.getCommand(node.command!);
return {
label: command!.label!,
execute: async () => this.commandRegistry.executeCommand(command!.id!)
};

})
];

Expand Down
30 changes: 25 additions & 5 deletions packages/core/src/browser/context-menu-renderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@

/* eslint-disable @typescript-eslint/no-explicit-any */

import { injectable } from 'inversify';
import { MenuPath } from '../common/menu';
import { injectable, inject } from 'inversify';
import { CompoundMenuNode, MenuModelRegistry, MenuPath } from '../common/menu';
import { Disposable, DisposableCollection } from '../common/disposable';
import { ContextMatcher } from './context-key-service';
import { ContextKeyService, ContextMatcher } from './context-key-service';

export interface Coordinate { x: number; y: number; }
export const Coordinate = Symbol('Coordinate');
Expand Down Expand Up @@ -53,6 +53,10 @@ export abstract class ContextMenuAccess implements Disposable {
@injectable()
export abstract class ContextMenuRenderer {

@inject(MenuModelRegistry) menuRegistry: MenuModelRegistry;
@inject(ContextKeyService)
protected readonly contextKeyService: ContextKeyService;

protected _current: ContextMenuAccess | undefined;
protected readonly toDisposeOnSetCurrent = new DisposableCollection();
/**
Expand All @@ -77,13 +81,28 @@ export abstract class ContextMenuRenderer {
}

render(options: RenderContextMenuOptions): ContextMenuAccess {
let menu = CompoundMenuNode.is(options.menu) ? options.menu : this.menuRegistry.getMenu(options.menuPath);

const resolvedOptions = this.resolve(options);
const access = this.doRender(resolvedOptions);

if (resolvedOptions.skipSingleRootNode) {
menu = MenuModelRegistry.removeSingleRootNode(menu);
}

const access = this.doRender(options.menuPath, menu, resolvedOptions.anchor, options.contextKeyService || this.contextKeyService, resolvedOptions.args, resolvedOptions.context, resolvedOptions.onHide);
this.setCurrent(access);
return access;
}

protected abstract doRender(options: RenderContextMenuOptions): ContextMenuAccess;
protected abstract doRender(
menuPath: MenuPath,
menu: CompoundMenuNode,
anchor: Anchor,
contextMatcher: ContextMatcher,
args?: any[],
context?: HTMLElement,
onHide?: () => void
): ContextMenuAccess;

protected resolve(options: RenderContextMenuOptions): RenderContextMenuOptions {
const args: any[] = options.args ? options.args.slice() : [];
Expand All @@ -99,6 +118,7 @@ export abstract class ContextMenuRenderer {
}

export interface RenderContextMenuOptions {
menu?: CompoundMenuNode,
menuPath: MenuPath;
anchor: Anchor;
args?: any[];
Expand Down
6 changes: 0 additions & 6 deletions packages/core/src/browser/frontend-application-module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,6 @@ import {
messageServicePath,
InMemoryTextResourceResolver,
UntitledResourceResolver,
MenuCommandAdapterRegistry,
MenuCommandExecutor,
MenuCommandAdapterRegistryImpl,
MenuCommandExecutorImpl,
MenuPath
} from '../common';
import { KeybindingRegistry, KeybindingContext, KeybindingContribution } from './keybinding';
Expand Down Expand Up @@ -271,8 +267,6 @@ export const frontendApplicationModule = new ContainerModule((bind, _unbind, _is

bind(MenuModelRegistry).toSelf().inSingletonScope();
bindContributionProvider(bind, MenuContribution);
bind(MenuCommandAdapterRegistry).to(MenuCommandAdapterRegistryImpl).inSingletonScope();
bind(MenuCommandExecutor).to(MenuCommandExecutorImpl).inSingletonScope();

bind(KeyboardLayoutService).toSelf().inSingletonScope();
bind(KeybindingRegistry).toSelf().inSingletonScope();
Expand Down
Loading
Loading