diff --git a/src/vs/workbench/contrib/terminal/browser/terminal.ts b/src/vs/workbench/contrib/terminal/browser/terminal.ts index d9399ea3f655c..915ed3cf6dddf 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminal.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminal.ts @@ -182,6 +182,7 @@ export interface ITerminalService { moveGroup(source: ITerminalInstance, target: ITerminalInstance): void; moveInstance(source: ITerminalInstance, target: ITerminalInstance, side: 'before' | 'after'): void; moveToEditor(source: ITerminalInstance): void; + moveToTerminalView(source?: ITerminalInstance): Promise; /** * Perform an action with the active terminal instance, if the terminal does @@ -246,6 +247,7 @@ export interface ITerminalEditorService { readonly terminalEditorInstances: ITerminalInstance[]; createEditor(instance: ITerminalInstance): Promise; + detachActiveEditorInstance(): ITerminalInstance; } export interface IRemoteTerminalService extends IOffProcessTerminalService { diff --git a/src/vs/workbench/contrib/terminal/browser/terminalActions.ts b/src/vs/workbench/contrib/terminal/browser/terminalActions.ts index ffa4e6fa93d46..c5856b6d4d92a 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalActions.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalActions.ts @@ -225,6 +225,20 @@ export function registerTerminalActions() { } }); + registerAction2(class extends Action2 { + constructor() { + super({ + id: TerminalCommandId.MoveToTerminalView, + title: { value: localize('workbench.action.terminal.moveToTerminalView', "Move From Editor to Terminal View"), original: 'Move From Editor to Terminal View' }, + f1: true, + category + }); + } + async run(accessor: ServicesAccessor) { + await accessor.get(ITerminalService).moveToTerminalView(); + } + }); + registerAction2(class extends Action2 { constructor() { super({ diff --git a/src/vs/workbench/contrib/terminal/browser/terminalEditorService.ts b/src/vs/workbench/contrib/terminal/browser/terminalEditorService.ts index f7c44b36add51..00229256ee603 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalEditorService.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalEditorService.ts @@ -30,4 +30,16 @@ export class TerminalEditorService implements ITerminalEditorService { }); this.terminalEditorInstances.push(instance); } + + detachActiveEditorInstance(): ITerminalInstance { + const activeEditor = this._editorService.activeEditor; + if (!(activeEditor instanceof TerminalEditorInput)) { + throw new Error('Active editor is not a terminal'); + } + const instance = activeEditor.terminalInstance; + this._editorInputs.delete(instance.instanceId); + // TODO: Ensure the terminal process doesn't get disposed here + activeEditor.dispose(); + return instance; + } } diff --git a/src/vs/workbench/contrib/terminal/browser/terminalService.ts b/src/vs/workbench/contrib/terminal/browser/terminalService.ts index 3044e2a45522a..3684842a8895e 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalService.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalService.ts @@ -764,6 +764,9 @@ export class TerminalService implements ITerminalService { } moveToEditor(source: ITerminalInstance): void { + if (source.target === TerminalTarget.Editor) { + return; + } const sourceGroup = this.getGroupForInstance(source); if (!sourceGroup) { return; @@ -772,6 +775,38 @@ export class TerminalService implements ITerminalService { this._terminalEditorService.createEditor(source); } + async moveToTerminalView(source?: ITerminalInstance): Promise { + if (!source) { + source = this._terminalEditorService.detachActiveEditorInstance(); + if (!source) { + return; + } + } + + if (source.target !== TerminalTarget.Editor) { + return; + } + source.target = TerminalTarget.TerminalView; + + // TODO: Share code with joinInstances + const group = this._instantiationService.createInstance(TerminalGroup, this._terminalContainer, undefined); + group.onPanelOrientationChanged((orientation) => this._onPanelOrientationChanged.fire(orientation)); + this._terminalGroups.push(group); + group.addDisposable(group.onDisposed(this._onGroupDisposed.fire, this._onGroupDisposed)); + group.addDisposable(group.onInstancesChanged(this._onInstancesChanged.fire, this._onInstancesChanged)); + + group.addInstance(source); + this.setActiveInstance(source); + await this.showPanel(true); + // TODO: Shouldn't this happen automatically? + source.setVisible(true); + + // Fire events + this._onInstancesChanged.fire(); + this._onGroupsChanged.fire(); + this._onActiveGroupChanged.fire(); + } + protected _initInstanceListeners(instance: ITerminalInstance): void { instance.addDisposable(instance.onDisposed(this._onInstanceDisposed.fire, this._onInstanceDisposed)); instance.addDisposable(instance.onTitleChanged(this._onInstanceTitleChanged.fire, this._onInstanceTitleChanged)); diff --git a/src/vs/workbench/contrib/terminal/common/terminal.ts b/src/vs/workbench/contrib/terminal/common/terminal.ts index e2a58a074f20d..d2bcc83a66e66 100644 --- a/src/vs/workbench/contrib/terminal/common/terminal.ts +++ b/src/vs/workbench/contrib/terminal/common/terminal.ts @@ -450,7 +450,8 @@ export const enum TerminalCommandId { SearchWorkspace = 'workbench.action.terminal.searchWorkspace', AttachToRemoteTerminal = 'workbench.action.terminal.attachToSession', DetachProcess = 'workbench.action.terminal.detachProcess', - MoveToEditor = 'workbench.action.terminal.moveToEditor' + MoveToEditor = 'workbench.action.terminal.moveToEditor', + MoveToTerminalView = 'workbench.action.terminal.moveToTerminalView', } export const DEFAULT_COMMANDS_TO_SKIP_SHELL: string[] = [