feat(web): add terminal.focus and chat.focusComposer keybindings - #5961
feat(web): add terminal.focus and chat.focusComposer keybindings#5961achtan wants to merge 3 commits into
Conversation
|
Important Review skippedAuto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
ApprovabilityVerdict: Needs human review This PR adds new user-facing keybindings ( You can customize Macroscope's approvability policy. Learn more. |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit e3adb5b. Configure here.

Part of #4641 (items 4 and 5).
Problem
Focus is coupled to panel visibility. Opening the terminal drawer requests terminal focus and closing it returns focus to the composer, but there is no keyboard route between the two while the drawer stays open: type-to-focus bails when focus sits in any input or textarea, and the terminal renders a textarea, so typing in the terminal can never bring you back. The workaround today is toggling the drawer twice with
mod+j.What changed
packages/contracts—terminal.focusandchat.focusComposerjoinSTATIC_KEYBINDING_COMMANDS. Older clients drop unknown commands through the existingForwardCompatibleArraydecoding, so no compatibility work was needed.packages/shared— both ship as one default key with mutually exclusivewhenclauses, so a single key hops focus in either direction without touching drawer visibility:{ "key": "ctrl+`", "command": "terminal.focus", "when": "!terminalFocus" }, { "key": "ctrl+`", "command": "chat.focusComposer", "when": "terminalFocus" }ctrl+`follows VS Code's focus-terminal binding and is unclaimed by the existing defaults on every platform. Each command is still independently rebindable; the startup default sync backfills both rules into existing configs.apps/web(ChatView) — dispatch in the existing global shortcut handler.terminal.focuspicks one target via a pureresolveTerminalFocusTargetdecision (unit-tested): the right-panel terminal when it is the only terminal showing (drawer closed, or right panel maximized), otherwise the drawer — opening it when closed, where the closed→open transition already requests focus and creates the first session. The right-panel terminal now consumes its ownpanelTerminalFocusRequestId— bumped by the panel's own lifecycle actions (add, split, activate, close, surface activation) and byterminal.focuswhen the panel is the target — so a focus request lands on exactly one surface instead of broadcasting to both terminal hosts.chat.focusComposercalls the existingfocusComposer()and leaves the terminal open.Settings → Keybindings — no changes needed: labels derive from the command IDs ("Terminal: Focus", "Chat: Focus Composer") and both commands appear in the add-binding dropdown because they ship as defaults.
docs/user/keybindings.md— short note on the pair and how it differs fromterminal.toggle.Verification
vp test runon the touched suites: web keybindings 46 passed (4 new: thectrl+`pair resolves perterminalFocuscontext on macOS and Windows, against the real shipped defaults so the rules are proven to parse), ChatView logic 43 passed (5 new covering everyresolveTerminalFocusTargetbranch), keybindings settings logic 9 passed (label + dropdown coverage), server keybindings 22 passed (default backfill is generic overDEFAULT_KEYBINDINGS).tsgo --noEmitclean forcontracts,shared, andweb;vp lintclean on touched files.Demo video (25s): ctrl-backtick-focus-demo.webm — recorded in a real browser against a dev build of this branch. It shows: typing in the composer →
ctrl+`opens the drawer and focuses the terminal (anechotyped immediately after the keypress lands at the shell prompt) →ctrl+`hops back to the composer with the drawer still open → a third press hops into the already-open terminal (pwd) → a final press returns to the composer. No mouse after the first click.Final state:
Built with Claude Fable 5 (claude-fable-5) via Claude Code.
Note
Low Risk
UI focus and keybinding routing only; no auth, data, or API changes. Logic is isolated and covered by new unit tests.
Overview
Adds
terminal.focusandchat.focusComposerso users can hop between the message composer and terminal without toggling the drawer (addresses the gap where typing cannot return focus from the terminal textarea).Defaults: Both bind to
ctrl+`with oppositewhen: terminalFocusclauses in shared keybindings; contracts register the new static commands.Behavior:
ChatViewhandles the commands in the global shortcut handler.resolveTerminalFocusTarget(pure, unit-tested) chooses the right-panel terminal vs drawer vs open-drawer, including when the right panel is maximized. Right-panel terminal actions bump a separatepanelTerminalFocusRequestIdso focus requests hit one surface instead of drawer + panel together. Either command un-maximizes the right panel when focus must land in the chat column.Docs and settings tests cover labels and the new commands in the keybindings UI.
Reviewed by Cursor Bugbot for commit 488b424. Bugbot is set up for automated code reviews on this repo. Configure here.
Note
Add
terminal.focusandchat.focusComposerkeybindings mapped to Ctrl+`resolveTerminalFocusTargetin ChatView.logic.ts to determine which terminal surface (panel,drawer, oropen-drawer) to target.panelTerminalFocusRequestIdstate separate fromterminalFocusRequestIdso panel terminal actions no longer interfere with drawer focus requests.addTerminalSurface,splitPanelTerminal, etc.) now incrementpanelTerminalFocusRequestIdinstead ofterminalFocusRequestId.Macroscope summarized 488b424.