diff --git a/README.en.md b/README.en.md index a5e38b50fd0..defecff23b2 100644 --- a/README.en.md +++ b/README.en.md @@ -63,6 +63,7 @@ Settings unique to Coderm that are not available in upstream VS Code. | `coderm.terminal.horizontalPadding` | `number` | `20` | Terminal horizontal padding (px, 0–100) | | `coderm.quickOpen.includeTerminals` | `boolean` | `true` | Include terminal editors in Quick Open | | `coderm.updateDownloadProgress.enabled` | `boolean` | `true` | Show progress notification during update download | +| `coderm.terminal.closeEmptyPaneOnKill` | `boolean` | `true` | Close empty pane and restore focus on terminal kill | --- diff --git a/README.md b/README.md index 185960fe121..4affcd14080 100644 --- a/README.md +++ b/README.md @@ -63,6 +63,7 @@ | `coderm.terminal.horizontalPadding` | `number` | `20` | ターミナルの水平パディング(px, 0–100) | | `coderm.quickOpen.includeTerminals` | `boolean` | `true` | Quick Openにターミナルエディタを含める | | `coderm.updateDownloadProgress.enabled` | `boolean` | `true` | アップデートダウンロード時に進捗通知を表示 | +| `coderm.terminal.closeEmptyPaneOnKill` | `boolean` | `true` | ターミナルkill時に空ペインを閉じてフォーカス復帰 | --- diff --git a/src/vs/workbench/contrib/coderm/browser/coderm.contribution.ts b/src/vs/workbench/contrib/coderm/browser/coderm.contribution.ts index d9700ef632e..737aa7a48eb 100644 --- a/src/vs/workbench/contrib/coderm/browser/coderm.contribution.ts +++ b/src/vs/workbench/contrib/coderm/browser/coderm.contribution.ts @@ -19,4 +19,5 @@ import './quickOpenIncludeTerminals.js'; import './resizePaneActions.js'; import './remoteSSHGuard.js'; import './terminalHorizontalPadding.js'; +import './terminalKillFocusRestore.js'; import './updateDownloadProgress.js'; diff --git a/src/vs/workbench/contrib/coderm/browser/terminalKillFocusRestore.ts b/src/vs/workbench/contrib/coderm/browser/terminalKillFocusRestore.ts new file mode 100644 index 00000000000..2e3b31434d7 --- /dev/null +++ b/src/vs/workbench/contrib/coderm/browser/terminalKillFocusRestore.ts @@ -0,0 +1,110 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { Disposable } from '../../../../base/common/lifecycle.js'; +import { localize } from '../../../../nls.js'; +import { IConfigurationService } from '../../../../platform/configuration/common/configuration.js'; +import { ConfigurationScope, Extensions as ConfigurationExtensions, IConfigurationRegistry } from '../../../../platform/configuration/common/configurationRegistry.js'; +import { Registry } from '../../../../platform/registry/common/platform.js'; +import { IWorkbenchContribution, WorkbenchPhase, registerWorkbenchContribution2 } from '../../../common/contributions.js'; +import { IEditorGroupsService } from '../../../services/editor/common/editorGroupsService.js'; +import { IEditorService } from '../../../services/editor/common/editorService.js'; +import { TerminalEditorInput } from '../../terminal/browser/terminalEditorInput.js'; + +// #region Configuration + +/** + * Configuration key for the terminal-kill focus restore feature. + * + * When enabled (default), killing a terminal-in-editor (e.g. via ctrl+d) + * automatically closes the resulting empty editor group and restores focus + * to the remaining pane. This provides tmux-like pane behavior where + * closing a terminal pane always focuses the adjacent pane. + * + * This works independently of the general `workbench.editor.closeEmptyGroups` + * setting — terminal kills always close the empty pane. + */ +export const CodermTerminalKillFocusRestoreSetting = 'coderm.terminal.closeEmptyPaneOnKill'; + +Registry.as(ConfigurationExtensions.Configuration).registerConfiguration({ + id: 'coderm.terminalKillFocusRestore', + order: 103, + title: localize('codermConfigurationTitle', 'Coderm'), + type: 'object', + properties: { + [CodermTerminalKillFocusRestoreSetting]: { + type: 'boolean', + default: true, + scope: ConfigurationScope.APPLICATION, + description: localize('coderm.terminal.closeEmptyPaneOnKill', + 'Controls whether an empty editor group is automatically closed and focus is restored to the remaining pane when a terminal-in-editor is killed (e.g. via ctrl+d). This provides tmux-like pane behavior independent of the closeEmptyGroups setting.'), + }, + }, +}); + +// #endregion + +// #region Controller + +/** + * Workbench contribution that restores focus to the remaining pane when a + * terminal-in-editor is killed and the editor group becomes empty. + * + * Without this, the default behavior depends on `workbench.editor.closeEmptyGroups`: + * - `true`: group closes and focus moves to the most recently active group (works) + * - `false`: group stays empty and focus remains in the empty group (broken UX) + * + * This contribution ensures that for terminal kills, the empty pane is always + * closed regardless of the general setting. + */ +export class TerminalKillFocusRestoreController extends Disposable implements IWorkbenchContribution { + + static readonly ID = 'workbench.contrib.coderm.terminalKillFocusRestore'; + + constructor( + @IEditorService private readonly _editorService: IEditorService, + @IEditorGroupsService private readonly _editorGroupsService: IEditorGroupsService, + @IConfigurationService private readonly _configurationService: IConfigurationService, + ) { + super(); + + this._register(this._editorService.onDidCloseEditor(e => { + if (!this._isEnabled()) { + return; + } + + // Only handle terminal editor inputs + if (!(e.editor instanceof TerminalEditorInput)) { + return; + } + + const group = this._editorGroupsService.getGroup(e.groupId); + if (!group) { + return; + } + + // If the group is now empty and there are other groups, remove it + if (group.isEmpty && this._editorGroupsService.count > 1) { + this._editorGroupsService.removeGroup(group); + } + })); + } + + private _isEnabled(): boolean { + return this._configurationService.getValue(CodermTerminalKillFocusRestoreSetting) ?? true; + } +} + +// #endregion + +// #region Registration + +registerWorkbenchContribution2( + TerminalKillFocusRestoreController.ID, + TerminalKillFocusRestoreController, + WorkbenchPhase.AfterRestored +); + +// #endregion