Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.en.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 |

---

Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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時に空ペインを閉じてフォーカス復帰 |

---

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,5 @@ import './quickOpenIncludeTerminals.js';
import './resizePaneActions.js';
import './remoteSSHGuard.js';
import './terminalHorizontalPadding.js';
import './terminalKillFocusRestore.js';
import './updateDownloadProgress.js';
110 changes: 110 additions & 0 deletions src/vs/workbench/contrib/coderm/browser/terminalKillFocusRestore.ts
Original file line number Diff line number Diff line change
@@ -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<IConfigurationRegistry>(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<boolean>(CodermTerminalKillFocusRestoreSetting) ?? true;
}
}

// #endregion

// #region Registration

registerWorkbenchContribution2(
TerminalKillFocusRestoreController.ID,
TerminalKillFocusRestoreController,
WorkbenchPhase.AfterRestored
);

// #endregion
Loading