pub struct MotionContext<'a> {Show 20 fields
pub buffer: &'a Buffer,
pub buffer_id: BufferId,
pub from: Position,
pub count: Count,
pub has_explicit_count: bool,
pub args: Args,
pub cancel: &'a CancellationToken,
pub scope_resolver: Option<&'a dyn ScopeResolver>,
pub path: Option<&'a Path>,
pub syntax: Option<&'a Arc<dyn Any + Send + Sync>>,
pub last_find: Option<LastFind>,
pub fold_resolver: Option<&'a dyn FoldResolver>,
pub last_search: Option<&'a LastSearch>,
pub marks: Option<&'a dyn MarkResolver>,
pub viewport: Option<&'a dyn ViewportResolver>,
pub nostartofline: bool,
pub curswant: Option<Curswant>,
pub display: Option<&'a dyn DisplayResolver>,
pub scrolloff: u32,
pub operator_pending: bool,
}Expand description
Context passed to a motion’s evaluator.
M.2.b.0.A (2026-05-31): buffer_id carries the active
buffer’s registry identity through to motion handlers. Built-
in motions (purely content-based: w / e / ]p / etc.)
ignore it; kind-specific motions (multibuffer ]e / [e /
]E / [E, future file-tree / oil structural motions, future
plugin-defined kinds) use it to look up the active major
mode’s typed state through a service registry their handler
closure captures at registration time. Adding it here keeps
the grammar layer free of lattice-mode / ServiceRegistry
coupling — the handler decides what to look up.
Fields§
§buffer: &'a BufferThe buffer text the motion reads. Motions never edit.
buffer_id: BufferIdRegistry-level identity of the active buffer this motion
is firing against. Distinct from lattice_protocol::ids:: DocumentId (per-actor stable id); BufferId is the
registry key that mode-state lookups use.
from: PositionWhere the motion starts: the cursor, or the Visual head.
count: CountThe count, 1 when none was typed; see Self::has_explicit_count.
has_explicit_count: boolTrue when the invocation carried an explicit count (e.g.
5G). False for bare invocations (G alone). Motions
whose semantic changes with an explicit count (goto-last-
line: last vs. specific line) use this to disambiguate.
args: ArgsThe motion’s own arguments, e.g. Args::Char for f{char} or a
mark name for 'x.
cancel: &'a CancellationTokenCooperative cancellation handle (DESIGN.md §5.2.5). Hot
loops should poll cancel.check()? on each iteration; on a
flipped token the evaluator returns
crate::CommandError::Cancelled and the dispatcher
commits no effect.
scope_resolver: Option<&'a dyn ScopeResolver>N.1.4-motions: the active buffer’s tree-sitter resolver for structural
motions (]f/[c/…). None on Plain buffers with no parse — the
motion then no-ops. Threaded by the host, identical to TextObjectContext.
path: Option<&'a Path>OM.6b: the file the motion’s buffer is backed by, so a plugin motion’s
document handle can answer path(). A borrow — this context is
already borrowing, so carrying it costs nothing on the keystroke path
(motions fire on every j). None for a buffer with no file.
syntax: Option<&'a Arc<dyn Any + Send + Sync>>OT.1: the same type-erased tree-sitter snapshot ActionContext::syntax
carries, so a plugin motion can resolve structurally instead of scanning
text. Copied straight from GrammarEnv::syntax, which the host has
always threaded here — until OT.1 motions simply did not read it.
Borrowed, not cloned, unlike the owned ActionContext peer: motions
fire on every j, so a native motion (which ignores this) must pay
nothing, and only a plugin motion that actually mints a tree-snapshot
resource pays the Arc bump. Same reasoning as path above.
Acquired the same instant as buffer, so tree and text versions agree
(plugin-treesitter-seam.md §7). None when the buffer has no parse.
last_find: Option<LastFind>VM.3c: the last f / F / t / T, copied from
GrammarEnv::last_find. Read by motion:find-repeat and its
reverse; every other motion ignores it. Copy, so carrying it costs
nothing on the keystroke path.
fold_resolver: Option<&'a dyn FoldResolver>VM.3i: the fold edges zj / zk step between, copied from
GrammarEnv::fold_resolver. Borrowed, so a motion that ignores it
pays nothing.
last_search: Option<&'a LastSearch>VM.3d-2: the search n / N / * / # repeat, copied from
GrammarEnv::last_search. Borrowed; every other motion ignores it.
marks: Option<&'a dyn MarkResolver>VM.3e: the marks 'x / `x jump to, copied from
GrammarEnv::marks. Borrowed; every other motion ignores it.
viewport: Option<&'a dyn ViewportResolver>VM.3f: the window’s lines for H / M / L, copied from
GrammarEnv::viewport.
nostartofline: boolVM.3f: vim’s nostartofline — H / M / L keep the cursor’s column
instead of landing on the first non-blank.
curswant: Option<Curswant>VM.3g-1: the goal column, copied from GrammarEnv::curswant.
display: Option<&'a dyn DisplayResolver>VM.3g-2: the display geometry gj / gk / g0 / g$ read.
scrolloff: u32VM.3f: see GrammarEnv::scrolloff.
operator_pending: boolVM.3f: whether this motion is resolving an OPERATOR’s target.
H / L are adjusted for scrolloff “unless an operator is pending”
(:h H), so dH reaches the window’s real top edge while a bare H
stops at the margin. Checked in vim 9.2.