Expand description
The CommandRegistry holds every registered operator, motion, text
object, and ex-command. The dispatcher (super::dispatcher::execute)
looks up commands here.
Built-in commands are registered at editor startup via populate_builtins
(see super::builtins). Plugins register their own through the same
register_* methods. v1 keeps these as native Rust closures; the WASM
plugin host (Phase 7) wraps the same shape.
Structs§
- Action
Context - Context passed to a free-form action’s evaluator. Mirrors
ExCommandContext’s shape (no document mutation; the App applies the returnedcrate::effect::Effect) but omits thebangbit – chord-bound actions never carry one. Theregister/countslots flow the count and register prefixes the user typed before the chord (vim’s3"+yy-style); most actions ignore them. - Action
Spec - A registered free-form action: a command with no grammar role, usually bound to a chord.
- Command
Registry - The one registry of every command: motions, operators, text objects, ex-commands and actions, built-in and plugin alike (DESIGN.md §5.2.1).
- Comment
Syntax - N.1.6 (2026-06-10): per-buffer comment-leader descriptor for the
comment text objects (
aC/iC). Commentstring-driven (NOT tree-sitter) so it works for any language with a known leader, even without a parse tree. The host populates it from the active buffer’s language (Lang::comment_syntax);None(orline: None) means the comment objects resolve nothing (graceful operator no-op). - ExCommand
Context - Context handed to an ex-command’s evaluator. Mirrors the shape passed
to motion / operator / text-object specs but adds the
bangbit and drops direct document mutation: ex-commands describe their work by returning ancrate::effect::Effect, which the host applies. - ExCommand
Id - Strongly-typed handle to an ex-command in the registry.
- ExCommand
Spec - A registered ex-command: how the
:line parses it and what it returns. - Grammar
Env - The per-dispatch environment: everything the host knows that a
command’s
applymay need but the grammar layer cannot derive for itself. Bundled into ONE value so the dispatch seam carries a single env rather than a widening parameter list (the long-term-fit choice over parallel params).Copy;default()is the no-input case, and commands that read nothing from the env (iw,ap,i{) are unaffected by what it carries. - Last
Find - The last
f/F/t/Tthe user ran, which is all;and,need to repeat it. - Last
Search - VM.3d-2: the last completed
//?/*/#search, which is allnandNneed to repeat it. Moved here from the host (which re-exports the name, so no call site moved) for the reasonLastFindwas:nis a motion now, and the state it repeats has to reach the grammar. - Motion
Context - Context passed to a motion’s evaluator.
- Motion
Id - Strongly-typed handle to a motion command in the registry.
- Motion
Result - What a motion’s evaluator returned.
- Motion
Spec - A registered motion: its evaluator plus the vim properties the dispatcher and host need without running it.
- Native
Format Intents - RF.5b: which formatting intents the buffer handles natively.
- Operator
Context - Context passed to an operator’s evaluator.
- Operator
Id - Strongly-typed handle to an operator command in the registry.
- Operator
Spec - A registered operator: its evaluator plus how the dispatcher should feed it spans.
- RangeId
- Strongly-typed handle to a custom range source (plugin-registered) used by
Range::Custom(RangeId). - Shown
Lines - VM.3f: the window’s lines, top to bottom, each with its height in
line-heights (1.0 for an ordinary row). The host builds it from the walk it
paints with; this type owns vim’s rule for which of them
H/M/Lmean, so the keyboard motion and the host’sJumpViewportaction answer from one place. Checked in vim 9.2: a count past the window clamps to the far edge, andMis top + (lines shown − 1) / 2 — half the lines SHOWN, so a short buffer’s middle, not the window’s. - Text
Object Context - Context passed to a text-object’s evaluator.
- Text
Object Id - Strongly-typed handle to a text-object command in the registry.
- Text
Object Spec - A registered text object: an evaluator that returns the span around a position.
Enums§
- Command
Registration - What a registered command holds in the registry, beyond its metadata.
- Curswant
- VM.3g-1: vim’s
curswant— the column a vertical motion aims for, which survives passing through a SHORT line.jjfrom column 9 over a 2-column line lands back on 9, not on 2 (vim 9.2,vimcheck_curswant2.vim). - Curswant
Effect - VM.3g-1: what a motion does to the goal column. A property of the MOTION
(vim’s
jalways keeps it,$always pins it), so it lives on the spec rather than the result — andSelf::SetFromTargetis the default, so every motion that has never heard ofcurswant, plugin motions included, behaves as vim’s ordinary motions do. - Find
Kind f/F/t/T— which direction, and whether the target character is included.- Motion
Notice - VM.3d-2: something a motion wants the user told, alongside where it moved.
Copy, soMotionResultstaysCopy; the dispatcher renders the text. - NavBoundary
- Which boundary of the target node the motion lands on.
- NavDir
- Direction of travel for a structural motion.
Forwardscans toward EOF,Backwardtoward BOF. - Surface
Form - How the user types this command on the
:line. The default (Keyword) covers most commands –:write,:quit,:set number.Delimiteris for the small family of commands whose arguments are interleaved with delimiters::s/pat/repl/,:g/pat/body,:v/pat/body. The keyword form (:ex:substitute,:ex:global) for these is intentionally a hard error – the front-end parser routes them viatry_parse_substitute/try_parse_global. UI surfaces (completion, command palette) hideDelimitercommands because there’s no useful keyword-form completion for them; the user types the delimiter directly.
Constants§
- MODE_
TOGGLE_ COMMAND_ DOC - Doc string for an auto-generated
:<mode-name>mode-toggle ex-command — shared so native and plugin modes read identically in:describe-command.
Traits§
- Display
Resolver - VM.3g-2: what the DISPLAY looks like, for
gj/gk/g0/g$. Soft wrap is a rendering decision — the wrap width, and how many rows a line takes once tabs and wide characters are measured — so the grammar asks rather than computes, exactly as it does for folds and the viewport. - Fold
Resolver - VM.3i: where
zj/zkfind the next fold edge. - Indent
Resolver - IN.7: how deep should this line sit?
- Mark
Resolver - VM.3e: the mark table
'x/`xread, so they can be motions. The host owns the marks (mwrites them); the grammar only asks where one is.Nonemeans the mark isn’t set, which fails the motion with E20. - Scope
Resolver - Resolves a tree-sitter scope near the cursor, for the structural text
objects (
af/ac/aa/ …) and structural motions (]f/[c/ …). - Viewport
Resolver - VM.3f: which line of the window
H/M/Lmean. The layout — folds, row heights, window size — stays on the host; the grammar only asks.
Functions§
- mode_
toggle_ ex_ command_ spec - Build the auto-generated
:<mode-name>mode-toggle ex-command spec. Theapplyreturnscrate::effect::Effect::ToggleMode; the host routes that totoggle_mode_by_name, flipping the mode on the active buffer. Shared by boot (native modes,register_mode_toggle_commands) AND the plugin modes-seam drain, so a plugin-registered mode gets an IDENTICAL:<mode>toggle surface. The caller registers it under the right provenance:Builtinfor native modes;SourceLayer::Plugin(id)for plugin modes, so unload reverses it. Takes no arguments.