menios icon indicating copy to clipboard operation
menios copied to clipboard

Terminal scrollback with mouse wheel support

Open pbalduino opened this issue 3 months ago • 0 comments

Goal

Enable scrolling through terminal history using the mouse wheel, providing a more intuitive way to review command output and logs.

Context

After mouse support is implemented (#143), the terminal should support scrolling through the scrollback buffer using the mouse wheel. This is a standard feature in modern terminals (xterm, GNOME Terminal, Windows Terminal, etc.) that significantly improves usability when reviewing long outputs, build logs, or debugging information.

Current State

Terminal Capabilities

  • ✅ VGA text mode rendering
  • ✅ ANSI escape sequence support
  • ✅ Line editing and command history
  • ❌ Scrollback buffer (limited or none)
  • ❌ Mouse wheel event handling

Mouse Support Status

  • #143 - Mouse driver (PS/2 or USB HID) - NOT YET IMPLEMENTED
  • #32 - Input subsystem (keyboard support exists)

Proposed Implementation

Phase 1: Mouse Wheel Event Handling (2-3 days)

Prerequisites: #143 (Mouse driver) must be complete

PS/2 Mouse Wheel Detection

// Mouse wheel events come as button 4 (scroll up) and button 5 (scroll down)
// Or as Z-axis movement in IntelliMouse protocol

#define MOUSE_SCROLL_UP    4
#define MOUSE_SCROLL_DOWN  5

struct mouse_event {
    int dx, dy;      // Movement delta
    int dz;          // Wheel delta (IntelliMouse)
    uint8_t buttons; // Button state
};

Event Delivery to Terminal

  • Mouse events delivered to /dev/mouse0 or /dev/input/mice
  • Terminal reads mouse events when in focus
  • Distinguish between wheel events and button clicks

Phase 2: Scrollback Buffer Implementation (4-5 days)

Buffer Design

#define SCROLLBACK_LINES 1000  // Configurable

struct terminal_scrollback {
    char **lines;              // Circular buffer of line pointers
    size_t capacity;           // Total lines (default 1000)
    size_t count;              // Current number of lines
    size_t head;               // Newest line index
    size_t tail;               // Oldest line index
    size_t view_offset;        // Current scroll position (0 = bottom)
};

Line Storage

  • Allocate lines dynamically as terminal output is generated
  • Oldest lines evicted when buffer full (circular buffer behavior)
  • Store line attributes (color, bold, etc.) alongside text
  • Memory footprint: ~1000 lines × 80 chars = ~80 KB per terminal

Integration with VGA Renderer

// When view_offset > 0, render from scrollback instead of current screen
void terminal_render(struct terminal *term) {
    if (term->scrollback.view_offset > 0) {
        // Render from scrollback buffer
        render_scrollback(term);
    } else {
        // Render current screen (normal operation)
        render_current_screen(term);
    }
}

Phase 3: Mouse Wheel Scrolling Logic (2-3 days)

Scroll Handling

void terminal_handle_mouse_event(struct terminal *term, struct mouse_event *evt) {
    if (evt->dz > 0 || (evt->buttons & MOUSE_SCROLL_UP)) {
        // Scroll up (toward history)
        terminal_scroll_up(term, SCROLL_LINES_PER_TICK);
    } else if (evt->dz < 0 || (evt->buttons & MOUSE_SCROLL_DOWN)) {
        // Scroll down (toward present)
        terminal_scroll_down(term, SCROLL_LINES_PER_TICK);
    }
}

#define SCROLL_LINES_PER_TICK 3  // Lines per wheel notch

Scroll Constraints

  • Prevent scrolling past oldest line (top of buffer)
  • Auto-return to bottom on new output (configurable)
  • Reset scroll position on keyboard input (configurable)

Phase 4: Visual Indicators (1-2 days)

Scroll Position Indicator

[SCROLLBACK: -234 lines]  ← Top-right corner when scrolled
[END]                     ← When at bottom (normal mode)

Scrollbar (Optional)

  • Vertical scrollbar on right edge
  • Position indicator showing current view relative to total history
  • Similar to tmux or screen scrollback

Phase 5: Keyboard Shortcuts (1-2 days)

In addition to mouse wheel, provide keyboard alternatives:

  • Shift+Page Up: Scroll up one page
  • Shift+Page Down: Scroll down one page
  • Shift+Home: Jump to oldest line
  • Shift+End: Jump to bottom (current output)
  • Shift+Arrow Up/Down: Scroll line by line

Phase 6: Configuration and Polish (1-2 days)

Configurable Options

struct terminal_config {
    size_t scrollback_lines;       // Default 1000
    size_t scroll_lines_per_tick;  // Default 3
    bool auto_scroll_on_output;    // Default true
    bool reset_scroll_on_input;    // Default true
};

/dev/tty ioctl Extensions

#define TIOCGSCROLLBACK  _IOR('T', 128, size_t)  // Get scrollback size
#define TIOCSSCROLLBACK  _IOW('T', 129, size_t)  // Set scrollback size
#define TIOCSCROLLPOS    _IOR('T', 130, size_t)  // Get scroll position

Implementation Phases Summary

  1. Phase 1: Mouse wheel event handling (2-3 days) - Depends on #143
  2. Phase 2: Scrollback buffer (4-5 days)
  3. Phase 3: Scroll logic (2-3 days)
  4. Phase 4: Visual indicators (1-2 days)
  5. Phase 5: Keyboard shortcuts (1-2 days)
  6. Phase 6: Configuration (1-2 days)

Total Effort: 2-3 weeks (12-17 days)

Definition of Done

  • [ ] Mouse driver (#143) implemented and working
  • [ ] Mouse wheel events detected and delivered to terminal
  • [ ] Scrollback buffer stores terminal history (configurable size)
  • [ ] Mouse wheel scrolls up/down through history
  • [ ] Visual indicator shows scroll position
  • [ ] Keyboard shortcuts provide alternative to mouse wheel
  • [ ] Auto-scroll to bottom on new output
  • [ ] Reset scroll on keyboard input
  • [ ] Configuration options exposed via ioctl
  • [ ] Tested with long outputs (build logs, file listings)
  • [ ] Documented in docs/design/terminal.md

Dependencies

Critical Blockers

  • #143 - Mouse driver (PS/2 or USB HID) - MUST IMPLEMENT FIRST

Foundation (Complete)

  • #32 - Input subsystem (keyboard support exists)
  • #8 - ANSI and scrolling console
  • #136 - Device filesystem (/dev/mouse0)
  • #96 - File descriptor management

Related (Optional)

  • #336 - termios support (for terminal control)
  • #201 - Mouse selection (text selection with mouse)

Use Cases

1. Reviewing Build Output

$ make build
# Lots of compiler output...
# Scroll up with mouse wheel to review warnings
# Auto-scrolls back to bottom when build finishes

2. Debugging Kernel Logs

$ dmesg | tail -100
# Scroll through boot messages
# Identify where driver failed to load

3. Long File Listings

$ ls -la /HOME
# Hundreds of files
# Scroll up to see files at the top

4. Interactive Programs

  • Doom startup messages
  • Test suite output
  • Git log review

Technical Considerations

Memory Management

  • Default buffer: 1000 lines × 80 chars = ~80 KB
  • Worst case: 10000 lines × 160 chars = ~1.6 MB
  • Use circular buffer to avoid reallocation
  • Free old lines when buffer wraps

Rendering Performance

  • Only re-render when scroll position changes
  • Use dirty flag to avoid unnecessary redraws
  • Consider double-buffering for smooth scrolling

Concurrency

  • Lock scrollback buffer during updates
  • Coordinate between output thread and input thread
  • Prevent race conditions on view_offset

Edge Cases

  • Handle terminal resize (reflow lines?)
  • Clear scrollback on clear command (optional)
  • Preserve scrollback across shell restarts?
  • Multiple terminals with independent scrollback

Example Terminal Workflow

User types: make build
Output: [100 lines of compiler output]

User scrolls mouse wheel up:
  → view_offset increases
  → Render shows lines -50 to -1 (50 lines back)
  → Indicator shows "[SCROLLBACK: -50 lines]"

User scrolls more:
  → view_offset = 100
  → Shows oldest lines in buffer
  → Indicator shows "[SCROLLBACK: -100 lines (TOP)]"

User presses a key:
  → view_offset resets to 0
  → Returns to current output
  → Indicator shows "[END]"

Testing Strategy

Unit Tests

  • Scrollback buffer insertion/eviction
  • Circular buffer wraparound
  • Line retrieval at various offsets

Integration Tests

  • Mouse wheel events → scroll position changes
  • Keyboard shortcuts work correctly
  • Auto-scroll on output
  • Reset scroll on input

Manual Testing

# Generate long output
$ seq 1 1000

# Scroll up with mouse wheel
# Verify lines 1-50 visible
# Scroll down to bottom
# Type command → auto-returns to bottom

# Test keyboard shortcuts
# Shift+PgUp → scrolls up
# Shift+Home → jumps to top
# Shift+End → jumps to bottom

Timeline

Estimated effort: 2-3 weeks (12-17 days)
Blocked by: #143 (Mouse driver implementation)

Priority

Low - Nice-to-have quality-of-life feature, not critical for core functionality

User Experience Benefits

Before (Current)

  • Output scrolls off screen permanently
  • Must re-run commands to see previous output
  • No way to review build logs
  • Less productive debugging workflow

After (With Scrollback)

  • Scroll back through history with mouse wheel
  • Review command output at leisure
  • Debug issues by examining full logs
  • Professional terminal experience matching modern standards

References

  • xterm scrollback implementation
  • GNOME Terminal scrollback
  • tmux copy mode and scrollback
  • Windows Terminal scrollback buffer
  • Linux VT scrollback (Shift+Page Up/Down)

Related Issues

  • #143 - Mouse driver (CRITICAL DEPENDENCY)
  • #32 - Input subsystem ✅
  • #201 - Mouse selection (complementary feature)
  • #336 - termios support (terminal control)
  • #8 - ANSI and scrolling console ✅

Status: Blocked by #143 (Mouse driver)
Priority: Low (nice-to-have UX improvement)
Complexity: Medium (2-3 weeks with mouse driver complete)

pbalduino avatar Oct 30 '25 02:10 pbalduino