Expand description
Vim-mode engine.
Implements a command grammar of the form
Command := count? (operator count? (motion | text-object)
| motion
| insert-entry
| misc)The parser is a small state machine driven by one Input at a time.
Motions and text objects produce a [Range] (with inclusive/exclusive
/ linewise classification). A single Operator implementation
applies a range — so dw, d$, daw, and visual d all go through
the same code path.
The most recent mutating command is stored in
VimState::last_change so . can replay it.
§Roadmap
Tracked in the original plan at
~/.claude/plans/look-at-the-vim-curried-fern.md. Phases still
outstanding — each one can land as an isolated PR.
§P3 — Registers & marks
- TODO:
RegisterBankindexed by char:- unnamed
"", last-yank"0, small-delete"- - named
"a-"z(uppercase"A-"Zappends instead of overwriting) - blackhole
"_ - system clipboard
"+/"*(wire tocrate::clipboard::Clipboard) - read-only
":,".,"%— surface in:regoutput
- unnamed
- TODO: route every yank / cut / paste through the bank. Parser needs
a
"{reg}prefix state that captures the target register before a count / operator. - TODO:
m{a-z}sets a mark in aHashMap<char, (buffer_id, row, col)>;'xjumps to the line (FirstNonBlank),`xto the exact cell. Uppercase marks are global across tabs; lowercase are per-buffer. - TODO:
''and`` jump to the last-jump position;'[']'<'>bound the last change / visual region. - TODO:
:regand:marksex commands.
§P4 — Macros
- TODO:
q{a-z}starts recording rawInputs into the register; nextqstops. - TODO:
@{a-z}replays the register by re-feeding inputs throughstep.@@repeats the last macro. Nested macros need a sane depth cap (e.g. 100) to avoid runaway loops. - TODO: ensure recording doesn’t capture the initial
q{a-z}itself.
§P6 — Polish (still outstanding)
- TODO: indent operators
>/<(with line + text-object targets). - TODO: format operator
=— map to whatever SQL formatter we wire up; for now stub that returns the range unchanged with a toast. - TODO: case operators
gU/gu/g~on a range (already have single-char~). - TODO: screen motions
H/M/Lonce we track the render viewport height inside Editor. - TODO: scroll-to-cursor motions
zz/zt/zb.
§Known substrate / divergence notes
- TODO: insert-mode indent helpers —
Ctrl-t/Ctrl-d(increase / decrease indent on current line) andCtrl-r <reg>(paste from a register).Ctrl-rneeds theRegisterBankfrom P3 to be useful. - TODO:
/and?search prompts still live inthe host/src/lib.rs. The plan calls for moving them into the editor (so the editor ownslast_search_patternrather than the TUI loop). Safe to defer.
Structs§
- Insert
Session - Last
Visual - Saved visual-mode anchor + cursor for
gv(re-enters the last visual selection).modecarries which visual flavour to restore;anchor/cursormean different things per flavour: - Search
Prompt - Active
/or?search prompt. Text mutations drive the textarea’s live search pattern so matches highlight as the user types. - VimState
Enums§
- Insert
Dir - Direction for insert-mode arrow movement.
- Insert
Entry - Insert
Reason - Last
Change - Information needed to replay a mutating change via
.. - Last
Horizontal Motion - Tracks which kind of horizontal jump was last performed so
;/,can dispatch to the correct repeat handler. - Mode
- Motion
- Operator
- Pending
- Range
Kind - Classification determines how operators treat the range end.
- Scroll
Dir - Scroll direction for
scroll_full_page,scroll_half_page, andscroll_linecontroller methods. - Text
Object
Functions§
- matching_
tag_ pair - Resolve the HTML/XML tag-name pair under the cursor for matchparen-style
highlight (#243). Returns
[(row, name_start_col, name_end_col); 2]for the tag under the cursor and its structural partner, orNonewhen the cursor is not on a tag name or the tag is unpaired. Char-column ranges (display), consistent withmotions::matching_bracket_pos. - op_
is_ change truewhenoprecords alast_changeentry for dot-repeat purposes. Promoted topubin Phase 6.6e sohjkl-vim::normalcan use it without duplicating the logic.- parse_
motion - Parse the first key of a normal/visual-mode motion. Returns
Nonefor keys that don’t start a motion (operator keys, command keys, etc.). Promoted topubin Phase 6.6e sohjkl-vim::normalcan call it.