Summary #
Give each multi-cursor its own anchor/head so N independent selections exist, instead of one shared selection tied to the primary cursor (Helix/Zed model).
Motivation #
Multi-cursor today gives N bare cursors but a single visual selection that only tracks the primary. That blocks the core refactor loop: :select-all-matches drops bare cursors at match starts and can't select each whole match, so you can't see what each cursor covers or operate on all selections at once.
Current behavior #
- Buffer has
:cursors @[offset...]+:primary, plus a single:selection @{:anchor :head}(selection.janet). - Select-mode movement runs
(move/cursor-*)+(selection/update), which sets the head from the primary cursor only. - Render carries one
:selection {start,end}(KoaSelection); ui.rs paints one range. search/select-all-matchesadds bare cursors at match starts.
Proposed approach #
- Carry an anchor per cursor, e.g.
:cursors @[{:offset o :anchor a}...](anchor == offset = no selection), or a parallel:selectionsarray aligned with:cursors. - selection.janet:
range->ranges;start/update/clear/delete/get-selected-textbecome multi-aware, mirroring theinsert-all/apply-to-allpattern in buffer.janet. - Render:
:selectionbecomes a list; ui.rs paints each range (its span logic already loops). Wrap likeKoaHighlights/KoaRules(janet_binds has noVecderive). - Select mode: movement already moves all cursors, so heads move while anchors stay.
:select-all-matchesselects each match (anchor = start, head = end) instead of dropping bare cursors.
Scope / notes #
Real refactor across selection.janet, buffer.janet, render.janet, event.rs, ui.rs. Coordinate with undo/redo (must be multi-aware regardless).
Resolved by a recent commit in the multi-cursor + multi-buffer MVPs branch