export function registerTerminalActions()

in patched-vscode/src/vs/workbench/contrib/terminal/browser/terminalActions.ts [313:1645]


export function registerTerminalActions() {
	registerTerminalAction({
		id: TerminalCommandId.NewInActiveWorkspace,
		title: localize2('workbench.action.terminal.newInActiveWorkspace', 'Create New Terminal (In Active Workspace)'),
		run: async (c) => {
			if (c.service.isProcessSupportRegistered) {
				const instance = await c.service.createTerminal({ location: c.service.defaultLocation });
				if (!instance) {
					return;
				}
				c.service.setActiveInstance(instance);
			}
			await c.groupService.showPanel(true);
		}
	});

	// Register new with profile command
	refreshTerminalActions([]);

	registerTerminalAction({
		id: TerminalCommandId.CreateTerminalEditor,
		title: localize2('workbench.action.terminal.createTerminalEditor', 'Create New Terminal in Editor Area'),
		run: async (c, _, args) => {
			const options = (isObject(args) && 'location' in args) ? args as ICreateTerminalOptions : { location: TerminalLocation.Editor };
			const instance = await c.service.createTerminal(options);
			await instance.focusWhenReady();
		}
	});

	registerTerminalAction({
		id: TerminalCommandId.CreateTerminalEditorSameGroup,
		title: localize2('workbench.action.terminal.createTerminalEditor', 'Create New Terminal in Editor Area'),
		f1: false,
		run: async (c, accessor, args) => {
			// Force the editor into the same editor group if it's locked. This command is only ever
			// called when a terminal is the active editor
			const editorGroupsService = accessor.get(IEditorGroupsService);
			const instance = await c.service.createTerminal({
				location: { viewColumn: editorGroupToColumn(editorGroupsService, editorGroupsService.activeGroup) }
			});
			await instance.focusWhenReady();
		}
	});

	registerTerminalAction({
		id: TerminalCommandId.CreateTerminalEditorSide,
		title: localize2('workbench.action.terminal.createTerminalEditorSide', 'Create New Terminal in Editor Area to the Side'),
		run: async (c) => {
			const instance = await c.service.createTerminal({
				location: { viewColumn: SIDE_GROUP }
			});
			await instance.focusWhenReady();
		}
	});

	registerContextualInstanceAction({
		id: TerminalCommandId.MoveToEditor,
		title: terminalStrings.moveToEditor,
		precondition: sharedWhenClause.terminalAvailable_and_opened,
		activeInstanceType: 'view',
		run: (instance, c) => c.service.moveToEditor(instance),
		runAfter: (instances) => instances.at(-1)?.focus()
	});

	registerContextualInstanceAction({
		id: TerminalCommandId.MoveIntoNewWindow,
		title: terminalStrings.moveIntoNewWindow,
		precondition: sharedWhenClause.terminalAvailable_and_opened,
		run: (instance, c) => c.service.moveIntoNewEditor(instance),
		runAfter: (instances) => instances.at(-1)?.focus()
	});

	registerTerminalAction({
		id: TerminalCommandId.MoveToTerminalPanel,
		title: terminalStrings.moveToTerminalPanel,
		precondition: sharedWhenClause.terminalAvailable_and_editorActive,
		run: (c, _, args) => {
			const source = toOptionalUri(args) ?? c.editorService.activeInstance;
			if (source) {
				c.service.moveToTerminalView(source);
			}
		}
	});

	registerTerminalAction({
		id: TerminalCommandId.FocusPreviousPane,
		title: localize2('workbench.action.terminal.focusPreviousPane', 'Focus Previous Terminal in Terminal Group'),
		keybinding: {
			primary: KeyMod.Alt | KeyCode.LeftArrow,
			secondary: [KeyMod.Alt | KeyCode.UpArrow],
			mac: {
				primary: KeyMod.Alt | KeyMod.CtrlCmd | KeyCode.LeftArrow,
				secondary: [KeyMod.Alt | KeyMod.CtrlCmd | KeyCode.UpArrow]
			},
			when: TerminalContextKeys.focus,
			weight: KeybindingWeight.WorkbenchContrib
		},
		precondition: sharedWhenClause.terminalAvailable,
		run: async (c) => {
			c.groupService.activeGroup?.focusPreviousPane();
			await c.groupService.showPanel(true);
		}
	});

	registerTerminalAction({
		id: TerminalCommandId.FocusNextPane,
		title: localize2('workbench.action.terminal.focusNextPane', 'Focus Next Terminal in Terminal Group'),
		keybinding: {
			primary: KeyMod.Alt | KeyCode.RightArrow,
			secondary: [KeyMod.Alt | KeyCode.DownArrow],
			mac: {
				primary: KeyMod.Alt | KeyMod.CtrlCmd | KeyCode.RightArrow,
				secondary: [KeyMod.Alt | KeyMod.CtrlCmd | KeyCode.DownArrow]
			},
			when: TerminalContextKeys.focus,
			weight: KeybindingWeight.WorkbenchContrib
		},
		precondition: sharedWhenClause.terminalAvailable,
		run: async (c) => {
			c.groupService.activeGroup?.focusNextPane();
			await c.groupService.showPanel(true);
		}
	});

	registerActiveInstanceAction({
		id: TerminalCommandId.RunRecentCommand,
		title: localize2('workbench.action.terminal.runRecentCommand', 'Run Recent Command...'),
		precondition: sharedWhenClause.terminalAvailable,
		keybinding: [
			{
				primary: KeyMod.CtrlCmd | KeyCode.KeyR,
				when: ContextKeyExpr.and(CONTEXT_ACCESSIBILITY_MODE_ENABLED, ContextKeyExpr.or(TerminalContextKeys.focus, ContextKeyExpr.and(accessibleViewIsShown, accessibleViewCurrentProviderId.isEqualTo(AccessibleViewProviderId.Terminal)))),
				weight: KeybindingWeight.WorkbenchContrib
			},
			{
				primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.KeyR,
				mac: { primary: KeyMod.WinCtrl | KeyMod.Alt | KeyCode.KeyR },
				when: ContextKeyExpr.and(TerminalContextKeys.focus, CONTEXT_ACCESSIBILITY_MODE_ENABLED.negate()),
				weight: KeybindingWeight.WorkbenchContrib
			}
		],
		run: async (activeInstance, c) => {
			await activeInstance.runRecent('command');
			if (activeInstance?.target === TerminalLocation.Editor) {
				await c.editorService.revealActiveEditor();
			} else {
				await c.groupService.showPanel(false);
			}
		}
	});

	registerActiveInstanceAction({
		id: TerminalCommandId.CopyLastCommand,
		title: localize2('workbench.action.terminal.copyLastCommand', "Copy Last Command"),
		precondition: sharedWhenClause.terminalAvailable,
		run: async (instance, c, accessor) => {
			const clipboardService = accessor.get(IClipboardService);
			const commands = instance.capabilities.get(TerminalCapability.CommandDetection)?.commands;
			if (!commands || commands.length === 0) {
				return;
			}
			const command = commands[commands.length - 1];
			if (!command.command) {
				return;
			}
			await clipboardService.writeText(command.command);
		}
	});

	registerActiveInstanceAction({
		id: TerminalCommandId.CopyLastCommandOutput,
		title: localize2('workbench.action.terminal.copyLastCommandOutput', "Copy Last Command Output"),
		precondition: sharedWhenClause.terminalAvailable,
		run: async (instance, c, accessor) => {
			const clipboardService = accessor.get(IClipboardService);
			const commands = instance.capabilities.get(TerminalCapability.CommandDetection)?.commands;
			if (!commands || commands.length === 0) {
				return;
			}
			const command = commands[commands.length - 1];
			if (!command?.hasOutput()) {
				return;
			}
			const output = command.getOutput();
			if (isString(output)) {
				await clipboardService.writeText(output);
			}
		}
	});

	registerActiveInstanceAction({
		id: TerminalCommandId.CopyLastCommandAndLastCommandOutput,
		title: localize2('workbench.action.terminal.copyLastCommandAndOutput', "Copy Last Command and Output"),
		precondition: sharedWhenClause.terminalAvailable,
		run: async (instance, c, accessor) => {
			const clipboardService = accessor.get(IClipboardService);
			const commands = instance.capabilities.get(TerminalCapability.CommandDetection)?.commands;
			if (!commands || commands.length === 0) {
				return;
			}
			const command = commands[commands.length - 1];
			if (!command?.hasOutput()) {
				return;
			}
			const output = command.getOutput();
			if (isString(output)) {
				await clipboardService.writeText(`${command.command !== '' ? command.command + '\n' : ''}${output}`);
			}
		}
	});


	registerActiveInstanceAction({
		id: TerminalCommandId.GoToRecentDirectory,
		title: localize2('workbench.action.terminal.goToRecentDirectory', 'Go to Recent Directory...'),
		metadata: {
			description: localize2('goToRecentDirectory.metadata', 'Goes to a recent folder'),
		},
		precondition: sharedWhenClause.terminalAvailable,
		keybinding: {
			primary: KeyMod.CtrlCmd | KeyCode.KeyG,
			when: TerminalContextKeys.focus,
			weight: KeybindingWeight.WorkbenchContrib
		},
		run: async (activeInstance, c) => {
			await activeInstance.runRecent('cwd');
			if (activeInstance?.target === TerminalLocation.Editor) {
				await c.editorService.revealActiveEditor();
			} else {
				await c.groupService.showPanel(false);
			}
		}
	});

	registerTerminalAction({
		id: TerminalCommandId.ResizePaneLeft,
		title: localize2('workbench.action.terminal.resizePaneLeft', 'Resize Terminal Left'),
		keybinding: {
			linux: { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.LeftArrow },
			mac: { primary: KeyMod.CtrlCmd | KeyMod.WinCtrl | KeyCode.LeftArrow },
			when: TerminalContextKeys.focus,
			weight: KeybindingWeight.WorkbenchContrib
		},
		precondition: sharedWhenClause.terminalAvailable,
		run: (c) => c.groupService.activeGroup?.resizePane(Direction.Left)
	});

	registerTerminalAction({
		id: TerminalCommandId.ResizePaneRight,
		title: localize2('workbench.action.terminal.resizePaneRight', 'Resize Terminal Right'),
		keybinding: {
			linux: { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.RightArrow },
			mac: { primary: KeyMod.CtrlCmd | KeyMod.WinCtrl | KeyCode.RightArrow },
			when: TerminalContextKeys.focus,
			weight: KeybindingWeight.WorkbenchContrib
		},
		precondition: sharedWhenClause.terminalAvailable,
		run: (c) => c.groupService.activeGroup?.resizePane(Direction.Right)
	});

	registerTerminalAction({
		id: TerminalCommandId.ResizePaneUp,
		title: localize2('workbench.action.terminal.resizePaneUp', 'Resize Terminal Up'),
		keybinding: {
			mac: { primary: KeyMod.CtrlCmd | KeyMod.WinCtrl | KeyCode.UpArrow },
			when: TerminalContextKeys.focus,
			weight: KeybindingWeight.WorkbenchContrib
		},
		precondition: sharedWhenClause.terminalAvailable,
		run: (c) => c.groupService.activeGroup?.resizePane(Direction.Up)
	});

	registerTerminalAction({
		id: TerminalCommandId.ResizePaneDown,
		title: localize2('workbench.action.terminal.resizePaneDown', 'Resize Terminal Down'),
		keybinding: {
			mac: { primary: KeyMod.CtrlCmd | KeyMod.WinCtrl | KeyCode.DownArrow },
			when: TerminalContextKeys.focus,
			weight: KeybindingWeight.WorkbenchContrib
		},
		precondition: sharedWhenClause.terminalAvailable,
		run: (c) => c.groupService.activeGroup?.resizePane(Direction.Down)
	});

	registerTerminalAction({
		id: TerminalCommandId.Focus,
		title: terminalStrings.focus,
		keybinding: {
			when: ContextKeyExpr.and(CONTEXT_ACCESSIBILITY_MODE_ENABLED, accessibleViewOnLastLine, accessibleViewCurrentProviderId.isEqualTo(AccessibleViewProviderId.Terminal)),
			primary: KeyMod.CtrlCmd | KeyCode.DownArrow,
			weight: KeybindingWeight.WorkbenchContrib
		},
		precondition: sharedWhenClause.terminalAvailable,
		run: async (c) => {
			const instance = c.service.activeInstance || await c.service.createTerminal({ location: TerminalLocation.Panel });
			if (!instance) {
				return;
			}
			c.service.setActiveInstance(instance);
			focusActiveTerminal(instance, c);
		}
	});

	registerTerminalAction({
		id: TerminalCommandId.FocusTabs,
		title: localize2('workbench.action.terminal.focus.tabsView', 'Focus Terminal Tabs View'),
		keybinding: {
			primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.Backslash,
			weight: KeybindingWeight.WorkbenchContrib,
			when: ContextKeyExpr.or(TerminalContextKeys.tabsFocus, TerminalContextKeys.focus),
		},
		precondition: sharedWhenClause.terminalAvailable,
		run: (c) => c.groupService.focusTabs()
	});

	registerTerminalAction({
		id: TerminalCommandId.FocusNext,
		title: localize2('workbench.action.terminal.focusNext', 'Focus Next Terminal Group'),
		precondition: sharedWhenClause.terminalAvailable,
		keybinding: {
			primary: KeyMod.CtrlCmd | KeyCode.PageDown,
			mac: {
				primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.BracketRight
			},
			when: ContextKeyExpr.and(TerminalContextKeys.focus, TerminalContextKeys.editorFocus.negate()),
			weight: KeybindingWeight.WorkbenchContrib
		},
		run: async (c) => {
			c.groupService.setActiveGroupToNext();
			await c.groupService.showPanel(true);
		}
	});

	registerTerminalAction({
		id: TerminalCommandId.FocusPrevious,
		title: localize2('workbench.action.terminal.focusPrevious', 'Focus Previous Terminal Group'),
		precondition: sharedWhenClause.terminalAvailable,
		keybinding: {
			primary: KeyMod.CtrlCmd | KeyCode.PageUp,
			mac: {
				primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.BracketLeft
			},
			when: ContextKeyExpr.and(TerminalContextKeys.focus, TerminalContextKeys.editorFocus.negate()),
			weight: KeybindingWeight.WorkbenchContrib
		},
		run: async (c) => {
			c.groupService.setActiveGroupToPrevious();
			await c.groupService.showPanel(true);
		}
	});

	registerTerminalAction({
		id: TerminalCommandId.RunSelectedText,
		title: localize2('workbench.action.terminal.runSelectedText', 'Run Selected Text In Active Terminal'),
		run: async (c, accessor) => {
			const codeEditorService = accessor.get(ICodeEditorService);
			const editor = codeEditorService.getActiveCodeEditor();
			if (!editor || !editor.hasModel()) {
				return;
			}
			const instance = await c.service.getActiveOrCreateInstance({ acceptsInput: true });
			const selection = editor.getSelection();
			let text: string;
			if (selection.isEmpty()) {
				text = editor.getModel().getLineContent(selection.selectionStartLineNumber).trim();
			} else {
				const endOfLinePreference = isWindows ? EndOfLinePreference.LF : EndOfLinePreference.CRLF;
				text = editor.getModel().getValueInRange(selection, endOfLinePreference);
			}
			instance.sendText(text, true, true);
			await c.service.revealActiveTerminal(true);
		}
	});

	registerTerminalAction({
		id: TerminalCommandId.RunActiveFile,
		title: localize2('workbench.action.terminal.runActiveFile', 'Run Active File In Active Terminal'),
		precondition: sharedWhenClause.terminalAvailable,
		run: async (c, accessor) => {
			const codeEditorService = accessor.get(ICodeEditorService);
			const notificationService = accessor.get(INotificationService);
			const workbenchEnvironmentService = accessor.get(IWorkbenchEnvironmentService);

			const editor = codeEditorService.getActiveCodeEditor();
			if (!editor || !editor.hasModel()) {
				return;
			}

			const instance = await c.service.getActiveOrCreateInstance({ acceptsInput: true });
			const isRemote = instance ? instance.isRemote : (workbenchEnvironmentService.remoteAuthority ? true : false);
			const uri = editor.getModel().uri;
			if ((!isRemote && uri.scheme !== Schemas.file && uri.scheme !== Schemas.vscodeUserData) || (isRemote && uri.scheme !== Schemas.vscodeRemote)) {
				notificationService.warn(localize('workbench.action.terminal.runActiveFile.noFile', 'Only files on disk can be run in the terminal'));
				return;
			}

			// TODO: Convert this to ctrl+c, ctrl+v for pwsh?
			await instance.sendPath(uri, true);
			return c.groupService.showPanel();
		}
	});

	registerActiveXtermAction({
		id: TerminalCommandId.ScrollDownLine,
		title: localize2('workbench.action.terminal.scrollDown', 'Scroll Down (Line)'),
		keybinding: {
			primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.PageDown,
			linux: { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.DownArrow },
			when: sharedWhenClause.focusInAny_and_normalBuffer,
			weight: KeybindingWeight.WorkbenchContrib
		},
		precondition: sharedWhenClause.terminalAvailable,
		run: (xterm) => xterm.scrollDownLine()
	});

	registerActiveXtermAction({
		id: TerminalCommandId.ScrollDownPage,
		title: localize2('workbench.action.terminal.scrollDownPage', 'Scroll Down (Page)'),
		keybinding: {
			primary: KeyMod.Shift | KeyCode.PageDown,
			mac: { primary: KeyCode.PageDown },
			when: sharedWhenClause.focusInAny_and_normalBuffer,
			weight: KeybindingWeight.WorkbenchContrib
		},
		precondition: sharedWhenClause.terminalAvailable,
		run: (xterm) => xterm.scrollDownPage()
	});

	registerActiveXtermAction({
		id: TerminalCommandId.ScrollToBottom,
		title: localize2('workbench.action.terminal.scrollToBottom', 'Scroll to Bottom'),
		keybinding: {
			primary: KeyMod.CtrlCmd | KeyCode.End,
			linux: { primary: KeyMod.Shift | KeyCode.End },
			when: sharedWhenClause.focusInAny_and_normalBuffer,
			weight: KeybindingWeight.WorkbenchContrib
		},
		precondition: sharedWhenClause.terminalAvailable,
		run: (xterm) => xterm.scrollToBottom()
	});

	registerActiveXtermAction({
		id: TerminalCommandId.ScrollUpLine,
		title: localize2('workbench.action.terminal.scrollUp', 'Scroll Up (Line)'),
		keybinding: {
			primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.PageUp,
			linux: { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.UpArrow },
			when: sharedWhenClause.focusInAny_and_normalBuffer,
			weight: KeybindingWeight.WorkbenchContrib
		},
		precondition: sharedWhenClause.terminalAvailable,
		run: (xterm) => xterm.scrollUpLine()
	});

	registerActiveXtermAction({
		id: TerminalCommandId.ScrollUpPage,
		title: localize2('workbench.action.terminal.scrollUpPage', 'Scroll Up (Page)'),
		f1: true,
		category,
		keybinding: {
			primary: KeyMod.Shift | KeyCode.PageUp,
			mac: { primary: KeyCode.PageUp },
			when: sharedWhenClause.focusInAny_and_normalBuffer,
			weight: KeybindingWeight.WorkbenchContrib
		},
		precondition: sharedWhenClause.terminalAvailable,
		run: (xterm) => xterm.scrollUpPage()
	});

	registerActiveXtermAction({
		id: TerminalCommandId.ScrollToTop,
		title: localize2('workbench.action.terminal.scrollToTop', 'Scroll to Top'),
		keybinding: {
			primary: KeyMod.CtrlCmd | KeyCode.Home,
			linux: { primary: KeyMod.Shift | KeyCode.Home },
			when: sharedWhenClause.focusInAny_and_normalBuffer,
			weight: KeybindingWeight.WorkbenchContrib
		},
		precondition: sharedWhenClause.terminalAvailable,
		run: (xterm) => xterm.scrollToTop()
	});

	registerActiveXtermAction({
		id: TerminalCommandId.ClearSelection,
		title: localize2('workbench.action.terminal.clearSelection', 'Clear Selection'),
		keybinding: {
			primary: KeyCode.Escape,
			when: ContextKeyExpr.and(TerminalContextKeys.focusInAny, TerminalContextKeys.textSelected, TerminalContextKeys.notFindVisible),
			weight: KeybindingWeight.WorkbenchContrib
		},
		precondition: sharedWhenClause.terminalAvailable,
		run: (xterm) => {
			if (xterm.hasSelection()) {
				xterm.clearSelection();
			}
		}
	});

	registerTerminalAction({
		id: TerminalCommandId.ChangeIcon,
		title: terminalStrings.changeIcon,
		precondition: sharedWhenClause.terminalAvailable,
		run: (c, _, args: unknown) => getResourceOrActiveInstance(c, args)?.changeIcon()
	});

	registerTerminalAction({
		id: TerminalCommandId.ChangeIconActiveTab,
		title: terminalStrings.changeIcon,
		f1: false,
		precondition: sharedWhenClause.terminalAvailable_and_singularSelection,
		run: async (c, accessor, args) => {
			let icon: TerminalIcon | undefined;
			if (c.groupService.lastAccessedMenu === 'inline-tab') {
				getResourceOrActiveInstance(c, args)?.changeIcon();
				return;
			}
			for (const terminal of getSelectedInstances(accessor) ?? []) {
				icon = await terminal.changeIcon(icon);
			}
		}
	});

	registerTerminalAction({
		id: TerminalCommandId.ChangeColor,
		title: terminalStrings.changeColor,
		precondition: sharedWhenClause.terminalAvailable,
		run: (c, _, args) => getResourceOrActiveInstance(c, args)?.changeColor()
	});

	registerTerminalAction({
		id: TerminalCommandId.ChangeColorActiveTab,
		title: terminalStrings.changeColor,
		f1: false,
		precondition: sharedWhenClause.terminalAvailable_and_singularSelection,
		run: async (c, accessor, args) => {
			let color: string | undefined;
			let i = 0;
			if (c.groupService.lastAccessedMenu === 'inline-tab') {
				getResourceOrActiveInstance(c, args)?.changeColor();
				return;
			}
			for (const terminal of getSelectedInstances(accessor) ?? []) {
				const skipQuickPick = i !== 0;
				// Always show the quickpick on the first iteration
				color = await terminal.changeColor(color, skipQuickPick);
				i++;
			}
		}
	});

	registerTerminalAction({
		id: TerminalCommandId.Rename,
		title: terminalStrings.rename,
		precondition: sharedWhenClause.terminalAvailable,
		run: (c, accessor, args) => renameWithQuickPick(c, accessor, args)
	});

	registerTerminalAction({
		id: TerminalCommandId.RenameActiveTab,
		title: terminalStrings.rename,
		f1: false,
		keybinding: {
			primary: KeyCode.F2,
			mac: {
				primary: KeyCode.Enter
			},
			when: ContextKeyExpr.and(TerminalContextKeys.tabsFocus),
			weight: KeybindingWeight.WorkbenchContrib
		},
		precondition: sharedWhenClause.terminalAvailable_and_singularSelection,
		run: async (c, accessor) => {
			const terminalGroupService = accessor.get(ITerminalGroupService);
			const notificationService = accessor.get(INotificationService);
			const instances = getSelectedInstances(accessor);
			const firstInstance = instances?.[0];
			if (!firstInstance) {
				return;
			}

			if (terminalGroupService.lastAccessedMenu === 'inline-tab') {
				return renameWithQuickPick(c, accessor, firstInstance);
			}

			c.service.setEditingTerminal(firstInstance);
			c.service.setEditable(firstInstance, {
				validationMessage: value => validateTerminalName(value),
				onFinish: async (value, success) => {
					// Cancel editing first as instance.rename will trigger a rerender automatically
					c.service.setEditable(firstInstance, null);
					c.service.setEditingTerminal(undefined);
					if (success) {
						const promises: Promise<void>[] = [];
						for (const instance of instances) {
							promises.push((async () => {
								await instance.rename(value);
							})());
						}
						try {
							await Promise.all(promises);
						} catch (e) {
							notificationService.error(e);
						}
					}
				}
			});
		}
	});

	registerActiveInstanceAction({
		id: TerminalCommandId.DetachSession,
		title: localize2('workbench.action.terminal.detachSession', 'Detach Session'),
		run: (activeInstance) => activeInstance.detachProcessAndDispose(TerminalExitReason.User)
	});

	registerTerminalAction({
		id: TerminalCommandId.AttachToSession,
		title: localize2('workbench.action.terminal.attachToSession', 'Attach to Session'),
		run: async (c, accessor) => {
			const quickInputService = accessor.get(IQuickInputService);
			const labelService = accessor.get(ILabelService);
			const remoteAgentService = accessor.get(IRemoteAgentService);
			const notificationService = accessor.get(INotificationService);

			const remoteAuthority = remoteAgentService.getConnection()?.remoteAuthority ?? undefined;
			const backend = await accessor.get(ITerminalInstanceService).getBackend(remoteAuthority);

			if (!backend) {
				throw new Error(`No backend registered for remote authority '${remoteAuthority}'`);
			}

			const terms = await backend.listProcesses();

			backend.reduceConnectionGraceTime();

			const unattachedTerms = terms.filter(term => !c.service.isAttachedToTerminal(term));
			const items = unattachedTerms.map(term => {
				const cwdLabel = labelService.getUriLabel(URI.file(term.cwd));
				return {
					label: term.title,
					detail: term.workspaceName ? `${term.workspaceName} \u2E31 ${cwdLabel}` : cwdLabel,
					description: term.pid ? String(term.pid) : '',
					term
				};
			});
			if (items.length === 0) {
				notificationService.info(localize('noUnattachedTerminals', 'There are no unattached terminals to attach to'));
				return;
			}
			const selected = await quickInputService.pick<IRemoteTerminalPick>(items, { canPickMany: false });
			if (selected) {
				const instance = await c.service.createTerminal({
					config: { attachPersistentProcess: selected.term }
				});
				c.service.setActiveInstance(instance);
				await focusActiveTerminal(instance, c);
			}
		}
	});

	registerTerminalAction({
		id: TerminalCommandId.QuickOpenTerm,
		title: localize2('quickAccessTerminal', 'Switch Active Terminal'),
		precondition: sharedWhenClause.terminalAvailable,
		run: (c, accessor) => accessor.get(IQuickInputService).quickAccess.show(TerminalQuickAccessProvider.PREFIX)
	});

	registerActiveInstanceAction({
		id: TerminalCommandId.ScrollToPreviousCommand,
		title: terminalStrings.scrollToPreviousCommand,
		keybinding: {
			primary: KeyMod.CtrlCmd | KeyCode.UpArrow,
			when: ContextKeyExpr.and(TerminalContextKeys.focus, CONTEXT_ACCESSIBILITY_MODE_ENABLED.negate()),
			weight: KeybindingWeight.WorkbenchContrib
		},
		precondition: sharedWhenClause.terminalAvailable,
		icon: Codicon.arrowUp,
		menu: [
			{
				id: MenuId.ViewTitle,
				group: 'navigation',
				order: 4,
				when: ContextKeyExpr.equals('view', TERMINAL_VIEW_ID),
				isHiddenByDefault: true
			}
		],
		run: (activeInstance) => activeInstance.xterm?.markTracker.scrollToPreviousMark(undefined, undefined, activeInstance.capabilities.has(TerminalCapability.CommandDetection))
	});

	registerActiveInstanceAction({
		id: TerminalCommandId.ScrollToNextCommand,
		title: terminalStrings.scrollToNextCommand,
		keybinding: {
			primary: KeyMod.CtrlCmd | KeyCode.DownArrow,
			when: ContextKeyExpr.and(TerminalContextKeys.focus, CONTEXT_ACCESSIBILITY_MODE_ENABLED.negate()),
			weight: KeybindingWeight.WorkbenchContrib
		},
		precondition: sharedWhenClause.terminalAvailable,
		icon: Codicon.arrowDown,
		menu: [
			{
				id: MenuId.ViewTitle,
				group: 'navigation',
				order: 4,
				when: ContextKeyExpr.equals('view', TERMINAL_VIEW_ID),
				isHiddenByDefault: true
			}
		],
		run: (activeInstance) => {
			activeInstance.xterm?.markTracker.scrollToNextMark();
			activeInstance.focus();
		}
	});

	registerActiveInstanceAction({
		id: TerminalCommandId.SelectToPreviousCommand,
		title: localize2('workbench.action.terminal.selectToPreviousCommand', 'Select To Previous Command'),
		keybinding: {
			primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.UpArrow,
			when: TerminalContextKeys.focus,
			weight: KeybindingWeight.WorkbenchContrib
		},
		precondition: sharedWhenClause.terminalAvailable,
		run: (activeInstance) => {
			activeInstance.xterm?.markTracker.selectToPreviousMark();
			activeInstance.focus();
		}
	});

	registerActiveInstanceAction({
		id: TerminalCommandId.SelectToNextCommand,
		title: localize2('workbench.action.terminal.selectToNextCommand', 'Select To Next Command'),
		keybinding: {
			primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.DownArrow,
			when: TerminalContextKeys.focus,
			weight: KeybindingWeight.WorkbenchContrib
		},
		precondition: sharedWhenClause.terminalAvailable,
		run: (activeInstance) => {
			activeInstance.xterm?.markTracker.selectToNextMark();
			activeInstance.focus();
		}
	});

	registerActiveXtermAction({
		id: TerminalCommandId.SelectToPreviousLine,
		title: localize2('workbench.action.terminal.selectToPreviousLine', 'Select To Previous Line'),
		precondition: sharedWhenClause.terminalAvailable,
		run: async (xterm, _, instance) => {
			xterm.markTracker.selectToPreviousLine();
			// prefer to call focus on the TerminalInstance for additional accessibility triggers
			(instance || xterm).focus();
		}
	});

	registerActiveXtermAction({
		id: TerminalCommandId.SelectToNextLine,
		title: localize2('workbench.action.terminal.selectToNextLine', 'Select To Next Line'),
		precondition: sharedWhenClause.terminalAvailable,
		run: async (xterm, _, instance) => {
			xterm.markTracker.selectToNextLine();
			// prefer to call focus on the TerminalInstance for additional accessibility triggers
			(instance || xterm).focus();
		}
	});

	registerTerminalAction({
		id: TerminalCommandId.SendSequence,
		title: terminalStrings.sendSequence,
		f1: false,
		metadata: {
			description: terminalStrings.sendSequence.value,
			args: [{
				name: 'args',
				schema: {
					type: 'object',
					required: ['text'],
					properties: {
						text: {
							description: localize('sendSequence', "The sequence of text to send to the terminal"),
							type: 'string'
						}
					},
				}
			}]
		},
		run: (c, accessor, args) => terminalSendSequenceCommand(accessor, args)
	});

	registerTerminalAction({
		id: TerminalCommandId.NewWithCwd,
		title: terminalStrings.newWithCwd,
		metadata: {
			description: terminalStrings.newWithCwd.value,
			args: [{
				name: 'args',
				schema: {
					type: 'object',
					required: ['cwd'],
					properties: {
						cwd: {
							description: localize('workbench.action.terminal.newWithCwd.cwd', "The directory to start the terminal at"),
							type: 'string'
						}
					},
				}
			}]
		},
		run: async (c, _, args) => {
			const cwd = isObject(args) && 'cwd' in args ? toOptionalString(args.cwd) : undefined;
			const instance = await c.service.createTerminal({ cwd });
			if (!instance) {
				return;
			}
			c.service.setActiveInstance(instance);
			await focusActiveTerminal(instance, c);
		}
	});

	registerActiveInstanceAction({
		id: TerminalCommandId.RenameWithArgs,
		title: terminalStrings.renameWithArgs,
		metadata: {
			description: terminalStrings.renameWithArgs.value,
			args: [{
				name: 'args',
				schema: {
					type: 'object',
					required: ['name'],
					properties: {
						name: {
							description: localize('workbench.action.terminal.renameWithArg.name', "The new name for the terminal"),
							type: 'string',
							minLength: 1
						}
					}
				}
			}]
		},
		precondition: sharedWhenClause.terminalAvailable,
		run: async (activeInstance, c, accessor, args) => {
			const notificationService = accessor.get(INotificationService);
			const name = isObject(args) && 'name' in args ? toOptionalString(args.name) : undefined;
			if (!name) {
				notificationService.warn(localize('workbench.action.terminal.renameWithArg.noName', "No name argument provided"));
				return;
			}
			activeInstance.rename(name);
		}
	});

	registerActiveInstanceAction({
		id: TerminalCommandId.Relaunch,
		title: localize2('workbench.action.terminal.relaunch', 'Relaunch Active Terminal'),
		run: (activeInstance) => activeInstance.relaunch()
	});

	registerTerminalAction({
		id: TerminalCommandId.Split,
		title: terminalStrings.split,
		precondition: ContextKeyExpr.or(TerminalContextKeys.processSupported, TerminalContextKeys.webExtensionContributedProfile),
		keybinding: {
			primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.Digit5,
			weight: KeybindingWeight.WorkbenchContrib,
			mac: {
				primary: KeyMod.CtrlCmd | KeyCode.Backslash,
				secondary: [KeyMod.WinCtrl | KeyMod.Shift | KeyCode.Digit5]
			},
			when: TerminalContextKeys.focus
		},
		icon: Codicon.splitHorizontal,
		run: async (c, accessor, args) => {
			const optionsOrProfile = isObject(args) ? args as ICreateTerminalOptions | ITerminalProfile : undefined;
			const commandService = accessor.get(ICommandService);
			const workspaceContextService = accessor.get(IWorkspaceContextService);
			const options = convertOptionsOrProfileToOptions(optionsOrProfile);
			const activeInstance = (await c.service.getInstanceHost(options?.location)).activeInstance;
			if (!activeInstance) {
				return;
			}
			const cwd = await getCwdForSplit(activeInstance, workspaceContextService.getWorkspace().folders, commandService, c.configService);
			if (cwd === undefined) {
				return;
			}
			const instance = await c.service.createTerminal({ location: { parentTerminal: activeInstance }, config: options?.config, cwd });
			await focusActiveTerminal(instance, c);
		}
	});

	registerTerminalAction({
		id: TerminalCommandId.SplitActiveTab,
		title: terminalStrings.split,
		f1: false,
		keybinding: {
			primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.Digit5,
			mac: {
				primary: KeyMod.CtrlCmd | KeyCode.Backslash,
				secondary: [KeyMod.WinCtrl | KeyMod.Shift | KeyCode.Digit5]
			},
			weight: KeybindingWeight.WorkbenchContrib,
			when: TerminalContextKeys.tabsFocus
		},
		run: async (c, accessor) => {
			const instances = getSelectedInstances(accessor);
			if (instances) {
				const promises: Promise<void>[] = [];
				for (const t of instances) {
					promises.push((async () => {
						await c.service.createTerminal({ location: { parentTerminal: t } });
						await c.groupService.showPanel(true);
					})());
				}
				await Promise.all(promises);
			}
		}
	});

	registerContextualInstanceAction({
		id: TerminalCommandId.Unsplit,
		title: terminalStrings.unsplit,
		precondition: sharedWhenClause.terminalAvailable,
		run: async (instance, c) => {
			const group = c.groupService.getGroupForInstance(instance);
			if (group && group?.terminalInstances.length > 1) {
				c.groupService.unsplitInstance(instance);
			}
		}
	});

	registerTerminalAction({
		id: TerminalCommandId.JoinActiveTab,
		title: localize2('workbench.action.terminal.joinInstance', 'Join Terminals'),
		precondition: ContextKeyExpr.and(sharedWhenClause.terminalAvailable, TerminalContextKeys.tabsSingularSelection.toNegated()),
		run: async (c, accessor) => {
			const instances = getSelectedInstances(accessor);
			if (instances && instances.length > 1) {
				c.groupService.joinInstances(instances);
			}
		}
	});

	registerTerminalAction({
		id: TerminalCommandId.Join,
		title: localize2('workbench.action.terminal.join', 'Join Terminals...'),
		precondition: sharedWhenClause.terminalAvailable,
		run: async (c, accessor) => {
			const themeService = accessor.get(IThemeService);
			const notificationService = accessor.get(INotificationService);
			const quickInputService = accessor.get(IQuickInputService);

			const picks: ITerminalQuickPickItem[] = [];
			if (c.groupService.instances.length <= 1) {
				notificationService.warn(localize('workbench.action.terminal.join.insufficientTerminals', 'Insufficient terminals for the join action'));
				return;
			}
			const otherInstances = c.groupService.instances.filter(i => i.instanceId !== c.groupService.activeInstance?.instanceId);
			for (const terminal of otherInstances) {
				const group = c.groupService.getGroupForInstance(terminal);
				if (group?.terminalInstances.length === 1) {
					const iconId = getIconId(accessor, terminal);
					const label = `$(${iconId}): ${terminal.title}`;
					const iconClasses: string[] = [];
					const colorClass = getColorClass(terminal);
					if (colorClass) {
						iconClasses.push(colorClass);
					}
					const uriClasses = getUriClasses(terminal, themeService.getColorTheme().type);
					if (uriClasses) {
						iconClasses.push(...uriClasses);
					}
					picks.push({
						terminal,
						label,
						iconClasses
					});
				}
			}
			if (picks.length === 0) {
				notificationService.warn(localize('workbench.action.terminal.join.onlySplits', 'All terminals are joined already'));
				return;
			}
			const result = await quickInputService.pick(picks, {});
			if (result) {
				c.groupService.joinInstances([result.terminal, c.groupService.activeInstance!]);
			}
		}
	});

	registerActiveInstanceAction({
		id: TerminalCommandId.SplitInActiveWorkspace,
		title: localize2('workbench.action.terminal.splitInActiveWorkspace', 'Split Terminal (In Active Workspace)'),
		run: async (instance, c) => {
			const newInstance = await c.service.createTerminal({ location: { parentTerminal: instance } });
			if (newInstance?.target !== TerminalLocation.Editor) {
				await c.groupService.showPanel(true);
			}
		}
	});

	registerActiveXtermAction({
		id: TerminalCommandId.SelectAll,
		title: localize2('workbench.action.terminal.selectAll', 'Select All'),
		precondition: sharedWhenClause.terminalAvailable,
		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.KeyA },
			weight: KeybindingWeight.WorkbenchContrib,
			when: TerminalContextKeys.focusInAny
		}],
		run: (xterm) => xterm.selectAll()
	});

	registerTerminalAction({
		id: TerminalCommandId.New,
		title: localize2('workbench.action.terminal.new', 'Create New Terminal'),
		precondition: ContextKeyExpr.or(TerminalContextKeys.processSupported, TerminalContextKeys.webExtensionContributedProfile),
		icon: newTerminalIcon,
		keybinding: {
			primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.Backquote,
			mac: { primary: KeyMod.WinCtrl | KeyMod.Shift | KeyCode.Backquote },
			weight: KeybindingWeight.WorkbenchContrib
		},
		run: async (c, accessor, args) => {
			let eventOrOptions = isObject(args) ? args as MouseEvent | ICreateTerminalOptions : undefined;
			const workspaceContextService = accessor.get(IWorkspaceContextService);
			const commandService = accessor.get(ICommandService);
			const folders = workspaceContextService.getWorkspace().folders;
			if (eventOrOptions && isMouseEvent(eventOrOptions) && (eventOrOptions.altKey || eventOrOptions.ctrlKey)) {
				await c.service.createTerminal({ location: { splitActiveTerminal: true } });
				return;
			}

			if (c.service.isProcessSupportRegistered) {
				eventOrOptions = !eventOrOptions || isMouseEvent(eventOrOptions) ? {} : eventOrOptions;

				let instance: ITerminalInstance | undefined;
				if (folders.length <= 1) {
					// Allow terminal service to handle the path when there is only a
					// single root
					instance = await c.service.createTerminal(eventOrOptions);
				} else {
					const cwd = (await pickTerminalCwd(accessor))?.cwd;
					if (!cwd) {
						// Don't create the instance if the workspace picker was canceled
						return;
					}
					eventOrOptions.cwd = cwd;
					instance = await c.service.createTerminal(eventOrOptions);
				}
				c.service.setActiveInstance(instance);
				await focusActiveTerminal(instance, c);
			} else {
				if (c.profileService.contributedProfiles.length > 0) {
					commandService.executeCommand(TerminalCommandId.NewWithProfile);
				} else {
					commandService.executeCommand(TerminalCommandId.Toggle);
				}
			}
		}
	});

	async function killInstance(c: ITerminalServicesCollection, instance: ITerminalInstance | undefined): Promise<void> {
		if (!instance) {
			return;
		}
		await c.service.safeDisposeTerminal(instance);
		if (c.groupService.instances.length > 0) {
			await c.groupService.showPanel(true);
		}
	}
	registerTerminalAction({
		id: TerminalCommandId.Kill,
		title: localize2('workbench.action.terminal.kill', 'Kill the Active Terminal Instance'),
		precondition: ContextKeyExpr.or(sharedWhenClause.terminalAvailable, TerminalContextKeys.isOpen),
		icon: killTerminalIcon,
		run: async (c) => killInstance(c, c.groupService.activeInstance)
	});
	registerTerminalAction({
		id: TerminalCommandId.KillViewOrEditor,
		title: terminalStrings.kill,
		f1: false, // This is an internal command used for context menus
		precondition: ContextKeyExpr.or(sharedWhenClause.terminalAvailable, TerminalContextKeys.isOpen),
		run: async (c) => killInstance(c, c.service.activeInstance)
	});

	registerTerminalAction({
		id: TerminalCommandId.KillAll,
		title: localize2('workbench.action.terminal.killAll', 'Kill All Terminals'),
		precondition: ContextKeyExpr.or(sharedWhenClause.terminalAvailable, TerminalContextKeys.isOpen),
		icon: Codicon.trash,
		run: async (c) => {
			const disposePromises: Promise<void>[] = [];
			for (const instance of c.service.instances) {
				disposePromises.push(c.service.safeDisposeTerminal(instance));
			}
			await Promise.all(disposePromises);
		}
	});

	registerTerminalAction({
		id: TerminalCommandId.KillEditor,
		title: localize2('workbench.action.terminal.killEditor', 'Kill the Active Terminal in Editor Area'),
		precondition: sharedWhenClause.terminalAvailable,
		keybinding: {
			primary: KeyMod.CtrlCmd | KeyCode.KeyW,
			win: { primary: KeyMod.CtrlCmd | KeyCode.F4, secondary: [KeyMod.CtrlCmd | KeyCode.KeyW] },
			weight: KeybindingWeight.WorkbenchContrib,
			when: ContextKeyExpr.and(TerminalContextKeys.focus, TerminalContextKeys.editorFocus)
		},
		run: (c, accessor) => accessor.get(ICommandService).executeCommand(CLOSE_EDITOR_COMMAND_ID)
	});

	registerTerminalAction({
		id: TerminalCommandId.KillActiveTab,
		title: terminalStrings.kill,
		f1: false,
		precondition: ContextKeyExpr.or(sharedWhenClause.terminalAvailable, TerminalContextKeys.isOpen),
		keybinding: {
			primary: KeyCode.Delete,
			mac: {
				primary: KeyMod.CtrlCmd | KeyCode.Backspace,
				secondary: [KeyCode.Delete]
			},
			weight: KeybindingWeight.WorkbenchContrib,
			when: TerminalContextKeys.tabsFocus
		},
		run: async (c, accessor) => {
			const disposePromises: Promise<void>[] = [];
			for (const terminal of getSelectedInstances(accessor, true) ?? []) {
				disposePromises.push(c.service.safeDisposeTerminal(terminal));
			}
			await Promise.all(disposePromises);
			c.groupService.focusTabs();
		}
	});

	registerTerminalAction({
		id: TerminalCommandId.FocusHover,
		title: terminalStrings.focusHover,
		precondition: ContextKeyExpr.or(sharedWhenClause.terminalAvailable, TerminalContextKeys.isOpen),
		keybinding: {
			primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KeyK, KeyMod.CtrlCmd | KeyCode.KeyI),
			weight: KeybindingWeight.WorkbenchContrib,
			when: ContextKeyExpr.or(TerminalContextKeys.tabsFocus, TerminalContextKeys.focus)
		},
		run: (c) => c.groupService.focusHover()
	});

	registerActiveInstanceAction({
		id: TerminalCommandId.Clear,
		title: localize2('workbench.action.terminal.clear', 'Clear'),
		precondition: sharedWhenClause.terminalAvailable,
		keybinding: [{
			primary: 0,
			mac: { primary: KeyMod.CtrlCmd | KeyCode.KeyK },
			// Weight is higher than work workbench contributions so the keybinding remains
			// highest priority when chords are registered afterwards
			weight: KeybindingWeight.WorkbenchContrib + 1,
			// Disable the keybinding when accessibility mode is enabled as chords include
			// important screen reader keybindings such as cmd+k, cmd+i to show the hover
			when: ContextKeyExpr.or(ContextKeyExpr.and(TerminalContextKeys.focus, CONTEXT_ACCESSIBILITY_MODE_ENABLED.negate()), ContextKeyExpr.and(CONTEXT_ACCESSIBILITY_MODE_ENABLED, accessibleViewIsShown, accessibleViewCurrentProviderId.isEqualTo(AccessibleViewProviderId.Terminal))),
		}],
		run: (activeInstance) => activeInstance.clearBuffer()
	});

	registerTerminalAction({
		id: TerminalCommandId.SelectDefaultProfile,
		title: localize2('workbench.action.terminal.selectDefaultShell', 'Select Default Profile'),
		run: (c) => c.service.showProfileQuickPick('setDefault')
	});

	registerTerminalAction({
		id: TerminalCommandId.ConfigureTerminalSettings,
		title: localize2('workbench.action.terminal.openSettings', 'Configure Terminal Settings'),
		precondition: sharedWhenClause.terminalAvailable,
		run: (c, accessor) => accessor.get(IPreferencesService).openSettings({ jsonEditor: false, query: '@feature:terminal' })
	});

	registerActiveInstanceAction({
		id: TerminalCommandId.SetDimensions,
		title: localize2('workbench.action.terminal.setFixedDimensions', 'Set Fixed Dimensions'),
		precondition: sharedWhenClause.terminalAvailable_and_opened,
		run: (activeInstance) => activeInstance.setFixedDimensions()
	});

	registerContextualInstanceAction({
		id: TerminalCommandId.SizeToContentWidth,
		title: terminalStrings.toggleSizeToContentWidth,
		precondition: sharedWhenClause.terminalAvailable_and_opened,
		keybinding: {
			primary: KeyMod.Alt | KeyCode.KeyZ,
			weight: KeybindingWeight.WorkbenchContrib,
			when: TerminalContextKeys.focus
		},
		run: (instance) => instance.toggleSizeToContentWidth()
	});

	registerTerminalAction({
		id: TerminalCommandId.ClearPreviousSessionHistory,
		title: localize2('workbench.action.terminal.clearPreviousSessionHistory', 'Clear Previous Session History'),
		precondition: sharedWhenClause.terminalAvailable,
		run: async (c, accessor) => {
			getCommandHistory(accessor).clear();
			clearShellFileHistory();
		}
	});

	// Some commands depend on platform features
	if (BrowserFeatures.clipboard.writeText) {
		registerActiveXtermAction({
			id: TerminalCommandId.CopySelection,
			title: localize2('workbench.action.terminal.copySelection', 'Copy Selection'),
			// TODO: Why is copy still showing up when text isn't selected?
			precondition: ContextKeyExpr.or(TerminalContextKeys.textSelectedInFocused, ContextKeyExpr.and(sharedWhenClause.terminalAvailable, TerminalContextKeys.textSelected)),
			keybinding: [{
				primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KeyC,
				mac: { primary: KeyMod.CtrlCmd | KeyCode.KeyC },
				weight: KeybindingWeight.WorkbenchContrib,
				when: ContextKeyExpr.or(
					ContextKeyExpr.and(TerminalContextKeys.textSelected, TerminalContextKeys.focus),
					TerminalContextKeys.textSelectedInFocused,
				)
			}],
			run: (activeInstance) => activeInstance.copySelection()
		});

		registerActiveXtermAction({
			id: TerminalCommandId.CopyAndClearSelection,
			title: localize2('workbench.action.terminal.copyAndClearSelection', 'Copy and Clear Selection'),
			precondition: ContextKeyExpr.or(TerminalContextKeys.textSelectedInFocused, ContextKeyExpr.and(sharedWhenClause.terminalAvailable, TerminalContextKeys.textSelected)),
			keybinding: [{
				win: { primary: KeyMod.CtrlCmd | KeyCode.KeyC },
				weight: KeybindingWeight.WorkbenchContrib,
				when: ContextKeyExpr.or(
					ContextKeyExpr.and(TerminalContextKeys.textSelected, TerminalContextKeys.focus),
					TerminalContextKeys.textSelectedInFocused,
				)
			}],
			run: async (xterm) => {
				await xterm.copySelection();
				xterm.clearSelection();
			}
		});

		registerActiveXtermAction({
			id: TerminalCommandId.CopySelectionAsHtml,
			title: localize2('workbench.action.terminal.copySelectionAsHtml', 'Copy Selection as HTML'),
			f1: true,
			category,
			precondition: ContextKeyExpr.or(TerminalContextKeys.textSelectedInFocused, ContextKeyExpr.and(sharedWhenClause.terminalAvailable, TerminalContextKeys.textSelected)),
			run: (xterm) => xterm.copySelection(true)
		});
	}

	if (BrowserFeatures.clipboard.readText) {
		registerActiveInstanceAction({
			id: TerminalCommandId.Paste,
			title: localize2('workbench.action.terminal.paste', 'Paste into Active Terminal'),
			precondition: sharedWhenClause.terminalAvailable,
			keybinding: [{
				primary: KeyMod.CtrlCmd | KeyCode.KeyV,
				win: { primary: KeyMod.CtrlCmd | KeyCode.KeyV, secondary: [KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KeyV] },
				linux: { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KeyV },
				weight: KeybindingWeight.WorkbenchContrib,
				when: TerminalContextKeys.focus
			}],
			run: (activeInstance) => activeInstance.paste()
		});
	}

	if (BrowserFeatures.clipboard.readText && isLinux) {
		registerActiveInstanceAction({
			id: TerminalCommandId.PasteSelection,
			title: localize2('workbench.action.terminal.pasteSelection', 'Paste Selection into Active Terminal'),
			precondition: sharedWhenClause.terminalAvailable,
			keybinding: [{
				linux: { primary: KeyMod.Shift | KeyCode.Insert },
				weight: KeybindingWeight.WorkbenchContrib,
				when: TerminalContextKeys.focus
			}],
			run: (activeInstance) => activeInstance.pasteSelection()
		});
	}

	registerTerminalAction({
		id: TerminalCommandId.SwitchTerminal,
		title: localize2('workbench.action.terminal.switchTerminal', 'Switch Terminal'),
		precondition: sharedWhenClause.terminalAvailable,
		run: async (c, accessor, args) => {
			const item = toOptionalString(args);
			if (!item) {
				return;
			}
			if (item === switchTerminalActionViewItemSeparator) {
				c.service.refreshActiveGroup();
				return;
			}
			if (item === switchTerminalShowTabsTitle) {
				accessor.get(IConfigurationService).updateValue(TerminalSettingId.TabsEnabled, true);
				return;
			}

			const terminalIndexRe = /^([0-9]+): /;
			const indexMatches = terminalIndexRe.exec(item);
			if (indexMatches) {
				c.groupService.setActiveGroupByIndex(Number(indexMatches[1]) - 1);
				return c.groupService.showPanel(true);
			}

			const quickSelectProfiles = c.profileService.availableProfiles;

			// Remove 'New ' from the selected item to get the profile name
			const profileSelection = item.substring(4);
			if (quickSelectProfiles) {
				const profile = quickSelectProfiles.find(profile => profile.profileName === profileSelection);
				if (profile) {
					const instance = await c.service.createTerminal({
						config: profile
					});
					c.service.setActiveInstance(instance);
				} else {
					console.warn(`No profile with name "${profileSelection}"`);
				}
			} else {
				console.warn(`Unmatched terminal item: "${item}"`);
			}
		}
	});
}