Expand description
Keep selections valid across an edit (#63).
Multi-cursor edits cascade: an edit made at selection N moves every position
after it, so the other selections have to be rewritten or they silently point
at the wrong text. This module is that rewrite, as a pure function over
(Position, Edit) — no editor, no buffer mutation.
§Contract
shift_position is called with the pre-edit buffer geometry, i.e.
before edit is applied. It answers: where does this selection end up once
the edit lands?
It returns Option, and None means “this position cannot be tracked
through this edit — drop it”. That is deliberate. The alternative for an
edit whose geometry we do not model exactly is to guess, and a guessed
position is a selection pointing at the wrong text: the edit still applies,
just somewhere the user did not ask for. Dropping degrades multi-cursor to
single-cursor, which is visible and harmless; guessing corrupts the buffer,
which is neither.
Today None is returned only for SplitLines, which is the undo-inverse of
a join: it is emitted when history rewinds, not when a user edits, and undo
restores a whole snapshot without preserving secondary carets anyway.
JoinLines, InsertBlock and DeleteBlockChunks ARE modelled — they mirror
hjkl_buffer’s own geometry, and they matter: vim’s J is a JoinLines, and
visual-block I/A are the block edits, so dropping carets on those would
make multi-cursor collapse under exactly the operations that need it most.
§Position semantics
A position exactly at an insertion point moves right (the text lands before it). A position strictly inside a deleted range collapses to the range start.
Structs§
- Sel
- One selection: an
anchor(the fixed end) and ahead(the end a motion moves). Both are inclusive char positions —anchor == headis a bare caret, and a selection with extent covers[start, end]inclusive of both.
Functions§
- merge_
overlapping - Collapse a set of selections so no two overlap, merging any that do into their union. Order of the input is not preserved — callers that need a stable order should re-sort the result.
- shift_
position - Rewrite
pso it still points at the same text aftereditlands, orNonewhen the edit’s geometry is not modelled and the position must be dropped rather than guessed. - shift_
sel - Rewrite BOTH ends of
selso it still covers the same text afteredit, orNonewhen either end is untrackable.