Identify select feature gaps for multi-cursor
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
- Add tests for
SelectWord(single cursor) - Add tests for
SelectLine(single cursor)
Phase 2: Multi-Cursor SelectWord/SelectLine
- Add
select_word_at(idx)andselect_line_at(idx)primitives toEditorState - Update
SelectWordhandler to iterate all cursors - Update
SelectLinehandler to iterate all cursors - Add multi-cursor tests
Phase 3: Selection Merging
- Implement
merge_overlapping_selections()in EditorState - Call it after SelectWord/SelectLine when multiple cursors exist
- 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?
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.
Done! Here's what I did:
Created:
- docs/feature/MULTI_CURSOR_SELECTION_GAPS.md - comprehensive implementation plan with all 6 phases
Archived (all marked ✅ Complete):
MULTI_CURSOR_MOVEMENT.md→docs/archived/SELECTION_MULTICURSOR.md→docs/archived/TEXT-SHRINK-EXPAND-SELECTION.md→docs/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.
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.
Now I'll add merge_overlapping_selections() right after deduplicate_cursors(). Let me implement it:
Now let me add tests for merge_overlapping_selections() and then proceed to Phase 2. First, let me verify the build works:
Now let me add tests for Phase 1 and implement Phase 2 (SelectAll fix):
Now I'll add tests for merge_overlapping_selections() and the other new functionality at the end of the file:
Now let me implement Phase 2 - fix SelectAll to properly collapse to a single cursor:
Now let's run the tests to verify Phase 1 and 2 work:
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:
I'll add word_under_cursor_at right after word_under_cursor and refactor to avoid code duplication:
Now update the SelectWord handler in update.rs:
Now let's implement Phase 4 - multi-cursor SelectLine:
Now let's implement Phase 5 - fix ExtendSelectionToPosition to collapse multi-cursor first:
Now let's add the remaining tests and verify everything works:
Now let's run all the tests to make sure everything works:
All 47 selection tests pass. Let's run the full test suite to make sure we haven't broken anything:
All tests pass. Let me calculate the new total:
Excellent! Test count increased from 383 to 401 (+18 new tests). Let me update the todo list and docs:
Now update the ROADMAP and CHANGELOG:
Now update the CHANGELOG:
Now update the ROADMAP module structure to reflect the new test count:
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)