mirror of
https://github.com/Microsoft/vscode
synced 2024-09-13 13:46:13 +00:00
Merge pull request #114566 from microsoft/tyriar/92038
Remove getAction from terminal
This commit is contained in:
commit
6b3d751206
|
@ -148,6 +148,7 @@ export class MenuId {
|
|||
static readonly TimelineTitleContext = new MenuId('TimelineTitleContext');
|
||||
static readonly AccountsContext = new MenuId('AccountsContext');
|
||||
static readonly PanelTitle = new MenuId('PanelTitle');
|
||||
static readonly TerminalContext = new MenuId('TerminalContext');
|
||||
|
||||
readonly id: number;
|
||||
readonly _debugName: string;
|
||||
|
|
|
@ -10,18 +10,16 @@ import 'vs/css!./media/terminal';
|
|||
import 'vs/css!./media/widgets';
|
||||
import 'vs/css!./media/xterm';
|
||||
import * as nls from 'vs/nls';
|
||||
import { SyncActionDescriptor } from 'vs/platform/actions/common/actions';
|
||||
import { CommandsRegistry } from 'vs/platform/commands/common/commands';
|
||||
import { ContextKeyExpr, ContextKeyExpression } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { KeybindingWeight, KeybindingsRegistry, IKeybindings } from 'vs/platform/keybinding/common/keybindingsRegistry';
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
import * as panel from 'vs/workbench/browser/panel';
|
||||
import { getQuickNavigateHandler } from 'vs/workbench/browser/quickaccess';
|
||||
import { Extensions as ActionExtensions, IWorkbenchActionRegistry } from 'vs/workbench/common/actions';
|
||||
import { Extensions as ViewContainerExtensions, IViewContainersRegistry, ViewContainerLocation, IViewsRegistry } from 'vs/workbench/common/views';
|
||||
import { registerTerminalActions, ClearTerminalAction, CopyTerminalSelectionAction, CreateNewTerminalAction, KillTerminalAction, SelectAllTerminalAction, SelectDefaultShellWindowsTerminalAction, SplitInActiveWorkspaceTerminalAction, SplitTerminalAction, TerminalPasteAction, terminalSendSequenceCommand } from 'vs/workbench/contrib/terminal/browser/terminalActions';
|
||||
import { registerTerminalActions, terminalSendSequenceCommand } from 'vs/workbench/contrib/terminal/browser/terminalActions';
|
||||
import { TerminalViewPane } from 'vs/workbench/contrib/terminal/browser/terminalView';
|
||||
import { KEYBINDING_CONTEXT_TERMINAL_SHELL_TYPE_KEY, KEYBINDING_CONTEXT_TERMINAL_FOCUS, KEYBINDING_CONTEXT_TERMINAL_TEXT_SELECTED, TERMINAL_VIEW_ID, TERMINAL_ACTION_CATEGORY, TERMINAL_COMMAND_ID, KEYBINDING_CONTEXT_TERMINAL_PROCESS_SUPPORTED } from 'vs/workbench/contrib/terminal/common/terminal';
|
||||
import { KEYBINDING_CONTEXT_TERMINAL_SHELL_TYPE_KEY, KEYBINDING_CONTEXT_TERMINAL_FOCUS, TERMINAL_VIEW_ID, TERMINAL_COMMAND_ID } from 'vs/workbench/contrib/terminal/common/terminal';
|
||||
import { registerColors } from 'vs/workbench/contrib/terminal/common/terminalColorRegistry';
|
||||
import { setupTerminalCommands } from 'vs/workbench/contrib/terminal/browser/terminalCommands';
|
||||
import { setupTerminalMenu } from 'vs/workbench/contrib/terminal/common/terminalMenu';
|
||||
|
@ -29,7 +27,6 @@ import { IConfigurationRegistry, Extensions } from 'vs/platform/configuration/co
|
|||
import { TerminalService } from 'vs/workbench/contrib/terminal/browser/terminalService';
|
||||
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
|
||||
import { ITerminalService, WindowsShellType } from 'vs/workbench/contrib/terminal/browser/terminal';
|
||||
import { BrowserFeatures } from 'vs/base/browser/canIUse';
|
||||
import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors';
|
||||
import { ViewPaneContainer } from 'vs/workbench/browser/parts/views/viewPaneContainer';
|
||||
import { IQuickAccessRegistry, Extensions as QuickAccessExtensions } from 'vs/platform/quickinput/common/quickAccess';
|
||||
|
@ -90,47 +87,7 @@ Registry.as<IViewsRegistry>(ViewContainerExtensions.ViewsRegistry).registerViews
|
|||
}], VIEW_CONTAINER);
|
||||
|
||||
// Register actions
|
||||
const actionRegistry = Registry.as<IWorkbenchActionRegistry>(ActionExtensions.WorkbenchActions);
|
||||
registerTerminalActions();
|
||||
const category = TERMINAL_ACTION_CATEGORY;
|
||||
actionRegistry.registerWorkbenchAction(SyncActionDescriptor.from(KillTerminalAction), 'Terminal: Kill the Active Terminal Instance', category, KEYBINDING_CONTEXT_TERMINAL_PROCESS_SUPPORTED);
|
||||
actionRegistry.registerWorkbenchAction(SyncActionDescriptor.from(CreateNewTerminalAction, {
|
||||
primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.US_BACKTICK,
|
||||
mac: { primary: KeyMod.WinCtrl | KeyMod.Shift | KeyCode.US_BACKTICK }
|
||||
}), 'Terminal: Create New Integrated Terminal', category);
|
||||
actionRegistry.registerWorkbenchAction(SyncActionDescriptor.from(SelectAllTerminalAction, {
|
||||
// Don't use ctrl+a by default as that would override the common go to start
|
||||
// of prompt shell binding
|
||||
primary: 0,
|
||||
// Technically this doesn't need to be here as it will fall back to this
|
||||
// behavior anyway when handed to xterm.js, having this handled by VS Code
|
||||
// makes it easier for users to see how it works though.
|
||||
mac: { primary: KeyMod.CtrlCmd | KeyCode.KEY_A }
|
||||
}, KEYBINDING_CONTEXT_TERMINAL_FOCUS), 'Terminal: Select All', category, KEYBINDING_CONTEXT_TERMINAL_PROCESS_SUPPORTED);
|
||||
// Weight is higher than work workbench contributions so the keybinding remains
|
||||
// highest priority when chords are registered afterwards
|
||||
actionRegistry.registerWorkbenchAction(SyncActionDescriptor.from(ClearTerminalAction, {
|
||||
primary: 0,
|
||||
mac: { primary: KeyMod.CtrlCmd | KeyCode.KEY_K }
|
||||
}, KEYBINDING_CONTEXT_TERMINAL_FOCUS, KeybindingWeight.WorkbenchContrib + 1), 'Terminal: Clear', category, KEYBINDING_CONTEXT_TERMINAL_PROCESS_SUPPORTED);
|
||||
actionRegistry.registerWorkbenchAction(SyncActionDescriptor.from(SelectDefaultShellWindowsTerminalAction), 'Terminal: Select Default Shell', category, KEYBINDING_CONTEXT_TERMINAL_PROCESS_SUPPORTED);
|
||||
actionRegistry.registerWorkbenchAction(SyncActionDescriptor.from(SplitTerminalAction, {
|
||||
primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_5,
|
||||
mac: {
|
||||
primary: KeyMod.CtrlCmd | KeyCode.US_BACKSLASH,
|
||||
secondary: [KeyMod.WinCtrl | KeyMod.Shift | KeyCode.KEY_5]
|
||||
}
|
||||
}, KEYBINDING_CONTEXT_TERMINAL_FOCUS), 'Terminal: Split Terminal', category, KEYBINDING_CONTEXT_TERMINAL_PROCESS_SUPPORTED);
|
||||
actionRegistry.registerWorkbenchAction(SyncActionDescriptor.from(SplitInActiveWorkspaceTerminalAction), 'Terminal: Split Terminal (In Active Workspace)', category, KEYBINDING_CONTEXT_TERMINAL_PROCESS_SUPPORTED);
|
||||
|
||||
// Commands might be affected by Web restrictons
|
||||
if (BrowserFeatures.clipboard.writeText) {
|
||||
actionRegistry.registerWorkbenchAction(SyncActionDescriptor.from(CopyTerminalSelectionAction, {
|
||||
primary: KeyMod.CtrlCmd | KeyCode.KEY_C,
|
||||
win: { primary: KeyMod.CtrlCmd | KeyCode.KEY_C, secondary: [KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_C] },
|
||||
linux: { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_C }
|
||||
}, ContextKeyExpr.and(KEYBINDING_CONTEXT_TERMINAL_TEXT_SELECTED, KEYBINDING_CONTEXT_TERMINAL_FOCUS)), 'Terminal: Copy Selection', category, KEYBINDING_CONTEXT_TERMINAL_PROCESS_SUPPORTED);
|
||||
}
|
||||
|
||||
function registerSendSequenceKeybinding(text: string, rule: { when?: ContextKeyExpression } & IKeybindings): void {
|
||||
KeybindingsRegistry.registerCommandAndKeybindingRule({
|
||||
|
@ -149,14 +106,6 @@ function registerSendSequenceKeybinding(text: string, rule: { when?: ContextKeyE
|
|||
// The text representation of `^<letter>` is `'A'.charCodeAt(0) + 1`.
|
||||
const CTRL_LETTER_OFFSET = 64;
|
||||
|
||||
if (BrowserFeatures.clipboard.readText) {
|
||||
actionRegistry.registerWorkbenchAction(SyncActionDescriptor.from(TerminalPasteAction, platform.isMacintosh && platform.isWeb ? undefined : {
|
||||
primary: KeyMod.CtrlCmd | KeyCode.KEY_V,
|
||||
win: { primary: KeyMod.CtrlCmd | KeyCode.KEY_V, secondary: [KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_V] },
|
||||
linux: { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_V }
|
||||
}, KEYBINDING_CONTEXT_TERMINAL_FOCUS), 'Terminal: Paste into Active Terminal', category, KEYBINDING_CONTEXT_TERMINAL_PROCESS_SUPPORTED);
|
||||
}
|
||||
|
||||
// An extra Windows-only ctrl+v keybinding is used for pwsh that sends ctrl+v directly to the
|
||||
// shell, this gets handled by PSReadLine which properly handles multi-line pastes. This is
|
||||
// disabled in accessibility mode as PowerShell does not run PSReadLine when it detects a screen
|
||||
|
|
|
@ -3,45 +3,49 @@
|
|||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { Action, IAction } from 'vs/base/common/actions';
|
||||
import { EndOfLinePreference } from 'vs/editor/common/model';
|
||||
import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService';
|
||||
import { ITerminalConfigHelper, TitleEventSource, TERMINAL_COMMAND_ID, KEYBINDING_CONTEXT_TERMINAL_FIND_FOCUSED, TERMINAL_ACTION_CATEGORY, KEYBINDING_CONTEXT_TERMINAL_FOCUS, KEYBINDING_CONTEXT_TERMINAL_FIND_VISIBLE, KEYBINDING_CONTEXT_TERMINAL_TEXT_SELECTED, KEYBINDING_CONTEXT_TERMINAL_FIND_NOT_VISIBLE, KEYBINDING_CONTEXT_TERMINAL_A11Y_TREE_FOCUS, KEYBINDING_CONTEXT_TERMINAL_PROCESS_SUPPORTED, IRemoteTerminalAttachTarget, KEYBINDING_CONTEXT_TERMINAL_ALT_BUFFER_ACTIVE } from 'vs/workbench/contrib/terminal/common/terminal';
|
||||
import { attachSelectBoxStyler, attachStylerCallback } from 'vs/platform/theme/common/styler';
|
||||
import { IThemeService, ThemeIcon } from 'vs/platform/theme/common/themeService';
|
||||
import { IQuickInputService, IPickOptions, IQuickPickItem } from 'vs/platform/quickinput/common/quickInput';
|
||||
import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IContextViewService } from 'vs/platform/contextview/browser/contextView';
|
||||
import { ICommandService } from 'vs/platform/commands/common/commands';
|
||||
import { IWorkspaceContextService, IWorkspaceFolder } from 'vs/platform/workspace/common/workspace';
|
||||
import { PICK_WORKSPACE_FOLDER_COMMAND_ID } from 'vs/workbench/browser/actions/workspaceCommands';
|
||||
import { INotificationService } from 'vs/platform/notification/common/notification';
|
||||
import { ISelectOptionItem } from 'vs/base/browser/ui/selectBox/selectBox';
|
||||
import { IConfigurationResolverService } from 'vs/workbench/services/configurationResolver/common/configurationResolver';
|
||||
import { IHistoryService } from 'vs/workbench/services/history/common/history';
|
||||
import { BrowserFeatures } from 'vs/base/browser/canIUse';
|
||||
import { Action } from 'vs/base/common/actions';
|
||||
import { Codicon } from 'vs/base/common/codicons';
|
||||
import { KeyCode, KeyMod } from 'vs/base/common/keyCodes';
|
||||
import { Schemas } from 'vs/base/common/network';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { isWindows } from 'vs/base/common/platform';
|
||||
import { withNullAsUndefined } from 'vs/base/common/types';
|
||||
import { ITerminalInstance, ITerminalService, Direction, IRemoteTerminalService, TerminalConnectionState } from 'vs/workbench/contrib/terminal/browser/terminal';
|
||||
import { Action2, registerAction2, ILocalizedString } from 'vs/platform/actions/common/actions';
|
||||
import { TerminalQuickAccessProvider } from 'vs/workbench/contrib/terminal/browser/terminalQuickAccess';
|
||||
import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { selectBorder } from 'vs/platform/theme/common/colorRegistry';
|
||||
import { KeyMod, KeyCode } from 'vs/base/common/keyCodes';
|
||||
import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService';
|
||||
import { EndOfLinePreference } from 'vs/editor/common/model';
|
||||
import { localize } from 'vs/nls';
|
||||
import { CONTEXT_ACCESSIBILITY_MODE_ENABLED } from 'vs/platform/accessibility/common/accessibility';
|
||||
import { IOpenerService } from 'vs/platform/opener/common/opener';
|
||||
import { ITerminalContributionService } from 'vs/workbench/contrib/terminal/common/terminalExtensionPoints';
|
||||
import { SelectActionViewItem } from 'vs/base/browser/ui/actionbar/actionViewItems';
|
||||
import { FindInFilesCommand, IFindInFilesArgs } from 'vs/workbench/contrib/search/browser/searchActions';
|
||||
import { Action2, ICommandActionTitle, ILocalizedString, MenuId, MenuRegistry, registerAction2 } from 'vs/platform/actions/common/actions';
|
||||
import { ICommandService } from 'vs/platform/commands/common/commands';
|
||||
import { ContextKeyEqualsExpr, ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
|
||||
import { ILabelService } from 'vs/platform/label/common/label';
|
||||
import { INotificationService } from 'vs/platform/notification/common/notification';
|
||||
import { IOpenerService } from 'vs/platform/opener/common/opener';
|
||||
import { IPickOptions, IQuickInputService, IQuickPickItem } from 'vs/platform/quickinput/common/quickInput';
|
||||
import { IWorkspaceContextService, IWorkspaceFolder } from 'vs/platform/workspace/common/workspace';
|
||||
import { PICK_WORKSPACE_FOLDER_COMMAND_ID } from 'vs/workbench/browser/actions/workspaceCommands';
|
||||
import { RemoteNameContext } from 'vs/workbench/browser/contextkeys';
|
||||
import { FindInFilesCommand, IFindInFilesArgs } from 'vs/workbench/contrib/search/browser/searchActions';
|
||||
import { Direction, IRemoteTerminalService, ITerminalInstance, 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_PROCESS_SUPPORTED, KEYBINDING_CONTEXT_TERMINAL_TEXT_SELECTED, TERMINAL_ACTION_CATEGORY, TERMINAL_COMMAND_ID, TERMINAL_VIEW_ID, TitleEventSource } from 'vs/workbench/contrib/terminal/common/terminal';
|
||||
import { ITerminalContributionService } from 'vs/workbench/contrib/terminal/common/terminalExtensionPoints';
|
||||
import { IConfigurationResolverService } from 'vs/workbench/services/configurationResolver/common/configurationResolver';
|
||||
import { IHistoryService } from 'vs/workbench/services/history/common/history';
|
||||
import { IPreferencesService } from 'vs/workbench/services/preferences/common/preferences';
|
||||
import { killTerminalIcon, newTerminalIcon } from 'vs/workbench/contrib/terminal/browser/terminalIcons';
|
||||
import { Codicon } from 'vs/base/common/codicons';
|
||||
import { equals } from 'vs/base/common/objects';
|
||||
|
||||
export const switchTerminalActionViewItemSeparator = '─────────';
|
||||
export const selectDefaultShellTitle = localize('workbench.action.terminal.selectDefaultShell', "Select Default Shell");
|
||||
export const configureTerminalSettingsTitle = localize('workbench.action.terminal.openSettings', "Configure Terminal Settings");
|
||||
|
||||
const enum ContextMenuGroup {
|
||||
Create = '1_create',
|
||||
Edit = '2_edit',
|
||||
Clear = '3_clear',
|
||||
Kill = '4_kill'
|
||||
}
|
||||
|
||||
async function getCwdForSplit(configHelper: ITerminalConfigHelper, instance: ITerminalInstance, folders?: IWorkspaceFolder[], commandService?: ICommandService): Promise<string | URI | undefined> {
|
||||
switch (configHelper.config.splitCwd) {
|
||||
|
@ -70,68 +74,6 @@ async function getCwdForSplit(configHelper: ITerminalConfigHelper, instance: ITe
|
|||
}
|
||||
}
|
||||
|
||||
export class KillTerminalAction extends Action {
|
||||
|
||||
public static readonly ID = TERMINAL_COMMAND_ID.KILL;
|
||||
public static readonly LABEL = localize('workbench.action.terminal.kill', "Kill the Active Terminal Instance");
|
||||
public static readonly PANEL_LABEL = localize('workbench.action.terminal.kill.short', "Kill Terminal");
|
||||
|
||||
constructor(
|
||||
id: string, label: string,
|
||||
@ITerminalService private readonly _terminalService: ITerminalService
|
||||
) {
|
||||
super(id, label, 'terminal-action ' + ThemeIcon.asClassName(killTerminalIcon));
|
||||
}
|
||||
|
||||
async run() {
|
||||
await this._terminalService.doWithActiveInstance(async t => {
|
||||
t.dispose(true);
|
||||
if (this._terminalService.terminalInstances.length > 0) {
|
||||
await this._terminalService.showPanel(true);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies the terminal selection. Note that since the command palette takes focus from the terminal,
|
||||
* this cannot be triggered through the command palette.
|
||||
*/
|
||||
export class CopyTerminalSelectionAction extends Action {
|
||||
|
||||
public static readonly ID = TERMINAL_COMMAND_ID.COPY_SELECTION;
|
||||
public static readonly LABEL = localize('workbench.action.terminal.copySelection', "Copy Selection");
|
||||
public static readonly SHORT_LABEL = localize('workbench.action.terminal.copySelection.short', "Copy");
|
||||
|
||||
constructor(
|
||||
id: string, label: string,
|
||||
@ITerminalService private readonly _terminalService: ITerminalService
|
||||
) {
|
||||
super(id, label);
|
||||
}
|
||||
|
||||
async run() {
|
||||
await this._terminalService.getActiveInstance()?.copySelection();
|
||||
}
|
||||
}
|
||||
|
||||
export class SelectAllTerminalAction extends Action {
|
||||
|
||||
public static readonly ID = TERMINAL_COMMAND_ID.SELECT_ALL;
|
||||
public static readonly LABEL = localize('workbench.action.terminal.selectAll', "Select All");
|
||||
|
||||
constructor(
|
||||
id: string, label: string,
|
||||
@ITerminalService private readonly _terminalService: ITerminalService
|
||||
) {
|
||||
super(id, label);
|
||||
}
|
||||
|
||||
async run() {
|
||||
this._terminalService.getActiveInstance()?.selectAll();
|
||||
}
|
||||
}
|
||||
|
||||
export const terminalSendSequenceCommand = (accessor: ServicesAccessor, args: { text?: string } | undefined) => {
|
||||
accessor.get(ITerminalService).doWithActiveInstance(t => {
|
||||
if (!args?.text) {
|
||||
|
@ -147,280 +89,8 @@ export const terminalSendSequenceCommand = (accessor: ServicesAccessor, args: {
|
|||
});
|
||||
};
|
||||
|
||||
|
||||
export class CreateNewTerminalAction extends Action {
|
||||
|
||||
public static readonly ID = TERMINAL_COMMAND_ID.NEW;
|
||||
public static readonly LABEL = localize('workbench.action.terminal.new', "Create New Integrated Terminal");
|
||||
public static readonly SHORT_LABEL = localize('workbench.action.terminal.new.short', "New Terminal");
|
||||
|
||||
constructor(
|
||||
id: string, label: string,
|
||||
@ITerminalService private readonly _terminalService: ITerminalService,
|
||||
@ICommandService private readonly _commandService: ICommandService,
|
||||
@IWorkspaceContextService private readonly _workspaceContextService: IWorkspaceContextService
|
||||
) {
|
||||
super(id, label, 'terminal-action ' + ThemeIcon.asClassName(newTerminalIcon));
|
||||
}
|
||||
|
||||
async run(event?: any) {
|
||||
const folders = this._workspaceContextService.getWorkspace().folders;
|
||||
if (event instanceof MouseEvent && (event.altKey || event.ctrlKey)) {
|
||||
const activeInstance = this._terminalService.getActiveInstance();
|
||||
if (activeInstance) {
|
||||
const cwd = await getCwdForSplit(this._terminalService.configHelper, activeInstance);
|
||||
this._terminalService.splitInstance(activeInstance, { cwd });
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (this._terminalService.isProcessSupportRegistered) {
|
||||
let instance: ITerminalInstance | undefined;
|
||||
if (folders.length <= 1) {
|
||||
// Allow terminal service to handle the path when there is only a
|
||||
// single root
|
||||
instance = this._terminalService.createTerminal(undefined);
|
||||
} else {
|
||||
const options: IPickOptions<IQuickPickItem> = {
|
||||
placeHolder: localize('workbench.action.terminal.newWorkspacePlaceholder', "Select current working directory for new terminal")
|
||||
};
|
||||
const workspace = await this._commandService.executeCommand(PICK_WORKSPACE_FOLDER_COMMAND_ID, [options]);
|
||||
if (!workspace) {
|
||||
// Don't create the instance if the workspace picker was canceled
|
||||
return;
|
||||
}
|
||||
instance = this._terminalService.createTerminal({ cwd: workspace.uri });
|
||||
}
|
||||
this._terminalService.setActiveInstance(instance);
|
||||
}
|
||||
await this._terminalService.showPanel(true);
|
||||
}
|
||||
}
|
||||
|
||||
export class SplitTerminalAction extends Action {
|
||||
public static readonly ID = TERMINAL_COMMAND_ID.SPLIT;
|
||||
public static readonly LABEL = localize('workbench.action.terminal.split', "Split Terminal");
|
||||
public static readonly SHORT_LABEL = localize('workbench.action.terminal.split.short', "Split");
|
||||
public static readonly HORIZONTAL_CLASS = 'terminal-action ' + Codicon.splitHorizontal.classNames;
|
||||
public static readonly VERTICAL_CLASS = 'terminal-action ' + Codicon.splitVertical.classNames;
|
||||
|
||||
constructor(
|
||||
id: string, label: string,
|
||||
@ITerminalService private readonly _terminalService: ITerminalService,
|
||||
@ICommandService private readonly _commandService: ICommandService,
|
||||
@IWorkspaceContextService private readonly _workspaceContextService: IWorkspaceContextService
|
||||
) {
|
||||
super(id, label, SplitTerminalAction.HORIZONTAL_CLASS);
|
||||
}
|
||||
|
||||
public async run(): Promise<any> {
|
||||
await this._terminalService.doWithActiveInstance(async t => {
|
||||
const cwd = await getCwdForSplit(this._terminalService.configHelper, t, this._workspaceContextService.getWorkspace().folders, this._commandService);
|
||||
if (cwd === undefined) {
|
||||
return undefined;
|
||||
}
|
||||
this._terminalService.splitInstance(t, { cwd });
|
||||
return this._terminalService.showPanel(true);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export class SplitInActiveWorkspaceTerminalAction extends Action {
|
||||
public static readonly ID = TERMINAL_COMMAND_ID.SPLIT_IN_ACTIVE_WORKSPACE;
|
||||
public static readonly LABEL = localize('workbench.action.terminal.splitInActiveWorkspace', "Split Terminal (In Active Workspace)");
|
||||
|
||||
constructor(
|
||||
id: string, label: string,
|
||||
@ITerminalService private readonly _terminalService: ITerminalService
|
||||
) {
|
||||
super(id, label);
|
||||
}
|
||||
|
||||
async run() {
|
||||
await this._terminalService.doWithActiveInstance(async t => {
|
||||
const cwd = await getCwdForSplit(this._terminalService.configHelper, t);
|
||||
this._terminalService.splitInstance(t, { cwd });
|
||||
await this._terminalService.showPanel(true);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export class TerminalPasteAction extends Action {
|
||||
|
||||
public static readonly ID = TERMINAL_COMMAND_ID.PASTE;
|
||||
public static readonly LABEL = localize('workbench.action.terminal.paste', "Paste into Active Terminal");
|
||||
public static readonly SHORT_LABEL = localize('workbench.action.terminal.paste.short', "Paste");
|
||||
|
||||
constructor(
|
||||
id: string, label: string,
|
||||
@ITerminalService private readonly _terminalService: ITerminalService
|
||||
) {
|
||||
super(id, label);
|
||||
}
|
||||
|
||||
async run() {
|
||||
this._terminalService.getActiveOrCreateInstance()?.paste();
|
||||
}
|
||||
}
|
||||
|
||||
export class SelectDefaultShellWindowsTerminalAction extends Action {
|
||||
|
||||
public static readonly ID = TERMINAL_COMMAND_ID.SELECT_DEFAULT_SHELL;
|
||||
public static readonly LABEL = localize('workbench.action.terminal.selectDefaultShell', "Select Default Shell");
|
||||
|
||||
constructor(
|
||||
id: string, label: string,
|
||||
@ITerminalService private readonly _terminalService: ITerminalService
|
||||
) {
|
||||
super(id, label);
|
||||
}
|
||||
|
||||
async run() {
|
||||
this._terminalService.selectDefaultShell();
|
||||
}
|
||||
}
|
||||
|
||||
export class ConfigureTerminalSettingsAction extends Action {
|
||||
|
||||
public static readonly ID = TERMINAL_COMMAND_ID.CONFIGURE_TERMINAL_SETTINGS;
|
||||
public static readonly LABEL = localize('workbench.action.terminal.openSettings', "Configure Terminal Settings");
|
||||
|
||||
constructor(
|
||||
id: string, label: string,
|
||||
@IPreferencesService private readonly _preferencesService: IPreferencesService
|
||||
) {
|
||||
super(id, label);
|
||||
}
|
||||
|
||||
async run() {
|
||||
this._preferencesService.openSettings(false, '@feature:terminal');
|
||||
}
|
||||
}
|
||||
|
||||
const terminalIndexRe = /^([0-9]+): /;
|
||||
|
||||
export class SwitchTerminalAction extends Action {
|
||||
|
||||
public static readonly ID = TERMINAL_COMMAND_ID.SWITCH_TERMINAL;
|
||||
public static readonly LABEL = localize('workbench.action.terminal.switchTerminal', "Switch Terminal");
|
||||
|
||||
constructor(
|
||||
id: string, label: string,
|
||||
@ITerminalService private readonly _terminalService: ITerminalService,
|
||||
@ITerminalContributionService private readonly _contributions: ITerminalContributionService,
|
||||
@ICommandService private readonly _commands: ICommandService,
|
||||
@IPreferencesService private readonly preferencesService: IPreferencesService
|
||||
) {
|
||||
super(id, label, 'terminal-action switch-terminal');
|
||||
}
|
||||
|
||||
public run(item?: string): Promise<any> {
|
||||
if (!item || !item.split) {
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
if (item === SwitchTerminalActionViewItem.SEPARATOR) {
|
||||
this._terminalService.refreshActiveTab();
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
if (item === SelectDefaultShellWindowsTerminalAction.LABEL) {
|
||||
this._terminalService.refreshActiveTab();
|
||||
return this._terminalService.selectDefaultShell();
|
||||
}
|
||||
if (item === ConfigureTerminalSettingsAction.LABEL) {
|
||||
const settingsAction = new ConfigureTerminalSettingsAction(ConfigureTerminalSettingsAction.ID, ConfigureTerminalSettingsAction.LABEL, this.preferencesService);
|
||||
settingsAction.run();
|
||||
this._terminalService.refreshActiveTab();
|
||||
}
|
||||
const indexMatches = terminalIndexRe.exec(item);
|
||||
if (indexMatches) {
|
||||
this._terminalService.setActiveTabByIndex(Number(indexMatches[1]) - 1);
|
||||
return this._terminalService.showPanel(true);
|
||||
}
|
||||
|
||||
const customType = this._contributions.terminalTypes.find(t => t.title === item);
|
||||
if (customType) {
|
||||
return this._commands.executeCommand(customType.command);
|
||||
}
|
||||
console.warn(`Unmatched terminal item: "${item}"`);
|
||||
return Promise.resolve();
|
||||
}
|
||||
}
|
||||
|
||||
export class SwitchTerminalActionViewItem extends SelectActionViewItem {
|
||||
|
||||
public static readonly SEPARATOR = '─────────';
|
||||
private _lastOptions: ISelectOptionItem[] = [];
|
||||
constructor(
|
||||
action: IAction,
|
||||
@ITerminalService private readonly _terminalService: ITerminalService,
|
||||
@IThemeService private readonly _themeService: IThemeService,
|
||||
@ITerminalContributionService private readonly _contributions: ITerminalContributionService,
|
||||
@IContextViewService contextViewService: IContextViewService,
|
||||
) {
|
||||
super(null, action, getTerminalSelectOpenItems(_terminalService, _contributions), _terminalService.activeTabIndex, contextViewService, { ariaLabel: localize('terminals', 'Open Terminals.'), optionsAsChildren: true });
|
||||
|
||||
this._register(_terminalService.onInstancesChanged(this._updateItems, this));
|
||||
this._register(_terminalService.onActiveTabChanged(this._updateItems, this));
|
||||
this._register(_terminalService.onInstanceTitleChanged(this._updateItems, this));
|
||||
this._register(_terminalService.onTabDisposed(this._updateItems, this));
|
||||
this._register(_terminalService.onDidChangeConnectionState(this._updateItems, this));
|
||||
this._register(attachSelectBoxStyler(this.selectBox, this._themeService));
|
||||
}
|
||||
|
||||
render(container: HTMLElement): void {
|
||||
super.render(container);
|
||||
container.classList.add('switch-terminal');
|
||||
this._register(attachStylerCallback(this._themeService, { selectBorder }, colors => {
|
||||
container.style.borderColor = colors.selectBorder ? `${colors.selectBorder}` : '';
|
||||
}));
|
||||
}
|
||||
|
||||
private _updateItems(): void {
|
||||
const options = getTerminalSelectOpenItems(this._terminalService, this._contributions);
|
||||
// only update options if they've changed
|
||||
if (!equals(Object.values(options), Object.values(this._lastOptions))) {
|
||||
this.setOptions(options, this._terminalService.activeTabIndex);
|
||||
this._lastOptions = options;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getTerminalSelectOpenItems(terminalService: ITerminalService, contributions: ITerminalContributionService): ISelectOptionItem[] {
|
||||
const items = terminalService.connectionState === TerminalConnectionState.Connected ?
|
||||
terminalService.getTabLabels().map(label => <ISelectOptionItem>{ text: label }) :
|
||||
[{ text: localize('terminalConnectingLabel', "Starting...") }];
|
||||
|
||||
items.push({ text: SwitchTerminalActionViewItem.SEPARATOR, isDisabled: true });
|
||||
|
||||
for (const contributed of contributions.terminalTypes) {
|
||||
items.push({ text: contributed.title });
|
||||
}
|
||||
|
||||
items.push({ text: SelectDefaultShellWindowsTerminalAction.LABEL });
|
||||
items.push({ text: ConfigureTerminalSettingsAction.LABEL });
|
||||
return items;
|
||||
}
|
||||
|
||||
export class ClearTerminalAction extends Action {
|
||||
|
||||
public static readonly ID = TERMINAL_COMMAND_ID.CLEAR;
|
||||
public static readonly LABEL = localize('workbench.action.terminal.clear', "Clear");
|
||||
|
||||
constructor(
|
||||
id: string, label: string,
|
||||
@ITerminalService private readonly _terminalService: ITerminalService
|
||||
) {
|
||||
super(id, label);
|
||||
}
|
||||
|
||||
async run() {
|
||||
this._terminalService.doWithActiveInstance(t => {
|
||||
t.clear();
|
||||
t.focus();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export class TerminalLaunchHelpAction extends Action {
|
||||
|
||||
constructor(
|
||||
|
@ -1441,6 +1111,379 @@ export function registerTerminalActions() {
|
|||
accessor.get(ITerminalService).getActiveInstance()?.showEnvironmentInfoHover();
|
||||
}
|
||||
});
|
||||
registerAction2(class extends Action2 {
|
||||
constructor() {
|
||||
super({
|
||||
id: TERMINAL_COMMAND_ID.SPLIT,
|
||||
title: { value: localize('workbench.action.terminal.split', "Split Terminal"), original: 'Split Terminal' },
|
||||
f1: true,
|
||||
category,
|
||||
precondition: KEYBINDING_CONTEXT_TERMINAL_PROCESS_SUPPORTED,
|
||||
keybinding: [{
|
||||
primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_5,
|
||||
weight: KeybindingWeight.WorkbenchContrib,
|
||||
mac: {
|
||||
primary: KeyMod.CtrlCmd | KeyCode.US_BACKSLASH,
|
||||
secondary: [KeyMod.WinCtrl | KeyMod.Shift | KeyCode.KEY_5]
|
||||
},
|
||||
when: KEYBINDING_CONTEXT_TERMINAL_FOCUS
|
||||
}],
|
||||
icon: Codicon.splitHorizontal,
|
||||
menu: [{
|
||||
id: MenuId.ViewTitle,
|
||||
group: 'navigation',
|
||||
order: 2,
|
||||
when: ContextKeyEqualsExpr.create('view', TERMINAL_VIEW_ID),
|
||||
}]
|
||||
});
|
||||
}
|
||||
async run(accessor: ServicesAccessor) {
|
||||
const terminalService = accessor.get(ITerminalService);
|
||||
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;
|
||||
}
|
||||
terminalService.splitInstance(t, { cwd });
|
||||
return terminalService.showPanel(true);
|
||||
});
|
||||
}
|
||||
});
|
||||
MenuRegistry.appendMenuItem(MenuId.TerminalContext, {
|
||||
command: {
|
||||
id: TERMINAL_COMMAND_ID.SPLIT,
|
||||
title: localize('workbench.action.terminal.split.short', "Split")
|
||||
},
|
||||
group: ContextMenuGroup.Create
|
||||
});
|
||||
registerAction2(class extends Action2 {
|
||||
constructor() {
|
||||
super({
|
||||
id: TERMINAL_COMMAND_ID.SPLIT_IN_ACTIVE_WORKSPACE,
|
||||
title: { value: localize('workbench.action.terminal.splitInActiveWorkspace', "Split Terminal (In Active Workspace)"), original: 'Split Terminal (In Active Workspace)' },
|
||||
f1: true,
|
||||
category,
|
||||
precondition: KEYBINDING_CONTEXT_TERMINAL_PROCESS_SUPPORTED,
|
||||
});
|
||||
}
|
||||
async run(accessor: ServicesAccessor) {
|
||||
const terminalService = accessor.get(ITerminalService);
|
||||
await terminalService.doWithActiveInstance(async t => {
|
||||
const cwd = await getCwdForSplit(terminalService.configHelper, t);
|
||||
terminalService.splitInstance(t, { cwd });
|
||||
await terminalService.showPanel(true);
|
||||
});
|
||||
}
|
||||
});
|
||||
registerAction2(class extends Action2 {
|
||||
constructor() {
|
||||
super({
|
||||
id: TERMINAL_COMMAND_ID.SELECT_ALL,
|
||||
title: { value: localize('workbench.action.terminal.selectAll', "Select All"), original: 'Select All' },
|
||||
f1: true,
|
||||
category,
|
||||
precondition: KEYBINDING_CONTEXT_TERMINAL_PROCESS_SUPPORTED,
|
||||
keybinding: [{
|
||||
// Don't use ctrl+a by default as that would override the common go to start
|
||||
// of prompt shell binding
|
||||
primary: 0,
|
||||
// Technically this doesn't need to be here as it will fall back to this
|
||||
// behavior anyway when handed to xterm.js, having this handled by VS Code
|
||||
// makes it easier for users to see how it works though.
|
||||
mac: { primary: KeyMod.CtrlCmd | KeyCode.KEY_A },
|
||||
weight: KeybindingWeight.WorkbenchContrib,
|
||||
when: KEYBINDING_CONTEXT_TERMINAL_FOCUS
|
||||
}],
|
||||
menu: {
|
||||
id: MenuId.TerminalContext,
|
||||
group: ContextMenuGroup.Edit,
|
||||
order: 3
|
||||
}
|
||||
});
|
||||
}
|
||||
run(accessor: ServicesAccessor) {
|
||||
accessor.get(ITerminalService).getActiveInstance()?.selectAll();
|
||||
}
|
||||
});
|
||||
registerAction2(class extends Action2 {
|
||||
constructor() {
|
||||
super({
|
||||
id: TERMINAL_COMMAND_ID.NEW,
|
||||
title: { value: localize('workbench.action.terminal.new', "Create New Integrated Terminal"), original: 'Create New Integrated Terminal' },
|
||||
f1: true,
|
||||
category,
|
||||
precondition: KEYBINDING_CONTEXT_TERMINAL_PROCESS_SUPPORTED,
|
||||
icon: Codicon.plus,
|
||||
menu: {
|
||||
id: MenuId.ViewTitle,
|
||||
group: 'navigation',
|
||||
order: 1,
|
||||
when: ContextKeyEqualsExpr.create('view', TERMINAL_VIEW_ID)
|
||||
}
|
||||
});
|
||||
}
|
||||
async run(accessor: ServicesAccessor, event: unknown) {
|
||||
const terminalService = accessor.get(ITerminalService);
|
||||
const workspaceContextService = accessor.get(IWorkspaceContextService);
|
||||
const commandService = accessor.get(ICommandService);
|
||||
const folders = workspaceContextService.getWorkspace().folders;
|
||||
if (event instanceof MouseEvent && (event.altKey || event.ctrlKey)) {
|
||||
const activeInstance = terminalService.getActiveInstance();
|
||||
if (activeInstance) {
|
||||
const cwd = await getCwdForSplit(terminalService.configHelper, activeInstance);
|
||||
terminalService.splitInstance(activeInstance, { cwd });
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (terminalService.isProcessSupportRegistered) {
|
||||
let instance: ITerminalInstance | undefined;
|
||||
if (folders.length <= 1) {
|
||||
// Allow terminal service to handle the path when there is only a
|
||||
// single root
|
||||
instance = terminalService.createTerminal(undefined);
|
||||
} else {
|
||||
const options: IPickOptions<IQuickPickItem> = {
|
||||
placeHolder: localize('workbench.action.terminal.newWorkspacePlaceholder', "Select current working directory for new terminal")
|
||||
};
|
||||
const workspace = await commandService.executeCommand(PICK_WORKSPACE_FOLDER_COMMAND_ID, [options]);
|
||||
if (!workspace) {
|
||||
// Don't create the instance if the workspace picker was canceled
|
||||
return;
|
||||
}
|
||||
instance = terminalService.createTerminal({ cwd: workspace.uri });
|
||||
}
|
||||
terminalService.setActiveInstance(instance);
|
||||
}
|
||||
await terminalService.showPanel(true);
|
||||
}
|
||||
});
|
||||
MenuRegistry.appendMenuItem(MenuId.TerminalContext, {
|
||||
command: {
|
||||
id: TERMINAL_COMMAND_ID.NEW,
|
||||
title: localize('workbench.action.terminal.new.short', "New Terminal")
|
||||
},
|
||||
group: ContextMenuGroup.Create
|
||||
});
|
||||
registerAction2(class extends Action2 {
|
||||
constructor() {
|
||||
super({
|
||||
id: TERMINAL_COMMAND_ID.KILL,
|
||||
title: { value: localize('workbench.action.terminal.kill', "Kill the Active Terminal Instance"), original: 'Kill the Active Terminal Instance' },
|
||||
f1: true,
|
||||
category,
|
||||
precondition: KEYBINDING_CONTEXT_TERMINAL_PROCESS_SUPPORTED,
|
||||
icon: Codicon.trash,
|
||||
menu: {
|
||||
id: MenuId.ViewTitle,
|
||||
group: 'navigation',
|
||||
order: 3,
|
||||
when: ContextKeyEqualsExpr.create('view', TERMINAL_VIEW_ID)
|
||||
}
|
||||
});
|
||||
}
|
||||
async run(accessor: ServicesAccessor) {
|
||||
const terminalService = accessor.get(ITerminalService);
|
||||
await terminalService.doWithActiveInstance(async t => {
|
||||
t.dispose(true);
|
||||
if (terminalService.terminalInstances.length > 0) {
|
||||
await terminalService.showPanel(true);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
MenuRegistry.appendMenuItem(MenuId.TerminalContext, {
|
||||
command: {
|
||||
id: TERMINAL_COMMAND_ID.KILL,
|
||||
title: localize('workbench.action.terminal.kill.short', "Kill Terminal")
|
||||
},
|
||||
group: ContextMenuGroup.Kill
|
||||
});
|
||||
registerAction2(class extends Action2 {
|
||||
constructor() {
|
||||
super({
|
||||
id: TERMINAL_COMMAND_ID.KILL,
|
||||
title: { value: localize('workbench.action.terminal.clear', "Clear"), original: 'Clear' },
|
||||
f1: true,
|
||||
category,
|
||||
precondition: KEYBINDING_CONTEXT_TERMINAL_PROCESS_SUPPORTED,
|
||||
keybinding: [{
|
||||
primary: 0,
|
||||
mac: { primary: KeyMod.CtrlCmd | KeyCode.KEY_K },
|
||||
// Weight is higher than work workbench contributions so the keybinding remains
|
||||
// highest priority when chords are registered afterwards
|
||||
weight: KeybindingWeight.WorkbenchContrib + 1,
|
||||
when: KEYBINDING_CONTEXT_TERMINAL_FOCUS
|
||||
}],
|
||||
menu: {
|
||||
id: MenuId.TerminalContext,
|
||||
group: ContextMenuGroup.Clear
|
||||
}
|
||||
});
|
||||
}
|
||||
run(accessor: ServicesAccessor) {
|
||||
accessor.get(ITerminalService).doWithActiveInstance(t => {
|
||||
t.clear();
|
||||
t.focus();
|
||||
});
|
||||
}
|
||||
});
|
||||
registerAction2(class extends Action2 {
|
||||
constructor() {
|
||||
super({
|
||||
id: TERMINAL_COMMAND_ID.SELECT_DEFAULT_SHELL,
|
||||
title: { value: localize('workbench.action.terminal.selectDefaultShell', "Select Default Shell"), original: 'Select Default Shell' },
|
||||
f1: true,
|
||||
category,
|
||||
precondition: KEYBINDING_CONTEXT_TERMINAL_PROCESS_SUPPORTED
|
||||
});
|
||||
}
|
||||
async run(accessor: ServicesAccessor) {
|
||||
await accessor.get(ITerminalService).selectDefaultShell();
|
||||
}
|
||||
});
|
||||
registerAction2(class extends Action2 {
|
||||
constructor() {
|
||||
super({
|
||||
id: TERMINAL_COMMAND_ID.CONFIGURE_TERMINAL_SETTINGS,
|
||||
title: { value: configureTerminalSettingsTitle, original: 'Configure Terminal Settings' },
|
||||
f1: true,
|
||||
category,
|
||||
precondition: KEYBINDING_CONTEXT_TERMINAL_PROCESS_SUPPORTED
|
||||
});
|
||||
}
|
||||
async run(accessor: ServicesAccessor) {
|
||||
await accessor.get(IPreferencesService).openSettings(false, '@feature:terminal');
|
||||
}
|
||||
});
|
||||
|
||||
// Some commands depend on platform features
|
||||
if (BrowserFeatures.clipboard.writeText) {
|
||||
registerAction2(class extends Action2 {
|
||||
constructor() {
|
||||
super({
|
||||
id: TERMINAL_COMMAND_ID.COPY_SELECTION,
|
||||
title: { value: localize('workbench.action.terminal.copySelection', "Copy Selection"), original: 'Copy Selection' },
|
||||
f1: true,
|
||||
category,
|
||||
// TODO: Why is copy still showing up when text isn't selected?
|
||||
precondition: ContextKeyExpr.and(KEYBINDING_CONTEXT_TERMINAL_PROCESS_SUPPORTED, KEYBINDING_CONTEXT_TERMINAL_TEXT_SELECTED),
|
||||
keybinding: [{
|
||||
primary: KeyMod.CtrlCmd | KeyCode.KEY_C,
|
||||
win: { primary: KeyMod.CtrlCmd | KeyCode.KEY_C, secondary: [KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_C] },
|
||||
linux: { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_C },
|
||||
weight: KeybindingWeight.WorkbenchContrib,
|
||||
when: ContextKeyExpr.and(KEYBINDING_CONTEXT_TERMINAL_TEXT_SELECTED, KEYBINDING_CONTEXT_TERMINAL_FOCUS)
|
||||
}]
|
||||
});
|
||||
}
|
||||
async run(accessor: ServicesAccessor) {
|
||||
await accessor.get(ITerminalService).getActiveInstance()?.copySelection();
|
||||
}
|
||||
});
|
||||
MenuRegistry.appendMenuItem(MenuId.TerminalContext, {
|
||||
command: {
|
||||
id: TERMINAL_COMMAND_ID.COPY_SELECTION,
|
||||
title: localize('workbench.action.terminal.copySelection.short', "Copy")
|
||||
},
|
||||
group: ContextMenuGroup.Edit,
|
||||
order: 1
|
||||
});
|
||||
}
|
||||
|
||||
if (BrowserFeatures.clipboard.readText) {
|
||||
registerAction2(class extends Action2 {
|
||||
constructor() {
|
||||
super({
|
||||
id: TERMINAL_COMMAND_ID.PASTE,
|
||||
title: { value: localize('workbench.action.terminal.paste', "Paste into Active Terminal"), original: 'Paste into Active Terminal' },
|
||||
f1: true,
|
||||
category,
|
||||
precondition: KEYBINDING_CONTEXT_TERMINAL_PROCESS_SUPPORTED,
|
||||
keybinding: [{
|
||||
primary: KeyMod.CtrlCmd | KeyCode.KEY_V,
|
||||
win: { primary: KeyMod.CtrlCmd | KeyCode.KEY_V, secondary: [KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_V] },
|
||||
linux: { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_V },
|
||||
weight: KeybindingWeight.WorkbenchContrib,
|
||||
when: KEYBINDING_CONTEXT_TERMINAL_FOCUS
|
||||
}],
|
||||
});
|
||||
}
|
||||
async run(accessor: ServicesAccessor) {
|
||||
await accessor.get(ITerminalService).getActiveInstance()?.paste();
|
||||
}
|
||||
});
|
||||
MenuRegistry.appendMenuItem(MenuId.TerminalContext, {
|
||||
command: {
|
||||
id: TERMINAL_COMMAND_ID.PASTE,
|
||||
title: localize('workbench.action.terminal.paste.short', "Paste")
|
||||
},
|
||||
group: ContextMenuGroup.Edit,
|
||||
order: 2
|
||||
});
|
||||
}
|
||||
|
||||
const switchTerminalTitle: ICommandActionTitle = { value: localize('workbench.action.terminal.switchTerminal', "Switch Terminal"), original: 'Switch Terminal' };
|
||||
registerAction2(class extends Action2 {
|
||||
constructor() {
|
||||
super({
|
||||
id: TERMINAL_COMMAND_ID.SWITCH_TERMINAL,
|
||||
title: switchTerminalTitle,
|
||||
f1: true,
|
||||
category,
|
||||
precondition: KEYBINDING_CONTEXT_TERMINAL_PROCESS_SUPPORTED,
|
||||
keybinding: [{
|
||||
primary: KeyMod.CtrlCmd | KeyCode.KEY_V,
|
||||
win: { primary: KeyMod.CtrlCmd | KeyCode.KEY_V, secondary: [KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_V] },
|
||||
linux: { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_V },
|
||||
weight: KeybindingWeight.WorkbenchContrib,
|
||||
when: KEYBINDING_CONTEXT_TERMINAL_FOCUS
|
||||
}],
|
||||
});
|
||||
}
|
||||
async run(accessor: ServicesAccessor, item?: string) {
|
||||
const terminalService = accessor.get(ITerminalService);
|
||||
const terminalContributionService = accessor.get(ITerminalContributionService);
|
||||
const commandService = accessor.get(ICommandService);
|
||||
if (!item || !item.split) {
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
if (item === switchTerminalActionViewItemSeparator) {
|
||||
terminalService.refreshActiveTab();
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
if (item === selectDefaultShellTitle) {
|
||||
terminalService.refreshActiveTab();
|
||||
return terminalService.selectDefaultShell();
|
||||
}
|
||||
if (item === configureTerminalSettingsTitle) {
|
||||
await commandService.executeCommand(TERMINAL_COMMAND_ID.CONFIGURE_TERMINAL_SETTINGS);
|
||||
terminalService.refreshActiveTab();
|
||||
}
|
||||
const indexMatches = terminalIndexRe.exec(item);
|
||||
if (indexMatches) {
|
||||
terminalService.setActiveTabByIndex(Number(indexMatches[1]) - 1);
|
||||
return terminalService.showPanel(true);
|
||||
}
|
||||
|
||||
const customType = terminalContributionService.terminalTypes.find(t => t.title === item);
|
||||
if (customType) {
|
||||
return commandService.executeCommand(customType.command);
|
||||
}
|
||||
|
||||
console.warn(`Unmatched terminal item: "${item}"`);
|
||||
return Promise.resolve();
|
||||
}
|
||||
});
|
||||
MenuRegistry.appendMenuItem(MenuId.ViewTitle, {
|
||||
command: {
|
||||
id: TERMINAL_COMMAND_ID.SWITCH_TERMINAL,
|
||||
title: switchTerminalTitle
|
||||
},
|
||||
group: 'navigation',
|
||||
order: 0,
|
||||
when: ContextKeyEqualsExpr.create('view', TERMINAL_VIEW_ID)
|
||||
});
|
||||
}
|
||||
|
||||
interface IRemoteTerminalPick extends IQuickPickItem {
|
||||
|
|
|
@ -6,41 +6,46 @@
|
|||
import * as dom from 'vs/base/browser/dom';
|
||||
import * as nls from 'vs/nls';
|
||||
import * as platform from 'vs/base/common/platform';
|
||||
import { Action, IAction, Separator, IActionViewItem } from 'vs/base/common/actions';
|
||||
import { Action, IAction, IActionViewItem } from 'vs/base/common/actions';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
|
||||
import { IContextMenuService, IContextViewService } from 'vs/platform/contextview/browser/contextView';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { IThemeService, IColorTheme, registerThemingParticipant, ICssStyleCollector } from 'vs/platform/theme/common/themeService';
|
||||
import { TerminalFindWidget } from 'vs/workbench/contrib/terminal/browser/terminalFindWidget';
|
||||
import { KillTerminalAction, SwitchTerminalAction, SwitchTerminalActionViewItem, CopyTerminalSelectionAction, TerminalPasteAction, ClearTerminalAction, SelectAllTerminalAction, CreateNewTerminalAction, SplitTerminalAction } from 'vs/workbench/contrib/terminal/browser/terminalActions';
|
||||
import { configureTerminalSettingsTitle, selectDefaultShellTitle, switchTerminalActionViewItemSeparator } from 'vs/workbench/contrib/terminal/browser/terminalActions';
|
||||
import { StandardMouseEvent } from 'vs/base/browser/mouseEvent';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { TERMINAL_BACKGROUND_COLOR, TERMINAL_BORDER_COLOR } from 'vs/workbench/contrib/terminal/common/terminalColorRegistry';
|
||||
import { DataTransfers } from 'vs/base/browser/dnd';
|
||||
import { INotificationService, IPromptChoice, Severity } from 'vs/platform/notification/common/notification';
|
||||
import { ITerminalService, TerminalConnectionState } from 'vs/workbench/contrib/terminal/browser/terminal';
|
||||
import { BrowserFeatures } from 'vs/base/browser/canIUse';
|
||||
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 } from 'vs/workbench/common/theme';
|
||||
import { Orientation } from 'vs/base/browser/ui/sash/sash';
|
||||
import { IMenu, IMenuService, MenuId } from 'vs/platform/actions/common/actions';
|
||||
import { createAndFillInContextMenuActions } from 'vs/platform/actions/browser/menuEntryActionViewItem';
|
||||
import { TERMINAL_COMMAND_ID } from 'vs/workbench/contrib/terminal/common/terminal';
|
||||
import { 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';
|
||||
import { ISelectOptionItem } from 'vs/base/browser/ui/selectBox/selectBox';
|
||||
import { equals } from 'vs/base/common/arrays';
|
||||
|
||||
const FIND_FOCUS_CLASS = 'find-focused';
|
||||
|
||||
export class TerminalViewPane extends ViewPane {
|
||||
private _menu: IMenu;
|
||||
private _actions: IAction[] | undefined;
|
||||
private _copyContextMenuAction: IAction | undefined;
|
||||
private _contextMenuActions: IAction[] | undefined;
|
||||
private _cancelContextMenu: boolean = false;
|
||||
private _fontStyleElement: HTMLElement | undefined;
|
||||
private _parentDomElement: HTMLElement | undefined;
|
||||
private _terminalContainer: HTMLElement | undefined;
|
||||
private _findWidget: TerminalFindWidget | undefined;
|
||||
private _splitTerminalAction: IAction | undefined;
|
||||
private _terminalsInitialized = false;
|
||||
private _bodyDimensions: { width: number, height: number } = { width: 0, height: 0 };
|
||||
|
||||
|
@ -57,8 +62,10 @@ export class TerminalViewPane extends ViewPane {
|
|||
@ITelemetryService telemetryService: ITelemetryService,
|
||||
@INotificationService private readonly _notificationService: INotificationService,
|
||||
@IOpenerService openerService: IOpenerService,
|
||||
@IMenuService menuService: IMenuService,
|
||||
) {
|
||||
super(options, keybindingService, _contextMenuService, configurationService, contextKeyService, viewDescriptorService, _instantiationService, openerService, themeService, telemetryService);
|
||||
this._menu = this._register(menuService.createMenu(MenuId.TerminalContext, contextKeyService));
|
||||
this._terminalService.onDidRegisterProcessSupport(() => {
|
||||
if (this._actions) {
|
||||
for (const action of this._actions) {
|
||||
|
@ -148,67 +155,10 @@ export class TerminalViewPane extends ViewPane {
|
|||
this._bodyDimensions.width = width;
|
||||
this._bodyDimensions.height = height;
|
||||
this._terminalService.terminalTabs.forEach(t => t.layout(width, height));
|
||||
// Update orientation of split button icon
|
||||
if (this._splitTerminalAction) {
|
||||
this._splitTerminalAction.class = this.orientation === Orientation.HORIZONTAL ? SplitTerminalAction.HORIZONTAL_CLASS : SplitTerminalAction.VERTICAL_CLASS;
|
||||
}
|
||||
}
|
||||
|
||||
public getActions(): IAction[] {
|
||||
if (!this._actions) {
|
||||
this._splitTerminalAction = this._instantiationService.createInstance(SplitTerminalAction, SplitTerminalAction.ID, SplitTerminalAction.LABEL);
|
||||
this._actions = [
|
||||
this._instantiationService.createInstance(SwitchTerminalAction, SwitchTerminalAction.ID, SwitchTerminalAction.LABEL),
|
||||
this._instantiationService.createInstance(CreateNewTerminalAction, CreateNewTerminalAction.ID, CreateNewTerminalAction.SHORT_LABEL),
|
||||
this._splitTerminalAction,
|
||||
this._instantiationService.createInstance(KillTerminalAction, KillTerminalAction.ID, KillTerminalAction.PANEL_LABEL)
|
||||
];
|
||||
for (const action of this._actions) {
|
||||
if (!this._terminalService.isProcessSupportRegistered) {
|
||||
action.enabled = false;
|
||||
}
|
||||
this._register(action);
|
||||
}
|
||||
}
|
||||
return this._actions;
|
||||
}
|
||||
|
||||
private _getContextMenuActions(): IAction[] {
|
||||
if (!this._contextMenuActions || !this._copyContextMenuAction) {
|
||||
this._copyContextMenuAction = this._instantiationService.createInstance(CopyTerminalSelectionAction, CopyTerminalSelectionAction.ID, CopyTerminalSelectionAction.SHORT_LABEL);
|
||||
|
||||
const clipboardActions = [];
|
||||
if (BrowserFeatures.clipboard.writeText) {
|
||||
clipboardActions.push(this._copyContextMenuAction);
|
||||
}
|
||||
if (BrowserFeatures.clipboard.readText) {
|
||||
clipboardActions.push(this._instantiationService.createInstance(TerminalPasteAction, TerminalPasteAction.ID, TerminalPasteAction.SHORT_LABEL));
|
||||
}
|
||||
|
||||
clipboardActions.push(this._instantiationService.createInstance(SelectAllTerminalAction, SelectAllTerminalAction.ID, SelectAllTerminalAction.LABEL));
|
||||
|
||||
this._contextMenuActions = [
|
||||
this._instantiationService.createInstance(CreateNewTerminalAction, CreateNewTerminalAction.ID, CreateNewTerminalAction.SHORT_LABEL),
|
||||
this._instantiationService.createInstance(SplitTerminalAction, SplitTerminalAction.ID, SplitTerminalAction.SHORT_LABEL),
|
||||
new Separator(),
|
||||
...clipboardActions,
|
||||
new Separator(),
|
||||
this._instantiationService.createInstance(ClearTerminalAction, ClearTerminalAction.ID, ClearTerminalAction.LABEL),
|
||||
new Separator(),
|
||||
this._instantiationService.createInstance(KillTerminalAction, KillTerminalAction.ID, KillTerminalAction.PANEL_LABEL)
|
||||
|
||||
];
|
||||
this._contextMenuActions.forEach(a => {
|
||||
this._register(a);
|
||||
});
|
||||
}
|
||||
const activeInstance = this._terminalService.getActiveInstance();
|
||||
this._copyContextMenuAction.enabled = !!activeInstance && activeInstance.hasSelection();
|
||||
return this._contextMenuActions;
|
||||
}
|
||||
|
||||
public getActionViewItem(action: Action): IActionViewItem | undefined {
|
||||
if (action.id === SwitchTerminalAction.ID) {
|
||||
if (action.id === TERMINAL_COMMAND_ID.SWITCH_TERMINAL) {
|
||||
return this._instantiationService.createInstance(SwitchTerminalActionViewItem, action);
|
||||
}
|
||||
|
||||
|
@ -362,10 +312,15 @@ export class TerminalViewPane extends ViewPane {
|
|||
private _openContextMenu(event: MouseEvent): void {
|
||||
const standardEvent = new StandardMouseEvent(event);
|
||||
const anchor: { x: number, y: number } = { x: standardEvent.posx, y: standardEvent.posy };
|
||||
|
||||
const actions: IAction[] = [];
|
||||
const actionsDisposable = createAndFillInContextMenuActions(this._menu, undefined, actions);
|
||||
|
||||
this._contextMenuService.showContextMenu({
|
||||
getAnchor: () => anchor,
|
||||
getActions: () => this._getContextMenuActions(),
|
||||
getActionsContext: () => this._parentDomElement
|
||||
getActions: () => actions,
|
||||
getActionsContext: () => this._parentDomElement,
|
||||
onHide: () => actionsDisposable.dispose()
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -394,3 +349,58 @@ registerThemingParticipant((theme: IColorTheme, collector: ICssStyleCollector) =
|
|||
collector.addRule(`.monaco-workbench .pane-body.integrated-terminal .split-view-view:not(:first-child) { border-color: ${borderColor.toString()}; }`);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
class SwitchTerminalActionViewItem extends SelectActionViewItem {
|
||||
private _lastOptions: ISelectOptionItem[] = [];
|
||||
|
||||
constructor(
|
||||
action: IAction,
|
||||
@ITerminalService private readonly _terminalService: ITerminalService,
|
||||
@IThemeService private readonly _themeService: IThemeService,
|
||||
@ITerminalContributionService private readonly _contributions: ITerminalContributionService,
|
||||
@IContextViewService contextViewService: IContextViewService,
|
||||
) {
|
||||
super(null, action, getTerminalSelectOpenItems(_terminalService, _contributions), _terminalService.activeTabIndex, contextViewService, { ariaLabel: nls.localize('terminals', 'Open Terminals.'), optionsAsChildren: true });
|
||||
|
||||
this._register(_terminalService.onInstancesChanged(this._updateItems, this));
|
||||
this._register(_terminalService.onActiveTabChanged(this._updateItems, this));
|
||||
this._register(_terminalService.onInstanceTitleChanged(this._updateItems, this));
|
||||
this._register(_terminalService.onTabDisposed(this._updateItems, this));
|
||||
this._register(_terminalService.onDidChangeConnectionState(this._updateItems, this));
|
||||
this._register(attachSelectBoxStyler(this.selectBox, this._themeService));
|
||||
}
|
||||
|
||||
render(container: HTMLElement): void {
|
||||
super.render(container);
|
||||
container.classList.add('switch-terminal');
|
||||
this._register(attachStylerCallback(this._themeService, { selectBorder }, colors => {
|
||||
container.style.borderColor = colors.selectBorder ? `${colors.selectBorder}` : '';
|
||||
}));
|
||||
}
|
||||
|
||||
private _updateItems(): void {
|
||||
const options = getTerminalSelectOpenItems(this._terminalService, this._contributions);
|
||||
// only update options if they've changed
|
||||
if (!equals(Object.values(options), Object.values(this._lastOptions))) {
|
||||
this.setOptions(options, this._terminalService.activeTabIndex);
|
||||
this._lastOptions = options;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getTerminalSelectOpenItems(terminalService: ITerminalService, contributions: ITerminalContributionService): ISelectOptionItem[] {
|
||||
const items = terminalService.connectionState === TerminalConnectionState.Connected ?
|
||||
terminalService.getTabLabels().map(label => <ISelectOptionItem>{ text: label }) :
|
||||
[{ text: nls.localize('terminalConnectingLabel', "Starting...") }];
|
||||
|
||||
items.push({ text: switchTerminalActionViewItemSeparator, isDisabled: true });
|
||||
|
||||
for (const contributed of contributions.terminalTypes) {
|
||||
items.push({ text: contributed.title });
|
||||
}
|
||||
|
||||
items.push({ text: selectDefaultShellTitle });
|
||||
items.push({ text: configureTerminalSettingsTitle });
|
||||
return items;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue