Skip to content

[Architecture] oclite: Scroll region layout with fixed bottom panel #72

@randomm

Description

@randomm

Description

Implement ANSI scroll region architecture for oclite — scrollable conversation area with fixed bottom panel.

Problem

After removing alt screen buffer (#66), oclite writes everything append-only to the main terminal buffer. This means:

  • ❌ Cannot rewrite tool status lines once scrolled
  • ❌ Cannot have a persistent status bar
  • ❌ Cannot show live metrics during streaming
  • ❌ Cannot have a fixed input area

Solution: ANSI Scroll Regions

Use \x1b[{top};{bottom}r to define a scroll region that covers most of the terminal, with 2-3 fixed lines at the bottom.

Layout:

┌─────────────────────────────────────┐
│ Scrollable conversation area        │ ← Scroll region (rows 1 to N-3)
│ User messages, agent responses      │
│ Tool output, markdown text          │
│ ...scrolls naturally...             │
│                                     │
├─────────────────────────────────────┤
│ ◆ Thinking · 5s · 3/5 tools        │ ← Fixed status line (row N-2)
│ project-manager ❯ █                │ ← Fixed input line (row N-1)
│ Esc cancel · Shift+Tab agents      │ ← Fixed hint bar (row N)
└─────────────────────────────────────┘

Requirements

Scroll Region Setup

  • On startup: query terminal size, set scroll region \x1b[1;{rows-3}r
  • Handle SIGWINCH (terminal resize) — recalculate and reset scroll region
  • On cleanup: reset scroll region to full terminal \x1b[r

Fixed Bottom Panel (3 lines)

  • Status line: During streaming shows spinner + elapsed time + tool count + token count. During idle shows nothing or session info.
  • Input line: Prompt + user input (project-manager ❯ █)
  • Hint bar: Context-sensitive keyboard shortcuts (Esc cancel · Shift+Tab agents · /help)

Writing to Scroll Region

  • All conversation output (text, tool display, errors) writes to scroll region
  • Scroll region scrolls naturally — old content preserved in scroll buffer
  • New content appends at bottom of scroll region, pushing old content up

Writing to Fixed Panel

  • Use \x1b[s (save cursor) before updating fixed lines
  • Move to fixed line with \x1b[{row};1H (absolute position)
  • Write content + clear to end of line
  • Use \x1b[u (restore cursor) to return to scroll region
  • Update fixed panel without disturbing scroll region content

Terminal Resize Handling

  • Listen for SIGWINCH signal
  • Recalculate scroll region boundaries
  • Redraw fixed bottom panel
  • Preserve scroll position in conversation area

Implementation Plan

  1. Create src/cli/lite/layout.ts — scroll region manager
  2. Modify index.ts — use layout manager for all writes
  3. Modify spinner.ts — render in status line instead of scroll region
  4. Modify bottombar.ts — render in fixed input/hint lines

Depends On

  • None (foundational)

Blocks

Technical Reference

  • ANSI scroll region: \x1b[{top};{bottom}r (DEC origin mode)
  • Terminal size: process.stdout.rows, process.stdout.columns
  • Resize signal: process.on('SIGWINCH', handler)
  • Save/restore cursor: \x1b[s / \x1b[u
  • Absolute position: \x1b[{row};{col}H

Files

  • New: packages/opencode/src/cli/lite/layout.ts
  • Modified: packages/opencode/src/cli/lite/index.ts
  • Modified: packages/opencode/src/cli/lite/spinner.ts
  • Modified: packages/opencode/src/cli/lite/bottombar.ts

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions