diff options
| author | sl0p <sl0p@sl0p.foo> | 2026-08-13 22:26:02 +0200 |
|---|---|---|
| committer | sl0p <sl0p@sl0p.foo> | 2026-08-13 22:26:02 +0200 |
| commit | 34fcd16e59e3087e9bf84ebce4e05d439eea9198 (patch) | |
| tree | e07b9dfc235e3a0b67047d59a9c521c6e98a28ae /DESIGN.md | |
| parent | sl0ptty: input decoder + per-pane re-encode (diff) | |
| download | slosh-34fcd16e59e3087e9bf84ebce4e05d439eea9198.tar.gz slosh-34fcd16e59e3087e9bf84ebce4e05d439eea9198.tar.xz slosh-34fcd16e59e3087e9bf84ebce4e05d439eea9198.zip | |
sl0ptty: M0.5 — the headless driver and the harness everything rests on
--script runs the whole compositor with no tty: commands in (send, raw,
settle, resize, snapshot, alive), composited screen out as JSON — rows of
text, style runs, cursor, and the hit list.
Styles are emitted as runs rather than per-cell objects, because a test wants
'columns 0..5 of row 0 are bold red', not 1920 objects.
The hit list is empty until M1 paints something clickable, but the type, the
JSON, and hit_test() exist now: one geometry, established before there is
anything to get wrong.
Also fixes two host-policy defaults found by the cursor never appearing.
lib-vt is a VT library, not a terminal, so it starts with DECTCEM (mode 25)
off and grapheme clustering (2027) off. Both are now set via MODE_DEFAULT, so
they survive RIS.
tests/harness.py + tests/test_screen.py: 19 checks over composition, styling,
wide chars/clusters, scrollback, resize and the full input round trip —
including the kitty/legacy re-encoding matrix, which no longer needs a pty.
make test is now 2.4s for 59 checks; make test-live keeps the four that
genuinely need a tty.
Diffstat (limited to '')
| -rw-r--r-- | DESIGN.md | 35 |
1 files changed, 28 insertions, 7 deletions
@@ -42,6 +42,21 @@ it is *not* a free OSC 5577 hook. Three consequences, all cheap: 3. Worth an upstream issue: a generic "unhandled OSC" callback. Mitchell's library, our use case, small patch. +### lib-vt assumes nothing a host terminal would + +It is a VT *library*, not a terminal, so host policy is ours to set. Found by +the cursor never appearing: + +- **DECTCEM (mode 25) starts off.** The cursor is invisible until the host says + otherwise. We set it via `MODE_DEFAULT`, which updates the current value *and* + the one restored by RIS, so a program that resets the terminal does not lose + its cursor. +- **Grapheme clustering (mode 2027) starts off**, so flags and ZWJ emoji occupy + several cells. We default it on, matching the outer terminal we assume (D11). + +Both are set in `pane_new()`. Expect more of these; the rule is that anything a +terminal emulator would decide is not decided for us. + ### What we own 1. **Input decoding.** lib-vt encodes events *out* to a pane; nothing decodes @@ -83,13 +98,19 @@ Drawing and hit-testing cannot disagree, because there is only one of them. From the sl0ppi roadmap, four separate times: *unit tests were necessary and insufficient.* Every real bug was found by reading the screen. -> **`sl0ptty --headless` runs the entire compositor with no tty, and dumps the -> composited screen — text, styles, cursor, hit-list — as JSON on the control -> socket.** +> **`sl0ptty --script` runs the entire compositor with no tty: commands in +> (`send`, `raw`, `settle`, `resize`, `snapshot`), and the composited screen out +> as JSON — rows of text, style runs, cursor, hit-list.** + +Tests are "drive these events, assert this screen". `make test` is **2.4s for +59 checks**; `make test-live` keeps the handful that genuinely need a tty (raw +mode, the diff emitter, SIGWINCH, the prefix key). The command vocabulary is +deliberately the one M2's control socket will speak, so the harness moves over +unchanged. -Tests are "drive these events, assert this screen", deterministic and -sub-second. This lands before splits do, because everything after it rests on -it. +Styles are emitted as **runs**, not per-cell objects: a test wants to say +"columns 0..5 of row 0 are bold red", and 1920 cell objects per snapshot is +unreadable. ## Decisions @@ -156,7 +177,7 @@ Frame pacing: pty reads are coalesced and painted on a timerfd at a cap - **M0.25** — input decoder + per-pane re-encode ✅ (pulled forward: retrofitting it under a layout tree would have been worse, and it is the load-bearing half of the mouse work in M4) -- **M0.5** — headless mode + screen-assert harness (seeded: `--headless`) +- **M0.5** — headless driver + screen-assert harness ✅ - **M1** — layout tree, splits, focus, frames (gap/padding/title alignment) - **M2** — server/client split, detach/reattach, control socket - **M3** — tabs, `purpose=`, JSON control API |
