Implementing split view phases 3-7 for Token editor

Continuing work from thread T-60e201bf-322a-4190-8671-3afe9ad7500e. When you lack specific information you can use read_thread to get it. @docs/feature/SPLIT_VIEW.md @src/model/editor_area.rs @src/model/mod.rs @src/model/document.rs @src/model/editor.rs @src/update.rs @src/messages.rs @src/main.rs @docs/ROADMAP.md @tests/common/mod.rs I'm implementing split view for a Rust text editor (Token) following docs/feature/SPLIT_VIEW.md. Current Progress: - Phase 1 (Core Data Structures): COMPLETE - Created src/model/editor_area.rs with ID types (DocumentId, EditorId, GroupId, TabId), Rect, Tab, EditorGroup, LayoutNode enum, SplitContainer, and EditorArea. Added optional id fields to Document and EditorState. - Phase 2 (Layout System): COMPLETE - Implemented compute_layout() that recursively assigns rects to groups, group_at_point() for hit testing, splitter_at_point(), and SplitterBar type. Added 7 unit tests. - Phases 3-7: NOT STARTED Remaining Phases from the design doc: - Phase 3: Update AppModel to replace document/editor fields with EditorArea, add accessor methods, update all call sites - Phase 4: Add LayoutMsg enum with SplitGroup, CloseGroup, FocusGroup, MoveTab operations; wire into update() - Phase 5: Rendering - multi-group rendering, tab bars, splitters, focus indicators - Phase 6: Document synchronization - propagate edits to all views of same document, adjust cursors - Phase 7: Keyboard shortcuts - Cmd+\, Cmd+W, Cmd+1/2/3 for group focus Key architectural decisions: - EditorArea::single_document() is the migration helper that creates an EditorArea from existing Document + EditorState - Documents are shared (HashMap by DocumentId), editors are view-specific (HashMap by EditorId) - Each EditorGroup has tabs, each Tab references an EditorId - LayoutNode is either Group(GroupId) or Split(SplitContainer with direction and ratios) - compute_layout() updates group.rect fields and returns SplitterBar list Established patterns I should follow: - TDD: write failing tests first, then implement - Use saturating_sub for arithmetic to prevent overflow panics - Keybindings use (ctrl || logo) for cross-platform Cmd/Ctrl support - Messages flow through Msg enum -> update() function - Export new types from model/mod.rs Test count is 253 (all passing). The design doc has detailed implementation notes for each phase. provide enough context to start implementing phase 3+, include the plan and our current progress

Based on the attached files, here's the context for Phase 3+:

Current State

Phase 1-2 Complete:

  • EditorArea with single_document() migration helper
  • compute_layout(), group_at_point(), splitter_at_point()
  • 7 unit tests in editor_area.rs

Phase 3: Update AppModel

Goal: Replace AppModel.document + AppModel.editor with AppModel.editor_area

Key changes needed:

  1. AppModel struct (mod.rs:51-66): Replace fields

    // FROM:
    pub document: Document,
    pub editor: EditorState,
    // TO:
    pub editor_area: EditorArea,
    
  2. Add accessor methods to AppModel:

    • focused_document()&Document
    • focused_document_mut()&mut Document
    • focused_editor()&EditorState
    • focused_editor_mut()&mut EditorState
  3. Update all call sites - Currently ~100+ references to model.document and model.editor in:

    • update.rs (most complex - cursor movement, editing)
    • main.rs (rendering, input handling)
    • tests/common/mod.rs (test helpers)
  4. Migration path - Use EditorArea::single_document() in AppModel::new()

Phase 4: Messages

Add to messages.rs:

pub enum LayoutMsg {
    SplitGroup { group_id: GroupId, direction: SplitDirection },
    CloseGroup(GroupId),
    FocusGroup(GroupId),
    MoveTab { tab_id: TabId, to_group: GroupId },
}

Wire into Msg enum and update().

Recommended Approach

Start Phase 3 with TDD:

  1. Update tests/common/mod.rs helper first (simpler)
  2. Add accessor methods to AppModel
  3. Update AppModel::new() to use EditorArea
  4. Fix compilation errors in update.rs
  5. Fix compilation errors in main.rs
  6. Run make test to verify

Want me to begin Phase 3 implementation?

yes

Phase 3 Complete!

Summary

Successfully migrated AppModel from direct document/editor fields to the new EditorArea architecture:

Changes Made

  1. AppModel struct (mod.rs):

    • Replaced document: Document and editor: EditorState with editor_area: EditorArea
    • Added accessor methods: document(), document_mut(), editor(), editor_mut()
    • Updated new() to use EditorArea::single_document()
  2. status_bar.rs: Updated sync_status_bar() to use accessor methods

  3. update.rs: ~300+ changes from model.editor.*model.editor().* / model.editor_mut().*

  4. main.rs: Similar accessor method updates for rendering and input

  5. tests/common/mod.rs: Updated test helpers to construct EditorArea

  6. All test files (7 files, ~304 fixes): Updated to use accessor methods

  7. Bug fix: Fixed DeleteLine logic for edge cases with trailing newlines

Test Results

  • 253 tests passing (same count as before)
  • Build succeeds
  • All existing functionality preserved

Next Steps (Phases 4-7)

  • Phase 4: Add LayoutMsg enum for split/close/focus operations
  • Phase 5: Render multiple groups, tab bars, splitters
  • Phase 6: Document synchronization across views
  • Phase 7: Keyboard shortcuts (Cmd+, Cmd+W, etc.)
continue

Phase 4 Complete!

Summary

Successfully implemented the LayoutMsg message system for split views:

New Messages (messages.rs)

Added LayoutMsg enum with operations:

  • SplitFocused(direction) / SplitGroup { group_id, direction } - Split groups
  • CloseGroup(id) / CloseFocusedGroup - Close groups
  • FocusGroup(id) / FocusNextGroup / FocusPrevGroup / FocusGroupByIndex(n) - Focus navigation
  • MoveTab { tab_id, to_group } - Move tabs between groups
  • CloseTab(id) / CloseFocusedTab - Close tabs
  • NextTab / PrevTab / SwitchToTab(n) - Tab navigation

New Functions (update.rs)

  • update_layout() - Main handler dispatching to helpers
  • split_focused_group() / split_group() - Create new groups with same document
  • insert_split_in_layout() - Update layout tree with new splits
  • close_group() / remove_group_from_layout() - Remove groups and collapse tree
  • collect_group_ids() - Traverse layout tree
  • focus_adjacent_group() - Cycle through groups
  • move_tab() / close_tab() - Tab management

Tests (tests/layout.rs)

17 new tests covering:

  • Split operations (horizontal, vertical, multiple)
  • Close group (last group protection, cleanup, layout collapse)
  • Focus operations (direct, next/prev, by index)
  • Tab navigation
  • Integration: edits affecting shared document

Test Results

  • 270 tests passing (up from 253)
  • All existing tests still pass

Next Steps

  • Phase 5: Rendering - multi-group rendering, tab bars, splitters
  • Phase 6: Document synchronization
  • Phase 7: Keyboard shortcuts
continue continue

Split View Implementation Complete! 🎉

All 7 phases of the Split View feature are now complete:

Summary

Phase Status Description
Phase 1 Core Data Structures - ID types, EditorArea, Tab, EditorGroup, LayoutNode
Phase 2 Layout System - compute_layout(), group_at_point(), splitter hit testing
Phase 3 Update AppModel - Replaced Document/EditorState with EditorArea, accessor methods
Phase 4 Messages - LayoutMsg enum, split/close/focus operations, 17 tests
Phase 5 Rendering - Multi-group rendering, tab bars, splitters, focus indicators
Phase 6 Document Sync - Shared document architecture (cursor adjustment deferred)
Phase 7 Keyboard Shortcuts - Cmd+\, Cmd+W, Cmd+1/2/3/4, Ctrl+Tab

New Keyboard Shortcuts

Shortcut Action
Cmd+\ / Ctrl+\ Split horizontally
Cmd+Shift+\ / Ctrl+Shift+\ Split vertically
Cmd+W / Ctrl+W Close tab/group
Cmd+1/2/3/4 / Ctrl+1/2/3/4 Focus group by index
Ctrl+Tab Focus next group
Ctrl+Shift+Tab Focus previous group

Test Results

  • 293 tests passing (up from 253 at start)
  • 40 new tests added (17 layout + 23 renderer)

Key Files Modified

  • src/model/editor_area.rs - Core split view data structures
  • src/model/mod.rs - AppModel with EditorArea integration
  • src/messages.rs - LayoutMsg enum
  • src/update.rs - update_layout() and helper functions
  • src/theme.rs - TabBarTheme, SplitterTheme
  • src/main.rs - Multi-group rendering and keyboard shortcuts
  • tests/layout.rs - 17 layout operation tests
what is our next step?
Explored 1 file

The Split View feature is now complete. Looking at the ROADMAP, here are the next options:

Recommended Next Steps

  1. Move Split View to "Recently Completed" - Update ROADMAP structure

  2. Choose next feature from the planned list:

    • Occurrence Selection (Phase 9) - Cmd+J to select next match (JetBrains-style)
    • Expand/Shrink Selection - Progressive selection with Option+Up/Down
    • File Dropping - Drag-and-drop files to open
    • Workspace Management - CLI args for multiple files/directories
  3. Polish items (deferred from Split View):

    • Cursor adjustment when other views edit
    • Splitter drag resize (currently splitters render but aren't draggable)
    • Tab drag-and-drop between groups

My Recommendation

Occurrence Selection (Cmd+J) is a high-value feature that builds on the existing multi-cursor infrastructure and is commonly expected in modern editors.

Alternatively, File Dropping would make the editor more usable for daily work.

Which would you like to tackle next?