diff options
| author | user <user@clank> | 2026-08-16 01:06:42 +0200 |
|---|---|---|
| committer | user <user@clank> | 2026-08-16 01:06:42 +0200 |
| commit | 3b9c1d987db7dae1db68a8ea304e8227344a1cdb (patch) | |
| tree | b2aa66a61e2111720115442611ca092d261c161c /DESIGN.md | |
| parent | sl0ppty: a reply is never a request (diff) | |
| download | slosh-3b9c1d987db7dae1db68a8ea304e8227344a1cdb.tar.gz slosh-3b9c1d987db7dae1db68a8ea304e8227344a1cdb.tar.xz slosh-3b9c1d987db7dae1db68a8ea304e8227344a1cdb.zip | |
sl0ppty: a pane can set its own shaders
printf '\033]5577;1;shader;chrome;tint color="#ff5fd7" amount="abs(t / 8 % 510 - 255)"\033\\'
The field after `shader` is which rect -- `content` or `chrome` -- and the
rest of the payload is a chain in exactly the syntax a `shaders { }` block
uses, taken verbatim so that `;` can go on separating entries. Empty text
clears that chain. The session answers on the program's stdin, `shader-reply;ok`
or `shader-reply;error;bad amount for tint: ...`, because a prototyping loop
that gets no answer cannot tell a typo from a build without the feature.
`contrib/shader-repl` is the prompt this exists for: type a chain, watch the
pane, and `:paste` prints what you have as a config block. Both ends are the
same parser, so what you arrive at is what you can keep -- verified by
pasting `:paste`'s output into a file, linting it, and checking the frame
comes out the same colour.
**D13 said this was impossible on purpose, and the reasoning stands**: a
program that can restyle the session it happens to be running in is a hazard,
and `cat hostile.txt` should not dim your panes. But *impossible* was the
wrong shape for it -- editing a file, saving, looking and guessing again is
slow enough that shaders go unwritten. So it takes `in_band_shaders true`,
one line of consent, and it is scoped to the pane that asked: its own two
chains, never its neighbour's, never what the config said about anyone else.
There is a test for the neighbour.
Each chain owns the programs its expressions compiled to, and is swapped in
whole, so a chain that turns out not to read leaves the pane looking like it
did rather than half-restyled. Measured: 1,800 replacements of an animated
chain, resident size flat after the first pass.
Also here, because it is the same paint order: the chrome chain now sits
between the config's and policy's, exactly where the content chain does.
Dead code out -- `app_shade_add`/`app_shade_clear`/`app_shade_count` had no
callers and their comment claimed the opposite of what this commit does.
Diffstat (limited to '')
| -rw-r--r-- | DESIGN.md | 23 |
1 files changed, 22 insertions, 1 deletions
@@ -366,7 +366,7 @@ M4 landed: the pi extensions' exact byte patterns are an acceptance test no payload — answer-picker's way of dropping buttons while keeping the status text — and a click report that satisfies the extension's own `CLICK_RE`. -Two protocol details worth keeping in mind, both found by testing: +Three protocol details worth keeping in mind, all found by testing: - **An over-long button id must be rejected, not truncated.** Unescaping a 40-character id into a 33-byte buffer produced a *valid* 32-character id, so @@ -376,6 +376,27 @@ Two protocol details worth keeping in mind, both found by testing: - **BEL terminates an OSC just as ST does**, which matters more than it looks: a trailing `ESC \` inside a double-quoted shell string escapes the quote, so anything scripting this from a shell will reach for BEL. +- **A reply must never re-parse as a request.** Every message the session sends + a program ends its verb in `-reply`, and nothing dispatches one. `hello` used + to answer with the verb `hello`, so a pane that echoed what it was sent — a + shell with echo on, `cat`, a REPL waiting for a line — answered the answer: + measured at 4.3 MB and 165,532 hellos in a second and a half. Fixed as the + rule rather than the instance, because the loop is a property of "a reply that + looks like a request" and the next verb to get an answer would have found it + again. + +**D13, revisited: a program may set its own pane's shader chains**, behind +`in_band_shaders` (off by default). The original reasoning stands — a program +that can restyle the session it is running in is a hazard, and `cat +hostile.txt` must not be able to dim your panes — but *impossible* was the wrong +shape for it: arriving at a colour pass by editing a file, saving, looking and +guessing again is slow enough that shaders go unwritten. So it is possible, it +costs a line of consent, and it is scoped to the pane that asked: its own two +chains, never its neighbour's and never what the config said about everybody +else. The payload is the config's own chain syntax parsed by the same function +(`config_parse_chain`), because a chain that meant one thing typed and another +thing pasted would be worse than not having it. `contrib/shader-repl` is the +prompt this exists for, and `:paste` prints the block to keep. ## Non-goals |
