fix(plugin-codemirror): sync cursor from editor selection on keydown#62
fix(plugin-codemirror): sync cursor from editor selection on keydown#62babarot wants to merge 1 commit into
Conversation
Sync CodeMirror's selection.main.head back into the vim context at the start of every keydown handler. This ensures mouse clicks and other external selection changes are reflected before the next keystroke is processed. Visual modes are skipped because the editor selection head represents the visual range boundary, not the cursor position.
Patch @vimee/plugin-codemirror to read CodeMirror's selection back into the vim context before each keystroke. Without this, clicking in the editor moves the CodeMirror selection but leaves vimee's internal cursor at the old position, causing it to jump back on the next keypress. Upstream fix: vimeejs/vimee#62
|
@babarot Thank you for your contribution. 🎉 I will review it later. Please wait. |
There was a problem hiding this comment.
Pull request overview
This PR fixes cursor drift in the CodeMirror plugin by syncing the vim engine cursor (ctx.cursor) from CodeMirror’s current selection head at the start of each keydown, so external cursor moves (e.g., mouse clicks) don’t cause the next vim command to operate from a stale position.
Changes:
- Add
syncCursorFromEditor()and call it at the start of the plugin’skeydownhandler (skipping visual modes). - Extend the minimal CodeMirror state typing to include
selection.main.head. - Add tests that simulate mouse-driven selection movement and verify subsequent vim actions operate from the clicked position.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
| packages/plugin-codemirror/src/types.ts | Extends the minimal CodeMirror state type surface to include selection head access. |
| packages/plugin-codemirror/src/attach.ts | Syncs vim cursor from editor selection before processing keystrokes. |
| packages/plugin-codemirror/src/tests/attach.test.ts | Adds mock selection head control and tests for cursor syncing behavior. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| return; | ||
| } | ||
| const offset = view.state.selection.main.head; | ||
| const editorCursor = offsetToCursor(buffer.getContent(), offset); |
|
Since more than 30 days have passed since the PR was created, the CI approval button has disappeared. Therefore, I will close and then reopen the PR once. |
Merging this PR will improve performance by 14.6%
|
| Benchmark | BASE |
HEAD |
Efficiency | |
|---|---|---|---|---|
| ⚡ | dw (delete word) |
472.5 µs | 336.9 µs | +40.25% |
| ⚡ | W (WORD) |
495.7 µs | 328.2 µs | +51.01% |
| ❌ | b |
354.8 µs | 499.4 µs | -28.95% |
Tip
Investigate this regression by commenting @codspeedbot fix this regression on this PR, or directly use the CodSpeed MCP with your agent.
Comparing babarot:fix/codemirror-click-cursor-sync (2706087) with main (10740b9)
Footnotes
-
12 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports. ↩
What
Add
syncCursorFromEditor()to the CodeMirror plugin's keydown handler. Before each keystroke is processed, the function readsview.state.selection.main.headand updates the vim context's cursor position if it differs. Visual modes (visual, visual-line, visual-block) are skipped because the editor selection head represents the visual range boundary, not the cursor position.The
CodeMirrorStatetype is extended with a minimalselectioninterface so the plugin can read the selection without depending on the full@codemirror/statetypes.Why
The vimee CodeMirror plugin maintains its own cursor state (
ctx.cursor) but never reads back from CodeMirror's selection. When a user clicks in the editor to move the cursor, CodeMirror updates its selection butctx.cursorstays at the old position. The next keystroke (j/k movement, entering insert mode, entering visual mode, etc.) operates from the stale position, causing the cursor to jump back unexpectedly.This is the same class of issue as #61 (shiki-editor cursor drift) — an external position change that the vim engine doesn't pick up.