Architecture¶
src/ is flat, and each file holds one concern. The split exists so the pure
logic — everything that turns data into data — can be tested without a
terminal, while the code that actually talks to the OS stays small enough to
audit. See Compatibility for why that boundary is drawn
where it is.
The layers¶
| Layer | Files | OS access |
|---|---|---|
| Conditions | conditions.lisp |
none |
| Utilities and codecs | clamp.lisp, string-empty.lisp, utf8.lisp |
none |
| Character width | char-width.lisp, char-width-data.lisp |
none |
| Text layout | text-layout.lisp |
none |
| Color, widgets, geometry | color.lisp, format.lisp, rect.lisp |
none |
| ANSI sequences | ansi.lisp, ansi-control.lisp, ansi-osc.lisp, sixel.lisp |
none |
| Input decoding | key-tables.lisp, keys.lisp, keys-decode*.lisp, input-state.lisp, input-decode*.lisp, mouse.lisp |
none |
| Screen and cells | cell.lisp, screen.lisp, screen-regions.lisp, screen-text.lisp, box.lisp, cursor.lisp |
none |
| Rendering | render-style.lisp, sgr-parse.lisp, render-commands.lisp, render-diff.lisp, render.lisp, renderer.lisp |
none |
| Raw mode and size | raw-mode.lisp, raw-mode-sbcl.lisp, terminal-size.lisp |
SBCL-specific |
| Session lifecycle | session.lisp |
SBCL-specific |
| PTY | pty.lisp, pty-fd.lisp |
SBCL-specific |
Only the last three rows touch the operating system. Everything above them is a function from values to values, which is why the test suite can assert on exact escape-sequence output and decoded event shapes without allocating a terminal.
Notable boundaries¶
conditions.lisp defines the public condition types and the %assert
validation macro that the rest of the library signals through, so an invalid
argument produces a typed condition with the offending value rather than a
generic error. See Conditions.
char-width.lisp expresses width as relations over the East Asian and
combining-mark data tables in char-width-data.lisp, which keeps the tables
reviewable as data and the policy (including the East Asian ambiguous-width
switch) reviewable as code. See Text Layout.
The ANSI layer is split three ways because the sequence families have
different shapes: ansi.lisp builds the core SGR and cursor strings,
ansi-control.lisp the scroll/mode control sequences, and ansi-osc.lisp
the OSC string-terminated ones. See ANSI Helpers.
Rendering separates the decision from the emission:
render-commands.lisp and render-diff.lisp decide which cells changed and
what to do about it, and render-style.lisp turns a normalized style into
bytes. That is what lets t/properties-test.lisp assert the property that matters
— a diff's visible result matches a full repaint, and is never longer than
one — instead of pinning a byte-for-byte transcript. See
Screen and Rendering.
pty.lisp wraps the SBCL process and stream; pty-fd.lisp sits alongside it
as a byte-transparent layer over the bare master file descriptor, for callers
running their own select(2) loop over many descriptors. See PTY.
See also¶
- Feature Audit — what exists, what was deferred, and why
- API Reference — every exported symbol, by subsystem
- Quality Gates — the file-organization policy this split follows