ship the Vim keymap preset

T-65 — the capstone of the Vim epic. assets/keymaps/vim.yaml binds the
muscle-memory set guarded on vim.normal/insert/visual: hjkl/w/b/e/0/$/^/
gg/G motions, x/dd/dw/D/yy/p/P/cc/cw edits, i/a/I/A/o/O insert entries,
v + d/y/c in visual, Esc back to normal, and counts via the matcher. App
shortcuts (palette, find, zoom) are carried in the preset so they survive
under Vim.

The editor now feeds Shift chords to the matcher (Vim's capitals: G, D,
A, P, $) while still bubbling Ctrl/Alt/Meta to the global handler. The
keybindings-ui stub gains palette commands (`Keymap: Vim` / `Keymap:
Default`) to switch presets — the user-facing way to turn Vim on.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-01 21:32:40 +02:00
co-authored by Claude Opus 4.8
parent caca816233
commit bcb57bc75f
8 changed files with 355 additions and 9 deletions
+7 -4
View File
@@ -201,10 +201,13 @@ class _EditorViewState extends State<EditorView> {
return KeyEventResult.ignored;
}
// Normal / visual mode. Modified chords are app shortcuts (palette,
// find, …) — let them bubble to the global handler. Bare keys drive
// the Vim matcher and never reach text input.
if (chord.modifiers.isNotEmpty) return KeyEventResult.ignored;
// Normal / visual mode. Ctrl/Alt/Meta chords are app shortcuts
// (palette, find, …) — let them bubble to the global handler. Bare
// keys and Shift chords (Vim's capitals: G, D, A, P, $) drive the
// matcher and never reach text input.
if (chord.modifiers.any((m) => m != KeyModifier.shift)) {
return KeyEventResult.ignored;
}
final r = _matcher!.feed(chord);
switch (r.outcome) {