Path: blob/main/src/vs/editor/contrib/floatingMenu/browser/floatingMenu.ts
4779 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 { h } from '../../../../base/browser/dom.js';6import { Disposable } from '../../../../base/common/lifecycle.js';7import { autorun, constObservable, observableFromEvent } from '../../../../base/common/observable.js';8import { MenuEntryActionViewItem } from '../../../../platform/actions/browser/menuEntryActionViewItem.js';9import { HiddenItemStrategy, MenuWorkbenchToolBar } from '../../../../platform/actions/browser/toolbar.js';10import { IMenuService, MenuId, MenuItemAction } from '../../../../platform/actions/common/actions.js';11import { IInstantiationService } from '../../../../platform/instantiation/common/instantiation.js';12import { IKeybindingService } from '../../../../platform/keybinding/common/keybinding.js';13import { ICodeEditor, OverlayWidgetPositionPreference } from '../../../browser/editorBrowser.js';14import { observableCodeEditor } from '../../../browser/observableCodeEditor.js';15import { IEditorContribution } from '../../../common/editorCommon.js';1617export class FloatingEditorToolbar extends Disposable implements IEditorContribution {18static readonly ID = 'editor.contrib.floatingToolbar';1920constructor(21editor: ICodeEditor,22@IInstantiationService instantiationService: IInstantiationService,23@IKeybindingService keybindingService: IKeybindingService,24@IMenuService menuService: IMenuService25) {26super();2728const editorObs = this._register(observableCodeEditor(editor));2930const menu = this._register(menuService.createMenu(MenuId.EditorContent, editor.contextKeyService));31const menuIsEmptyObs = observableFromEvent(this, menu.onDidChange, () => menu.getActions().length === 0);3233this._register(autorun(reader => {34const menuIsEmpty = menuIsEmptyObs.read(reader);35if (menuIsEmpty) {36return;37}3839const container = h('div.floating-menu-overlay-widget');4041// Set height explicitly to ensure that the floating menu element42// is rendered in the lower right corner at the correct position.43container.root.style.height = '28px';4445// Toolbar46const toolbar = instantiationService.createInstance(MenuWorkbenchToolBar, container.root, MenuId.EditorContent, {47actionViewItemProvider: (action, options) => {48if (!(action instanceof MenuItemAction)) {49return undefined;50}5152const keybinding = keybindingService.lookupKeybinding(action.id);53if (!keybinding) {54return undefined;55}5657return instantiationService.createInstance(class extends MenuEntryActionViewItem {58protected override updateLabel(): void {59if (this.options.label && this.label) {60this.label.textContent = `${this._commandAction.label} (${keybinding.getLabel()})`;61}62}63}, action, { ...options, keybindingNotRenderedWithLabel: true });64},65hiddenItemStrategy: HiddenItemStrategy.Ignore,66menuOptions: {67shouldForwardArgs: true68},69telemetrySource: 'editor.overlayToolbar',70toolbarOptions: {71primaryGroup: () => true,72useSeparatorsInPrimaryActions: true73},74});7576reader.store.add(toolbar);77reader.store.add(autorun(reader => {78const model = editorObs.model.read(reader);79toolbar.context = model?.uri;80}));8182// Overlay widget83reader.store.add(editorObs.createOverlayWidget({84allowEditorOverflow: false,85domNode: container.root,86minContentWidthInPx: constObservable(0),87position: constObservable({88preference: OverlayWidgetPositionPreference.BOTTOM_RIGHT_CORNER89})90}));91}));92}93}949596