Skip to content

fix(web): run Vim keys typed outside the composer as commands - #62

Merged
NicholasZolton merged 2 commits into
mainfrom
NicholasZolton/fix-vim-mode-new-chat-keys
Nov 7, 2026
Merged

NicholasZolton merged 2 commits into
mainfrom
NicholasZolton/fix-vim-mode-new-chat-keys

Conversation

@NicholasZolton

Copy link
Copy Markdown
Owner

With Vim enabled, the first key or two after switching chats sometimes typed a literal character (pressing a added "a") while the composer still showed NORMAL. Those keys arrived while focus was outside the composer, so type-to-focus inserted the key as text at the end of the draft and focused the editor a frame later. Vim never saw them.

Type-to-focus now hands the key to the composer instead of inserting it. With Vim on, the composer focuses its editor and runs the key through Vim at the existing caret, so a enters insert mode and x deletes the character under the cursor. In insert mode the key is typed at the caret. A collapsed mobile composer cannot take focus until it expands, so its first key only expands it. With Vim off, type-to-focus behaves exactly as before.

Before + After

Composer focused in normal mode, focus moves outside it, then a and ! are typed. Frames are cropped to the composer.

Before: pressing a while unfocused types "a" and stays in NORMAL

After: pressing a while unfocused enters INSERT, then ! is typed at the caret

Test plan

  • New Vim composer test: a key from outside the editor runs as a command in normal mode and comes back as text in insert mode.
  • vp run check:changed: format, lint, Knip, typecheck, 4 test files, React Compiler.
  • Dev app in headless Chromium, focus outside the composer: a enters insert mode with no stray text, x deletes at the caret, and insert mode types at the caret. The same steps on origin/main type "a" and stay in NORMAL.
  • Signed local macOS desktop build (pnpm run dist:desktop:local --arch arm64).
  • The collapsed mobile and scroll-collapsed composer paths were not exercised in a browser.
  • The exact thread-switch sequence that leaves focus outside the composer was not reproduced locally; the fix covers every key that reaches type-to-focus.

bronze-ferret-orchid

Type-to-focus inserted a key typed outside the composer as literal text,
so with Vim in normal mode the first keys after switching threads typed
characters instead of running commands. The composer now focuses its
editor and hands the key to Vim, falling back to text only in insert mode.
Keys typed outside the composer ran with the caret moved to the end of
the draft, so commands like x and dd acted on the wrong place. Vim now
keeps its caret when type-to-focus hands it a key.
Copilot AI balanced review requested due to automatic review settings November 7, 2026 17:13

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Warning

Copilot couldn't run its full agentic review because it didn't start before the timeout. Make sure your repository has a runner available, or add a copilot-code-review.yml file specifying one with the runs-on attribute. See the docs for more details.

Copilot review overview

1 open issue
What changed in this PR

Fixes type-to-focus behavior when Vim mode is enabled so keys pressed while focus is outside the composer are interpreted as Vim commands (or inserted at the caret in insert mode) instead of being appended as literal text at the end of the draft.

Changes:

  • Route type-to-focus key events through a new ChatComposerHandle.typeKey(event) API.
  • Implement typeKey in ChatComposer to focus/reveal the editor and run keys through Vim where appropriate (with mobile/scroll-collapsed handling).
  • Add Vim integration test coverage for “key typed outside editor” behavior and expose handleVimKey via the editor imperative handle.
File Description
apps/​web/​src/​components/​chat/​useChatShortcuts.ts Switches type-to-focus from “append key” to delegating the key event to the composer.
apps/​web/​src/​components/​chat/​useChatShortcuts.browser.test.tsx Updates the stand-in composer in tests to implement typeKey(event).
apps/​web/​src/​components/​chat/​ChatComposer.tsx Adds typeKey implementation to run Vim commands at caret (or insert), with collapsed editor handling.
apps/​web/​src/​components/​ComposerPromptEditorTiptap.vim.browser.test.tsx Adds a Vim test for handling a key pressed “from outside the editor”.
apps/​web/​src/​components/​ComposerPromptEditorTiptap.tsx Exposes handleVimKey on the editor handle to support routing external key events into Vim.

Review effort: Lite

@NicholasZolton
NicholasZolton merged commit e11c827 into main Nov 7, 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.

2 participants