Skip to content

fix(tui): release keybind suspension when autocomplete unmounts - #2141

Open
anandlo wants to merge 1 commit into
XiaomiMiMo:mainfrom
anandlo:fix/tui-autocomplete-keybinds-suspend
Open

fix(tui): release keybind suspension when autocomplete unmounts#2141
anandlo wants to merge 1 commit into
XiaomiMiMo:mainfrom
anandlo:fix/tui-autocomplete-keybinds-suspend

Conversation

@anandlo

@anandlo anandlo commented Aug 16, 2026

Copy link
Copy Markdown
Contributor

Issue / context (if applicable)

Fixes #1897 — "Ctrl+X keybindings stop working until user types and clears text". This issue was closed on 2026-07-26 but the fix never actually landed: PR #1913 (merged that day) only touches packages/opencode/src/provider/transform.ts (DeepSeek provider scoping) and does not touch the keybind suspension code. The contributor branch fix/ctrl-x-keybinds-suspend-race with the real fix (2f0f8940, d7e0d451) was never merged to mainline — verified with git merge-base --is-ancestor.

Type of change

Bug fix

What does this PR do?

command.keybinds() in dialog-command.tsx gates ALL command keybinds — including <leader> (ctrl+x) chords like ctrl+x l (session list) and ctrl+x m (model list) — on suspendCount > 0.

Two independent sources increment that counter:

  1. Autocomplete show()/hide() (this PR). autocomplete.tsx show() unconditionally calls command.keybinds(false) and hide() unconditionally calls keybinds(true) — no idempotency guard — and the Autocomplete component has no unmount cleanup. When the prompt unmounts while an @-mention autocomplete is visible (session switch, permission/question prompt arriving, agent switch, plugin prompt-slot replacement at session/index.tsx:1456-1471), hide() never runs and suspendCount stays > 0 permanently — keybinds stay dead until the app is restarted. Typing does not recover this one.

  2. Ghost-text prediction (reported symptom). After each idle turn, fetchGhost() (prompt/index.tsx:428-444) shows a next-prompt prediction as inline ghost text; while visible, the effect at prompt/index.tsx:470-474 calls command.keybinds(false), gating every chord until the ghost is dismissed. Typing any character clears the ghost and re-arms keybinds — the reported "type random text + backspace" workaround. The interaction-design fix (dismiss the ghost when the leader is pressed) is deliberately out of scope for this PR per CONTRIBUTING.md (interaction-design changes need an issue first).

This PR fixes #1: idempotent show()/hide() plus an onCleanup that releases the suspension when the component unmounts.

How did you verify your code works?

  • bun typecheck from packages/opencode — PASS
  • bun lint (oxlint) — PASS (0 errors)
  • bunx prettier --check on the changed file — PASS
  • bun test test/cli/cmd/tui/autocomplete-detect.test.ts test/config/tui.test.ts — 52 pass / 4 skip / 0 fail
  • The 15 failures in the full-suite run are pre-existing on unpatched main (verified by stashing the change and re-running: skill-discovery/workflow tests fail identically in this environment; none touch autocomplete/keybinds)

Screenshots / recordings

If this is a UI change, please include a screenshot or recording. N/A — TUI behavior fix.

Checklist

  • I have tested my changes locally
  • I have not included unrelated changes in this PR

command.keybinds() gates all leader (ctrl+x) chords on suspendCount.
Autocomplete show()/hide() increment/decrement it but had no idempotency
guard, and the component had no unmount cleanup: if the prompt unmounts
while the autocomplete is visible (session switch, permission prompt,
agent switch), hide() never runs and suspendCount stays above 0, leaving
every command keybind dead until restart. Add idempotency guards to
show()/hide() and an onCleanup that releases the suspension on unmount.
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.

fix(tui): Ctrl+X keybindings stop working until user types and clears text [FEATURE]: Build it in Rust?

1 participant