From 80d13215499a794b37822566a7967d8987358b5b Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Thu, 24 Jun 2021 16:46:54 -0700 Subject: [PATCH 01/17] Terminal editor + button Part of #126256 --- .../dropdownWithPrimaryActionViewItem.ts | 4 +- .../terminal/browser/terminalEditor.ts | 98 ++++++++++++++++++- .../contrib/terminal/browser/terminalMenus.ts | 10 ++ 3 files changed, 107 insertions(+), 5 deletions(-) diff --git a/src/vs/platform/actions/browser/dropdownWithPrimaryActionViewItem.ts b/src/vs/platform/actions/browser/dropdownWithPrimaryActionViewItem.ts index 3dc33976b98..df19cf3f10f 100644 --- a/src/vs/platform/actions/browser/dropdownWithPrimaryActionViewItem.ts +++ b/src/vs/platform/actions/browser/dropdownWithPrimaryActionViewItem.ts @@ -32,8 +32,8 @@ export class DropdownWithPrimaryActionViewItem extends BaseActionViewItem { dropdownMenuActions: IAction[], className: string, private readonly _contextMenuProvider: IContextMenuProvider, - _keybindingService: IKeybindingService, - _notificationService: INotificationService + @IKeybindingService _keybindingService: IKeybindingService, + @INotificationService _notificationService: INotificationService ) { super(null, primaryAction); this._primaryAction = new MenuEntryActionViewItem(primaryAction, _keybindingService, _notificationService); diff --git a/src/vs/workbench/contrib/terminal/browser/terminalEditor.ts b/src/vs/workbench/contrib/terminal/browser/terminalEditor.ts index f151e8accec..c1ddc99bc80 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalEditor.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalEditor.ts @@ -4,20 +4,31 @@ *--------------------------------------------------------------------------------------------*/ import { Dimension } from 'vs/base/browser/dom'; +import { IActionViewItem } from 'vs/base/browser/ui/actionbar/actionbar'; +import { Action, IAction, Separator, SubmenuAction } from 'vs/base/common/actions'; import { CancellationToken } from 'vs/base/common/cancellation'; +import { Codicon } from 'vs/base/common/codicons'; import { FindReplaceState } from 'vs/editor/contrib/find/findState'; +import { localize } from 'vs/nls'; +import { DropdownWithPrimaryActionViewItem } from 'vs/platform/actions/browser/dropdownWithPrimaryActionViewItem'; +import { MenuItemAction } from 'vs/platform/actions/common/actions'; import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; +import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; import { IEditorOptions } from 'vs/platform/editor/common/editor'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IStorageService } from 'vs/platform/storage/common/storage'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; +import { ITerminalProfile } from 'vs/platform/terminal/common/terminal'; import { IThemeService } from 'vs/platform/theme/common/themeService'; import { EditorPane } from 'vs/workbench/browser/parts/editor/editorPane'; import { IEditorOpenContext } from 'vs/workbench/common/editor'; -import { ITerminalEditorService } from 'vs/workbench/contrib/terminal/browser/terminal'; +import { ITerminalEditorService, ITerminalService } from 'vs/workbench/contrib/terminal/browser/terminal'; import { TerminalEditorInput } from 'vs/workbench/contrib/terminal/browser/terminalEditorInput'; import { TerminalFindWidget } from 'vs/workbench/contrib/terminal/browser/terminalFindWidget'; -import { KEYBINDING_CONTEXT_TERMINAL_FIND_VISIBLE } from 'vs/workbench/contrib/terminal/common/terminal'; +import { TerminalTabContextMenuGroup } from 'vs/workbench/contrib/terminal/browser/terminalMenus'; +import { ITerminalProfileResolverService, KEYBINDING_CONTEXT_TERMINAL_FIND_VISIBLE, TerminalCommandId } from 'vs/workbench/contrib/terminal/common/terminal'; +import { ITerminalContributionService } from 'vs/workbench/contrib/terminal/common/terminalExtensionPoints'; +import { terminalStrings } from 'vs/workbench/contrib/terminal/common/terminalStrings'; import { IEditorGroup } from 'vs/workbench/services/editor/common/editorGroupsService'; const xtermSelector = '.terminal.xterm'; @@ -44,8 +55,13 @@ export class TerminalEditor extends EditorPane { @IThemeService themeService: IThemeService, @IStorageService storageService: IStorageService, @ITerminalEditorService private readonly _terminalEditorService: ITerminalEditorService, + @ITerminalProfileResolverService private readonly _terminalProfileResolverService: ITerminalProfileResolverService, + @ITerminalContributionService private readonly _terminalContributionService: ITerminalContributionService, + @ITerminalService private readonly _terminalService: ITerminalService, @IInstantiationService instantiationService: IInstantiationService, - @IContextKeyService contextKeyService: IContextKeyService + @IContextKeyService contextKeyService: IContextKeyService, + @IInstantiationService private readonly _instantiationService: IInstantiationService, + @IContextMenuService private readonly _contextMenuService: IContextMenuService, ) { super(TerminalEditor.ID, telemetryService, themeService, storageService); this._findState = new FindReplaceState(); @@ -96,6 +112,82 @@ export class TerminalEditor extends EditorPane { return this._editorInput?.terminalInstance?.setVisible(visible); } + override getActionViewItem(action: IAction): IActionViewItem | undefined { + switch (action.id) { + case TerminalCommandId.CreateWithProfileButton: { + // if (this._tabButtons) { + // this._tabButtons.dispose(); + // } + const actions = this._getTabActionBarArgs(this._terminalService.availableProfiles); + + const button = this._instantiationService.createInstance(DropdownWithPrimaryActionViewItem, actions.primaryAction, actions.dropdownAction, actions.dropdownMenuActions, actions.className, this._contextMenuService); + // this._updateTabActionBar(this._terminalService.availableProfiles); + return button; + } + } + return super.getActionViewItem(action); + } + + private _getTabActionBarArgs(profiles: ITerminalProfile[]): { + primaryAction: MenuItemAction, + dropdownAction: IAction, + dropdownMenuActions: IAction[], + className: string, + dropdownIcon?: string + } { + const dropdownActions: IAction[] = []; + const submenuActions: IAction[] = []; + + const defaultProfileName = this._terminalProfileResolverService.defaultProfileName; + // TODO: Pass in args to create an editor terminal specifically + for (const p of profiles) { + const isDefault = p.profileName === defaultProfileName; + if (isDefault) { + dropdownActions.unshift(this._instantiationService.createInstance(MenuItemAction, { id: TerminalCommandId.NewWithProfile, title: localize('defaultTerminalProfile', "{0} (Default)", p.profileName), category: TerminalTabContextMenuGroup.Profile }, undefined, { arg: p, shouldForwardArgs: true })); + submenuActions.unshift(this._instantiationService.createInstance(MenuItemAction, { id: TerminalCommandId.Split, title: localize('defaultTerminalProfile', "{0} (Default)", p.profileName), category: TerminalTabContextMenuGroup.Profile }, undefined, { arg: p, shouldForwardArgs: true })); + } else { + dropdownActions.push(this._instantiationService.createInstance(MenuItemAction, { id: TerminalCommandId.NewWithProfile, title: p.profileName.replace(/[\n\r\t]/g, ''), category: TerminalTabContextMenuGroup.Profile }, undefined, { arg: p, shouldForwardArgs: true })); + submenuActions.push(this._instantiationService.createInstance(MenuItemAction, { id: TerminalCommandId.Split, title: p.profileName.replace(/[\n\r\t]/g, ''), category: TerminalTabContextMenuGroup.Profile }, undefined, { arg: p, shouldForwardArgs: true })); + } + } + + for (const contributed of this._terminalContributionService.terminalProfiles) { + dropdownActions.push(new Action(TerminalCommandId.NewWithProfile, contributed.title.replace(/[\n\r\t]/g, ''), undefined, true, () => this._terminalService.createContributedTerminalProfile(contributed.extensionIdentifier, contributed.id, false))); + submenuActions.push(new Action(TerminalCommandId.NewWithProfile, contributed.title.replace(/[\n\r\t]/g, ''), undefined, true, () => this._terminalService.createContributedTerminalProfile(contributed.extensionIdentifier, contributed.id, true))); + } + + if (dropdownActions.length > 0) { + dropdownActions.push(new SubmenuAction('split.profile', 'Split...', submenuActions)); + dropdownActions.push(new Separator()); + } + + // for (const [, configureActions] of this._dropdownMenu.getActions()) { + // for (const action of configureActions) { + // // make sure the action is a MenuItemAction + // if ('alt' in action) { + // dropdownActions.push(action); + // } + // } + // } + + const primaryAction = this._instantiationService.createInstance( + MenuItemAction, + { + id: TerminalCommandId.CreateTerminalEditor, + title: localize('terminal.new', "New Terminal"), + icon: Codicon.plus + }, + { + id: 'workbench.action.splitEditor', + title: terminalStrings.split.value, + icon: Codicon.splitHorizontal + }, + undefined); + + const dropdownAction = new Action('refresh profiles', 'Launch Profile...', 'codicon-chevron-down', true); + return { primaryAction, dropdownAction, dropdownMenuActions: dropdownActions, className: 'terminal-tab-actions' }; + } + focusFindWidget() { if (this._parentElement && !this._parentElement?.querySelector(findWidgetSelector)) { this._parentElement.querySelector(xtermSelector)!.appendChild(this._findWidget.getDomNode()); diff --git a/src/vs/workbench/contrib/terminal/browser/terminalMenus.ts b/src/vs/workbench/contrib/terminal/browser/terminalMenus.ts index 93bfeecd360..174b7397e12 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalMenus.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalMenus.ts @@ -529,4 +529,14 @@ export function setupTerminalMenus(): void { when: ResourceContextKey.Scheme.isEqualTo(Schemas.vscodeTerminal), group: '2_files' }); + + MenuRegistry.appendMenuItem(MenuId.EditorTitle, { + command: { + id: TerminalCommandId.CreateWithProfileButton, + title: TerminalCommandId.CreateWithProfileButton + }, + group: 'navigation', + order: 0, + when: ResourceContextKey.Scheme.isEqualTo(Schemas.vscodeTerminal) + }); } From 6931c0205f107d2f131e7d54b4711dd8d8ba378f Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Thu, 24 Jun 2021 16:52:12 -0700 Subject: [PATCH 02/17] Create new default terminal in editor --- .../contrib/terminal/browser/terminalActions.ts | 7 ++++--- .../contrib/terminal/browser/terminalEditor.ts | 17 +++++++++++------ 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/browser/terminalActions.ts b/src/vs/workbench/contrib/terminal/browser/terminalActions.ts index f59efaa997b..58afec88f76 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalActions.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalActions.ts @@ -30,7 +30,7 @@ import { ILocalTerminalService, ITerminalProfile, TerminalSettingId, TitleEventS import { IWorkspaceContextService, IWorkspaceFolder } from 'vs/platform/workspace/common/workspace'; import { PICK_WORKSPACE_FOLDER_COMMAND_ID } from 'vs/workbench/browser/actions/workspaceCommands'; import { FindInFilesCommand, IFindInFilesArgs } from 'vs/workbench/contrib/search/browser/searchActions'; -import { Direction, IRemoteTerminalService, ITerminalEditorService, ITerminalGroupService, ITerminalInstance, ITerminalInstanceService, ITerminalService } from 'vs/workbench/contrib/terminal/browser/terminal'; +import { Direction, ICreateTerminalOptions, IRemoteTerminalService, ITerminalEditorService, ITerminalGroupService, ITerminalInstance, ITerminalInstanceService, ITerminalService } from 'vs/workbench/contrib/terminal/browser/terminal'; import { TerminalQuickAccessProvider } from 'vs/workbench/contrib/terminal/browser/terminalQuickAccess'; import { IRemoteTerminalAttachTarget, ITerminalConfigHelper, KEYBINDING_CONTEXT_TERMINAL_A11Y_TREE_FOCUS, KEYBINDING_CONTEXT_TERMINAL_ALT_BUFFER_ACTIVE, KEYBINDING_CONTEXT_TERMINAL_FIND_FOCUSED, KEYBINDING_CONTEXT_TERMINAL_FIND_NOT_VISIBLE, KEYBINDING_CONTEXT_TERMINAL_FIND_VISIBLE, KEYBINDING_CONTEXT_TERMINAL_FOCUS, KEYBINDING_CONTEXT_TERMINAL_IS_OPEN, KEYBINDING_CONTEXT_TERMINAL_PROCESS_SUPPORTED, KEYBINDING_CONTEXT_TERMINAL_TABS_FOCUS, KEYBINDING_CONTEXT_TERMINAL_TABS_SINGULAR_SELECTION, KEYBINDING_CONTEXT_TERMINAL_TEXT_SELECTED, TerminalCommandId, TerminalLocation, TERMINAL_ACTION_CATEGORY } from 'vs/workbench/contrib/terminal/common/terminal'; import { terminalStrings } from 'vs/workbench/contrib/terminal/common/terminalStrings'; @@ -1440,7 +1440,7 @@ export function registerTerminalActions() { } }); } - async run(accessor: ServicesAccessor, profile?: ITerminalProfile) { + async run(accessor: ServicesAccessor, profile?: ICreateTerminalOptions) { const terminalService = accessor.get(ITerminalService); const commandService = accessor.get(ICommandService); await terminalService.doWithActiveInstance(async t => { @@ -1449,9 +1449,10 @@ export function registerTerminalActions() { return undefined; } if (t.target === TerminalLocation.Editor) { + // TODO: Support creating profiles commandService.executeCommand('workbench.action.splitEditor'); } else { - terminalService.splitInstance(t, profile, cwd); + terminalService.splitInstance(t, profile?.config, cwd); return accessor.get(ITerminalGroupService).showPanel(true); } }); diff --git a/src/vs/workbench/contrib/terminal/browser/terminalEditor.ts b/src/vs/workbench/contrib/terminal/browser/terminalEditor.ts index c1ddc99bc80..377cf4f6efa 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalEditor.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalEditor.ts @@ -22,11 +22,11 @@ import { ITerminalProfile } from 'vs/platform/terminal/common/terminal'; import { IThemeService } from 'vs/platform/theme/common/themeService'; import { EditorPane } from 'vs/workbench/browser/parts/editor/editorPane'; import { IEditorOpenContext } from 'vs/workbench/common/editor'; -import { ITerminalEditorService, ITerminalService } from 'vs/workbench/contrib/terminal/browser/terminal'; +import { ICreateTerminalOptions, ITerminalEditorService, ITerminalService } from 'vs/workbench/contrib/terminal/browser/terminal'; import { TerminalEditorInput } from 'vs/workbench/contrib/terminal/browser/terminalEditorInput'; import { TerminalFindWidget } from 'vs/workbench/contrib/terminal/browser/terminalFindWidget'; import { TerminalTabContextMenuGroup } from 'vs/workbench/contrib/terminal/browser/terminalMenus'; -import { ITerminalProfileResolverService, KEYBINDING_CONTEXT_TERMINAL_FIND_VISIBLE, TerminalCommandId } from 'vs/workbench/contrib/terminal/common/terminal'; +import { ITerminalProfileResolverService, KEYBINDING_CONTEXT_TERMINAL_FIND_VISIBLE, TerminalCommandId, TerminalLocation } from 'vs/workbench/contrib/terminal/common/terminal'; import { ITerminalContributionService } from 'vs/workbench/contrib/terminal/common/terminalExtensionPoints'; import { terminalStrings } from 'vs/workbench/contrib/terminal/common/terminalStrings'; import { IEditorGroup } from 'vs/workbench/services/editor/common/editorGroupsService'; @@ -142,15 +142,20 @@ export class TerminalEditor extends EditorPane { // TODO: Pass in args to create an editor terminal specifically for (const p of profiles) { const isDefault = p.profileName === defaultProfileName; + const arg: ICreateTerminalOptions = { + config: p, + target: TerminalLocation.Editor + }; if (isDefault) { - dropdownActions.unshift(this._instantiationService.createInstance(MenuItemAction, { id: TerminalCommandId.NewWithProfile, title: localize('defaultTerminalProfile', "{0} (Default)", p.profileName), category: TerminalTabContextMenuGroup.Profile }, undefined, { arg: p, shouldForwardArgs: true })); - submenuActions.unshift(this._instantiationService.createInstance(MenuItemAction, { id: TerminalCommandId.Split, title: localize('defaultTerminalProfile', "{0} (Default)", p.profileName), category: TerminalTabContextMenuGroup.Profile }, undefined, { arg: p, shouldForwardArgs: true })); + dropdownActions.unshift(this._instantiationService.createInstance(MenuItemAction, { id: TerminalCommandId.NewWithProfile, title: localize('defaultTerminalProfile', "{0} (Default)", p.profileName), category: TerminalTabContextMenuGroup.Profile }, undefined, { arg, shouldForwardArgs: true })); + submenuActions.unshift(this._instantiationService.createInstance(MenuItemAction, { id: TerminalCommandId.Split, title: localize('defaultTerminalProfile', "{0} (Default)", p.profileName), category: TerminalTabContextMenuGroup.Profile }, undefined, { arg, shouldForwardArgs: true })); } else { - dropdownActions.push(this._instantiationService.createInstance(MenuItemAction, { id: TerminalCommandId.NewWithProfile, title: p.profileName.replace(/[\n\r\t]/g, ''), category: TerminalTabContextMenuGroup.Profile }, undefined, { arg: p, shouldForwardArgs: true })); - submenuActions.push(this._instantiationService.createInstance(MenuItemAction, { id: TerminalCommandId.Split, title: p.profileName.replace(/[\n\r\t]/g, ''), category: TerminalTabContextMenuGroup.Profile }, undefined, { arg: p, shouldForwardArgs: true })); + dropdownActions.push(this._instantiationService.createInstance(MenuItemAction, { id: TerminalCommandId.NewWithProfile, title: p.profileName.replace(/[\n\r\t]/g, ''), category: TerminalTabContextMenuGroup.Profile }, undefined, { arg, shouldForwardArgs: true })); + submenuActions.push(this._instantiationService.createInstance(MenuItemAction, { id: TerminalCommandId.Split, title: p.profileName.replace(/[\n\r\t]/g, ''), category: TerminalTabContextMenuGroup.Profile }, undefined, { arg, shouldForwardArgs: true })); } } + // TODO: Pass in target for (const contributed of this._terminalContributionService.terminalProfiles) { dropdownActions.push(new Action(TerminalCommandId.NewWithProfile, contributed.title.replace(/[\n\r\t]/g, ''), undefined, true, () => this._terminalService.createContributedTerminalProfile(contributed.extensionIdentifier, contributed.id, false))); submenuActions.push(new Action(TerminalCommandId.NewWithProfile, contributed.title.replace(/[\n\r\t]/g, ''), undefined, true, () => this._terminalService.createContributedTerminalProfile(contributed.extensionIdentifier, contributed.id, true))); From 52f57284adef6e05b499fdd832494ed2894ad65d Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Fri, 25 Jun 2021 04:17:12 -0700 Subject: [PATCH 03/17] Support splitting in editor with profile --- .../contrib/terminal/browser/terminal.ts | 1 + .../terminal/browser/terminalActions.ts | 13 ++++-- .../terminal/browser/terminalEditorInput.ts | 11 ++++- .../terminal/browser/terminalEditorService.ts | 2 +- .../browser/terminalInstanceService.ts | 41 ++++++++++++++++--- 5 files changed, 56 insertions(+), 12 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/browser/terminal.ts b/src/vs/workbench/contrib/terminal/browser/terminal.ts index ad6316ee5fd..a5e0d8567be 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminal.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminal.ts @@ -153,6 +153,7 @@ export interface ITerminalService extends ITerminalInstanceHost { /** * Creates a raw terminal instance, this should not be used outside of the terminal part. */ + createInstance(profile: ITerminalProfile): ITerminalInstance; createInstance(shellLaunchConfig: IShellLaunchConfig): ITerminalInstance; getInstanceFromId(terminalId: number): ITerminalInstance | undefined; getInstanceFromIndex(terminalIndex: number): ITerminalInstance; diff --git a/src/vs/workbench/contrib/terminal/browser/terminalActions.ts b/src/vs/workbench/contrib/terminal/browser/terminalActions.ts index 58afec88f76..9c1c0cc8af4 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalActions.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalActions.ts @@ -35,6 +35,7 @@ import { TerminalQuickAccessProvider } from 'vs/workbench/contrib/terminal/brows import { IRemoteTerminalAttachTarget, ITerminalConfigHelper, KEYBINDING_CONTEXT_TERMINAL_A11Y_TREE_FOCUS, KEYBINDING_CONTEXT_TERMINAL_ALT_BUFFER_ACTIVE, KEYBINDING_CONTEXT_TERMINAL_FIND_FOCUSED, KEYBINDING_CONTEXT_TERMINAL_FIND_NOT_VISIBLE, KEYBINDING_CONTEXT_TERMINAL_FIND_VISIBLE, KEYBINDING_CONTEXT_TERMINAL_FOCUS, KEYBINDING_CONTEXT_TERMINAL_IS_OPEN, KEYBINDING_CONTEXT_TERMINAL_PROCESS_SUPPORTED, KEYBINDING_CONTEXT_TERMINAL_TABS_FOCUS, KEYBINDING_CONTEXT_TERMINAL_TABS_SINGULAR_SELECTION, KEYBINDING_CONTEXT_TERMINAL_TEXT_SELECTED, TerminalCommandId, TerminalLocation, TERMINAL_ACTION_CATEGORY } from 'vs/workbench/contrib/terminal/common/terminal'; import { terminalStrings } from 'vs/workbench/contrib/terminal/common/terminalStrings'; import { IConfigurationResolverService } from 'vs/workbench/services/configurationResolver/common/configurationResolver'; +import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { IHistoryService } from 'vs/workbench/services/history/common/history'; import { IPreferencesService } from 'vs/workbench/services/preferences/common/preferences'; import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService'; @@ -1442,15 +1443,21 @@ export function registerTerminalActions() { } async run(accessor: ServicesAccessor, profile?: ICreateTerminalOptions) { const terminalService = accessor.get(ITerminalService); + const terminalEditorService = accessor.get(ITerminalEditorService); const commandService = accessor.get(ICommandService); + const editorService = accessor.get(IEditorService); await terminalService.doWithActiveInstance(async t => { const cwd = await getCwdForSplit(terminalService.configHelper, t, accessor.get(IWorkspaceContextService).getWorkspace().folders, accessor.get(ICommandService)); if (cwd === undefined) { return undefined; } - if (t.target === TerminalLocation.Editor) { - // TODO: Support creating profiles - commandService.executeCommand('workbench.action.splitEditor'); + if ((profile?.target || t.target) === TerminalLocation.Editor) { + const activeResource = editorService.activeEditor?.resource; + if (activeResource) { + const input = terminalEditorService.getOrCreateEditorInput(t); + input.setCopyConfig(profile?.config || {}); + commandService.executeCommand('workbench.action.splitEditor'); + } } else { terminalService.splitInstance(t, profile?.config, cwd); return accessor.get(ITerminalGroupService).showPanel(true); diff --git a/src/vs/workbench/contrib/terminal/browser/terminalEditorInput.ts b/src/vs/workbench/contrib/terminal/browser/terminalEditorInput.ts index c972f400ec5..b155518b0d8 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalEditorInput.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalEditorInput.ts @@ -13,12 +13,14 @@ import { TerminalEditor } from 'vs/workbench/contrib/terminal/browser/terminalEd import { TerminalLocation } from 'vs/workbench/contrib/terminal/common/terminal'; import { getColorClass, getUriClasses } from 'vs/workbench/contrib/terminal/browser/terminalIcon'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; +import { IShellLaunchConfig } from 'vs/platform/terminal/common/terminal'; export class TerminalEditorInput extends EditorInput { static readonly ID = 'workbench.editors.terminal'; private _isDetached = false; + private _copyConfig?: IShellLaunchConfig; override get typeId(): string { return TerminalEditorInput.ID; @@ -29,10 +31,15 @@ export class TerminalEditorInput extends EditorInput { } override copy(): IEditorInput { - const instance = this._terminalInstanceService.createInstance({}, TerminalLocation.Editor); + const instance = this._terminalInstanceService.createInstance(this._copyConfig || {}, TerminalLocation.Editor); + this._copyConfig = undefined; return this._instantiationService.createInstance(TerminalEditorInput, instance); } + setCopyConfig(shellLaunchConfig: IShellLaunchConfig) { + this._copyConfig = shellLaunchConfig; + } + /** * Returns the terminal instance for this input if it has not yet been detached from the input. */ @@ -48,7 +55,7 @@ export class TerminalEditorInput extends EditorInput { private readonly _terminalInstance: ITerminalInstance, @IThemeService private readonly _themeService: IThemeService, @ITerminalInstanceService private readonly _terminalInstanceService: ITerminalInstanceService, - private readonly _instantiationService: IInstantiationService + @IInstantiationService private readonly _instantiationService: IInstantiationService ) { super(); this._register(this._terminalInstance.onTitleChanged(() => this._onDidChangeLabel.fire())); diff --git a/src/vs/workbench/contrib/terminal/browser/terminalEditorService.ts b/src/vs/workbench/contrib/terminal/browser/terminalEditorService.ts index f008d5eae96..4e46833eab4 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalEditorService.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalEditorService.ts @@ -125,7 +125,7 @@ export class TerminalEditorService extends Disposable implements ITerminalEditor }); } - getOrCreateEditorInput(instance: ITerminalInstance | SerializedTerminalEditorInput): TerminalEditorInput { + getOrCreateEditorInput(instance: ITerminalInstance | SerializedTerminalEditorInput, isFutureSplit: boolean = false): TerminalEditorInput { let cachedEditor; if ('id' in instance) { cachedEditor = this._editorInputs.get(instance.id); diff --git a/src/vs/workbench/contrib/terminal/browser/terminalInstanceService.ts b/src/vs/workbench/contrib/terminal/browser/terminalInstanceService.ts index 64f19777902..49a8caf1585 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalInstanceService.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalInstanceService.ts @@ -10,7 +10,7 @@ import type { Unicode11Addon as XTermUnicode11Addon } from 'xterm-addon-unicode1 import type { WebglAddon as XTermWebglAddon } from 'xterm-addon-webgl'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { Disposable } from 'vs/base/common/lifecycle'; -import { ILocalTerminalService, IShellLaunchConfig, TerminalShellType, WindowsShellType } from 'vs/platform/terminal/common/terminal'; +import { ILocalTerminalService, IShellLaunchConfig, ITerminalProfile, TerminalShellType, WindowsShellType } from 'vs/platform/terminal/common/terminal'; import { IInstantiationService, optional } from 'vs/platform/instantiation/common/instantiation'; import { escapeNonWindowsPath } from 'vs/platform/terminal/common/terminalEnvironment'; import { basename } from 'vs/base/common/path'; @@ -19,6 +19,7 @@ import { TerminalInstance } from 'vs/workbench/contrib/terminal/browser/terminal import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { TerminalConfigHelper } from 'vs/workbench/contrib/terminal/browser/terminalConfigHelper'; import { KEYBINDING_CONTEXT_TERMINAL_FOCUS, KEYBINDING_CONTEXT_TERMINAL_SHELL_TYPE, KEYBINDING_CONTEXT_TERMINAL_ALT_BUFFER_ACTIVE, TerminalLocation } from 'vs/workbench/contrib/terminal/common/terminal'; +import { URI } from 'vs/base/common/uri'; let Terminal: typeof XTermTerminal; let SearchAddon: typeof XTermSearchAddon; @@ -47,20 +48,48 @@ export class TerminalInstanceService extends Disposable implements ITerminalInst this._configHelper = _instantiationService.createInstance(TerminalConfigHelper); } - createInstance(launchConfig: IShellLaunchConfig, target?: TerminalLocation): ITerminalInstance { + createInstance(profile: ITerminalProfile, target?: TerminalLocation): ITerminalInstance; + createInstance(shellLaunchConfig: IShellLaunchConfig, target?: TerminalLocation): ITerminalInstance; + createInstance(config: IShellLaunchConfig | ITerminalProfile, target?: TerminalLocation): ITerminalInstance { + const shellLaunchConfig = this._convertProfileToShellLaunchConfig(config); const instance = this._instantiationService.createInstance(TerminalInstance, this._terminalFocusContextKey, this._terminalShellTypeContextKey, this._terminalAltBufferActiveContextKey, this._configHelper, - launchConfig + shellLaunchConfig ); - if (target) { - instance.target = TerminalLocation.Editor; - } + instance.target = target; return instance; } + private _convertProfileToShellLaunchConfig(shellLaunchConfigOrProfile?: IShellLaunchConfig | ITerminalProfile, cwd?: string | URI): IShellLaunchConfig { + // Profile was provided + if (shellLaunchConfigOrProfile && 'profileName' in shellLaunchConfigOrProfile) { + const profile = shellLaunchConfigOrProfile; + return { + executable: profile.path, + args: profile.args, + env: profile.env, + icon: profile.icon, + color: profile.color, + name: profile.overrideName ? profile.profileName : undefined, + cwd + }; + } + + // Shell launch config was provided + if (shellLaunchConfigOrProfile) { + if (cwd) { + shellLaunchConfigOrProfile.cwd = cwd; + } + return shellLaunchConfigOrProfile; + } + + // Return empty shell launch config + return {}; + } + async getXtermConstructor(): Promise { if (!Terminal) { Terminal = (await import('xterm')).Terminal; From 062c3324c2a382a4b7506c2c444c4e1f598ba823 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Fri, 25 Jun 2021 04:33:21 -0700 Subject: [PATCH 04/17] Add configure options to editor dropdown --- .../terminal/browser/terminalActions.ts | 23 ++++++++++++------- .../terminal/browser/terminalEditor.ts | 23 +++++++++++-------- 2 files changed, 29 insertions(+), 17 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/browser/terminalActions.ts b/src/vs/workbench/contrib/terminal/browser/terminalActions.ts index 9c1c0cc8af4..abdf66f637e 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalActions.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalActions.ts @@ -142,12 +142,17 @@ export function registerTerminalActions() { }, }); } - async run(accessor: ServicesAccessor, eventOrProfile: unknown | ITerminalProfile, profile?: ITerminalProfile) { + async run(accessor: ServicesAccessor, eventOrOptions: unknown | ICreateTerminalOptions | ITerminalProfile | undefined, profile?: ITerminalProfile) { let event: MouseEvent | undefined; - if (eventOrProfile && typeof eventOrProfile === 'object' && 'profileName' in eventOrProfile) { - profile = eventOrProfile as ITerminalProfile; - } else { - event = eventOrProfile as MouseEvent; + let options: ICreateTerminalOptions = { config: profile }; + if (eventOrOptions && typeof eventOrOptions === 'object' && eventOrOptions !== null) { + if ('profileName' in eventOrOptions) { + options.config = eventOrOptions as ITerminalProfile; + } else if ('target' in eventOrOptions || 'config' in eventOrOptions || 'cwd' in eventOrOptions) { + options = eventOrOptions as ICreateTerminalOptions; + } else { + event = eventOrOptions as MouseEvent | undefined; + } } const terminalService = accessor.get(ITerminalService); const workspaceContextService = accessor.get(IWorkspaceContextService); @@ -157,7 +162,8 @@ export function registerTerminalActions() { const activeInstance = terminalService.activeInstance; if (activeInstance) { const cwd = await getCwdForSplit(terminalService.configHelper, activeInstance); - terminalService.splitInstance(activeInstance, profile, cwd); + // TODO: Support split in editor + terminalService.splitInstance(activeInstance, options.config, cwd); return; } } @@ -178,9 +184,10 @@ export function registerTerminalActions() { cwd = workspace.uri; } - if (profile) { - instance = terminalService.createTerminal({ config: profile, cwd }); + if ('config' in options) { + instance = terminalService.createTerminal(options); } else { + // TODO: Fix instance = await terminalService.showProfileQuickPick('createInstance', cwd); } diff --git a/src/vs/workbench/contrib/terminal/browser/terminalEditor.ts b/src/vs/workbench/contrib/terminal/browser/terminalEditor.ts index 377cf4f6efa..35ded72fa0a 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalEditor.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalEditor.ts @@ -11,7 +11,7 @@ import { Codicon } from 'vs/base/common/codicons'; import { FindReplaceState } from 'vs/editor/contrib/find/findState'; import { localize } from 'vs/nls'; import { DropdownWithPrimaryActionViewItem } from 'vs/platform/actions/browser/dropdownWithPrimaryActionViewItem'; -import { MenuItemAction } from 'vs/platform/actions/common/actions'; +import { IMenu, IMenuService, MenuId, MenuItemAction } from 'vs/platform/actions/common/actions'; import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; import { IEditorOptions } from 'vs/platform/editor/common/editor'; @@ -44,6 +44,8 @@ export class TerminalEditor extends EditorPane { private _lastDimension?: Dimension; + private readonly _dropdownMenu: IMenu; + private _findWidget: TerminalFindWidget; private _findWidgetVisible: IContextKey; private _findState: FindReplaceState; @@ -60,6 +62,7 @@ export class TerminalEditor extends EditorPane { @ITerminalService private readonly _terminalService: ITerminalService, @IInstantiationService instantiationService: IInstantiationService, @IContextKeyService contextKeyService: IContextKeyService, + @IMenuService menuService: IMenuService, @IInstantiationService private readonly _instantiationService: IInstantiationService, @IContextMenuService private readonly _contextMenuService: IContextMenuService, ) { @@ -67,6 +70,7 @@ export class TerminalEditor extends EditorPane { this._findState = new FindReplaceState(); this._findWidget = instantiationService.createInstance(TerminalFindWidget, this._findState); this._findWidgetVisible = KEYBINDING_CONTEXT_TERMINAL_FIND_VISIBLE.bindTo(contextKeyService); + this._dropdownMenu = this._register(menuService.createMenu(MenuId.TerminalNewDropdownContext, contextKeyService)); } override async setInput(newInput: TerminalEditorInput, options: IEditorOptions | undefined, context: IEditorOpenContext, token: CancellationToken) { @@ -156,6 +160,7 @@ export class TerminalEditor extends EditorPane { } // TODO: Pass in target + // TODO: Fix contributed for (const contributed of this._terminalContributionService.terminalProfiles) { dropdownActions.push(new Action(TerminalCommandId.NewWithProfile, contributed.title.replace(/[\n\r\t]/g, ''), undefined, true, () => this._terminalService.createContributedTerminalProfile(contributed.extensionIdentifier, contributed.id, false))); submenuActions.push(new Action(TerminalCommandId.NewWithProfile, contributed.title.replace(/[\n\r\t]/g, ''), undefined, true, () => this._terminalService.createContributedTerminalProfile(contributed.extensionIdentifier, contributed.id, true))); @@ -166,14 +171,14 @@ export class TerminalEditor extends EditorPane { dropdownActions.push(new Separator()); } - // for (const [, configureActions] of this._dropdownMenu.getActions()) { - // for (const action of configureActions) { - // // make sure the action is a MenuItemAction - // if ('alt' in action) { - // dropdownActions.push(action); - // } - // } - // } + for (const [, configureActions] of this._dropdownMenu.getActions()) { + for (const action of configureActions) { + // make sure the action is a MenuItemAction + if ('alt' in action) { + dropdownActions.push(action); + } + } + } const primaryAction = this._instantiationService.createInstance( MenuItemAction, From c4f332d5e642cd702e79ff74489095f6eda536dd Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Fri, 25 Jun 2021 05:24:37 -0700 Subject: [PATCH 05/17] Fix icons coming through as strings not codicons --- src/vs/platform/terminal/common/terminal.ts | 2 +- src/vs/platform/terminal/node/terminalProfiles.ts | 13 ++++++++++--- .../contrib/terminal/browser/terminalActions.ts | 14 ++++++++------ .../contrib/terminal/browser/terminalEditor.ts | 15 ++++++--------- 4 files changed, 25 insertions(+), 19 deletions(-) diff --git a/src/vs/platform/terminal/common/terminal.ts b/src/vs/platform/terminal/common/terminal.ts index c6644120aac..998eb37cfd9 100644 --- a/src/vs/platform/terminal/common/terminal.ts +++ b/src/vs/platform/terminal/common/terminal.ts @@ -594,7 +594,7 @@ export interface IBaseUnresolvedTerminalProfile { args?: string | string[] | undefined; isAutoDetected?: boolean; overrideName?: boolean; - icon?: ThemeIcon | URI | { light: URI, dark: URI }; + icon?: string | ThemeIcon | URI | { light: URI, dark: URI }; color?: string; env?: ITerminalEnvironment; } diff --git a/src/vs/platform/terminal/node/terminalProfiles.ts b/src/vs/platform/terminal/node/terminalProfiles.ts index 6f9b221b428..ebb842c80fb 100644 --- a/src/vs/platform/terminal/node/terminalProfiles.ts +++ b/src/vs/platform/terminal/node/terminalProfiles.ts @@ -9,7 +9,7 @@ import { findExecutable, getWindowsBuildNumber } from 'vs/platform/terminal/node import * as cp from 'child_process'; import { ILogService } from 'vs/platform/log/common/log'; import * as pfs from 'vs/base/node/pfs'; -import { ITerminalEnvironment, ITerminalProfile, ITerminalProfileObject, ProfileSource, TerminalSettingId } from 'vs/platform/terminal/common/terminal'; +import { ITerminalEnvironment, ITerminalProfile, ITerminalProfileObject, ProfileSource, TerminalIcon, TerminalSettingId } from 'vs/platform/terminal/common/terminal'; import { Codicon } from 'vs/base/common/codicons'; import { isLinux, isWindows } from 'vs/base/common/platform'; import { ThemeIcon } from 'vs/platform/theme/common/themeService'; @@ -156,14 +156,14 @@ async function transformToTerminalProfiles( // if there are configured args, override the default ones args = profile.args || source.args; if (profile.icon) { - icon = profile.icon; + icon = validateIcon(profile.icon); } else if (source.icon) { icon = source.icon; } } else { originalPaths = Array.isArray(profile.path) ? profile.path : [profile.path]; args = isWindows ? profile.args : Array.isArray(profile.args) ? profile.args : undefined; - icon = profile.icon || undefined; + icon = validateIcon(profile.icon) || undefined; } const paths = (await variableResolver?.(originalPaths)) || originalPaths.slice(); @@ -180,6 +180,13 @@ async function transformToTerminalProfiles( return resultProfiles; } +function validateIcon(icon: string | TerminalIcon | undefined): TerminalIcon | undefined { + if (typeof icon === 'string') { + return { id: icon }; + } + return icon; +} + async function initializeWindowsProfiles(testPwshSourcePaths?: string[]): Promise { if (profileSources && !testPwshSourcePaths) { return; diff --git a/src/vs/workbench/contrib/terminal/browser/terminalActions.ts b/src/vs/workbench/contrib/terminal/browser/terminalActions.ts index abdf66f637e..5663ba03ac4 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalActions.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalActions.ts @@ -144,10 +144,10 @@ export function registerTerminalActions() { } async run(accessor: ServicesAccessor, eventOrOptions: unknown | ICreateTerminalOptions | ITerminalProfile | undefined, profile?: ITerminalProfile) { let event: MouseEvent | undefined; - let options: ICreateTerminalOptions = { config: profile }; + let options: ICreateTerminalOptions | undefined = profile ? { config: profile } : undefined; if (eventOrOptions && typeof eventOrOptions === 'object' && eventOrOptions !== null) { if ('profileName' in eventOrOptions) { - options.config = eventOrOptions as ITerminalProfile; + options = { config: eventOrOptions as ITerminalProfile }; } else if ('target' in eventOrOptions || 'config' in eventOrOptions || 'cwd' in eventOrOptions) { options = eventOrOptions as ICreateTerminalOptions; } else { @@ -155,6 +155,7 @@ export function registerTerminalActions() { } } const terminalService = accessor.get(ITerminalService); + const terminalGroupService = accessor.get(ITerminalGroupService); const workspaceContextService = accessor.get(IWorkspaceContextService); const commandService = accessor.get(ICommandService); const folders = workspaceContextService.getWorkspace().folders; @@ -163,7 +164,7 @@ export function registerTerminalActions() { if (activeInstance) { const cwd = await getCwdForSplit(terminalService.configHelper, activeInstance); // TODO: Support split in editor - terminalService.splitInstance(activeInstance, options.config, cwd); + terminalService.splitInstance(activeInstance, options?.config, cwd); return; } } @@ -184,10 +185,11 @@ export function registerTerminalActions() { cwd = workspace.uri; } - if ('config' in options) { + if (options) { instance = terminalService.createTerminal(options); } else { - // TODO: Fix + // TODO: Support target + // TODO: Fix alt+click instance = await terminalService.showProfileQuickPick('createInstance', cwd); } @@ -195,7 +197,7 @@ export function registerTerminalActions() { terminalService.setActiveInstance(instance); } } - await accessor.get(ITerminalGroupService).showPanel(true); + await terminalGroupService.showPanel(true); } }); diff --git a/src/vs/workbench/contrib/terminal/browser/terminalEditor.ts b/src/vs/workbench/contrib/terminal/browser/terminalEditor.ts index 35ded72fa0a..4d17ac3d9c2 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalEditor.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalEditor.ts @@ -27,7 +27,6 @@ import { TerminalEditorInput } from 'vs/workbench/contrib/terminal/browser/termi import { TerminalFindWidget } from 'vs/workbench/contrib/terminal/browser/terminalFindWidget'; import { TerminalTabContextMenuGroup } from 'vs/workbench/contrib/terminal/browser/terminalMenus'; import { ITerminalProfileResolverService, KEYBINDING_CONTEXT_TERMINAL_FIND_VISIBLE, TerminalCommandId, TerminalLocation } from 'vs/workbench/contrib/terminal/common/terminal'; -import { ITerminalContributionService } from 'vs/workbench/contrib/terminal/common/terminalExtensionPoints'; import { terminalStrings } from 'vs/workbench/contrib/terminal/common/terminalStrings'; import { IEditorGroup } from 'vs/workbench/services/editor/common/editorGroupsService'; @@ -58,7 +57,7 @@ export class TerminalEditor extends EditorPane { @IStorageService storageService: IStorageService, @ITerminalEditorService private readonly _terminalEditorService: ITerminalEditorService, @ITerminalProfileResolverService private readonly _terminalProfileResolverService: ITerminalProfileResolverService, - @ITerminalContributionService private readonly _terminalContributionService: ITerminalContributionService, + // @ITerminalContributionService private readonly _terminalContributionService: ITerminalContributionService, @ITerminalService private readonly _terminalService: ITerminalService, @IInstantiationService instantiationService: IInstantiationService, @IContextKeyService contextKeyService: IContextKeyService, @@ -143,7 +142,6 @@ export class TerminalEditor extends EditorPane { const submenuActions: IAction[] = []; const defaultProfileName = this._terminalProfileResolverService.defaultProfileName; - // TODO: Pass in args to create an editor terminal specifically for (const p of profiles) { const isDefault = p.profileName === defaultProfileName; const arg: ICreateTerminalOptions = { @@ -159,12 +157,11 @@ export class TerminalEditor extends EditorPane { } } - // TODO: Pass in target - // TODO: Fix contributed - for (const contributed of this._terminalContributionService.terminalProfiles) { - dropdownActions.push(new Action(TerminalCommandId.NewWithProfile, contributed.title.replace(/[\n\r\t]/g, ''), undefined, true, () => this._terminalService.createContributedTerminalProfile(contributed.extensionIdentifier, contributed.id, false))); - submenuActions.push(new Action(TerminalCommandId.NewWithProfile, contributed.title.replace(/[\n\r\t]/g, ''), undefined, true, () => this._terminalService.createContributedTerminalProfile(contributed.extensionIdentifier, contributed.id, true))); - } + // TODO: Support contributed profiles with editor target + // for (const contributed of this._terminalContributionService.terminalProfiles) { + // dropdownActions.push(new Action(TerminalCommandId.NewWithProfile, contributed.title.replace(/[\n\r\t]/g, ''), undefined, true, () => this._terminalService.createContributedTerminalProfile(contributed.extensionIdentifier, contributed.id, false))); + // submenuActions.push(new Action(TerminalCommandId.NewWithProfile, contributed.title.replace(/[\n\r\t]/g, ''), undefined, true, () => this._terminalService.createContributedTerminalProfile(contributed.extensionIdentifier, contributed.id, true))); + // } if (dropdownActions.length > 0) { dropdownActions.push(new SubmenuAction('split.profile', 'Split...', submenuActions)); From af31cacb72d56a74a3294922d1f040e451b39389 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Fri, 25 Jun 2021 05:29:36 -0700 Subject: [PATCH 06/17] Fix split with profile in panel --- .../contrib/terminal/browser/terminalActions.ts | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/browser/terminalActions.ts b/src/vs/workbench/contrib/terminal/browser/terminalActions.ts index 5663ba03ac4..ec6d9c184d3 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalActions.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalActions.ts @@ -1450,25 +1450,31 @@ export function registerTerminalActions() { } }); } - async run(accessor: ServicesAccessor, profile?: ICreateTerminalOptions) { + async run(accessor: ServicesAccessor, optionsOrProfile?: ICreateTerminalOptions | ITerminalProfile) { const terminalService = accessor.get(ITerminalService); const terminalEditorService = accessor.get(ITerminalEditorService); const commandService = accessor.get(ICommandService); const editorService = accessor.get(IEditorService); + let options: ICreateTerminalOptions | undefined; + if (typeof optionsOrProfile === 'object' && 'profileName' in optionsOrProfile) { + options = { config: optionsOrProfile as ITerminalProfile }; + } else { + options = optionsOrProfile; + } await terminalService.doWithActiveInstance(async t => { const cwd = await getCwdForSplit(terminalService.configHelper, t, accessor.get(IWorkspaceContextService).getWorkspace().folders, accessor.get(ICommandService)); if (cwd === undefined) { return undefined; } - if ((profile?.target || t.target) === TerminalLocation.Editor) { + if ((options?.target || t.target) === TerminalLocation.Editor) { const activeResource = editorService.activeEditor?.resource; if (activeResource) { const input = terminalEditorService.getOrCreateEditorInput(t); - input.setCopyConfig(profile?.config || {}); + input.setCopyConfig(options?.config || {}); commandService.executeCommand('workbench.action.splitEditor'); } } else { - terminalService.splitInstance(t, profile?.config, cwd); + terminalService.splitInstance(t, options?.config, cwd); return accessor.get(ITerminalGroupService).showPanel(true); } }); From f20eceb458fc254ef470127a48e33f890ae4ffdc Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Fri, 25 Jun 2021 05:34:59 -0700 Subject: [PATCH 07/17] Tidy up options or profile validation --- .../terminal/browser/terminalActions.ts | 37 ++++++++++--------- 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/browser/terminalActions.ts b/src/vs/workbench/contrib/terminal/browser/terminalActions.ts index ec6d9c184d3..8635cca42b3 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalActions.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalActions.ts @@ -142,22 +142,21 @@ export function registerTerminalActions() { }, }); } - async run(accessor: ServicesAccessor, eventOrOptions: unknown | ICreateTerminalOptions | ITerminalProfile | undefined, profile?: ITerminalProfile) { - let event: MouseEvent | undefined; - let options: ICreateTerminalOptions | undefined = profile ? { config: profile } : undefined; - if (eventOrOptions && typeof eventOrOptions === 'object' && eventOrOptions !== null) { - if ('profileName' in eventOrOptions) { - options = { config: eventOrOptions as ITerminalProfile }; - } else if ('target' in eventOrOptions || 'config' in eventOrOptions || 'cwd' in eventOrOptions) { - options = eventOrOptions as ICreateTerminalOptions; - } else { - event = eventOrOptions as MouseEvent | undefined; - } - } + async run(accessor: ServicesAccessor, eventOrOptionsOrProfile: MouseEvent | ICreateTerminalOptions | ITerminalProfile | undefined, profile?: ITerminalProfile) { const terminalService = accessor.get(ITerminalService); const terminalGroupService = accessor.get(ITerminalGroupService); const workspaceContextService = accessor.get(IWorkspaceContextService); const commandService = accessor.get(ICommandService); + + let event: MouseEvent | undefined; + let options: ICreateTerminalOptions | undefined; + if (eventOrOptionsOrProfile && typeof eventOrOptionsOrProfile === 'object' && 'altKey' in eventOrOptionsOrProfile) { + event = eventOrOptionsOrProfile as MouseEvent; + options = profile ? { config: profile } : undefined; + } else { + options = convertOptionsOrProfileToOptions(eventOrOptionsOrProfile); + } + const folders = workspaceContextService.getWorkspace().folders; if (event instanceof MouseEvent && (event.altKey || event.ctrlKey)) { const activeInstance = terminalService.activeInstance; @@ -1455,12 +1454,7 @@ export function registerTerminalActions() { const terminalEditorService = accessor.get(ITerminalEditorService); const commandService = accessor.get(ICommandService); const editorService = accessor.get(IEditorService); - let options: ICreateTerminalOptions | undefined; - if (typeof optionsOrProfile === 'object' && 'profileName' in optionsOrProfile) { - options = { config: optionsOrProfile as ITerminalProfile }; - } else { - options = optionsOrProfile; - } + const options = convertOptionsOrProfileToOptions(optionsOrProfile); await terminalService.doWithActiveInstance(async t => { const cwd = await getCwdForSplit(terminalService.configHelper, t, accessor.get(IWorkspaceContextService).getWorkspace().folders, accessor.get(ICommandService)); if (cwd === undefined) { @@ -1965,3 +1959,10 @@ export function validateTerminalName(name: string): { content: string, severity: return null; } + +function convertOptionsOrProfileToOptions(optionsOrProfile?: ICreateTerminalOptions | ITerminalProfile): ICreateTerminalOptions | undefined { + if (typeof optionsOrProfile === 'object' && 'profileName' in optionsOrProfile) { + return { config: optionsOrProfile as ITerminalProfile }; + } + return optionsOrProfile; +} From ada9e8c66c049b62051416661f0a72f7a583e3f0 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Fri, 25 Jun 2021 06:07:15 -0700 Subject: [PATCH 08/17] Use correct instance host for split submenu --- .../contrib/terminal/browser/terminal.ts | 1 + .../terminal/browser/terminalActions.ts | 67 ++++++++++++------- .../terminal/browser/terminalEditor.ts | 20 +++--- .../terminal/browser/terminalEditorInput.ts | 11 ++- .../terminal/browser/terminalEditorService.ts | 15 ++++- .../terminal/browser/terminalService.ts | 25 +++++-- .../contrib/terminal/browser/terminalView.ts | 22 ++++-- 7 files changed, 108 insertions(+), 53 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/browser/terminal.ts b/src/vs/workbench/contrib/terminal/browser/terminal.ts index a5e0d8567be..4538af4be37 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminal.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminal.ts @@ -215,6 +215,7 @@ export interface ITerminalEditorService extends ITerminalInstanceHost, ITerminal getOrCreateEditorInput(instance: ITerminalInstance | SerializedTerminalEditorInput): TerminalEditorInput; detachActiveEditorInstance(): ITerminalInstance; detachInstance(instance: ITerminalInstance): void; + splitInstance(instanceToSplit: ITerminalInstance, shellLaunchConfig?: IShellLaunchConfig): ITerminalInstance; } /** diff --git a/src/vs/workbench/contrib/terminal/browser/terminalActions.ts b/src/vs/workbench/contrib/terminal/browser/terminalActions.ts index 8635cca42b3..03b6ae2d8b4 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalActions.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalActions.ts @@ -30,12 +30,11 @@ import { ILocalTerminalService, ITerminalProfile, TerminalSettingId, TitleEventS import { IWorkspaceContextService, IWorkspaceFolder } from 'vs/platform/workspace/common/workspace'; import { PICK_WORKSPACE_FOLDER_COMMAND_ID } from 'vs/workbench/browser/actions/workspaceCommands'; import { FindInFilesCommand, IFindInFilesArgs } from 'vs/workbench/contrib/search/browser/searchActions'; -import { Direction, ICreateTerminalOptions, IRemoteTerminalService, ITerminalEditorService, ITerminalGroupService, ITerminalInstance, ITerminalInstanceService, ITerminalService } from 'vs/workbench/contrib/terminal/browser/terminal'; +import { Direction, ICreateTerminalOptions, IRemoteTerminalService, ITerminalEditorService, ITerminalGroupService, ITerminalInstance, ITerminalInstanceHost, ITerminalInstanceService, ITerminalService } from 'vs/workbench/contrib/terminal/browser/terminal'; import { TerminalQuickAccessProvider } from 'vs/workbench/contrib/terminal/browser/terminalQuickAccess'; import { IRemoteTerminalAttachTarget, ITerminalConfigHelper, KEYBINDING_CONTEXT_TERMINAL_A11Y_TREE_FOCUS, KEYBINDING_CONTEXT_TERMINAL_ALT_BUFFER_ACTIVE, KEYBINDING_CONTEXT_TERMINAL_FIND_FOCUSED, KEYBINDING_CONTEXT_TERMINAL_FIND_NOT_VISIBLE, KEYBINDING_CONTEXT_TERMINAL_FIND_VISIBLE, KEYBINDING_CONTEXT_TERMINAL_FOCUS, KEYBINDING_CONTEXT_TERMINAL_IS_OPEN, KEYBINDING_CONTEXT_TERMINAL_PROCESS_SUPPORTED, KEYBINDING_CONTEXT_TERMINAL_TABS_FOCUS, KEYBINDING_CONTEXT_TERMINAL_TABS_SINGULAR_SELECTION, KEYBINDING_CONTEXT_TERMINAL_TEXT_SELECTED, TerminalCommandId, TerminalLocation, TERMINAL_ACTION_CATEGORY } from 'vs/workbench/contrib/terminal/common/terminal'; import { terminalStrings } from 'vs/workbench/contrib/terminal/common/terminalStrings'; import { IConfigurationResolverService } from 'vs/workbench/services/configurationResolver/common/configurationResolver'; -import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { IHistoryService } from 'vs/workbench/services/history/common/history'; import { IPreferencesService } from 'vs/workbench/services/preferences/common/preferences'; import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService'; @@ -148,17 +147,17 @@ export function registerTerminalActions() { const workspaceContextService = accessor.get(IWorkspaceContextService); const commandService = accessor.get(ICommandService); - let event: MouseEvent | undefined; + let event: MouseEvent | PointerEvent | KeyboardEvent | undefined; let options: ICreateTerminalOptions | undefined; - if (eventOrOptionsOrProfile && typeof eventOrOptionsOrProfile === 'object' && 'altKey' in eventOrOptionsOrProfile) { - event = eventOrOptionsOrProfile as MouseEvent; + if (eventOrOptionsOrProfile instanceof MouseEvent || eventOrOptionsOrProfile instanceof PointerEvent || eventOrOptionsOrProfile instanceof KeyboardEvent) { + event = eventOrOptionsOrProfile; options = profile ? { config: profile } : undefined; } else { options = convertOptionsOrProfileToOptions(eventOrOptionsOrProfile); } const folders = workspaceContextService.getWorkspace().folders; - if (event instanceof MouseEvent && (event.altKey || event.ctrlKey)) { + if (event && (event.altKey || event.ctrlKey)) { const activeInstance = terminalService.activeInstance; if (activeInstance) { const cwd = await getCwdForSplit(terminalService.configHelper, activeInstance); @@ -1450,28 +1449,48 @@ export function registerTerminalActions() { }); } async run(accessor: ServicesAccessor, optionsOrProfile?: ICreateTerminalOptions | ITerminalProfile) { - const terminalService = accessor.get(ITerminalService); - const terminalEditorService = accessor.get(ITerminalEditorService); const commandService = accessor.get(ICommandService); - const editorService = accessor.get(IEditorService); + const terminalGroupService = accessor.get(ITerminalGroupService); + const terminalService = accessor.get(ITerminalService); + const workspaceContextService = accessor.get(IWorkspaceContextService); + const terminalEditorService = accessor.get(ITerminalEditorService); + // const editorService = accessor.get(IEditorService); const options = convertOptionsOrProfileToOptions(optionsOrProfile); - await terminalService.doWithActiveInstance(async t => { - const cwd = await getCwdForSplit(terminalService.configHelper, t, accessor.get(IWorkspaceContextService).getWorkspace().folders, accessor.get(ICommandService)); - if (cwd === undefined) { - return undefined; - } - if ((options?.target || t.target) === TerminalLocation.Editor) { - const activeResource = editorService.activeEditor?.resource; - if (activeResource) { - const input = terminalEditorService.getOrCreateEditorInput(t); - input.setCopyConfig(options?.config || {}); - commandService.executeCommand('workbench.action.splitEditor'); - } + // let activeInstance: ITerminalInstance; + let instanceHost: ITerminalInstanceHost; + if (options?.target) { + if (options.target === TerminalLocation.Editor) { + instanceHost = terminalEditorService; } else { - terminalService.splitInstance(t, options?.config, cwd); - return accessor.get(ITerminalGroupService).showPanel(true); + instanceHost = terminalGroupService; } - }); + } else { + instanceHost = terminalService; + } + const activeInstance = instanceHost.activeInstance; + if (!activeInstance) { + return; + } + const cwd = await getCwdForSplit(terminalService.configHelper, activeInstance, workspaceContextService.getWorkspace().folders, commandService); + if (cwd === undefined) { + return undefined; + } + const instance = terminalService.splitInstance(activeInstance, options?.config, cwd); + if (instance?.target !== TerminalLocation.Editor) { + return terminalGroupService.showPanel(true); + } + // if ((options?.target || t.target) === TerminalLocation.Editor) { + // const activeResource = editorService.activeEditor?.resource; + // if (activeResource) { + // const input = terminalEditorService.getOrCreateEditorInput(t); + // const instance = terminalService.createInstance(options?.config || {}); + // input.setCopyConfig(options?.config || {}); + // commandService.executeCommand('workbench.action.splitEditor'); + // } + // } else { + // terminalService.splitInstance(t, options?.config, cwd); + // return accessor.get(ITerminalGroupService).showPanel(true); + // } } }); registerAction2(class extends Action2 { diff --git a/src/vs/workbench/contrib/terminal/browser/terminalEditor.ts b/src/vs/workbench/contrib/terminal/browser/terminalEditor.ts index 4d17ac3d9c2..cc45153b075 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalEditor.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalEditor.ts @@ -11,7 +11,7 @@ import { Codicon } from 'vs/base/common/codicons'; import { FindReplaceState } from 'vs/editor/contrib/find/findState'; import { localize } from 'vs/nls'; import { DropdownWithPrimaryActionViewItem } from 'vs/platform/actions/browser/dropdownWithPrimaryActionViewItem'; -import { IMenu, IMenuService, MenuId, MenuItemAction } from 'vs/platform/actions/common/actions'; +import { IMenu, IMenuActionOptions, IMenuService, MenuId, MenuItemAction } from 'vs/platform/actions/common/actions'; import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; import { IEditorOptions } from 'vs/platform/editor/common/editor'; @@ -117,6 +117,7 @@ export class TerminalEditor extends EditorPane { override getActionViewItem(action: IAction): IActionViewItem | undefined { switch (action.id) { + // TODO: Pass target arg to split command case TerminalCommandId.CreateWithProfileButton: { // if (this._tabButtons) { // this._tabButtons.dispose(); @@ -144,16 +145,19 @@ export class TerminalEditor extends EditorPane { const defaultProfileName = this._terminalProfileResolverService.defaultProfileName; for (const p of profiles) { const isDefault = p.profileName === defaultProfileName; - const arg: ICreateTerminalOptions = { - config: p, - target: TerminalLocation.Editor + const options: IMenuActionOptions = { + arg: { + config: p, + target: TerminalLocation.Editor + } as ICreateTerminalOptions, + shouldForwardArgs: true }; if (isDefault) { - dropdownActions.unshift(this._instantiationService.createInstance(MenuItemAction, { id: TerminalCommandId.NewWithProfile, title: localize('defaultTerminalProfile', "{0} (Default)", p.profileName), category: TerminalTabContextMenuGroup.Profile }, undefined, { arg, shouldForwardArgs: true })); - submenuActions.unshift(this._instantiationService.createInstance(MenuItemAction, { id: TerminalCommandId.Split, title: localize('defaultTerminalProfile', "{0} (Default)", p.profileName), category: TerminalTabContextMenuGroup.Profile }, undefined, { arg, shouldForwardArgs: true })); + dropdownActions.unshift(this._instantiationService.createInstance(MenuItemAction, { id: TerminalCommandId.NewWithProfile, title: localize('defaultTerminalProfile', "{0} (Default)", p.profileName), category: TerminalTabContextMenuGroup.Profile }, undefined, options)); + submenuActions.unshift(this._instantiationService.createInstance(MenuItemAction, { id: TerminalCommandId.Split, title: localize('defaultTerminalProfile', "{0} (Default)", p.profileName), category: TerminalTabContextMenuGroup.Profile }, undefined, options)); } else { - dropdownActions.push(this._instantiationService.createInstance(MenuItemAction, { id: TerminalCommandId.NewWithProfile, title: p.profileName.replace(/[\n\r\t]/g, ''), category: TerminalTabContextMenuGroup.Profile }, undefined, { arg, shouldForwardArgs: true })); - submenuActions.push(this._instantiationService.createInstance(MenuItemAction, { id: TerminalCommandId.Split, title: p.profileName.replace(/[\n\r\t]/g, ''), category: TerminalTabContextMenuGroup.Profile }, undefined, { arg, shouldForwardArgs: true })); + dropdownActions.push(this._instantiationService.createInstance(MenuItemAction, { id: TerminalCommandId.NewWithProfile, title: p.profileName.replace(/[\n\r\t]/g, ''), category: TerminalTabContextMenuGroup.Profile }, undefined, options)); + submenuActions.push(this._instantiationService.createInstance(MenuItemAction, { id: TerminalCommandId.Split, title: p.profileName.replace(/[\n\r\t]/g, ''), category: TerminalTabContextMenuGroup.Profile }, undefined, options)); } } diff --git a/src/vs/workbench/contrib/terminal/browser/terminalEditorInput.ts b/src/vs/workbench/contrib/terminal/browser/terminalEditorInput.ts index b155518b0d8..477c4c23f49 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalEditorInput.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalEditorInput.ts @@ -13,14 +13,13 @@ import { TerminalEditor } from 'vs/workbench/contrib/terminal/browser/terminalEd import { TerminalLocation } from 'vs/workbench/contrib/terminal/common/terminal'; import { getColorClass, getUriClasses } from 'vs/workbench/contrib/terminal/browser/terminalIcon'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import { IShellLaunchConfig } from 'vs/platform/terminal/common/terminal'; export class TerminalEditorInput extends EditorInput { static readonly ID = 'workbench.editors.terminal'; private _isDetached = false; - private _copyConfig?: IShellLaunchConfig; + private _copyInstance?: ITerminalInstance; override get typeId(): string { return TerminalEditorInput.ID; @@ -31,13 +30,13 @@ export class TerminalEditorInput extends EditorInput { } override copy(): IEditorInput { - const instance = this._terminalInstanceService.createInstance(this._copyConfig || {}, TerminalLocation.Editor); - this._copyConfig = undefined; + const instance = this._copyInstance || this._terminalInstanceService.createInstance({}, TerminalLocation.Editor); + this._copyInstance = undefined; return this._instantiationService.createInstance(TerminalEditorInput, instance); } - setCopyConfig(shellLaunchConfig: IShellLaunchConfig) { - this._copyConfig = shellLaunchConfig; + setCopyInstance(instance: ITerminalInstance) { + this._copyInstance = instance; } /** diff --git a/src/vs/workbench/contrib/terminal/browser/terminalEditorService.ts b/src/vs/workbench/contrib/terminal/browser/terminalEditorService.ts index 4e46833eab4..bee83193e9c 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalEditorService.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalEditorService.ts @@ -6,16 +6,18 @@ import { Emitter, Event } from 'vs/base/common/event'; import { Disposable, dispose, IDisposable, toDisposable } from 'vs/base/common/lifecycle'; import { FindReplaceState } from 'vs/editor/contrib/find/findState'; +import { ICommandService } from 'vs/platform/commands/common/commands'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; +import { IShellLaunchConfig } from 'vs/platform/terminal/common/terminal'; import { IEditorInput } from 'vs/workbench/common/editor'; -import { ITerminalEditorService, ITerminalFindHost, ITerminalInstance, ITerminalInstanceService } from 'vs/workbench/contrib/terminal/browser/terminal'; +import { ITerminalEditorService, ITerminalInstance, ITerminalInstanceService } from 'vs/workbench/contrib/terminal/browser/terminal'; import { TerminalEditor } from 'vs/workbench/contrib/terminal/browser/terminalEditor'; import { TerminalEditorInput } from 'vs/workbench/contrib/terminal/browser/terminalEditorInput'; import { SerializedTerminalEditorInput } from 'vs/workbench/contrib/terminal/browser/terminalEditorSerializer'; import { TerminalLocation } from 'vs/workbench/contrib/terminal/common/terminal'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; -export class TerminalEditorService extends Disposable implements ITerminalEditorService, ITerminalFindHost { +export class TerminalEditorService extends Disposable implements ITerminalEditorService { declare _serviceBrand: undefined; instances: ITerminalInstance[] = []; @@ -32,6 +34,7 @@ export class TerminalEditorService extends Disposable implements ITerminalEditor get onDidChangeInstances(): Event { return this._onDidChangeInstances.event; } constructor( + @ICommandService private readonly _commandService: ICommandService, @IEditorService private readonly _editorService: IEditorService, @ITerminalInstanceService private readonly _terminalInstanceService: ITerminalInstanceService, @IInstantiationService private readonly _instantiationService: IInstantiationService @@ -151,6 +154,14 @@ export class TerminalEditorService extends Disposable implements ITerminalEditor return input; } + splitInstance(instanceToSplit: ITerminalInstance, shellLaunchConfig: IShellLaunchConfig = {}): ITerminalInstance { + const input = this.getOrCreateEditorInput(instanceToSplit); + const instance = this._terminalInstanceService.createInstance(shellLaunchConfig, TerminalLocation.Editor); + input.setCopyInstance(instance); + this._commandService.executeCommand('workbench.action.splitEditor'); + return instance; + } + detachActiveEditorInstance(): ITerminalInstance { const activeEditor = this._editorService.activeEditor; if (!(activeEditor instanceof TerminalEditorInput)) { diff --git a/src/vs/workbench/contrib/terminal/browser/terminalService.ts b/src/vs/workbench/contrib/terminal/browser/terminalService.ts index c7974103f68..3110a08bda9 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalService.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalService.ts @@ -600,10 +600,6 @@ export class TerminalService implements ITerminalService { splitInstance(instanceToSplit: ITerminalInstance, shellLaunchConfig?: IShellLaunchConfig): ITerminalInstance | null; splitInstance(instanceToSplit: ITerminalInstance, profile: ITerminalProfile, cwd?: string | URI): ITerminalInstance | null splitInstance(instanceToSplit: ITerminalInstance, shellLaunchConfigOrProfile: IShellLaunchConfig | ITerminalProfile = {}, cwd?: string | URI): ITerminalInstance | null { - const group = this._terminalGroupService.getGroupForInstance(instanceToSplit); - if (!group) { - return null; - } const shellLaunchConfig = this._convertProfileToShellLaunchConfig(shellLaunchConfigOrProfile, cwd); // Use the URI from the base instance if it exists, this will correctly split local terminals @@ -615,11 +611,27 @@ export class TerminalService implements ITerminalService { this._evaluateLocalCwd(shellLaunchConfig); } - const instance = group.split(shellLaunchConfig); + // Handle editor terminals + let instance: ITerminalInstance; + switch (instanceToSplit.target) { + case TerminalLocation.Editor: + instance = this._terminalEditorService.splitInstance(instanceToSplit, shellLaunchConfig); + break; + case TerminalLocation.TerminalView: + default: + const group = this._terminalGroupService.getGroupForInstance(instanceToSplit); + if (!group) { + return null; + } + instance = group.split(shellLaunchConfig); + break; + } this._initInstanceListeners(instance); - this._terminalGroupService.groups.forEach((g, i) => g.setVisible(i === this._terminalGroupService.activeGroupIndex)); + if (instanceToSplit.target !== TerminalLocation.Editor) { + this._terminalGroupService.groups.forEach((g, i) => g.setVisible(i === this._terminalGroupService.activeGroupIndex)); + } return instance; } @@ -877,6 +889,7 @@ export class TerminalService implements ITerminalService { } else { if (keyMods?.alt && activeInstance) { // create split, only valid if there's an active instance + // TODO: This doesn't work for editor terminals instance = this.splitInstance(activeInstance, value.profile, cwd); } else { instance = this.createTerminal({ target: this.configHelper.config.defaultLocation, config: value.profile, cwd }); diff --git a/src/vs/workbench/contrib/terminal/browser/terminalView.ts b/src/vs/workbench/contrib/terminal/browser/terminalView.ts index d33d6f1e077..5f7cf5e197b 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalView.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalView.ts @@ -14,15 +14,15 @@ import { IThemeService, IColorTheme, registerThemingParticipant, ICssStyleCollec import { switchTerminalActionViewItemSeparator, switchTerminalShowTabsTitle } from 'vs/workbench/contrib/terminal/browser/terminalActions'; import { TERMINAL_BACKGROUND_COLOR, TERMINAL_BORDER_COLOR, TERMINAL_DRAG_AND_DROP_BACKGROUND } from 'vs/workbench/contrib/terminal/common/terminalColorRegistry'; import { INotificationService, IPromptChoice, Severity } from 'vs/platform/notification/common/notification'; -import { ITerminalGroupService, ITerminalInstance, ITerminalService, TerminalConnectionState } from 'vs/workbench/contrib/terminal/browser/terminal'; +import { ICreateTerminalOptions, ITerminalGroupService, ITerminalInstance, ITerminalService, TerminalConnectionState } from 'vs/workbench/contrib/terminal/browser/terminal'; import { ViewPane, IViewPaneOptions } from 'vs/workbench/browser/parts/views/viewPane'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { IViewDescriptorService } from 'vs/workbench/common/views'; import { IOpenerService } from 'vs/platform/opener/common/opener'; import { PANEL_BACKGROUND, SIDE_BAR_BACKGROUND, EDITOR_DRAG_AND_DROP_BACKGROUND } from 'vs/workbench/common/theme'; -import { IMenu, IMenuService, MenuId, MenuItemAction } from 'vs/platform/actions/common/actions'; -import { ITerminalProfileResolverService, TerminalCommandId } from 'vs/workbench/contrib/terminal/common/terminal'; +import { IMenu, IMenuActionOptions, IMenuService, MenuId, MenuItemAction } from 'vs/platform/actions/common/actions'; +import { ITerminalProfileResolverService, TerminalCommandId, TerminalLocation } from 'vs/workbench/contrib/terminal/common/terminal'; import { TerminalSettingId, ITerminalProfile } from 'vs/platform/terminal/common/terminal'; import { SelectActionViewItem } from 'vs/base/browser/ui/actionbar/actionViewItems'; import { ITerminalContributionService } from 'vs/workbench/contrib/terminal/common/terminalExtensionPoints'; @@ -178,6 +178,7 @@ export class TerminalViewPane extends ViewPane { override getActionViewItem(action: Action): IActionViewItem | undefined { switch (action.id) { + // TODO: Pass target arg to split command case TerminalCommandId.SwitchTerminal: { return this._instantiationService.createInstance(SwitchTerminalActionViewItem, action); } @@ -218,12 +219,19 @@ export class TerminalViewPane extends ViewPane { const defaultProfileName = this._terminalProfileResolverService.defaultProfileName; for (const p of profiles) { const isDefault = p.profileName === defaultProfileName; + const options: IMenuActionOptions = { + arg: { + config: p, + target: TerminalLocation.TerminalView + } as ICreateTerminalOptions, + shouldForwardArgs: true + }; if (isDefault) { - dropdownActions.unshift(new MenuItemAction({ id: TerminalCommandId.NewWithProfile, title: nls.localize('defaultTerminalProfile', "{0} (Default)", p.profileName), category: TerminalTabContextMenuGroup.Profile }, undefined, { arg: p, shouldForwardArgs: true }, this._contextKeyService, this._commandService)); - submenuActions.unshift(new MenuItemAction({ id: TerminalCommandId.Split, title: nls.localize('defaultTerminalProfile', "{0} (Default)", p.profileName), category: TerminalTabContextMenuGroup.Profile }, undefined, { arg: p, shouldForwardArgs: true }, this._contextKeyService, this._commandService)); + dropdownActions.unshift(new MenuItemAction({ id: TerminalCommandId.NewWithProfile, title: nls.localize('defaultTerminalProfile', "{0} (Default)", p.profileName), category: TerminalTabContextMenuGroup.Profile }, undefined, options, this._contextKeyService, this._commandService)); + submenuActions.unshift(new MenuItemAction({ id: TerminalCommandId.Split, title: nls.localize('defaultTerminalProfile', "{0} (Default)", p.profileName), category: TerminalTabContextMenuGroup.Profile }, undefined, options, this._contextKeyService, this._commandService)); } else { - dropdownActions.push(new MenuItemAction({ id: TerminalCommandId.NewWithProfile, title: p.profileName.replace(/[\n\r\t]/g, ''), category: TerminalTabContextMenuGroup.Profile }, undefined, { arg: p, shouldForwardArgs: true }, this._contextKeyService, this._commandService)); - submenuActions.push(new MenuItemAction({ id: TerminalCommandId.Split, title: p.profileName.replace(/[\n\r\t]/g, ''), category: TerminalTabContextMenuGroup.Profile }, undefined, { arg: p, shouldForwardArgs: true }, this._contextKeyService, this._commandService)); + dropdownActions.push(new MenuItemAction({ id: TerminalCommandId.NewWithProfile, title: p.profileName.replace(/[\n\r\t]/g, ''), category: TerminalTabContextMenuGroup.Profile }, undefined, options, this._contextKeyService, this._commandService)); + submenuActions.push(new MenuItemAction({ id: TerminalCommandId.Split, title: p.profileName.replace(/[\n\r\t]/g, ''), category: TerminalTabContextMenuGroup.Profile }, undefined, options, this._contextKeyService, this._commandService)); } } From 590516eba6f8132c86959f875aded418b997f985 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Fri, 25 Jun 2021 06:52:43 -0700 Subject: [PATCH 09/17] Split in active workspace editor support --- .../contrib/terminal/browser/terminal.ts | 1 + .../terminal/browser/terminalActions.ts | 41 ++++--------------- .../terminal/browser/terminalService.ts | 10 +++++ 3 files changed, 18 insertions(+), 34 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/browser/terminal.ts b/src/vs/workbench/contrib/terminal/browser/terminal.ts index 4538af4be37..bbe9a97283f 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminal.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminal.ts @@ -198,6 +198,7 @@ export interface ITerminalService extends ITerminalInstanceHost { setEditable(instance: ITerminalInstance, data: IEditableData | null): Promise; safeDisposeTerminal(instance: ITerminalInstance): Promise; + getInstanceHost(target: TerminalLocation | undefined): ITerminalInstanceHost; getFindHost(): ITerminalFindHost; } diff --git a/src/vs/workbench/contrib/terminal/browser/terminalActions.ts b/src/vs/workbench/contrib/terminal/browser/terminalActions.ts index 03b6ae2d8b4..b7329fba4e9 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalActions.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalActions.ts @@ -30,7 +30,7 @@ import { ILocalTerminalService, ITerminalProfile, TerminalSettingId, TitleEventS import { IWorkspaceContextService, IWorkspaceFolder } from 'vs/platform/workspace/common/workspace'; import { PICK_WORKSPACE_FOLDER_COMMAND_ID } from 'vs/workbench/browser/actions/workspaceCommands'; import { FindInFilesCommand, IFindInFilesArgs } from 'vs/workbench/contrib/search/browser/searchActions'; -import { Direction, ICreateTerminalOptions, IRemoteTerminalService, ITerminalEditorService, ITerminalGroupService, ITerminalInstance, ITerminalInstanceHost, ITerminalInstanceService, ITerminalService } from 'vs/workbench/contrib/terminal/browser/terminal'; +import { Direction, ICreateTerminalOptions, IRemoteTerminalService, ITerminalEditorService, ITerminalGroupService, ITerminalInstance, ITerminalInstanceService, ITerminalService } from 'vs/workbench/contrib/terminal/browser/terminal'; import { TerminalQuickAccessProvider } from 'vs/workbench/contrib/terminal/browser/terminalQuickAccess'; import { IRemoteTerminalAttachTarget, ITerminalConfigHelper, KEYBINDING_CONTEXT_TERMINAL_A11Y_TREE_FOCUS, KEYBINDING_CONTEXT_TERMINAL_ALT_BUFFER_ACTIVE, KEYBINDING_CONTEXT_TERMINAL_FIND_FOCUSED, KEYBINDING_CONTEXT_TERMINAL_FIND_NOT_VISIBLE, KEYBINDING_CONTEXT_TERMINAL_FIND_VISIBLE, KEYBINDING_CONTEXT_TERMINAL_FOCUS, KEYBINDING_CONTEXT_TERMINAL_IS_OPEN, KEYBINDING_CONTEXT_TERMINAL_PROCESS_SUPPORTED, KEYBINDING_CONTEXT_TERMINAL_TABS_FOCUS, KEYBINDING_CONTEXT_TERMINAL_TABS_SINGULAR_SELECTION, KEYBINDING_CONTEXT_TERMINAL_TEXT_SELECTED, TerminalCommandId, TerminalLocation, TERMINAL_ACTION_CATEGORY } from 'vs/workbench/contrib/terminal/common/terminal'; import { terminalStrings } from 'vs/workbench/contrib/terminal/common/terminalStrings'; @@ -1453,21 +1453,8 @@ export function registerTerminalActions() { const terminalGroupService = accessor.get(ITerminalGroupService); const terminalService = accessor.get(ITerminalService); const workspaceContextService = accessor.get(IWorkspaceContextService); - const terminalEditorService = accessor.get(ITerminalEditorService); - // const editorService = accessor.get(IEditorService); const options = convertOptionsOrProfileToOptions(optionsOrProfile); - // let activeInstance: ITerminalInstance; - let instanceHost: ITerminalInstanceHost; - if (options?.target) { - if (options.target === TerminalLocation.Editor) { - instanceHost = terminalEditorService; - } else { - instanceHost = terminalGroupService; - } - } else { - instanceHost = terminalService; - } - const activeInstance = instanceHost.activeInstance; + const activeInstance = terminalService.getInstanceHost(options?.target).activeInstance; if (!activeInstance) { return; } @@ -1479,18 +1466,6 @@ export function registerTerminalActions() { if (instance?.target !== TerminalLocation.Editor) { return terminalGroupService.showPanel(true); } - // if ((options?.target || t.target) === TerminalLocation.Editor) { - // const activeResource = editorService.activeEditor?.resource; - // if (activeResource) { - // const input = terminalEditorService.getOrCreateEditorInput(t); - // const instance = terminalService.createInstance(options?.config || {}); - // input.setCopyConfig(options?.config || {}); - // commandService.executeCommand('workbench.action.splitEditor'); - // } - // } else { - // terminalService.splitInstance(t, options?.config, cwd); - // return accessor.get(ITerminalGroupService).showPanel(true); - // } } }); registerAction2(class extends Action2 { @@ -1592,14 +1567,12 @@ export function registerTerminalActions() { } async run(accessor: ServicesAccessor) { const terminalService = accessor.get(ITerminalService); - const commandService = accessor.get(ICommandService); + const terminalGroupService = accessor.get(ITerminalGroupService); await terminalService.doWithActiveInstance(async t => { - if (t.target === TerminalLocation.Editor) { - commandService.executeCommand('workbench.action.splitEditor'); - } else { - const cwd = await getCwdForSplit(terminalService.configHelper, t); - terminalService.splitInstance(t, { cwd }); - await accessor.get(ITerminalGroupService).showPanel(true); + const cwd = await getCwdForSplit(terminalService.configHelper, t); + const instance = terminalService.splitInstance(t, { cwd }); + if (instance?.target !== TerminalLocation.Editor) { + await terminalGroupService.showPanel(true); } }); } diff --git a/src/vs/workbench/contrib/terminal/browser/terminalService.ts b/src/vs/workbench/contrib/terminal/browser/terminalService.ts index 3110a08bda9..849cd87adb2 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalService.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalService.ts @@ -926,6 +926,16 @@ export class TerminalService implements ITerminalService { return undefined; } + getInstanceHost(target: TerminalLocation | undefined): ITerminalInstanceHost { + if (target) { + if (target === TerminalLocation.Editor) { + return this._terminalEditorService; + } + return this._terminalGroupService; + } + return this; + } + getFindHost(): ITerminalFindHost { return this.activeInstance?.target === TerminalLocation.Editor ? this._terminalEditorService : this._terminalGroupService; } From de0f40532e1fd0927653c1e1c7dda7ebc92f8b26 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Fri, 25 Jun 2021 07:01:39 -0700 Subject: [PATCH 10/17] Use default instance host for new with profile regardless of active --- src/vs/workbench/contrib/terminal/browser/terminal.ts | 1 + .../contrib/terminal/browser/terminalActions.ts | 1 - .../contrib/terminal/browser/terminalService.ts | 9 ++++++++- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/browser/terminal.ts b/src/vs/workbench/contrib/terminal/browser/terminal.ts index bbe9a97283f..328fe685440 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminal.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminal.ts @@ -198,6 +198,7 @@ export interface ITerminalService extends ITerminalInstanceHost { setEditable(instance: ITerminalInstance, data: IEditableData | null): Promise; safeDisposeTerminal(instance: ITerminalInstance): Promise; + getDefaultInstanceHost(): ITerminalInstanceHost; getInstanceHost(target: TerminalLocation | undefined): ITerminalInstanceHost; getFindHost(): ITerminalFindHost; } diff --git a/src/vs/workbench/contrib/terminal/browser/terminalActions.ts b/src/vs/workbench/contrib/terminal/browser/terminalActions.ts index b7329fba4e9..714ebadd30d 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalActions.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalActions.ts @@ -161,7 +161,6 @@ export function registerTerminalActions() { const activeInstance = terminalService.activeInstance; if (activeInstance) { const cwd = await getCwdForSplit(terminalService.configHelper, activeInstance); - // TODO: Support split in editor terminalService.splitInstance(activeInstance, options?.config, cwd); return; } diff --git a/src/vs/workbench/contrib/terminal/browser/terminalService.ts b/src/vs/workbench/contrib/terminal/browser/terminalService.ts index 849cd87adb2..5205b7e4042 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalService.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalService.ts @@ -880,7 +880,7 @@ export class TerminalService implements ITerminalService { return; } if (type === 'createInstance') { - const activeInstance = this.activeInstance; + const activeInstance = this.getDefaultInstanceHost().activeInstance; let instance; if ('id' in value.profile) { @@ -926,6 +926,13 @@ export class TerminalService implements ITerminalService { return undefined; } + getDefaultInstanceHost(): ITerminalInstanceHost { + if (this.configHelper.config.defaultLocation === TerminalLocation.Editor) { + return this._terminalEditorService; + } + return this._terminalGroupService; + } + getInstanceHost(target: TerminalLocation | undefined): ITerminalInstanceHost { if (target) { if (target === TerminalLocation.Editor) { From 03fd0b19c995c11b5019a867eda6edc3581a31ce Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Fri, 25 Jun 2021 07:16:32 -0700 Subject: [PATCH 11/17] Clean up resolved todos --- .../workbench/contrib/terminal/browser/terminalActions.ts | 2 -- src/vs/workbench/contrib/terminal/browser/terminalEditor.ts | 6 ------ .../workbench/contrib/terminal/browser/terminalService.ts | 1 - 3 files changed, 9 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/browser/terminalActions.ts b/src/vs/workbench/contrib/terminal/browser/terminalActions.ts index 714ebadd30d..569d1f872d3 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalActions.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalActions.ts @@ -185,8 +185,6 @@ export function registerTerminalActions() { if (options) { instance = terminalService.createTerminal(options); } else { - // TODO: Support target - // TODO: Fix alt+click instance = await terminalService.showProfileQuickPick('createInstance', cwd); } diff --git a/src/vs/workbench/contrib/terminal/browser/terminalEditor.ts b/src/vs/workbench/contrib/terminal/browser/terminalEditor.ts index cc45153b075..f30860faa08 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalEditor.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalEditor.ts @@ -117,15 +117,9 @@ export class TerminalEditor extends EditorPane { override getActionViewItem(action: IAction): IActionViewItem | undefined { switch (action.id) { - // TODO: Pass target arg to split command case TerminalCommandId.CreateWithProfileButton: { - // if (this._tabButtons) { - // this._tabButtons.dispose(); - // } const actions = this._getTabActionBarArgs(this._terminalService.availableProfiles); - const button = this._instantiationService.createInstance(DropdownWithPrimaryActionViewItem, actions.primaryAction, actions.dropdownAction, actions.dropdownMenuActions, actions.className, this._contextMenuService); - // this._updateTabActionBar(this._terminalService.availableProfiles); return button; } } diff --git a/src/vs/workbench/contrib/terminal/browser/terminalService.ts b/src/vs/workbench/contrib/terminal/browser/terminalService.ts index 5205b7e4042..08ec0a09a06 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalService.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalService.ts @@ -889,7 +889,6 @@ export class TerminalService implements ITerminalService { } else { if (keyMods?.alt && activeInstance) { // create split, only valid if there's an active instance - // TODO: This doesn't work for editor terminals instance = this.splitInstance(activeInstance, value.profile, cwd); } else { instance = this.createTerminal({ target: this.configHelper.config.defaultLocation, config: value.profile, cwd }); From 4aba8c49dc75aa5f6ce1ea3e24cf15e2ca00b992 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Fri, 25 Jun 2021 07:34:21 -0700 Subject: [PATCH 12/17] Make split in panel only split panel terminals --- .../contrib/terminal/browser/terminalView.ts | 28 +++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/browser/terminalView.ts b/src/vs/workbench/contrib/terminal/browser/terminalView.ts index 5f7cf5e197b..d68a256dabf 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalView.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalView.ts @@ -24,7 +24,7 @@ import { PANEL_BACKGROUND, SIDE_BAR_BACKGROUND, EDITOR_DRAG_AND_DROP_BACKGROUND import { IMenu, IMenuActionOptions, IMenuService, MenuId, MenuItemAction } from 'vs/platform/actions/common/actions'; import { ITerminalProfileResolverService, TerminalCommandId, TerminalLocation } from 'vs/workbench/contrib/terminal/common/terminal'; import { TerminalSettingId, ITerminalProfile } from 'vs/platform/terminal/common/terminal'; -import { SelectActionViewItem } from 'vs/base/browser/ui/actionbar/actionViewItems'; +import { ActionViewItem, SelectActionViewItem } from 'vs/base/browser/ui/actionbar/actionViewItems'; import { ITerminalContributionService } from 'vs/workbench/contrib/terminal/common/terminalExtensionPoints'; import { attachSelectBoxStyler, attachStylerCallback } from 'vs/platform/theme/common/styler'; import { selectBorder } from 'vs/platform/theme/common/colorRegistry'; @@ -43,6 +43,7 @@ import { URI } from 'vs/base/common/uri'; import { ColorScheme } from 'vs/platform/theme/common/theme'; import { getColorClass, getUriClasses } from 'vs/workbench/contrib/terminal/browser/terminalIcon'; import { terminalStrings } from 'vs/workbench/contrib/terminal/common/terminalStrings'; +import { withNullAsUndefined } from 'vs/base/common/types'; export class TerminalViewPane extends ViewPane { private _actions: IAction[] | undefined; @@ -178,7 +179,26 @@ export class TerminalViewPane extends ViewPane { override getActionViewItem(action: Action): IActionViewItem | undefined { switch (action.id) { - // TODO: Pass target arg to split command + case TerminalCommandId.Split: { + // Split needs to be special cased to force splitting within the panel, not the editor + const panelOnlySplitAction: IAction = { + id: action.id, + checked: action.checked, + class: action.class, + enabled: action.enabled, + label: action.label, + dispose: action.dispose.bind(action), + tooltip: action.tooltip, + run: () => { + const instance = this._terminalGroupService.activeInstance; + if (instance) { + return this._terminalService.splitInstance(instance); + } + return; + } + }; + return new ActionViewItem(action, panelOnlySplitAction, { icon: true, label: false, keybinding: this._getKeybindingLabel(action) }); + } case TerminalCommandId.SwitchTerminal: { return this._instantiationService.createInstance(SwitchTerminalActionViewItem, action); } @@ -201,6 +221,10 @@ export class TerminalViewPane extends ViewPane { return super.getActionViewItem(action); } + private _getKeybindingLabel(action: IAction): string | undefined { + return withNullAsUndefined(this._keybindingService.lookupKeybinding(action.id)?.getLabel()); + } + private _updateTabActionBar(profiles: ITerminalProfile[]): void { const actions = this._getTabActionBarArgs(profiles); this._tabButtons?.update(actions.dropdownAction, actions.dropdownMenuActions); From 54c2969f32be459a6a3b03181acddb0f55bbe983 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Fri, 25 Jun 2021 07:37:25 -0700 Subject: [PATCH 13/17] Make panel alt actions split within panel only --- src/vs/workbench/contrib/terminal/browser/terminalView.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/browser/terminalView.ts b/src/vs/workbench/contrib/terminal/browser/terminalView.ts index d68a256dabf..0d9c3777d41 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalView.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalView.ts @@ -290,7 +290,10 @@ export class TerminalViewPane extends ViewPane { title: terminalStrings.split.value, icon: Codicon.splitHorizontal }, - undefined); + { + shouldForwardArgs: true, + arg: { target: TerminalLocation.TerminalView } as ICreateTerminalOptions, + }); const dropdownAction = new Action('refresh profiles', 'Launch Profile...', 'codicon-chevron-down', true); return { primaryAction, dropdownAction, dropdownMenuActions: dropdownActions, className: 'terminal-tab-actions' }; @@ -442,7 +445,7 @@ class SingleTerminalTabActionViewItem extends MenuEntryActionViewItem { override async onClick(event: MouseEvent): Promise { if (event.altKey && this._menuItemAction.alt) { - this._commandService.executeCommand(this._menuItemAction.alt.id); + this._commandService.executeCommand(this._menuItemAction.alt.id, { target: TerminalLocation.TerminalView } as ICreateTerminalOptions); } else { this._openContextMenu(); } From f47b7ac42ac91a8be74928dbb4064f15d588a235 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Fri, 25 Jun 2021 07:42:16 -0700 Subject: [PATCH 14/17] Fix terminal kill when editor terminal is focused --- .../terminal/browser/terminalActions.ts | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/browser/terminalActions.ts b/src/vs/workbench/contrib/terminal/browser/terminalActions.ts index 569d1f872d3..240170c614b 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalActions.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalActions.ts @@ -1667,16 +1667,15 @@ export function registerTerminalActions() { }); } async run(accessor: ServicesAccessor) { - const terminalService = accessor.get(ITerminalService); - await terminalService.doWithActiveInstance(async t => { - if (t.target === TerminalLocation.Editor) { - return; - } - t.dispose(true); - if (terminalService.instances.length > 0) { - await accessor.get(ITerminalGroupService).showPanel(true); - } - }); + const terminalGroupService = accessor.get(ITerminalGroupService); + const instance = terminalGroupService.activeInstance; + if (!instance) { + return; + } + instance.dispose(true); + if (terminalGroupService.instances.length > 0) { + await terminalGroupService.showPanel(true); + } } }); From fbc9500800377d8620bab8e061280687139be86d Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Fri, 25 Jun 2021 07:51:12 -0700 Subject: [PATCH 15/17] Verify accessor isn't used after await --- .../terminal/browser/terminalActions.ts | 40 ++++++++++++------- 1 file changed, 25 insertions(+), 15 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/browser/terminalActions.ts b/src/vs/workbench/contrib/terminal/browser/terminalActions.ts index 240170c614b..d065f1095ae 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalActions.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalActions.ts @@ -304,8 +304,9 @@ export function registerTerminalActions() { }); } async run(accessor: ServicesAccessor) { - accessor.get(ITerminalGroupService).activeGroup?.focusPreviousPane(); - await accessor.get(ITerminalGroupService).showPanel(true); + const terminalGroupService = accessor.get(ITerminalGroupService); + terminalGroupService.activeGroup?.focusPreviousPane(); + await terminalGroupService.showPanel(true); } }); registerAction2(class extends Action2 { @@ -329,8 +330,9 @@ export function registerTerminalActions() { }); } async run(accessor: ServicesAccessor) { - accessor.get(ITerminalGroupService).activeGroup?.focusNextPane(); - await accessor.get(ITerminalGroupService).showPanel(true); + const terminalGroupService = accessor.get(ITerminalGroupService); + terminalGroupService.activeGroup?.focusNextPane(); + await terminalGroupService.showPanel(true); } }); registerAction2(class extends Action2 { @@ -469,8 +471,9 @@ export function registerTerminalActions() { }); } async run(accessor: ServicesAccessor) { - accessor.get(ITerminalGroupService).setActiveGroupToNext(); - await accessor.get(ITerminalGroupService).showPanel(true); + const terminalGroupService = accessor.get(ITerminalGroupService); + terminalGroupService.setActiveGroupToNext(); + await terminalGroupService.showPanel(true); } }); registerAction2(class extends Action2 { @@ -492,8 +495,9 @@ export function registerTerminalActions() { }); } async run(accessor: ServicesAccessor) { - accessor.get(ITerminalGroupService).setActiveGroupToPrevious(); - await accessor.get(ITerminalGroupService).showPanel(true); + const terminalGroupService = accessor.get(ITerminalGroupService); + terminalGroupService.setActiveGroupToPrevious(); + await terminalGroupService.showPanel(true); } }); registerAction2(class extends Action2 { @@ -508,6 +512,7 @@ export function registerTerminalActions() { } async run(accessor: ServicesAccessor) { const terminalService = accessor.get(ITerminalService); + const terminalGroupService = accessor.get(ITerminalGroupService); const codeEditorService = accessor.get(ICodeEditorService); const instance = terminalService.getActiveOrCreateInstance(); @@ -524,7 +529,7 @@ export function registerTerminalActions() { text = editor.getModel().getValueInRange(selection, endOfLinePreference); } instance.sendText(text, true); - return accessor.get(ITerminalGroupService).showPanel(); + return terminalGroupService.showPanel(); } }); registerAction2(class extends Action2 { @@ -539,6 +544,8 @@ export function registerTerminalActions() { } async run(accessor: ServicesAccessor) { const terminalService = accessor.get(ITerminalService); + const terminalGroupService = accessor.get(ITerminalGroupService); + const terminalInstanceService = accessor.get(ITerminalInstanceService); const codeEditorService = accessor.get(ICodeEditorService); const notificationService = accessor.get(INotificationService); @@ -555,9 +562,9 @@ export function registerTerminalActions() { // TODO: Convert this to ctrl+c, ctrl+v for pwsh? const instance = terminalService.getActiveOrCreateInstance(); - const path = await accessor.get(ITerminalInstanceService).preparePathForTerminalAsync(uri.fsPath, instance.shellLaunchConfig.executable, instance.title, instance.shellType, instance.isRemote); + const path = await terminalInstanceService.preparePathForTerminalAsync(uri.fsPath, instance.shellLaunchConfig.executable, instance.title, instance.shellType, instance.isRemote); instance.sendText(path, true); - return accessor.get(ITerminalGroupService).showPanel(); + return terminalGroupService.showPanel(); } }); registerAction2(class extends Action2 { @@ -1486,6 +1493,7 @@ export function registerTerminalActions() { } async run(accessor: ServicesAccessor) { const terminalService = accessor.get(ITerminalService); + const terminalGroupService = accessor.get(ITerminalGroupService); const instances = getSelectedInstances(accessor); if (instances) { for (const t of instances) { @@ -1493,7 +1501,7 @@ export function registerTerminalActions() { terminalService.doWithActiveInstance(async instance => { const cwd = await getCwdForSplit(terminalService.configHelper, instance); terminalService.splitInstance(instance, { cwd }); - await accessor.get(ITerminalGroupService).showPanel(true); + await terminalGroupService.showPanel(true); }); } } @@ -1617,6 +1625,7 @@ export function registerTerminalActions() { } async run(accessor: ServicesAccessor, event: unknown) { const terminalService = accessor.get(ITerminalService); + const terminalGroupService = accessor.get(ITerminalGroupService); const workspaceContextService = accessor.get(IWorkspaceContextService); const commandService = accessor.get(ICommandService); const folders = workspaceContextService.getWorkspace().folders; @@ -1652,7 +1661,7 @@ export function registerTerminalActions() { } terminalService.setActiveInstance(instance); } - await accessor.get(ITerminalGroupService).showPanel(true); + await terminalGroupService.showPanel(true); } }); registerAction2(class extends Action2 { @@ -1864,6 +1873,7 @@ export function registerTerminalActions() { } async run(accessor: ServicesAccessor, item?: string) { const terminalService = accessor.get(ITerminalService); + const terminalGroupService = accessor.get(ITerminalGroupService); if (!item || !item.split) { return Promise.resolve(null); } @@ -1877,8 +1887,8 @@ export function registerTerminalActions() { } const indexMatches = terminalIndexRe.exec(item); if (indexMatches) { - accessor.get(ITerminalGroupService).setActiveGroupByIndex(Number(indexMatches[1]) - 1); - return accessor.get(ITerminalGroupService).showPanel(true); + terminalGroupService.setActiveGroupByIndex(Number(indexMatches[1]) - 1); + return terminalGroupService.showPanel(true); } const quickSelectProfiles = terminalService.availableProfiles; From 86c67404143debd3f69e86bc8e7857d869687f66 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Fri, 25 Jun 2021 07:54:58 -0700 Subject: [PATCH 16/17] Use getFindHost in find actions --- .../contrib/terminal/browser/terminal.ts | 2 +- .../terminal/browser/terminalActions.ts | 35 +++++++------------ .../terminal/browser/terminalService.ts | 4 +-- 3 files changed, 16 insertions(+), 25 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/browser/terminal.ts b/src/vs/workbench/contrib/terminal/browser/terminal.ts index 328fe685440..fbe7f6f59dc 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminal.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminal.ts @@ -200,7 +200,7 @@ export interface ITerminalService extends ITerminalInstanceHost { getDefaultInstanceHost(): ITerminalInstanceHost; getInstanceHost(target: TerminalLocation | undefined): ITerminalInstanceHost; - getFindHost(): ITerminalFindHost; + getFindHost(instance?: ITerminalInstance): ITerminalFindHost; } /** diff --git a/src/vs/workbench/contrib/terminal/browser/terminalActions.ts b/src/vs/workbench/contrib/terminal/browser/terminalActions.ts index d065f1095ae..b254ee0e393 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalActions.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalActions.ts @@ -30,7 +30,7 @@ import { ILocalTerminalService, ITerminalProfile, TerminalSettingId, TitleEventS import { IWorkspaceContextService, IWorkspaceFolder } from 'vs/platform/workspace/common/workspace'; import { PICK_WORKSPACE_FOLDER_COMMAND_ID } from 'vs/workbench/browser/actions/workspaceCommands'; import { FindInFilesCommand, IFindInFilesArgs } from 'vs/workbench/contrib/search/browser/searchActions'; -import { Direction, ICreateTerminalOptions, IRemoteTerminalService, ITerminalEditorService, ITerminalGroupService, ITerminalInstance, ITerminalInstanceService, ITerminalService } from 'vs/workbench/contrib/terminal/browser/terminal'; +import { Direction, ICreateTerminalOptions, IRemoteTerminalService, ITerminalGroupService, ITerminalInstance, ITerminalInstanceService, ITerminalService } from 'vs/workbench/contrib/terminal/browser/terminal'; import { TerminalQuickAccessProvider } from 'vs/workbench/contrib/terminal/browser/terminalQuickAccess'; import { IRemoteTerminalAttachTarget, ITerminalConfigHelper, KEYBINDING_CONTEXT_TERMINAL_A11Y_TREE_FOCUS, KEYBINDING_CONTEXT_TERMINAL_ALT_BUFFER_ACTIVE, KEYBINDING_CONTEXT_TERMINAL_FIND_FOCUSED, KEYBINDING_CONTEXT_TERMINAL_FIND_NOT_VISIBLE, KEYBINDING_CONTEXT_TERMINAL_FIND_VISIBLE, KEYBINDING_CONTEXT_TERMINAL_FOCUS, KEYBINDING_CONTEXT_TERMINAL_IS_OPEN, KEYBINDING_CONTEXT_TERMINAL_PROCESS_SUPPORTED, KEYBINDING_CONTEXT_TERMINAL_TABS_FOCUS, KEYBINDING_CONTEXT_TERMINAL_TABS_SINGULAR_SELECTION, KEYBINDING_CONTEXT_TERMINAL_TEXT_SELECTED, TerminalCommandId, TerminalLocation, TERMINAL_ACTION_CATEGORY } from 'vs/workbench/contrib/terminal/common/terminal'; import { terminalStrings } from 'vs/workbench/contrib/terminal/common/terminalStrings'; @@ -1258,13 +1258,10 @@ export function registerTerminalActions() { }); } run(accessor: ServicesAccessor) { - if (accessor.get(ITerminalService).activeInstance?.target === TerminalLocation.Editor) { - const state = accessor.get(ITerminalEditorService).getFindState(); - state.change({ matchCase: !state.matchCase }, false); - } else { - const state = accessor.get(ITerminalGroupService).getFindState(); - state.change({ matchCase: !state.matchCase }, false); - } + const terminalService = accessor.get(ITerminalService); + const instanceHost = terminalService.getFindHost(); + const state = instanceHost.getFindState(); + state.change({ matchCase: !state.matchCase }, false); } }); registerAction2(class extends Action2 { @@ -1284,13 +1281,10 @@ export function registerTerminalActions() { }); } run(accessor: ServicesAccessor) { - if (accessor.get(ITerminalService).activeInstance?.target === TerminalLocation.Editor) { - const state = accessor.get(ITerminalEditorService).getFindState(); - state.change({ wholeWord: !state.wholeWord }, false); - } else { - const state = accessor.get(ITerminalGroupService).getFindState(); - state.change({ wholeWord: !state.wholeWord }, false); - } + const terminalService = accessor.get(ITerminalService); + const instanceHost = terminalService.getFindHost(); + const state = instanceHost.getFindState(); + state.change({ wholeWord: !state.wholeWord }, false); } }); registerAction2(class extends Action2 { @@ -1310,13 +1304,10 @@ export function registerTerminalActions() { }); } run(accessor: ServicesAccessor) { - if (accessor.get(ITerminalService).activeInstance?.target === TerminalLocation.Editor) { - const state = accessor.get(ITerminalEditorService).getFindState(); - state.change({ matchCase: !state.matchCase }, false); - } else { - const state = accessor.get(ITerminalGroupService).getFindState(); - state.change({ matchCase: !state.matchCase }, false); - } + const terminalService = accessor.get(ITerminalService); + const instanceHost = terminalService.getFindHost(); + const state = instanceHost.getFindState(); + state.change({ matchCase: !state.matchCase }, false); } }); registerAction2(class extends Action2 { diff --git a/src/vs/workbench/contrib/terminal/browser/terminalService.ts b/src/vs/workbench/contrib/terminal/browser/terminalService.ts index 08ec0a09a06..a6655ef8f25 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalService.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalService.ts @@ -942,8 +942,8 @@ export class TerminalService implements ITerminalService { return this; } - getFindHost(): ITerminalFindHost { - return this.activeInstance?.target === TerminalLocation.Editor ? this._terminalEditorService : this._terminalGroupService; + getFindHost(instance: ITerminalInstance | undefined = this.activeInstance): ITerminalFindHost { + return instance?.target === TerminalLocation.Editor ? this._terminalEditorService : this._terminalGroupService; } async createContributedTerminalProfile(extensionIdentifier: string, id: string, isSplitTerminal: boolean): Promise { From fed8dfca7b9557dd35cd38f92b7df5157deaa40b Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Fri, 25 Jun 2021 08:34:51 -0700 Subject: [PATCH 17/17] Document setCopyInstance --- .../workbench/contrib/terminal/browser/terminalEditorInput.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/vs/workbench/contrib/terminal/browser/terminalEditorInput.ts b/src/vs/workbench/contrib/terminal/browser/terminalEditorInput.ts index 477c4c23f49..f9802f69658 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalEditorInput.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalEditorInput.ts @@ -35,6 +35,10 @@ export class TerminalEditorInput extends EditorInput { return this._instantiationService.createInstance(TerminalEditorInput, instance); } + /** + * Sets what instance to use for the next call to IEditorInput.copy, this is used to define what + * terminal instance is used when the editor's split command is run. + */ setCopyInstance(instance: ITerminalInstance) { this._copyInstance = instance; }