From f727e50c1a841b2c4c1fbcc60a4475b24096fda2 Mon Sep 17 00:00:00 2001 From: Megan Rogge Date: Tue, 27 Apr 2021 19:19:14 -0700 Subject: [PATCH] Use a menu instead of hard coding actions in tabsWidget (#122461) --- src/vs/platform/actions/common/actions.ts | 1 + .../terminal/browser/terminalActions.ts | 25 +++++++++++- .../terminal/browser/terminalService.ts | 2 +- .../terminal/browser/terminalTabbedView.ts | 3 +- .../terminal/browser/terminalTabsWidget.ts | 40 ++++++------------- 5 files changed, 39 insertions(+), 32 deletions(-) diff --git a/src/vs/platform/actions/common/actions.ts b/src/vs/platform/actions/common/actions.ts index 5f946cf2ea093..a2a1b4c49f71c 100644 --- a/src/vs/platform/actions/common/actions.ts +++ b/src/vs/platform/actions/common/actions.ts @@ -162,6 +162,7 @@ export class MenuId { static readonly TerminalTabsWidgetContext = new MenuId('TerminalTabsWidgetContext'); static readonly TerminalTabsWidgetEmptyContext = new MenuId('TerminalTabsWidgetEmptyContext'); static readonly TerminalSingleTabContext = new MenuId('TerminalSingleTabContext'); + static readonly TerminalTabInlineActions = new MenuId('TerminalTabInlineActions'); readonly id: number; readonly _debugName: string; diff --git a/src/vs/workbench/contrib/terminal/browser/terminalActions.ts b/src/vs/workbench/contrib/terminal/browser/terminalActions.ts index d5e93299ae676..aa49146dcc4d6 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalActions.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalActions.ts @@ -1394,7 +1394,7 @@ export function registerTerminalActions() { constructor() { super({ id: TERMINAL_COMMAND_ID.SPLIT_INSTANCE, - title: { value: localize('workbench.action.terminal.split', "Split Terminal"), original: 'Split Terminal' }, + title: { value: localize('workbench.action.terminal.splitInstance', "Split Terminal"), original: 'Split Terminal' }, f1: false, category, precondition: KEYBINDING_CONTEXT_TERMINAL_PROCESS_SUPPORTED, @@ -1422,6 +1422,13 @@ export function registerTerminalActions() { } } }); + MenuRegistry.appendMenuItem(MenuId.TerminalTabInlineActions, { + command: { + id: TERMINAL_COMMAND_ID.SPLIT_INSTANCE, + title: localize('workbench.action.terminal.splitInstance', "Split Terminal"), + }, + group: ContextMenuGroup.Create + }); registerAction2(class extends Action2 { constructor() { super({ @@ -1586,7 +1593,7 @@ export function registerTerminalActions() { super({ id: TERMINAL_COMMAND_ID.KILL_INSTANCE, title: { - value: localize('workbench.action.terminal.kill.short', "Kill Terminal"), original: 'Kill Terminal' + value: localize('workbench.action.terminal.killInstance', "Kill Terminal"), original: 'Kill Terminal' }, f1: false, category, @@ -1608,8 +1615,17 @@ export function registerTerminalActions() { } async run(accessor: ServicesAccessor) { getSelectedInstances(accessor)?.forEach(instance => instance.dispose(true)); + accessor.get(ITerminalService).focusTabs(); + focusNext(accessor); } }); + MenuRegistry.appendMenuItem(MenuId.TerminalTabInlineActions, { + command: { + id: TERMINAL_COMMAND_ID.KILL_INSTANCE, + title: localize('workbench.action.terminal.killInstance', "Kill Terminal") + }, + group: ContextMenuGroup.Kill + }); registerAction2(class extends Action2 { constructor() { super({ @@ -1889,3 +1905,8 @@ function getSelectedInstances(accessor: ServicesAccessor): ITerminalInstance[] | } return instances; } + +function focusNext(accessor: ServicesAccessor): void { + const listService = accessor.get(IListService); + listService.lastFocusedList?.focusNext(); +} diff --git a/src/vs/workbench/contrib/terminal/browser/terminalService.ts b/src/vs/workbench/contrib/terminal/browser/terminalService.ts index c2338957583a5..8ac26e737912d 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalService.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalService.ts @@ -453,7 +453,7 @@ export class TerminalService implements ITerminalService { const newIndex = index < this._terminalTabs.length ? index : this._terminalTabs.length - 1; this.setActiveTabByIndex(newIndex); const activeInstance = this.getActiveInstance(); - if (activeInstance) { + if (this._onActiveInstanceChanged && activeInstance?.hadFocusOnExit) { activeInstance.focus(true); } } else if (activeTabIndex >= this._terminalTabs.length) { diff --git a/src/vs/workbench/contrib/terminal/browser/terminalTabbedView.ts b/src/vs/workbench/contrib/terminal/browser/terminalTabbedView.ts index 35f4179a8a956..e8d76943b3c9d 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalTabbedView.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalTabbedView.ts @@ -93,8 +93,9 @@ export class TerminalTabbedView extends Disposable { this._instanceMenu = this._register(menuService.createMenu(MenuId.TerminalContainerContext, contextKeyService)); this._tabsWidgetMenu = this._register(menuService.createMenu(MenuId.TerminalTabsWidgetContext, contextKeyService)); this._tabsWidgetEmptyMenu = this._register(menuService.createMenu(MenuId.TerminalTabsWidgetEmptyContext, contextKeyService)); + const inlineMenu = this._register(menuService.createMenu(MenuId.TerminalTabInlineActions, contextKeyService)); - this._register(this._tabsWidget = this._instantiationService.createInstance(TerminalTabsWidget, this._terminalTabTree)); + this._register(this._tabsWidget = this._instantiationService.createInstance(TerminalTabsWidget, this._terminalTabTree, inlineMenu)); this._register(this._findWidget = this._instantiationService.createInstance(TerminalFindWidget, this._terminalService.getFindState())); parentElement.appendChild(this._findWidget.getDomNode()); diff --git a/src/vs/workbench/contrib/terminal/browser/terminalTabsWidget.ts b/src/vs/workbench/contrib/terminal/browser/terminalTabsWidget.ts index 0d61ed6ba93e4..e292669bc3ebe 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalTabsWidget.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalTabsWidget.ts @@ -10,17 +10,15 @@ import { IAccessibilityService } from 'vs/platform/accessibility/common/accessib import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; -import { IThemeService, ThemeIcon } from 'vs/platform/theme/common/themeService'; +import { IThemeService } from 'vs/platform/theme/common/themeService'; import { ITerminalInstance, ITerminalService } from 'vs/workbench/contrib/terminal/browser/terminal'; import { localize } from 'vs/nls'; import * as DOM from 'vs/base/browser/dom'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar'; -import { MenuItemAction } from 'vs/platform/actions/common/actions'; +import { IMenu, MenuItemAction } from 'vs/platform/actions/common/actions'; import { MenuEntryActionViewItem } from 'vs/platform/actions/browser/menuEntryActionViewItem'; import { KEYBINDING_CONTEXT_TERMINAL_TABS_SINGULAR_SELECTION, TERMINAL_COMMAND_ID } from 'vs/workbench/contrib/terminal/common/terminal'; -import { Codicon } from 'vs/base/common/codicons'; -import { Action } from 'vs/base/common/actions'; import { MarkdownString } from 'vs/base/common/htmlContent'; import { TerminalDecorationsProvider } from 'vs/workbench/contrib/terminal/browser/terminalDecorationsProvider'; import { DEFAULT_LABELS_CONTAINER, IResourceLabel, ResourceLabels } from 'vs/workbench/browser/labels'; @@ -28,6 +26,7 @@ import { IDecorationsService } from 'vs/workbench/services/decorations/browser/d import { IHoverAction, IHoverService } from 'vs/workbench/services/hover/browser/hover'; import Severity from 'vs/base/common/severity'; import { DisposableStore } from 'vs/base/common/lifecycle'; +import { Codicon } from 'vs/base/common/codicons'; const $ = DOM.$; const TAB_HEIGHT = 22; @@ -41,6 +40,7 @@ export class TerminalTabsWidget extends WorkbenchObjectTree constructor( container: HTMLElement, + inlineMenu: IMenu, @IContextKeyService contextKeyService: IContextKeyService, @IListService listService: IListService, @IThemeService themeService: IThemeService, @@ -56,7 +56,7 @@ export class TerminalTabsWidget extends WorkbenchObjectTree getHeight: () => TAB_HEIGHT, getTemplateId: () => 'terminal.tabs' }, - [instantiationService.createInstance(TerminalTabsRenderer, container, instantiationService.createInstance(ResourceLabels, DEFAULT_LABELS_CONTAINER), () => this.getSelection())], + [instantiationService.createInstance(TerminalTabsRenderer, container, inlineMenu, instantiationService.createInstance(ResourceLabels, DEFAULT_LABELS_CONTAINER))], { horizontalScrolling: false, supportDynamicHeights: false, @@ -162,11 +162,10 @@ export class TerminalTabsWidget extends WorkbenchObjectTree class TerminalTabsRenderer implements ITreeRenderer { templateId = 'terminal.tabs'; - constructor( private readonly _container: HTMLElement, + private readonly _inlineMenu: IMenu, private readonly _labels: ResourceLabels, - private readonly _getSelection: () => (ITerminalInstance | null)[], @IInstantiationService private readonly _instantiationService: IInstantiationService, @ITerminalService private readonly _terminalService: ITerminalService, @IHoverService private readonly _hoverService: IHoverService, @@ -328,31 +327,16 @@ class TerminalTabsRenderer implements ITreeRenderer { - this._runForSelectionOrInstance(instance, e => this._terminalService.splitInstance(e)); - }), - new Action(TERMINAL_COMMAND_ID.KILL_INSTANCE, localize('terminal.kill', "Kill"), ThemeIcon.asClassName(Codicon.trashcan), true, async () => { - this._runForSelectionOrInstance(instance, e => e.dispose()); - }) - ]; + const actions = this._inlineMenu.getActions(); // TODO: Cache these in a way that will use the correct instance template.actionBar.clear(); - for (const action of actions) { - template.actionBar.push(action, { icon: true, label: false, keybinding: this._keybindingService.lookupKeybinding(action.id)?.getLabel() }); - } - } - - private _runForSelectionOrInstance(instance: ITerminalInstance, callback: (instance: ITerminalInstance) => void) { - const selection = this._getSelection(); - if (selection.includes(instance)) { - for (const s of selection) { - if (s) { - callback(s); + for (const [, action] of actions) { + for (const a of action) { + a.item.icon = a.id === TERMINAL_COMMAND_ID.KILL_INSTANCE ? Codicon.trashcan : Codicon.splitHorizontal; + if ('item' in a) { + template.actionBar.push(a, { icon: true, label: false, keybinding: this._keybindingService.lookupKeybinding(a.id)?.getLabel() }); } } - } else { - callback(instance); } } }