Skip to content

feat: implement window splitting functionality#63

Merged
fcoury merged 20 commits intomasterfrom
multi-windows2
Jun 17, 2025
Merged

feat: implement window splitting functionality#63
fcoury merged 20 commits intomasterfrom
multi-windows2

Conversation

@fcoury
Copy link
Contributor

@fcoury fcoury commented Jun 17, 2025

Summary

  • Implements full window splitting functionality with Vim-style keybindings
  • Adds window management commands for splitting, navigation, closing, and resizing
  • Fixes multiple rendering issues with window separators and intersections

Changes

Core Window Management

  • Added WindowManager and Split tree structure for managing window layouts
  • Implemented horizontal (split/Ctrl-w s) and vertical (vsplit/Ctrl-w v) splitting
  • Added window navigation commands (Ctrl-w h/j/k/l and Ctrl-w w)
  • Implemented window closing (Ctrl-w c/Ctrl-w q)
  • Added window resizing functionality (Ctrl-w +/-/</>)
  • Mouse support for window selection

Rendering Improvements

  • Window-aware rendering system that properly handles multiple windows
  • Fixed gutter rendering to work correctly with splits
  • Implemented proper window separator rendering with Unicode box-drawing characters
  • Fixed T-junction detection for window separator intersections
  • Added ASCII fallback mode via window_borders_ascii config option

Bug Fixes

  • Fixed arithmetic underflow when cursor position was above viewport
  • Fixed actions not rendering immediately in split windows
  • Fixed incorrect window being split when using vsplit
  • Resolved all compiler warnings and clippy errors

Configuration

  • Added window_borders_ascii option to use ASCII characters (|, -, +) instead of Unicode

Test Plan

  • Manual testing of window splitting, navigation, and closing
  • Verified gutter renders correctly in all windows
  • Tested window separator rendering with proper T-junctions
  • Confirmed actions render immediately without needing to switch windows
  • Tested with both Unicode and ASCII border modes
  • All code compiles without warnings and passes clippy

🤖 Generated with Claude Code

fcoury and others added 20 commits June 16, 2025 22:51
- Add WindowManager and Window structs to manage multiple views
- Add Split enum to represent window layout tree (horizontal/vertical splits)
- Maintain backward compatibility by keeping existing editor fields
- Add sync methods to synchronize window state with editor state
- Update resize handler to also resize window manager
- All tests pass, no regressions

This is the foundation for implementing window splits. The actual split
functionality will be implemented in follow-up commits.

🤖 Generated with Claude Code

Co-Authored-By: Claude <noreply@anthropic.com>
- Add WindowManager with tree-based split layout structure
- Implement window splitting actions (SplitHorizontal, SplitVertical)
- Add window navigation actions (NextWindow, PreviousWindow)
- Support command-line split commands (:split, :vsplit, :close)
- Add Vim-style keybindings for window management (Ctrl-w prefix)
- Update rendering system to handle multiple windows
- Synchronize editor state with active window
- Document window management features in CLAUDE.md

This provides the foundation for window splitting functionality.
Future work includes:
- Rendering window borders and separators
- Implementing window closing and resizing
- Adding visual indicators for active window
- Supporting different buffers per window
- Add window-aware rendering system that respects window boundaries
- Fix gutter rendering issue in horizontal splits (was being overwritten)
- Fix window split targeting (correct window now gets split)
- Implement proper window borders with intersection characters (┼, ├, ┤, ┬, ┴)
- Add window closing functionality (:close command and Ctrl-w c/q)
- Implement directional window navigation (Ctrl-w h/j/k/l)
- Support opening different files in splits (:split <file>, :vsplit <file>)
- Add coordinate transformation methods for window-aware rendering
- Update cursor positioning to work with active window
- Reserve space for window separators in layout calculations

All windows now render independently with proper visual separation.
State synchronization between editor and windows is maintained when
switching between windows.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
- Implement render_overlays_in_window() to handle overlays per window
- Add render_diagnostics_in_window() for window-specific diagnostics
- Add selected_cells_in_window() for window-aware selections
- Overlays now properly respect window boundaries
- Line highlights, selections, and diagnostics only render within their window
- Only active window shows cursor-related overlays

This completes Phase 1.3 of the window implementation plan.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
- Status line now shows information from the active window
- Added window indicator showing current window number and total
- Position (line:column) now reflects active window's viewport
- Buffer name and dirty state come from active window's buffer

The status line now shows "[1/3]" style indicators when multiple
windows are open, making it clear which window is active.

This completes Phase 4.1 of the window implementation plan.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
- Added resize_window() method to WindowManager
- Implemented smart split ratio adjustment based on resize direction
- Window resizing respects parent split orientations
- Keybindings: Ctrl-w < (left), > (right), + (down), - (up in config)
- Resize amount is configurable (default: 5% per step)
- Prevents windows from becoming too small (min 10% ratio)

The implementation finds the appropriate split containing the active
window and adjusts its ratio accordingly. Resizing is context-aware:
- In horizontal splits: Up/Down resizes the split
- In vertical splits: Left/Right resizes the split

This completes Phase 3.3 of the window implementation plan.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
- Mouse clicks now activate the window under the cursor
- Clicking in a window switches focus to that window
- Mouse position is properly translated to window-local coordinates
- Scrolling with mouse wheel now activates the window under cursor
- Cursor placement respects window boundaries and buffer limits

This improves the window management UX by allowing users to click
directly on a window to focus it, making multi-window workflows
more intuitive.

This completes Phase 4.3 of the window implementation plan.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
- Marked Phase 3.3 (window resizing) as complete
- Marked Phase 4.3 (mouse support) as complete
- Added note about minimum window size enforcement still needed
- All critical window functionality is now implemented

The window splitting feature set is now functionally complete with:
- Window creation, closing, and navigation
- Window-aware rendering (content, overlays, status line)
- Window resizing with smart split ratio adjustment
- Mouse support for window selection and scrolling
- Proper window borders with intersections

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
- Fixed panic caused by subtracting vtop from cy when cy < vtop
- Use saturating_sub to handle underflow gracefully
- Use window's local cursor position instead of global editor state
- This fixes crashes when cursor is outside the current viewport

The issue occurred when switching between windows with different
viewport positions, causing cursor coordinates to be out of sync.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
- Added sync_to_window() after executing actions to ensure window state is updated
- Added render call for multi-window mode to make changes immediately visible
- This fixes the issue where actions (like cursor movement) weren't visible until switching windows

The problem was that actions updated the global editor state but never synced
it back to the active window, causing changes to only appear after window switch.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
- Implement proper T-junction detection for window separators
- Add configurable ASCII/Unicode border characters via window_borders_ascii
- Rewrite separator rendering to use grid-based approach for accurate intersections
- Fix issue where horizontal lines overwrote vertical separator intersections

The new implementation correctly detects and renders T-junctions (┬, ┴, ├, ┤)
where horizontal and vertical window separators meet.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
- Handle cases where vertical lines end exactly at horizontal lines
- Check for vertical lines that start or end at horizontal separator positions
- Add detailed debug logging to trace separator detection
- Fix edge cases in intersection detection logic

The improved algorithm now correctly detects T-junctions in all split
configurations including Ctrl+W s followed by Ctrl+W v, and vice versa.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
- Use two-pass algorithm: first mark all positions, then determine characters
- Explicitly check for T-junctions where vertical lines start/end at horizontal lines
- Add support for corner characters (└, ┘, ┌, ┐) for better visual clarity
- Fix case where vertical separator meets horizontal separator from below

The new algorithm correctly handles all window configurations including:
- Horizontal split followed by vertical split of bottom window
- Vertical split followed by horizontal split
- Complex multi-window layouts with multiple intersections

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
- Pass 1: Draw all vertical and horizontal lines into a temporary grid
- Pass 2: Refine each position based on adjacent cells to select correct junction
- Check connections in all four directions (up, down, left, right)
- Correctly handle T-junctions, corners, and four-way intersections

The new algorithm determines junction characters based on the actual
topology of separators in the grid, not on abstract line segments.
This fixes all cases including:
- Vertical split with horizontal split of one side
- Horizontal split with vertical split of one side
- Complex multi-window layouts

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
- Handle all possible connection patterns explicitly
- Add exhaustive match patterns for Unicode mode
- Improve ASCII mode logic to use correct characters
- Add debug logging for junction detection
- Remove fallback to '+' character in Unicode mode

This should fix the issue where all separators were rendering as '+'
characters instead of proper box-drawing characters.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
Fixed the T-junction rendering issue where intersections between vertical
and horizontal window separators were not being detected properly. The
issue was that vertical lines were being drawn as separate segments with
gaps at horizontal separator positions.

Changes:
- Refactored separator detection to find continuous vertical/horizontal lines
- Vertical separators now span the full height of adjacent windows
- Horizontal separators now span the full width of adjacent windows
- Added comprehensive logging for debugging intersection detection
- This ensures proper T-junction characters (┬, ┴, ├, ┤) are rendered

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
- Removed unused methods: selected_cells, render_main_content,
  render_overlays, render_diagnostics, and render_gutter
- Fixed incorrect method call in render_overlays_in_window
- Fixed clippy warnings:
  - manual_map: simplified Option::map usage
  - empty_line_after_doc_comments: removed empty line
  - assign_op_pattern: use += operator
  - almost_swapped: fixed current_id tracking logic
  - only_used_in_recursion: added allow annotations for false positives

All code now compiles without warnings and passes clippy checks.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
- Marked Phase 1 (Window-Aware Rendering) as COMPLETE
- Marked Phase 2 (Window Borders and Separators) as COMPLETE
- Marked Phase 3 (Window Operations) as COMPLETE
- Updated Phase 4 status (status line complete, dialogs TODO)
- Added details about all implemented features and fixes
- Updated success criteria to reflect completion status
- Listed remaining TODO items for future work

The window splitting functionality is now feature-complete for the
core use cases, with only advanced features like window balancing
and window-aware dialogs remaining.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
- Added missing "-" keybinding for ResizeWindowUp
- Fixed resize logic to return true when successfully adjusting ratios
- Added comprehensive logging to debug resize operations
- Improved comments to clarify resize behavior for each window position

The issue was that the resize functions were returning false after
successfully adjusting the ratio, which prevented the changes from
being applied. Now all resize operations (Ctrl-w <, >, +, -) work
correctly for both horizontal and vertical splits.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
- Improved xy_to_char_idx to properly handle newlines in char count
- Added bounds checking in Buffer::insert to prevent panics
- Added comprehensive logging to trace emoji-related issues
- Better handling of line character counts excluding newlines
- Added test suite for emoji handling scenarios

This should help diagnose and prevent the "char index out of bounds"
panic when working with emoji characters. The logging will help
identify where cursor positions might be getting miscalculated.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
@fcoury fcoury requested a review from Copilot June 17, 2025 16:51
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR implements window splitting functionality in Red editor along with improvements to window rendering and configuration. Key changes include:

  • The addition of the WindowManager and Split tree structure to handle window layouts and operations (splitting, navigation, closing, resizing).
  • Enhancements in the rendering system to support window-aware rendering with proper borders, separators, and cursor positioning.
  • Updates to tests and configuration to support the new window management features.

Reviewed Changes

Copilot reviewed 15 out of 15 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
window-implementation-plan.md Updated planning document outlining window-aware rendering and operations.
tests/test_emoji_handling.rs Added tests for emoji handling with window functionality.
test_windows.txt New test file for verifying window splits.
test_windows.sh Bash script to run window split tests.
test_config.toml New configuration entries for window borders and keybindings.
src/lib.rs Added module for window management.
src/config.rs Added configuration option for ASCII window borders.
src/buffer.rs Updated buffer methods to use character indices, with added error logging and newline handling.
docs/multi-windows-plan.md Extended documentation regarding multi-window support.
default_config.toml Updated commented key bindings for window management.
CLAUDE.md Updated documentation with new window management commands and keybindings.
.claude/settings.local.json Minor configuration update for testing.
Comments suppressed due to low confidence (1)

tests/test_emoji_handling.rs:38

  • [nitpick] Verify that the expected cursor position (8) accurately reflects emoji width across different platforms and environments, as character width for emojis can vary.
    assert_eq!(x, 8); // "💕 hearts" has 8 characters

Comment on lines +639 to +644
// Handle newline - Ropey includes newlines in char count
let line_chars_without_newline = if line_chars > 0 && line.char(line_chars - 1) == '\n' {
line_chars - 1
} else {
line_chars
};
Copy link

Copilot AI Jun 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] Consider extracting the logic for computing the number of characters excluding the newline into a separate helper function for improved readability and maintainability.

Suggested change
// Handle newline - Ropey includes newlines in char count
let line_chars_without_newline = if line_chars > 0 && line.char(line_chars - 1) == '\n' {
line_chars - 1
} else {
line_chars
};
// Compute the number of characters excluding the newline
let line_chars_without_newline = count_chars_excluding_newline(&line);

Copilot uses AI. Check for mistakes.
@fcoury fcoury merged commit 8eab0cd into master Jun 17, 2025
15 checks passed
@fcoury fcoury deleted the multi-windows2 branch June 17, 2025 16:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant