pub enum Action {
Show 30 variants
Move(Motion),
Operator(Operator),
ApplyOperator {
op: Operator,
motion: Motion,
},
Edit(Edit),
ChangeMode(Mode),
Command {
name: String,
args: Vec<String>,
},
InsertChar(char),
SubmitCommand,
Undo,
Redo,
Save,
Quit,
SearchOpen(Direction),
SearchRepeat {
reverse: bool,
},
SearchWord {
reverse: bool,
},
ClearSearchHighlight,
SearchSubmitOperated {
op: Operator,
},
TextObject(TextObject),
ApplyOperatorObject {
op: Operator,
object: TextObject,
},
RepeatLastChange,
JumpBack,
JumpForward,
Backspace,
PromptCaret {
to: CaretMove,
},
SearchPreviewStep {
forward: bool,
},
DeleteForward,
DeleteWordBefore,
DeleteToLineStart,
PromptHistory {
back: bool,
},
Pending,
}Expand description
A fully-resolved editor action — what the keymap emits, what the buffer consumes.
Variants§
Move(Motion)
Move every cursor by motion.
Operator(Operator)
Begin an operator (the d/c/y key). The editor enters
operator-pending: the next motion composes into an Action::ApplyOperator.
Resolved by the operator-pending FSM, never executed directly.
ApplyOperator
Apply a pending operator over a motion (delete-word, yank-line, etc.).
Edit(Edit)
Apply a primitive edit at each cursor.
ChangeMode(Mode)
Enter the given mode.
Command
Run a named command (via the command registry).
InsertChar(char)
Insert a character at each caret. Separate from Edit so the keymap can stay ignorant of rope details.
SubmitCommand
Submit a minibuffer / command-mode line (e.g. :w, :q).
Undo
Undo / redo one change.
Redo
Save
Save the current buffer.
Quit
Quit the editor.
SearchOpen(Direction)
Open the search prompt in direction (the / and ? keys).
The prompt reuses Mode::Command rather than adding a mode variant:
vim’s / IS the command-line with a different prompt character, and
this module’s own doc states new modes are layered through pending
state, not new variants. SearchState’s typed Option<Prompt> is what
disambiguates a <CR> that submits a search from one that submits an
ex-command — a discriminator that cannot be forgotten, unlike a bool.
SearchRepeat
n (reverse = false) / N (reverse = true) — jump to the next
match, relative to the direction the search was committed with, so N
after a ? search moves forward.
SearchWord
* (reverse = false) / # (reverse = true) — search the whole word
under the cursor. Literal, not regex: the word may contain . or [
and the user means those characters.
ClearSearchHighlight
:noh — stop highlighting matches while keeping the pattern, so n
still works. Distinct from cancelling a search.
SearchSubmitOperated
d/foo<CR> — commit the open search prompt and apply op from the
prompt’s ORIGIN to wherever the search lands.
Emitted only by the operator-pending machine; no keymap produces it. It exists because committing a search MOVES the cursor, and the operator needs the pre-move position as its start point. Carrying the operator through the commit makes “operate over a search” one atomic action instead of two steps racing to own the cursor.
TextObject(TextObject)
gn / gN — the next/previous match AS AN OBJECT.
Not a motion. A motion resolves to a POINT and an operator acts over
[cursor, point); gn names an EXTENT that need not start at the
cursor, so dgn deletes the whole match wherever it is. That
distinction is why this is its own action rather than a Motion
variant — folding it into Motion would silently give
[cursor, match.start), which deletes the text BEFORE the match.
ApplyOperatorObject
{operator}gn — apply op over a text object’s extent.
Emitted only by the operator-pending machine.
RepeatLastChange
. — repeat the last text change.
Vim’s most-used key, and the half that makes cgn a workflow rather
than a curiosity: cgn changes the next match, then . changes the
one after it, giving a per-instance confirmable rename with no
multi-cursor machinery.
JumpBack
<C-o> — walk back to where the last far jump was taken from.
Lives beside the search actions because search is what made it
necessary — committing a / used to be a one-way door — but it is not
a search action: G, gg, % and tag jumps are the other consumers.
JumpForward
<C-i> — walk forward again after Action::JumpBack.
Backspace
<BS> — delete the character BEFORE the caret, wherever the caret is.
ONE action, three targets, routed by the runtime: the search prompt,
the ex command-line, or the buffer in Insert mode. It is deliberately
not three actions — a face binding <BS> should not have to know which
of the three the operator is currently typing into, and the routing
question (“is a prompt open?”) is already answered by typed state the
runtime owns.
Named PromptBackspace until 2026-08-09, when the Insert-mode target
landed. The old name was the honest one while the buffer arm did not
exist — text_effect below already described the buffer arm as though
it did, which is how it went unnoticed that Insert mode had NO way to
erase a character.
PromptCaret
Move the caret inside an open prompt (← → Home End).
The prompt was append-only until this existed, so a typo in the middle of a pattern could only be fixed by deleting back to it.
SearchPreviewStep
<C-g> / <C-t> — step the search PREVIEW to the next/previous
match without committing.
Distinct from n in the one way that matters: this is still
cancellable. Escape returns to where the search started, which n
after a commit cannot do.
DeleteForward
<Del> — delete the character AT the caret, wherever the caret is.
The forward-delete sibling of Action::Backspace, routed the same
way. Never closes a prompt: emptying the text by deleting rightwards is
not the “backspaced past the /” gesture that means “I changed my
mind”.
DeleteWordBefore
<C-w> — delete the word before the caret, wherever the caret is.
The word-sized member of the same erase family as Action::Backspace:
ONE action, three targets (search prompt / ex line / buffer), routed by
the runtime on typed state it already owns.
Named PromptDeleteWord until 2026-08-09, when the Insert-mode target
landed. <BS> and <Del> had been given their buffer arm that morning
and these two were left behind, so Insert mode could erase one character
at a time and nothing larger — the half-migration is exactly what the
Prompt prefix was hiding.
DeleteToLineStart
<C-u> — delete from the caret back to the start of the line.
The line-sized member of the erase family; routed exactly like
Action::DeleteWordBefore. In the buffer it stops at the first
non-blank before falling through to column 0, so the first press on an
indented line clears what was typed and the second clears the indent —
vim’s two-step, which is what keeps <C-u> from eating alignment you
wanted to keep.
PromptHistory
Up/Down inside a prompt — walk search history.
back = true is older. Stepping forward past the newest entry restores
the text that was being typed when browsing began, so arrowing through
history and back never destroys a half-typed pattern.
Pending
No-op — used when a key sequence is pending but not yet complete.
Implementations§
Source§impl Action
impl Action
Sourcepub const fn text_effect(&self) -> TextEffect
pub const fn text_effect(&self) -> TextEffect
Classify this action’s effect on buffer text.
Total over Action — no wildcard arm. A new variant fails to
compile here rather than silently defaulting to “preserves”, which is
the direction that produces a stale-cache bug rather than a slow one.
Deliberately CONSERVATIVE where a variant’s reach is open-ended:
Command/SubmitCommand can run an ex-command that edits. It is not
conservative for Backspace/DeleteForward — those genuinely edit the
buffer outside a prompt. This paragraph claimed they did for months
before the Insert-mode arm was written; the classifier was right about
the design and the executor had simply never implemented it.
Over-reporting costs one extra scan; under-reporting paints the wrong
columns, so the asymmetry decides the genuinely doubtful cases.
Source§impl Action
impl Action
Sourcepub const fn highlight_effect(&self) -> HighlightEffect
pub const fn highlight_effect(&self) -> HighlightEffect
Classify this action’s effect on search highlighting.
Total over Action — no wildcard arm. “We forgot to clear on the
new command” becomes unconstructible rather than remembered: adding a
variant forces the decision here.
Source§impl Action
impl Action
Sourcepub const fn edits_prompt(&self) -> bool
pub const fn edits_prompt(&self) -> bool
Does this action edit or navigate an OPEN PROMPT, rather than doing something to the buffer?
The operator-pending machine needs this: during d/foo the operator
must survive every keystroke that is part of composing the pattern, and
disarm on anything that is not.
Total over Action — no wildcard arm, and that totality is the
whole point. The machine originally listed the prompt actions inline;
when PromptCaret, DeleteForward, DeleteWordBefore,
DeleteToLineStart and SearchPreviewStep were added later, none was
added to that list, so pressing ← or <C-g> midway through d/foo
silently disarmed the operator — reintroducing exactly the defect the
AwaitingSearch state had been created to fix. A new prompt action now
cannot be added without deciding here.
Trait Implementations§
Source§impl<'de> Deserialize<'de> for Action
impl<'de> Deserialize<'de> for Action
Source§fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
impl Eq for Action
Source§impl JsonSchema for Action
impl JsonSchema for Action
Source§fn schema_name() -> String
fn schema_name() -> String
Source§fn schema_id() -> Cow<'static, str>
fn schema_id() -> Cow<'static, str>
Source§fn json_schema(generator: &mut SchemaGenerator) -> Schema
fn json_schema(generator: &mut SchemaGenerator) -> Schema
Source§fn is_referenceable() -> bool
fn is_referenceable() -> bool
$ref keyword. Read more