pub struct ExCommandContext {
pub bang: bool,
pub args: Args,
pub range: Option<Range>,
pub register: Register,
pub count: Count,
pub buffer_id: BufferId,
pub cursor: Position,
pub buffer: Buffer,
pub path: Option<Arc<PathBuf>>,
pub syntax: Option<Arc<dyn Any + Send + Sync>>,
pub cancel: CancellationToken,
}Expand description
Context handed to an ex-command’s evaluator. Mirrors the shape passed
to motion / operator / text-object specs but adds the bang bit and
drops direct document mutation: ex-commands describe their work by
returning an crate::effect::Effect, which the host applies.
Owns a crate::CancellationToken (not a borrow) so apply
closures can hold it across Box::new(move |ctx| ...)
boundaries without lifetime gymnastics. The actor flips a clone
when cancellation arrives.
Fields§
§bang: boolWhether the command was typed with a trailing ! (:q!).
args: ArgsArguments produced by the spec’s ExCommandSpec::parse_args.
range: Option<Range>The line range typed before the command (:%s, :1,5…), unresolved;
None when there was none. The command resolves it itself.
register: RegisterThe register named in the invocation, unnamed by default.
count: CountThe count, 1 when none was given.
buffer_id: BufferIdThe buffer the : line was submitted from (MR.2) — the same
fact ActionContext::buffer_id carries, filled from the same
place in crate::dispatcher::execute.
It was absent, and the absence was an asymmetry rather than a
decision: vim’s ex-commands are buffer-scoped by definition
(:w, :%s, :bd), the : line is a parser front-end onto the
one dispatcher (design §5.2.1), and a command reached that way
was seeing strictly less than the same command reached by a
chord. :magit-status is what found it: it must open the
repository of the buffer you are looking at, and via : it could
not name that buffer at all.
Deliberately just the id: an ex-command that needs the buffer’s
text, path or name resolves it through a handle it captured at
boot (SubsystemBoot::buffer_store), which keeps this context
free of services and keeps lattice-grammar unaware of them.
cursor: PositionOC.10: where the caret sits when the : line is submitted — the four
fields below are exactly the ones ActionContext already carries, and
they are here for the reason buffer_id above is.
MR.2 made that argument for the id: “a command reached that way was
seeing strictly less than the same command reached by a chord”. It is the
same argument, and stopping at the id left it half-made. A plugin
ex-command felt it hardest: apply-ex-command returns list<effect>,
and Effect::ApplyEdit names a target buffer the guest had no way to
obtain — so the seam offered an effect vocabulary a guest structurally
could not use. :org-clock-in is what found it.
Native ex-commands ignore all four; they cost an Arc bump each.
buffer: BufferA point-in-time view of the buffer the : line was submitted from.
O(1) rope clone (Arc-shared nodes), as on ActionContext::buffer.
path: Option<Arc<PathBuf>>The file behind that buffer, so a plugin’s document handle can answer
path(). An Arc bump per dispatch, None for a buffer with no file.
syntax: Option<Arc<dyn Any + Send + Sync>>The per-dispatch tree snapshot, type-erased for the same layering reason
ActionContext::syntax is. Cloned at the same instant as buffer, so
tree and text agree on version (§7).
cancel: CancellationTokenCooperative cancellation handle (DESIGN.md §5.2.5); owned so a closure can keep it.