aboutsummaryrefslogtreecommitdiffstats
path: root/src/sl0ptty.h
diff options
context:
space:
mode:
authorsl0p <sl0p@sl0p.foo>2026-08-13 22:26:02 +0200
committersl0p <sl0p@sl0p.foo>2026-08-13 22:26:02 +0200
commit34fcd16e59e3087e9bf84ebce4e05d439eea9198 (patch)
treee07b9dfc235e3a0b67047d59a9c521c6e98a28ae /src/sl0ptty.h
parentsl0ptty: input decoder + per-pane re-encode (diff)
downloadslosh-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 'src/sl0ptty.h')
-rw-r--r--src/sl0ptty.h22
1 files changed, 22 insertions, 0 deletions
diff --git a/src/sl0ptty.h b/src/sl0ptty.h
index c71ec9e..962de66 100644
--- a/src/sl0ptty.h
+++ b/src/sl0ptty.h
@@ -38,11 +38,31 @@ typedef struct {
color_t fg, bg;
} cell_t;
+/* One geometry (DESIGN.md): every painted interactive element records its rect
+ * here as it is painted, and a click is a lookup. Drawing and hit-testing
+ * cannot disagree because there is only one of them. */
+typedef struct {
+ uint16_t x, y, w, h;
+ char action[48];
+} hit_t;
+
+typedef struct {
+ hit_t *items;
+ size_t len, cap;
+} hitlist_t;
+
+void hit_reset(hitlist_t *hl);
+void hit_add(hitlist_t *hl, uint16_t x, uint16_t y, uint16_t w, uint16_t h,
+ const char *action);
+/* The action at a point, or NULL. Later entries win: painted last is on top. */
+const char *hit_test(const hitlist_t *hl, uint16_t x, uint16_t y);
+
typedef struct {
uint16_t cols, rows;
cell_t *cur; /* what we want on screen */
cell_t *prev; /* what the terminal last received */
bool force_full;
+ hitlist_t hits;
/* where the real cursor goes after a flush */
bool cursor_visible;
@@ -64,6 +84,8 @@ void screen_put_utf8(screen_t *s, uint16_t x, uint16_t y, const char *txt,
void screen_flush(screen_t *s, int fd);
/* Plain-text dump of the composited screen; caller frees. (headless tests) */
char *screen_dump(screen_t *s);
+/* The same screen as JSON: rows of text, style runs, cursor, hit-list. */
+char *screen_dump_json(screen_t *s);
/* ---- pty --------------------------------------------------------------- */