diff --git a/arduino-ide-extension/src/browser/arduino-ide-frontend-module.ts b/arduino-ide-extension/src/browser/arduino-ide-frontend-module.ts index 38ace419..009ac67b 100644 --- a/arduino-ide-extension/src/browser/arduino-ide-frontend-module.ts +++ b/arduino-ide-extension/src/browser/arduino-ide-frontend-module.ts @@ -131,6 +131,8 @@ import { Debug } from './contributions/debug'; import { DebugSessionManager } from './theia/debug/debug-session-manager'; import { DebugSessionManager as TheiaDebugSessionManager } from '@theia/debug/lib/browser/debug-session-manager'; import { Sketchbook } from './contributions/sketchbook'; +import { DebugFrontendApplicationContribution } from './theia/debug/debug-frontend-application-contribution'; +import { DebugFrontendApplicationContribution as TheiaDebugFrontendApplicationContribution } from '@theia/debug/lib/browser/debug-frontend-application-contribution'; const ElementQueries = require('css-element-queries/src/ElementQueries'); @@ -363,4 +365,7 @@ export default new ContainerModule((bind, unbind, isBound, rebind) => { // To avoid running `Save All` when there are no dirty editors before starting the debug session. bind(DebugSessionManager).toSelf().inSingletonScope(); rebind(TheiaDebugSessionManager).toService(DebugSessionManager); + // To remove the `Run` menu item from the application menu. + bind(DebugFrontendApplicationContribution).toSelf().inSingletonScope(); + rebind(TheiaDebugFrontendApplicationContribution).toService(DebugFrontendApplicationContribution); }); diff --git a/arduino-ide-extension/src/browser/boards/boards-data-menu-updater.ts b/arduino-ide-extension/src/browser/boards/boards-data-menu-updater.ts index a0c68738..ec517de9 100644 --- a/arduino-ide-extension/src/browser/boards/boards-data-menu-updater.ts +++ b/arduino-ide-extension/src/browser/boards/boards-data-menu-updater.ts @@ -1,14 +1,14 @@ import * as PQueue from 'p-queue'; import { inject, injectable } from 'inversify'; import { CommandRegistry } from '@theia/core/lib/common/command'; -import { MenuModelRegistry, MenuNode } from '@theia/core/lib/common/menu'; +import { MenuModelRegistry } from '@theia/core/lib/common/menu'; import { Disposable, DisposableCollection } from '@theia/core/lib/common/disposable'; import { BoardsServiceProvider } from './boards-service-provider'; import { Board, ConfigOption, Programmer } from '../../common/protocol'; import { FrontendApplicationContribution } from '@theia/core/lib/browser'; import { BoardsDataStore } from './boards-data-store'; import { MainMenuManager } from '../../common/main-menu-manager'; -import { ArduinoMenus } from '../menu/arduino-menus'; +import { ArduinoMenus, unregisterSubmenu } from '../menu/arduino-menus'; @injectable() export class BoardsDataMenuUpdater implements FrontendApplicationContribution { @@ -63,7 +63,7 @@ export class BoardsDataMenuUpdater implements FrontendApplicationContribution { this.menuRegistry.registerSubmenu(menuPath, label); this.toDisposeOnBoardChange.pushAll([ ...commands.values(), - Disposable.create(() => this.unregisterSubmenu(menuPath)), // We cannot dispose submenu entries: https://github.com/eclipse-theia/theia/issues/7299 + Disposable.create(() => unregisterSubmenu(menuPath, this.menuRegistry)), ...Array.from(commands.keys()).map((commandId, i) => { const { label } = commands.get(commandId)!; this.menuRegistry.registerMenuAction(menuPath, { commandId, order: `${i}`, label }); @@ -76,7 +76,7 @@ export class BoardsDataMenuUpdater implements FrontendApplicationContribution { const programmersMenuPath = [...ArduinoMenus.TOOLS__BOARD_SETTINGS_GROUP, 'z02_programmers']; const label = selectedProgrammer ? `Programmer: "${selectedProgrammer.name}"` : 'Programmer' this.menuRegistry.registerSubmenu(programmersMenuPath, label); - this.toDisposeOnBoardChange.push(Disposable.create(() => this.unregisterSubmenu(programmersMenuPath))); + this.toDisposeOnBoardChange.push(Disposable.create(() => unregisterSubmenu(programmersMenuPath, this.menuRegistry))); for (const programmer of programmers) { const { id, name } = programmer; const command = { id: `${fqbn}-programmer--${id}` }; @@ -98,20 +98,4 @@ export class BoardsDataMenuUpdater implements FrontendApplicationContribution { }); } - protected unregisterSubmenu(menuPath: string[]): void { - if (menuPath.length < 2) { - throw new Error(`Expected at least two item as a menu-path. Got ${JSON.stringify(menuPath)} instead.`); - } - const toRemove = menuPath[menuPath.length - 1]; - const parentMenuPath = menuPath.slice(0, menuPath.length - 1); - // This is unsafe. Calling `getMenu` with a non-existing menu-path will result in a new menu creation. - // https://github.com/eclipse-theia/theia/issues/7300 - const parent = this.menuRegistry.getMenu(parentMenuPath); - const index = parent.children.findIndex(({ id }) => id === toRemove); - if (index === -1) { - throw new Error(`Could not find menu with menu-path: ${JSON.stringify(menuPath)}.`); - } - (parent.children as Array).splice(index, 1); - } - } diff --git a/arduino-ide-extension/src/browser/menu/arduino-menus.ts b/arduino-ide-extension/src/browser/menu/arduino-menus.ts index d2ba0540..a4e0931d 100644 --- a/arduino-ide-extension/src/browser/menu/arduino-menus.ts +++ b/arduino-ide-extension/src/browser/menu/arduino-menus.ts @@ -1,6 +1,6 @@ import { isOSX } from '@theia/core/lib/common/os'; import { CommonMenus } from '@theia/core/lib/browser/common-frontend-contribution'; -import { MAIN_MENU_BAR } from '@theia/core/lib/common/menu'; +import { MAIN_MENU_BAR, MenuModelRegistry, MenuNode } from '@theia/core/lib/common/menu'; export namespace ArduinoMenus { @@ -67,3 +67,23 @@ export namespace ArduinoMenus { export const SKETCH_CONTROL__CONTEXT__RESOURCES_GROUP = [...SKETCH_CONTROL__CONTEXT, '2_resources']; } + +/** + * This is a hack. It removes a submenu with all its children if any. + * Theia cannot dispose submenu entries with a proper API: https://github.com/eclipse-theia/theia/issues/7299 + */ +export function unregisterSubmenu(menuPath: string[], menuRegistry: MenuModelRegistry): void { + if (menuPath.length < 2) { + throw new Error(`Expected at least two item as a menu-path. Got ${JSON.stringify(menuPath)} instead.`); + } + const toRemove = menuPath[menuPath.length - 1]; + const parentMenuPath = menuPath.slice(0, menuPath.length - 1); + // This is unsafe. Calling `getMenu` with a non-existing menu-path will result in a new menu creation. + // https://github.com/eclipse-theia/theia/issues/7300 + const parent = menuRegistry.getMenu(parentMenuPath); + const index = parent.children.findIndex(({ id }) => id === toRemove); + if (index === -1) { + throw new Error(`Could not find menu with menu-path: ${JSON.stringify(menuPath)}.`); + } + (parent.children as Array).splice(index, 1); +} diff --git a/arduino-ide-extension/src/browser/theia/debug/debug-frontend-application-contribution.ts b/arduino-ide-extension/src/browser/theia/debug/debug-frontend-application-contribution.ts new file mode 100644 index 00000000..94e960a4 --- /dev/null +++ b/arduino-ide-extension/src/browser/theia/debug/debug-frontend-application-contribution.ts @@ -0,0 +1,14 @@ +import { injectable } from 'inversify'; +import { MenuModelRegistry } from '@theia/core/lib/common/menu'; +import { DebugFrontendApplicationContribution as TheiaDebugFrontendApplicationContribution, DebugMenus } from '@theia/debug/lib/browser/debug-frontend-application-contribution'; +import { unregisterSubmenu } from '../../menu/arduino-menus'; + +@injectable() +export class DebugFrontendApplicationContribution extends TheiaDebugFrontendApplicationContribution { + + registerMenus(registry: MenuModelRegistry): void { + super.registerMenus(registry); + unregisterSubmenu(DebugMenus.DEBUG, registry); + } + +}