pub enum Edit {
InsertChar {
at: Position,
ch: char,
},
InsertStr {
at: Position,
text: String,
},
DeleteRange {
start: Position,
end: Position,
kind: MotionKind,
},
JoinLines {
row: usize,
count: usize,
with_space: bool,
},
SplitLines {
row: usize,
cols: Vec<usize>,
inserted_spaces: Vec<bool>,
},
Replace {
start: Position,
end: Position,
with: String,
},
InsertBlock {
at: Position,
chunks: Vec<String>,
},
DeleteBlockChunks {
at: Position,
widths: Vec<usize>,
pads: Vec<usize>,
},
}Expand description
One unit of buffer mutation. Constructed by the caller (vim
engine, ex command, …) and handed to View::apply_edit.
§Invariants
All Position arguments must satisfy the bounds documented on
Position before the edit is applied. Out-of-bounds positions
are clamped by View::clamp_position inside
View::apply_edit; if the clamped form changes the edit’s
meaning the result is implementation-defined.
See View::apply_edit for post-conditions that hold after
every variant.
Variants§
InsertChar
Insert one char at at. Cursor lands one position past it.
at must be a valid Position. ch must be a single Unicode
scalar. Multi-grapheme content must use Edit::InsertStr.
InsertStr
Insert text (possibly multi-line) at at. Cursor lands at
the end of the inserted content.
at must be a valid Position. text may contain \n — the
buffer splits on newline. CR (\r) is preserved as-is; the host
is responsible for CRLF normalization before insert.
DeleteRange
Delete [start, end) with the given kind.
start <= end in document order. MotionKind controls whether
trailing newlines are consumed:
MotionKind::Char: byte-precise; preserves enclosing newlines.MotionKind::Line: whole rows fromstart.row..=end.row; endpoint columns are ignored.MotionKind::Block: rectangle[start.row..=end.row] × [min_col..=max_col].
JoinLines
J (with_space = true) / gJ (false) — fold count rows
after row into row.
row + count - 1 must be a valid row. count >= 1.
SplitLines
Inverse of JoinLines. Splits row back at each char column
in cols.
inserted_spaces[i] records whether the join that produced
cols[i] ACTUALLY inserted a space there — NOT the caller’s
with_space intent passed to JoinLines, which is uniform for
the whole (possibly multi-join) batch while the per-join outcome
is not: do_join_lines skips the space whenever either side of
that specific join is empty. A single bool here (matching the
original, uniform with_space intent) can’t tell those joins
apart from ones that DID insert a space, so do_split_lines would
misidentify — and delete — an unrelated, legitimately-present
space character that happens to sit at that col (audit-r2 fix 6).
Parallel to cols.
Replace
Replace [start, end) with with (charwise, may span rows).
Same constraints as Edit::DeleteRange with
MotionKind::Char for the deleted range, plus the insert
constraints from Edit::InsertStr for with.
InsertBlock
Insert one chunk per row, each at (at.row + i, at.col).
Inverse of a blockwise delete; preserves the rectangle even
when rows are ragged shorter than at.col.
DeleteBlockChunks
Inverse of Edit::InsertBlock. Removes widths[i] chars
starting at (at.row + i, at.col), plus pads[i] more chars
immediately BEFORE at.col on that row. Carrying widths instead
of recomputing means a ragged-row block delete round-trips
exactly.
pads exists because do_insert_block space-pads a row that’s
shorter than at.col before splicing the chunk in, so that the
chunk lands at the intended column; without recording that pad
width here too, this inverse would remove the chunk but leave the
padding behind (audit-r2 fix 6). pads[i] is always 0 for a row
that didn’t need padding. DeleteBlockChunks only ever appears as
InsertBlock’s inverse (never constructed by a “forward” edit —
see do_delete_range’s MotionKind::Block arm, which builds its
own inverse InsertBlock directly via rope_cut_chars), so this
field has no bearing on any other call site’s semantics.