Skip to main content

Module selection_shift

Module selection_shift 

Source
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 a head (the end a motion moves). Both are inclusive char positions — anchor == head is a bare caret, and a selection with extent covers [start, end] inclusive of both.

Functions§

shift_position
Rewrite p so it still points at the same text after edit lands, or None when the edit’s geometry is not modelled and the position must be dropped rather than guessed.
shift_sel
Rewrite BOTH ends of sel so it still covers the same text after edit, or None when either end is untrackable.