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 /src/json.c | |
| 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 'src/json.c')
| -rw-r--r-- | src/json.c | 111 |
1 files changed, 111 insertions, 0 deletions
diff --git a/src/json.c b/src/json.c new file mode 100644 index 0000000..efbe120 --- /dev/null +++ b/src/json.c @@ -0,0 +1,111 @@ +#define _GNU_SOURCE +#include "json.h" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +static void reserve(json_t *j, size_t n) { + if (j->len + n <= j->cap) return; + size_t cap = j->cap ? j->cap : 4096; + while (cap < j->len + n) cap *= 2; + j->buf = realloc(j->buf, cap); + j->cap = cap; +} + +static void raw(json_t *j, const char *s, size_t n) { + reserve(j, n + 1); + memcpy(j->buf + j->len, s, n); + j->len += n; + j->buf[j->len] = 0; +} + +static void rawz(json_t *j, const char *s) { raw(j, s, strlen(s)); } + +void json_init(json_t *j) { + memset(j, 0, sizeof *j); + reserve(j, 4096); + j->buf[0] = 0; +} + +void json_free(json_t *j) { + free(j->buf); + memset(j, 0, sizeof *j); +} + +static void sep(json_t *j, const char *key) { + if (j->need_comma) rawz(j, ","); + if (key) { + rawz(j, "\""); + rawz(j, key); + rawz(j, "\":"); + } + j->need_comma = true; +} + +static void escaped(json_t *j, const char *s, size_t len) { + rawz(j, "\""); + for (size_t i = 0; i < len; i++) { + unsigned char c = (unsigned char)s[i]; + switch (c) { + case '"': rawz(j, "\\\""); break; + case '\\': rawz(j, "\\\\"); break; + case '\n': rawz(j, "\\n"); break; + case '\r': rawz(j, "\\r"); break; + case '\t': rawz(j, "\\t"); break; + default: + if (c < 0x20) { + char b[8]; + snprintf(b, sizeof b, "\\u%04x", c); + rawz(j, b); + } else { + raw(j, (const char *)&c, 1); /* UTF-8 passes through */ + } + } + } + rawz(j, "\""); +} + +void json_obj_open(json_t *j, const char *key) { + sep(j, key); + rawz(j, "{"); + j->need_comma = false; +} + +void json_obj_close(json_t *j) { + rawz(j, "}"); + j->need_comma = true; +} + +void json_arr_open(json_t *j, const char *key) { + sep(j, key); + rawz(j, "["); + j->need_comma = false; +} + +void json_arr_close(json_t *j) { + rawz(j, "]"); + j->need_comma = true; +} + +void json_str(json_t *j, const char *key, const char *val, size_t len) { + sep(j, key); + escaped(j, val, len); +} + +void json_int(json_t *j, const char *key, long long val) { + sep(j, key); + char b[32]; + snprintf(b, sizeof b, "%lld", val); + rawz(j, b); +} + +void json_bool(json_t *j, const char *key, bool val) { + sep(j, key); + rawz(j, val ? "true" : "false"); +} + +void json_null(json_t *j, const char *key) { + sep(j, key); + rawz(j, "null"); +} |
