Skip to main content

Module vim

Module vim 

Source
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: RegisterBank indexed by char:
    • unnamed "", last-yank "0, small-delete "-
    • named "a-"z (uppercase "A-"Z appends instead of overwriting)
    • blackhole "_
    • system clipboard "+ / "* (wire to crate::clipboard::Clipboard)
    • read-only ":, "., "% — surface in :reg output
  • 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 a HashMap<char, (buffer_id, row, col)>; 'x jumps to the line (FirstNonBlank), `x to 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: :reg and :marks ex commands.

§P4 — Macros

  • TODO: q{a-z} starts recording raw Inputs into the register; next q stops.
  • TODO: @{a-z} replays the register by re-feeding inputs through step. @@ 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 / L once 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) and Ctrl-r <reg> (paste from a register). Ctrl-r needs the RegisterBank from P3 to be useful.
  • TODO: / and ? search prompts still live in the host/src/lib.rs. The plan calls for moving them into the editor (so the editor owns last_search_pattern rather than the TUI loop). Safe to defer.

Structs§

InsertSession
LastVisual
Saved visual-mode anchor + cursor for gv (re-enters the last visual selection). mode carries which visual flavour to restore; anchor / cursor mean different things per flavour:
SearchPrompt
Active / or ? search prompt. Text mutations drive the textarea’s live search pattern so matches highlight as the user types.
VimState

Enums§

InsertDir
Direction for insert-mode arrow movement.
InsertEntry
InsertReason
LastChange
Information needed to replay a mutating change via ..
LastHorizontalMotion
Tracks which kind of horizontal jump was last performed so ; / , can dispatch to the correct repeat handler.
Mode
Motion
Operator
Pending
RangeKind
Classification determines how operators treat the range end.
ScrollDir
Scroll direction for scroll_full_page, scroll_half_page, and scroll_line controller methods.
TextObject

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, or None when the cursor is not on a tag name or the tag is unpaired. Char-column ranges (display), consistent with motions::matching_bracket_pos.
op_is_change
true when op records a last_change entry for dot-repeat purposes. Promoted to pub in Phase 6.6e so hjkl-vim::normal can use it without duplicating the logic.
parse_motion
Parse the first key of a normal/visual-mode motion. Returns None for keys that don’t start a motion (operator keys, command keys, etc.). Promoted to pub in Phase 6.6e so hjkl-vim::normal can call it.