Files
cl-tty/docs/ROADMAP.org
2026-05-12 22:22:06 +00:00

247 lines
10 KiB
Org Mode

#+TITLE: cl-tty Roadmap
#+STARTUP: content
#+FILETAGS: :docs:roadmap:cl-tty:
* The Roadmap
Each phase is one minor release. Phases ship in dependency order — each depends on
the components from prior phases.
** v0.0.1: Backend Protocol
DONE. Two backends implementing a common protocol:
- =modern-backend= — raw escape sequences, truecolor 24-bit, OSC 8 hyperlinks,
DECICM sync, SGR mouse, kitty keyboard protocol, bold/italic/underline,
box-drawing chars (rounded/single/double)
- =simple-backend= — ASCII art only, no color, universal compatibility for
SSH/piped output
~180 lines total. Dependencies: None (pure CL, no FFI).
*** Backend protocol generic functions:
- =initialize-backend=, =shutdown-backend=, =backend-size=, =backend-write=, =backend-clear=
- =draw-rect=, =draw-text=, =draw-border=, =draw-ellipsis=, =draw-link=
- =cursor-move=, =cursor-hide=, =cursor-show=, =cursor-style=
- =begin-sync=, =end-sync= (DECICM)
- =read-event=, =enable-mouse=, =enable-bracketed-paste=, =set-keyboard-mode=
- =capable-p= — query feature support
** Layout Engine (pure CL)
DONE. Pure Common Lisp Flexbox layout engine. No Yoga, no CFFI, no external
dependencies. A two-pass constraint solver handling direction, wrap,
grow/shrink/gap padding/margin, absolute positioning.
~190 lines. Macros: =vbox=, =hbox=, =spacer=.
** v0.2.0: Box, Text, Span, Dirty Tracking
DONE. The first two renderable types. Box draws borders and backgrounds.
Text renders strings with color, word-wrap, and inline style spans.
- =Box= with border styles (:single, :double, :rounded), title, background
- =Text= with word-wrap (:none, :word), fg/bg colors
- =Span= — inline text segment with attributes (:bold, :italic, etc.)
- =Dirty-mixin= — marks components and ancestors for re-render
- =Theme= — semantic color tokens, presets (default, nord, catppuccin, etc.)
- =render= generic function dispatched on component type
** v0.5.0: Text Input + Keybinding System
DONE. Text input widgets with readline-style keybindings.
- =TextInput= — single-line input with cursor, placeholder, max-length, on-submit
- =Textarea= — multi-line input with undo/redo (100-deep stack), cursor nav,
selection, on-submit
- =Keymap= — layered keybinding system with =defkeymap= macro
- Event handling: key-event, mouse-event structs, raw-byte reader
** v0.6.0: ScrollBox + TabBar
DONE. Container components.
- =ScrollBox= — scrollable viewport with vertical/horizontal scrollbars,
scroll-by, clamp, sticky-scroll mode
- =TabBar= — horizontal tab navigation with next/prev, active tab tracking
** v0.7.0: Select — Dropdown + Fuzzy Filter
DONE. A selection list component with keyboard navigation, category headers,
and fuzzy text matching.
** v0.8.0: Markdown + Code + Diff Rendering
DONE. Content rendering for agent responses and file diffs.
- Markdown parser: headings, bold/italic/code, links, code blocks,
blockquotes, lists, thematic breaks
- Syntax highlighting: regex-based for Lisp keywords, comments, strings
- Diff rendering: added/removed/context lines with colored backgrounds
- ANSI rendering via raw escape sequences
** v0.9.0: Dialog System + Toast
DONE. Modal overlays and transient notifications.
- =Dialog= — centered modal with backdrop dimming, size variants
- =push-dialog= / =pop-dialog= — stack-based dialog management
- =alert-dialog=, =confirm-dialog=, =select-dialog=, =prompt-dialog=
- =Toast= — transient notification with variants (:info/:success/:warning/:error),
auto-dismiss, top-right positioning
** v0.10.0: Mouse Support
DONE (minimal). Mouse event handling via mixin class.
- =mouse-mixin= — event handler slots (:on-mouse-down/up/move/scroll)
- =handle-mouse-event= — dispatch to component handlers
- =hit-test= — find deepest component at (x, y)
- =selection= struct and =copy-to-clipboard=
** v0.11.0: Plugin / Slot System
DONE. Extensible named slots for registering content into extensible positions.
- =defslot=, =slot-render=, =clear-slot=, =list-slots=
- Slot modes planned but not implemented
** v0.12.0: Terminal Capability Detection
DONE. Auto-detect terminal capabilities at startup and return the
appropriate backend.
- Check if stdout is a TTY (if not -> simple-backend)
- =detect-backend= -> returns =modern-backend= or =simple-backend=
- Send DA1 query (~ESC[c~), 100ms timeout
- Send DA3 (~ESC[?c~) for kitty/wezterm identification
- Query DECRPM (~ESC[?2026$p~) for DECICM sync support
- Check =COLORTERM= env var for truecolor support
- Cache detection result for subsequent instant calls
- Add =detect-backend= to backend package API
- ~100 lines
** v0.13.0: Rendering Pipeline
DONE. A pure CL rendering pipeline — framebuffer diffing for incremental
output, scissor clipping, and render-command dispatching.
- =*framebuffer*= — 2D array of (char, fg, bg, attrs) tuples
- =flush-framebuffer= — compares current to previous, writes only changed cells
- =with-scissor= — clips all render operations to a rectangle
- Component =render= methods produce render commands, not direct backend calls
- =diff-output= framework for minimum-escape optimization
- ~250 lines
** v0.14.0: Mouse Improvements
DONE. Enhance mouse support with drag-to-select and link clicking.
- Text selection via mouse drag (highlight region between drag start/end)
- Click on OSC 8 link: extract URL, open via xdg-open
- Copy-to-clipboard via xclip/wl-copy/pbcopy
- ~80 lines
** v0.15.0: Bug fixes, demo rewrite, verification, tangle tooling
DONE. Demo rewrite with interactive tabs, critical bug fixes, and
quality-of-life infrastructure.
- Demo (demo.lisp): full rewrite with Console, Components, Layout,
Events tabs — tab navigation, scrollbox with hot-reload, layout
visualization with live row/column swapping, event logging panel
- Demo uses backend-size instead of hardcoded 80x24
- Box title rendering: modern and simple backends now render titles
with title and title-align parameters
- Cursor rendering: text-input cursor renders as solid block at
cursor position
- Arrow key fix: demo arrow keys on Widgets tab no longer steal
focus from tab bar
- read-raw-byte buffer fix: sb-sys:with-pinned-objects + vector-sap
for proper sb-posix:read buffer (SBCL type error with plain arrays)
- EOF detection: read-raw-byte returns (values nil :eof) on stdin
EOF, not nil — prevents 100% CPU busy-spin on pipes
- Escape key: 50ms timeout in read-escape-sequence to disambiguate
lone Escape from escape-prefixed sequences
- confirm-dialog: fix option plist comparison (was comparing
objects, not keys)
- mouse-event: button slot type changed from keyword to (or keyword
null)
- tangle tooling: replace Emacs org-babel-tangle with pure-Python
script (scripts/tangle.py, later moved to Hermes skill)
- Verification: verify-api.py (API smoke tests), verify-demo-pty.py
(PTY-based demo verification — 17 checks)
- tangle.py fix: write-once-then-append logic (was always-appending,
triplicating files)
- Org/Lisp sync: verified — 483+57+17 checks pass on fresh tangle
- Project restructure: move backend/ and layout/ into src/
- .gitignore for compiled fasl files
- ~500 lines of changes across the codebase
|- Version: v1.0.0 (current)
Known gaps from earlier phases:
- (none — all protocol spec items implemented)
** v1.0.0: Release
DONE. All phases integrated and tested. Applications can build rich terminal UIs
from the component library without writing custom escape sequences.
Checklist:
- [X] README.org with overview, architecture, component table, quick start
- [X] demo.lisp — working interactive example
- [X] Full test suite: 454 checks, 100% passing across 14 suites
- [X] ASDF system with test-op
- [X] LICENSE file (GPL 3.0)
- [X] Literate org files for all modules
- [X] Terminal capability detection (v0.12.0)
- [X] Rendering pipeline (v0.13.0)
- [X] Mouse improvements (v0.14.0)
- [X] Org/Lisp sync verified (first tangle produces no regressions)
- [X] Suspend/resume-backend protocol methods (ARCHITECTURE.org spec)
- [X] Slot modes (defslot :mode parameter)
** v1.1.0: SGR Mouse Event Parsing
DONE. ~read-event~ now decodes SGR extended mouse sequences
(~ESC[<Cb;Cx;CyM/m~) into structured ~mouse-event~ structs, where previously
they fell through as ~:unknown~ key events and printed as control characters.
What was added:
- ~%read-digits~ — reads multi-digit numeric parameters from raw terminal
bytes, handling arbitrary-length values (e.g. coordinates > 99)
- ~%parse-sgr-mouse~ — full SGR mouse decoder: button code → keyword
(~:left~, ~:middle~, ~:right~, ~:scroll-up~, ~:scroll-down~, ~:drag~),
press/release detection, 1-based → 0-based coordinate conversion
- ~parse-csi-sequence~ detects the ~~<~~ marker byte (0x3C) and delegates
to ~%parse-sgr-mouse~ instead of treating the sequence as keyboard input
The mouse enable/disable sequences were already sent by
~initialize-backend~/~shutdown-backend~ (lines 126-128, 139-141 of
~modern.lisp~). The parsing gap was the only missing piece.
Test coverage: 461 unit tests + 32 integration tests, all at 100%.
Org source: ~org/text-input.org~ (tangled to ~src/components/input.lisp~).
** Feature Reference
| Phase | Component | Lines | Release | Status |
|-------+----------------------------------------+--------+---------|--------|
| 0 | Backend protocol (simple + modern) | ~180 | v0.0.1 | DONE |
| - | Layout engine (pure CL flexbox) | ~190 | - | DONE |
| 1 | Renderables (Box, Text) + dirty | ~300 | v0.2.0 | DONE |
| 2 | Theme engine (tokens, presets) | ~120 | v0.4.0 | DONE |
| 3 | TextInput + Textarea + keybindings | ~500 | v0.5.0 | DONE |
| 4 | ScrollBox + TabBar | ~200 | v0.6.0 | DONE |
| 5 | Select (dropdown + fuzzy filter) | ~150 | v0.7.0 | DONE |
| 6 | Markdown + Code + Diff | ~400 | v0.8.0 | DONE |
| 7 | Dialog system + Toast | ~220 | v0.9.0 | DONE |
| 8 | Mouse support | ~80 | v0.10.0 | DONE |
| 9 | Plugin / slot system | ~50 | v0.11.0 | DONE |
| 10 | Terminal capability detection | ~100 | v0.12.0 | DONE |
| 11 | Rendering pipeline (framebuffer diff) | ~250 | v0.13.0 | DONE |
| 12 | Mouse improvements (selection, links) | ~80 | v0.14.0 | DONE |
| 13 | Bug fixes, demo rewrite, verification | ~500 | v0.15.0 | DONE |
|-------+----------------------------------------+--------+---------|--------|
| | Total | ~5760 | | |