UNPKG

@sussudio/platform

Version:

Internal APIs for VS Code's service injection the base services.

259 lines (258 loc) 8.55 kB
/*--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? (desc = Object.getOwnPropertyDescriptor(target, key)) : desc, d; if (typeof Reflect === 'object' && typeof Reflect.decorate === 'function') r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if ((d = decorators[i])) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; }; var __param = (this && this.__param) || function (paramIndex, decorator) { return function (target, key) { decorator(target, key, paramIndex); }; }; import { addDisposableListener } from '@sussudio/base/browser/dom.mjs'; import { ToolBar } from '@sussudio/base/browser/ui/toolbar/toolbar.mjs'; import { Separator, toAction } from '@sussudio/base/common/actions.mjs'; import { coalesceInPlace } from '@sussudio/base/common/arrays.mjs'; import { BugIndicatingError } from '@sussudio/base/common/errors.mjs'; import { DisposableStore } from '@sussudio/base/common/lifecycle.mjs'; import { localize } from 'vscode-nls.mjs'; import { createAndFillInActionBarActions } from './menuEntryActionViewItem.mjs'; import { IMenuService, MenuItemAction, SubmenuItemAction } from '../common/actions.mjs'; import { IContextKeyService } from '../../contextkey/common/contextkey.mjs'; import { IContextMenuService } from '../../contextview/browser/contextView.mjs'; import { IKeybindingService } from '../../keybinding/common/keybinding.mjs'; import { ITelemetryService } from '../../telemetry/common/telemetry.mjs'; /** * The `WorkbenchToolBar` does * - support hiding of menu items * - lookup keybindings for each actions automatically * - send `workbenchActionExecuted`-events for each action * * See {@link MenuWorkbenchToolBar} for a toolbar that is backed by a menu. */ let WorkbenchToolBar = class WorkbenchToolBar extends ToolBar { _options; _menuService; _contextKeyService; _contextMenuService; _sessionDisposables = this._store.add(new DisposableStore()); constructor( container, _options, _menuService, _contextKeyService, _contextMenuService, keybindingService, telemetryService, ) { super(container, _contextMenuService, { // defaults getKeyBinding: (action) => keybindingService.lookupKeybinding(action.id) ?? undefined, // options (override defaults) ..._options, // mandatory (overide options) allowContextMenu: true, }); this._options = _options; this._menuService = _menuService; this._contextKeyService = _contextKeyService; this._contextMenuService = _contextMenuService; // telemetry logic if (_options?.telemetrySource) { this._store.add( this.actionBar.onDidRun((e) => telemetryService.publicLog2('workbenchActionExecuted', { id: e.action.id, from: _options.telemetrySource }), ), ); } } setActions(_primary, _secondary = [], menuIds) { this._sessionDisposables.clear(); const primary = _primary.slice(); const secondary = _secondary.slice(); const toggleActions = []; const extraSecondary = []; let someAreHidden = false; // unless disabled, move all hidden items to secondary group or ignore them if (this._options?.hiddenItemStrategy !== -1 /* HiddenItemStrategy.NoHide */) { for (let i = 0; i < primary.length; i++) { const action = primary[i]; if (!(action instanceof MenuItemAction) && !(action instanceof SubmenuItemAction)) { // console.warn(`Action ${action.id}/${action.label} is not a MenuItemAction`); continue; } if (!action.hideActions) { continue; } // collect all toggle actions toggleActions.push(action.hideActions.toggle); // hidden items move into overflow or ignore if (action.hideActions.isHidden) { someAreHidden = true; primary[i] = undefined; if (this._options?.hiddenItemStrategy !== 0 /* HiddenItemStrategy.Ignore */) { extraSecondary[i] = action; } } } } // count for max if (this._options?.maxNumberOfItems !== undefined) { let count = 0; for (let i = 0; i < primary.length; i++) { const action = primary[i]; if (!action) { continue; } if (++count >= this._options.maxNumberOfItems) { primary[i] = undefined; extraSecondary[i] = action; } } } coalesceInPlace(primary); coalesceInPlace(extraSecondary); super.setActions(primary, Separator.join(extraSecondary, secondary)); // add context menu for toggle actions if (toggleActions.length > 0) { this._sessionDisposables.add( addDisposableListener(this.getElement(), 'contextmenu', (e) => { const action = this.getItemAction(e.target); if (!action) { return; } e.preventDefault(); e.stopPropagation(); let actions = toggleActions; // add "hide foo" actions let hideAction; if (action instanceof MenuItemAction || action instanceof SubmenuItemAction) { if (!action.hideActions) { // no context menu for MenuItemAction instances that support no hiding // those are fake actions and need to be cleaned up return; } hideAction = action.hideActions.hide; } else { hideAction = toAction({ id: 'label', label: localize('hide', 'Hide'), enabled: false, run() {}, }); } actions = [hideAction, new Separator(), ...toggleActions]; // add "Reset Menu" action if (this._options?.resetMenu && !menuIds) { menuIds = [this._options.resetMenu]; } if (someAreHidden && menuIds) { actions.push(new Separator()); actions.push( toAction({ id: 'resetThisMenu', label: localize('resetThisMenu', 'Reset Menu'), run: () => this._menuService.resetHiddenStates(menuIds), }), ); } this._contextMenuService.showContextMenu({ getAnchor: () => e, getActions: () => actions, // add context menu actions (iff appicable) menuId: this._options?.contextMenu, menuActionOptions: { renderShortTitle: true, ...this._options?.menuOptions }, contextKeyService: this._contextKeyService, }); }), ); } } }; WorkbenchToolBar = __decorate( [ __param(2, IMenuService), __param(3, IContextKeyService), __param(4, IContextMenuService), __param(5, IKeybindingService), __param(6, ITelemetryService), ], WorkbenchToolBar, ); export { WorkbenchToolBar }; /** * A {@link WorkbenchToolBar workbench toolbar} that is purely driven from a {@link MenuId menu}-identifier. * * *Note* that Manual updates via `setActions` are NOT supported. */ let MenuWorkbenchToolBar = class MenuWorkbenchToolBar extends WorkbenchToolBar { constructor( container, menuId, options, menuService, contextKeyService, contextMenuService, keybindingService, telemetryService, ) { super( container, { resetMenu: menuId, ...options }, menuService, contextKeyService, contextMenuService, keybindingService, telemetryService, ); // update logic const menu = this._store.add( menuService.createMenu(menuId, contextKeyService, { emitEventsForSubmenuChanges: true }), ); const updateToolbar = () => { const primary = []; const secondary = []; createAndFillInActionBarActions( menu, options?.menuOptions, { primary, secondary }, options?.toolbarOptions?.primaryGroup, options?.toolbarOptions?.shouldInlineSubmenu, options?.toolbarOptions?.useSeparatorsInPrimaryActions, ); super.setActions(primary, secondary); }; this._store.add(menu.onDidChange(updateToolbar)); updateToolbar(); } /** * @deprecated The WorkbenchToolBar does not support this method because it works with menus. */ setActions() { throw new BugIndicatingError('This toolbar is populated from a menu.'); } }; MenuWorkbenchToolBar = __decorate( [ __param(3, IMenuService), __param(4, IContextKeyService), __param(5, IContextMenuService), __param(6, IKeybindingService), __param(7, ITelemetryService), ], MenuWorkbenchToolBar, ); export { MenuWorkbenchToolBar };