Path: blob/main/src/vs/workbench/browser/parts/titlebar/commandCenterControl.ts
3296 views
/*---------------------------------------------------------------------------------------------1* Copyright (c) Microsoft Corporation. All rights reserved.2* Licensed under the MIT License. See License.txt in the project root for license information.3*--------------------------------------------------------------------------------------------*/45import { isActiveDocument, reset } from '../../../../base/browser/dom.js';6import { BaseActionViewItem, IBaseActionViewItemOptions } from '../../../../base/browser/ui/actionbar/actionViewItems.js';7import { getDefaultHoverDelegate } from '../../../../base/browser/ui/hover/hoverDelegateFactory.js';8import { IHoverDelegate } from '../../../../base/browser/ui/hover/hoverDelegate.js';9import { renderIcon } from '../../../../base/browser/ui/iconLabel/iconLabels.js';10import { IAction, SubmenuAction } from '../../../../base/common/actions.js';11import { Codicon } from '../../../../base/common/codicons.js';12import { Emitter, Event } from '../../../../base/common/event.js';13import { DisposableStore } from '../../../../base/common/lifecycle.js';14import { localize } from '../../../../nls.js';15import { createActionViewItem } from '../../../../platform/actions/browser/menuEntryActionViewItem.js';16import { HiddenItemStrategy, MenuWorkbenchToolBar, WorkbenchToolBar } from '../../../../platform/actions/browser/toolbar.js';17import { MenuId, MenuRegistry, SubmenuItemAction } from '../../../../platform/actions/common/actions.js';18import { IInstantiationService } from '../../../../platform/instantiation/common/instantiation.js';19import { IKeybindingService } from '../../../../platform/keybinding/common/keybinding.js';20import { IQuickInputService } from '../../../../platform/quickinput/common/quickInput.js';21import { WindowTitle } from './windowTitle.js';22import { IEditorGroupsService } from '../../../services/editor/common/editorGroupsService.js';23import { IHoverService } from '../../../../platform/hover/browser/hover.js';2425export class CommandCenterControl {2627private readonly _disposables = new DisposableStore();2829private readonly _onDidChangeVisibility = this._disposables.add(new Emitter<void>());30readonly onDidChangeVisibility: Event<void> = this._onDidChangeVisibility.event;3132readonly element: HTMLElement = document.createElement('div');3334constructor(35windowTitle: WindowTitle,36hoverDelegate: IHoverDelegate,37@IInstantiationService instantiationService: IInstantiationService,38@IQuickInputService quickInputService: IQuickInputService,39) {40this.element.classList.add('command-center');4142const titleToolbar = instantiationService.createInstance(MenuWorkbenchToolBar, this.element, MenuId.CommandCenter, {43contextMenu: MenuId.TitleBarContext,44hiddenItemStrategy: HiddenItemStrategy.NoHide,45toolbarOptions: {46primaryGroup: () => true,47},48telemetrySource: 'commandCenter',49actionViewItemProvider: (action, options) => {50if (action instanceof SubmenuItemAction && action.item.submenu === MenuId.CommandCenterCenter) {51return instantiationService.createInstance(CommandCenterCenterViewItem, action, windowTitle, { ...options, hoverDelegate });52} else {53return createActionViewItem(instantiationService, action, { ...options, hoverDelegate });54}55}56});5758this._disposables.add(Event.filter(quickInputService.onShow, () => isActiveDocument(this.element), this._disposables)(this._setVisibility.bind(this, false)));59this._disposables.add(quickInputService.onHide(this._setVisibility.bind(this, true)));60this._disposables.add(titleToolbar);61}6263private _setVisibility(show: boolean): void {64this.element.classList.toggle('hide', !show);65this._onDidChangeVisibility.fire();66}6768dispose(): void {69this._disposables.dispose();70}71}727374class CommandCenterCenterViewItem extends BaseActionViewItem {7576private static readonly _quickOpenCommandId = 'workbench.action.quickOpenWithModes';7778private readonly _hoverDelegate: IHoverDelegate;7980constructor(81private readonly _submenu: SubmenuItemAction,82private readonly _windowTitle: WindowTitle,83options: IBaseActionViewItemOptions,84@IHoverService private readonly _hoverService: IHoverService,85@IKeybindingService private _keybindingService: IKeybindingService,86@IInstantiationService private _instaService: IInstantiationService,87@IEditorGroupsService private _editorGroupService: IEditorGroupsService,88) {89super(undefined, _submenu.actions.find(action => action.id === 'workbench.action.quickOpenWithModes') ?? _submenu.actions[0], options);90this._hoverDelegate = options.hoverDelegate ?? getDefaultHoverDelegate('mouse');91}9293override render(container: HTMLElement): void {94super.render(container);95container.classList.add('command-center-center');96container.classList.toggle('multiple', (this._submenu.actions.length > 1));9798const hover = this._store.add(this._hoverService.setupManagedHover(this._hoverDelegate, container, this.getTooltip()));99100// update label & tooltip when window title changes101this._store.add(this._windowTitle.onDidChange(() => {102hover.update(this.getTooltip());103}));104105const groups: (readonly IAction[])[] = [];106for (const action of this._submenu.actions) {107if (action instanceof SubmenuAction) {108groups.push(action.actions);109} else {110groups.push([action]);111}112}113114115for (let i = 0; i < groups.length; i++) {116const group = groups[i];117118// nested toolbar119const toolbar = this._instaService.createInstance(WorkbenchToolBar, container, {120hiddenItemStrategy: HiddenItemStrategy.NoHide,121telemetrySource: 'commandCenterCenter',122actionViewItemProvider: (action, options) => {123options = {124...options,125hoverDelegate: this._hoverDelegate,126};127128if (action.id !== CommandCenterCenterViewItem._quickOpenCommandId) {129return createActionViewItem(this._instaService, action, options);130}131132const that = this;133134return this._instaService.createInstance(class CommandCenterQuickPickItem extends BaseActionViewItem {135136constructor() {137super(undefined, action, options);138}139140override render(container: HTMLElement): void {141super.render(container);142container.classList.toggle('command-center-quick-pick');143container.role = 'button';144const action = this.action;145146// icon (search)147const searchIcon = document.createElement('span');148searchIcon.ariaHidden = 'true';149searchIcon.className = action.class ?? '';150searchIcon.classList.add('search-icon');151152// label: just workspace name and optional decorations153const label = this._getLabel();154const labelElement = document.createElement('span');155labelElement.classList.add('search-label');156labelElement.textContent = label;157reset(container, searchIcon, labelElement);158159const hover = this._store.add(that._hoverService.setupManagedHover(that._hoverDelegate, container, this.getTooltip()));160161// update label & tooltip when window title changes162this._store.add(that._windowTitle.onDidChange(() => {163hover.update(this.getTooltip());164labelElement.textContent = this._getLabel();165}));166167// update label & tooltip when tabs visibility changes168this._store.add(that._editorGroupService.onDidChangeEditorPartOptions(({ newPartOptions, oldPartOptions }) => {169if (newPartOptions.showTabs !== oldPartOptions.showTabs) {170hover.update(this.getTooltip());171labelElement.textContent = this._getLabel();172}173}));174}175176protected override getTooltip() {177return that.getTooltip();178}179180private _getLabel(): string {181const { prefix, suffix } = that._windowTitle.getTitleDecorations();182let label = that._windowTitle.workspaceName;183if (that._windowTitle.isCustomTitleFormat()) {184label = that._windowTitle.getWindowTitle();185} else if (that._editorGroupService.partOptions.showTabs === 'none') {186label = that._windowTitle.fileName ?? label;187}188if (!label) {189label = localize('label.dfl', "Search");190}191if (prefix) {192label = localize('label1', "{0} {1}", prefix, label);193}194if (suffix) {195label = localize('label2', "{0} {1}", label, suffix);196}197198return label.replaceAll(/\r\n|\r|\n/g, '\u23CE');199}200});201}202});203toolbar.setActions(group);204this._store.add(toolbar);205206207// spacer208if (i < groups.length - 1) {209const icon = renderIcon(Codicon.circleSmallFilled);210icon.style.padding = '0 12px';211icon.style.height = '100%';212icon.style.opacity = '0.5';213container.appendChild(icon);214}215}216}217218protected override getTooltip() {219220// tooltip: full windowTitle221const kb = this._keybindingService.lookupKeybinding(this.action.id)?.getLabel();222const title = kb223? localize('title', "Search {0} ({1}) \u2014 {2}", this._windowTitle.workspaceName, kb, this._windowTitle.value)224: localize('title2', "Search {0} \u2014 {1}", this._windowTitle.workspaceName, this._windowTitle.value);225226return title;227}228}229230MenuRegistry.appendMenuItem(MenuId.CommandCenter, {231submenu: MenuId.CommandCenterCenter,232title: localize('title3', "Command Center"),233icon: Codicon.shield,234order: 101,235});236237238