Skip to content

fix(search): Escape restores terminal focus after Cmd+F#283

Closed
KwaminaWhyte wants to merge 2 commits into
crynta:mainfrom
KwaminaWhyte:fix/search-escape-refocus-terminal
Closed

fix(search): Escape restores terminal focus after Cmd+F#283
KwaminaWhyte wants to merge 2 commits into
crynta:mainfrom
KwaminaWhyte:fix/search-escape-refocus-terminal

Conversation

@KwaminaWhyte

Copy link
Copy Markdown
Contributor

What

One-line bug fix so that pressing Escape in the search bar hands focus back to the active terminal pane.

-  focus: () => terminalRefs.current.get(activeId)?.focus(),
+  focus: () =>
+    activeLeafId !== null
+      ? terminalRefs.current.get(activeLeafId)?.focus()
+      : undefined,

Also adds activeLeafId to the useMemo dependency array (it was missing, so the closure would capture a stale leaf ID on pane switches).

Why

Closes #195.

searchTarget.focus() for a terminal pane called terminalRefs.current.get(activeId), where activeId is the tab ID. But terminalRefs is keyed by leaf ID — so the lookup always returned undefined, and focus() was never called. Every other callsite in App.tsx that addresses terminalRefs already uses activeLeafId (lines 508, 525, 774, 784).

The SearchInline component already had the correct Escape handler and called restoreTargetFocus() — it was just silently no-oping because the handle was never found.

How it was tested

  • tsc --noEmit — zero new errors (3 pre-existing missing-dep errors unchanged)
  • Verified the bug: with the old code, terminalRefs.current.get(activeId) returns undefined since the map holds leaf IDs as keys
  • Verified the fix: activeLeafId is derived from activeTerminalTab?.activeLeafId (line 112) and is the correct key

During Chinese/Korean/Japanese input the browser fires keydown events
with event.isComposing=true while the user is mid-composition. xterm's
attachCustomKeyEventHandler was forwarding those events straight to the
PTY, causing two problems:

  - Chinese IME (issue crynta#158): pressing Enter to commit a candidate also
    submitted the current shell command.
  - Korean Hangul (issue crynta#147): inline-composed jamo were duplicated or
    swallowed because raw keydown and the compositionend string both
    reached the shell.

Fix: return false from the custom key handler whenever isComposing is
true or keyCode === 229 (the synthetic 'Process' code Chromium reports
while any key is handled inside an IME session). Returning false tells
xterm to skip its own keydown processing; the final composed string
still arrives via xterm's compositionend path and is written to the PTY
exactly once.

Note: the upstream refactor moved terminal creation from
useTerminalSession.ts into rendererPool.ts (createSlot). The fix is
applied there, in the single place where all xterm Terminal instances
are constructed.

Closes crynta#158
Closes crynta#147
searchTarget.focus() for a terminal pane was calling
terminalRefs.current.get(activeId) where activeId is the *tab* ID.
terminalRefs is keyed by *leaf* ID, so the lookup always returned
undefined and focus was never restored.

Fix: use activeLeafId (already in scope) as the key, matching how
every other callsite in App.tsx addresses terminalRefs (see lines 508,
525, 774, 784). Also add activeLeafId to the useMemo dependency array
so the closure always captures the current leaf.

Result: pressing Escape in the search bar now closes it and hands focus
back to the active terminal pane, as described in issue crynta#195.

Closes crynta#195
@KwaminaWhyte KwaminaWhyte requested a review from crynta as a code owner May 16, 2026 08:36
@crynta

crynta commented May 19, 2026

Copy link
Copy Markdown
Owner

Tracked under #207 which landed the same fix. Closing as duplicate, thanks for the report.

@crynta crynta closed this May 19, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Shortcut to re-focus on terminal after focusing on search bar

2 participants