feat(desktop): ⌘W closes the focused terminal

Fold terminal close into the existing ⌘/Ctrl+W handler so focus decides the
target: a focused terminal takes ⌘W (closes the active tab) and otherwise the
keystroke closes the active preview tab as before. Only the ⌘ gesture is
intercepted — Ctrl+W stays the shell's werase — and a focused terminal never
lets ⌘/Ctrl+W close a preview out from under it.
This commit is contained in:
Brooklyn Nicholson 2026-06-28 19:10:06 -05:00
parent c1bb34d5e8
commit 2d55ff8fca
2 changed files with 23 additions and 2 deletions

View file

@ -129,6 +129,7 @@ import { ReviewPane } from './right-sidebar/review'
import { $terminalTakeover } from './right-sidebar/store'
import { TerminalPaneChrome } from './right-sidebar/terminal/chrome'
import { PersistentTerminal } from './right-sidebar/terminal/persistent'
import { closeActiveTerminal, isTerminalFocused } from './right-sidebar/terminal/terminals'
import { CRON_ROUTE, NEW_CHAT_ROUTE, routeSessionId, sessionRoute, SETTINGS_ROUTE } from './routes'
import { SessionPickerOverlay } from './session-picker-overlay'
import { SessionSwitcher } from './session-switcher'
@ -389,11 +390,25 @@ export function DesktopController() {
useEffect(() => {
const onKeyDown = (event: KeyboardEvent) => {
if (!$filePreviewTarget.get() && !$previewTarget.get()) {
if (event.altKey || event.shiftKey || event.key.toLowerCase() !== 'w' || (!event.metaKey && !event.ctrlKey)) {
return
}
if ((event.metaKey || event.ctrlKey) && !event.altKey && !event.shiftKey && event.key.toLowerCase() === 'w') {
// Terminal focused: ⌘W closes the active terminal. Ctrl+W is left untouched
// for the shell's werase, and nothing else may steal ⌘/Ctrl+W from a
// focused terminal (so it never closes a preview tab out from under it).
if (isTerminalFocused()) {
if (event.metaKey && !event.ctrlKey) {
event.preventDefault()
event.stopPropagation()
closeActiveTerminal()
}
return
}
// Otherwise ⌘/Ctrl+W closes the active preview tab when one is open.
if ($filePreviewTarget.get() || $previewTarget.get()) {
event.preventDefault()
event.stopPropagation()
closeActiveRightRailTab()

View file

@ -95,6 +95,12 @@ export function closeActiveTerminal(): void {
}
}
/** True while an in-app terminal's xterm holds focus (its helper textarea is the
* active element) lets W close the focused terminal without a ref dance. */
export function isTerminalFocused(): boolean {
return document.activeElement?.classList.contains('xterm-helper-textarea') ?? false
}
export function closeOtherTerminals(id: string): void {
const keep = $terminals.get().find(term => term.id === id)