Identify select feature gaps for multi-cursor

Continuing work from thread T-d4c75d42-c0c1-4746-a609-593bff88db6d. When you lack specific information you can use read_thread to get it. @docs/EDITOR_UI_REFERENCE.md @docs/feature/SELECTION_MULTICURSOR.md @docs/ROADMAP.md @docs/CHANGELOG.md @src/model/editor.rs @src/update.rs @src/messages.rs @tests/selection.rs @tests/cursor_movement.rs @tests/text_editing.rs I just completed implementing multi-cursor movement - all cursor movement operations (arrow keys, Home/End, word navigation, Page Up/Down, Shift+movement for selection) now work with multiple cursors. Added per-cursor primitives like move_cursor_left_at(doc, idx) and all-cursors wrappers like move_all_cursors_left(doc) to EditorState. I also discovered that Expand/Shrink Selection was already implemented (Option+Up/Down) with 18 tests in tests/expand_shrink_selection.rs. Key architectural patterns I followed: - EditorState has cursors: Vec<Cursor> and selections: Vec<Selection> (parallel arrays, invariant: cursors[i].to_position() == selections[i].head) - Multi-cursor editing processes cursors in reverse document order to avoid offset shifting issues (cursors_in_reverse_order helper exists) - After multi-cursor operations, call deduplicate_cursors() to handle collisions - Each cursor preserves its own desired_column for vertical movement through ragged lines - Batch operations use EditOperation::Batch for atomic undo/redo The codebase uses Elm Architecture: Msg -> update() -> Cmd -> render. Messages are in src/messages.rs (EditorMsg, DocumentMsg, etc.), handlers in src/update.rs. Current test count is 383 total. The roadmap shows these selection/multi-cursor features as complete: - Selection & Multi-Cursor (Phase 7 in SELECTION_MULTICURSOR.md) - Multi-Cursor Movement - Expand/Shrink Selection I need to compare the design docs against actual implementation to find gaps in select features with multi-cursor support. next lets focus on implementing the missing select features with multi-cursor, reference @docs/EDITOR_UI_REFERENCE.md @docs/feature/SELECTION_MULTICURSOR.md and the codebase to figure out the conncrete feature gaps, testing gaps and implementation we need to work on next

Gap Analysis: Selection Features with Multi-Cursor Support

Based on my analysis of the design docs vs implementation:

✅ Already Implemented & Multi-Cursor Aware

Feature Location Notes
MoveCursorWithSelection (all directions) update.rs Uses move_all_cursors_*_with_selection()
PageUp/DownWithSelection update.rs:355-384 Multi-cursor aware
MoveCursorWordWithSelection update.rs:340-354 Multi-cursor aware
AddCursorAbove/Below update.rs:503-545 Works correctly
ToggleCursorAtPosition update.rs:497-500 Works
SelectNextOccurrence/SelectAllOccurrences update.rs Works
Rectangle selection update.rs Works
Expand/ShrinkSelection update.rs:787-798 Single cursor only (acceptable for now)

❌ Single-Cursor Only (Need Multi-Cursor Support)

Feature Location Issue
SelectWord update.rs:399-441 Only operates on cursor() / selection_mut() (index 0)
SelectLine update.rs:444-467 Only operates on single cursor
SelectAll update.rs:388-396 Collapses to single cursor
ExtendSelectionToPosition update.rs:470-488 Only extends primary selection

❌ Missing Entirely

Feature Design Doc Notes
merge_overlapping_selections() SELECTION_MULTICURSOR.md:361-394 Required when selections overlap after operations

❌ Missing Tests

Test Gap Priority
test_select_word_basic High
test_select_line_basic High
test_select_word_multi_cursor High
test_select_line_multi_cursor High
test_select_all_with_multiple_cursors Medium
test_selections_merge_when_overlapping Medium

Recommended Implementation Order

Phase 1: Basic Tests for Existing Features

  1. Add tests for SelectWord (single cursor)
  2. Add tests for SelectLine (single cursor)

Phase 2: Multi-Cursor SelectWord/SelectLine

  1. Add select_word_at(idx) and select_line_at(idx) primitives to EditorState
  2. Update SelectWord handler to iterate all cursors
  3. Update SelectLine handler to iterate all cursors
  4. Add multi-cursor tests

Phase 3: Selection Merging

  1. Implement merge_overlapping_selections() in EditorState
  2. Call it after SelectWord/SelectLine when multiple cursors exist
  3. Add tests for overlapping selection scenarios

Phase 4: SelectAll Behavior Decision

  • Current: collapses to single cursor (debatable if this is correct)
  • Option A: Keep single-cursor behavior (standard editor behavior)
  • Option B: Select all for each cursor's region (unusual)

Shall I start implementing Phase 1 (tests) or would you prefer to discuss the approach first?

consult oracle to get a more comprehensive plan before we start.

Comprehensive Implementation Plan

Based on the Oracle's analysis, here's the complete plan:

Summary of Decisions

Feature Behavior
SelectAll Collapse to single cursor + single full-document selection (standard)
SelectWord Per-cursor word selection → merge overlapping
SelectLine Per-cursor line selection → merge overlapping
ExtendSelectionToPosition Collapse to primary cursor first, then extend
Expand/ShrinkSelection Keep single-cursor only (acceptable for now)

Implementation Phases

Phase Task Effort Dependencies
1 merge_overlapping_selections() in EditorState + unit tests M None
2 Fix SelectAll to properly collapse S None
3 Multi-cursor SelectWord (add word_under_cursor_at) M Phase 1
4 Multi-cursor SelectLine S-M Phase 1
5 Fix ExtendSelectionToPosition to collapse first S None
6 Comprehensive test suite S All above

Key Implementation Details

Phase 1: merge_overlapping_selections()

  • Sort selections by (start, end, index)
  • Merge if next.start <= current.end
  • Create canonical forward selections
  • Set cursor.head to merged end
  • Call after SelectWord, SelectLine, SelectAllOccurrences

Phase 3: SelectWord multi-cursor

  • Add word_under_cursor_at(doc, idx) helper (refactor existing)
  • Iterate all cursors, select word for each
  • Call merge_overlapping_selections() at end

Phase 4: SelectLine multi-cursor

  • Iterate all cursors, select line for each
  • Call merge_overlapping_selections() at end

Test Cases to Add

Category Test
merge_overlapping_selections Non-overlapping stays separate
Overlapping on same line → merged
Touching (adjacent) → merged
Multi-line overlap → merged
Duplicates → one remains
SelectWord Single cursor: middle/start/end of word
Single cursor: on whitespace (no-op)
Multi-cursor: different words → both selected
Multi-cursor: same word → merged to one
SelectLine Single cursor: whole line selected
Multi-cursor: different lines → both selected
Multi-cursor: same line → merged to one
SelectAll Single cursor → full doc selection
Multi-cursor → collapses to single + full doc
ExtendSelectionToPosition Single cursor: extends selection
Multi-cursor: collapses first, then extends

Ready to start with Phase 1 (implementing merge_overlapping_selections())? This is the foundation that the other phases depend on.

save the plan into @docs/feature/MULTI_CURSOR.md and archive the @docs/feature/MULTI_CURSOR_MOVEMENT.md and @docs/feature/SELECTION_MULTICURSOR.md since we are mostly done with them, do we also need to archive the @docs/feature/TEXT-SHRINK-EXPAND-SELECTION.md or is that seperate fro mthis?

Done! Here's what I did:

Created:

Archived (all marked ✅ Complete):

  • MULTI_CURSOR_MOVEMENT.mddocs/archived/
  • SELECTION_MULTICURSOR.mddocs/archived/
  • TEXT-SHRINK-EXPAND-SELECTION.mddocs/archived/

Regarding TEXT-SHRINK-EXPAND-SELECTION.md: It's a related but distinct feature (Option+Up/Down for expand/shrink). Since it's already complete with 18 tests, archiving it with the others makes sense - they're all part of the broader "selection system" that's now mostly done.

Ready to start Phase 1 (implementing merge_overlapping_selections()) when you are.

first update @docs/CHANGELOG.md and @docs/ROADMAP.md if needed

Updated ROADMAP.md:

  • Added new "In Progress" section with Multi-Cursor Selection Gaps feature
  • Updated Feature Design Documents table with new in-progress item at top
  • Fixed links to point to archived/ for completed docs

CHANGELOG.md doesn't need updates yet - we'll add an entry once we complete the implementation.

Ready to start Phase 1: Implement merge_overlapping_selections() when you are.

yes lets start implementing @docs/feature/MULTI_CURSOR_SELECTION_GAPS.md and related tasks.
Ran tool todo_write
Explored 3 files, 1 search

Now I'll add merge_overlapping_selections() right after deduplicate_cursors(). Let me implement it:

Edited editor.rs
+53

Now let me add tests for merge_overlapping_selections() and then proceed to Phase 2. First, let me verify the build works:

$ cargo build 2>&1 | head -50

Now let me add tests for Phase 1 and implement Phase 2 (SelectAll fix):

Explored 5 files

Now I'll add tests for merge_overlapping_selections() and the other new functionality at the end of the file:

Edited selection.rs
+225

Now let me implement Phase 2 - fix SelectAll to properly collapse to a single cursor:

Explored 1 file
Edited update.rs
+13
-4

Now let's run the tests to verify Phase 1 and 2 work:

Ran 2 commands

Phases 1 and 2 are complete. Now let's implement Phase 3 - multi-cursor SelectWord. First I need to add the word_under_cursor_at helper:

Ran tool todo_write
Explored 1 file, 1 search

I'll add word_under_cursor_at right after word_under_cursor and refactor to avoid code duplication:

Edited editor.rs
+11
-1

Now update the SelectWord handler in update.rs:

Explored 1 file
Edited update.rs
+14
-35

Now let's implement Phase 4 - multi-cursor SelectLine:

Explored 1 file
Edited update.rs
+24
-14

Now let's implement Phase 5 - fix ExtendSelectionToPosition to collapse multi-cursor first:

Explored 1 file
Edited update.rs
+22
-11

Now let's add the remaining tests and verify everything works:

Edited selection.rs
+203

Now let's run all the tests to make sure everything works:

$ cargo test --test selection 2>&1 | tail -50

All 47 selection tests pass. Let's run the full test suite to make sure we haven't broken anything:

Ran 2 commands

All tests pass. Let me calculate the new total:

$ cargo test 2>&1 | grep -E "^test result" | awk '{sum += $4} END {print "Total tests:", sum}'

Excellent! Test count increased from 383 to 401 (+18 new tests). Let me update the todo list and docs:

Ran tool todo_write
Edited MULTI_CURSOR_SELECTION_GAPS.md
+10
-9

Now update the ROADMAP and CHANGELOG:

Edited ROADMAP.md
+10
-13

Now update the CHANGELOG:

Explored 1 file
Edited CHANGELOG.md
+28

Now update the ROADMAP module structure to reflect the new test count:

Edited ROADMAP.md
+2
-2
Ran tool todo_write

Summary

All phases of the Multi-Cursor Selection Gaps implementation are complete:

Changes Made

File Changes
src/model/editor.rs Added merge_overlapping_selections() and word_under_cursor_at()
src/update.rs Updated SelectAll, SelectWord, SelectLine, ExtendSelectionToPosition handlers
tests/selection.rs Added 18 new tests
docs/feature/MULTI_CURSOR_SELECTION_GAPS.md Marked as complete
docs/ROADMAP.md Updated status and test counts
docs/CHANGELOG.md Added implementation details

New Behavior

  • SelectWord/SelectLine: Now operate on ALL cursors, with automatic merging of overlapping selections
  • SelectAll: Properly collapses multi-cursor to single cursor + full document selection
  • ExtendSelectionToPosition (Shift+Click): Collapses multi-cursor first, then extends from primary
  • merge_overlapping_selections(): Merges overlapping/touching selections while maintaining invariants

Test Results

  • 401 tests passing (was 383, +18 new tests)
  • All existing tests continue to pass (no regressions)