| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
sl0p + pty was error-prone to type and the zero made it worse; slosh
(slop + sh) is one syllable, impossible to typo, and slosh.foo is ours.
Mechanical rename everywhere it appears: binary, env vars (SLOSH,
SLOSH_SESSION, SLOSH_BIN, SLOSH_CONFIG), socket dir (/tmp/slosh-<uid>,
$XDG_RUNTIME_DIR/slosh), config path (~/.config/slosh), header guards,
src/sl0ppty.h -> src/slosh.h, contrib/sl0ppty-dev -> contrib/slosh-dev,
the driving-slosh skill, docs and tests. The sl0ppi fork references and
the sl0p theme stay: one is history, the other is the brand.
The rename surfaced a latent bug in test_osc5577: the hello-reply
answer always appeared on screen twice (ECHOCTL echo plus cat -v), but
a seven-character implementation name happened to wrap the second copy
across the 60-column boundary, so counting substrings in wrapped text
found one and passed for the wrong reason. A five-character name moved
the wrap and exposed it. The loop guard itself is correct -- with echo
off before the request there is exactly one reply -- so the test now
counts on de-wrapped text and tolerates the pane's own echo.
|
|
|
Adding an effect meant editing shader.c and rebuilding, which is fine for us
and useless to anyone else. Now any `*.so` in the shader directory that
exports a plugin table is loaded at startup, and what it declares is named in
the config exactly like a built-in -- same syntax, same three parameters,
same pass. Default location is a `shaders` directory beside the config file,
so dropping the .so next to config.kdl is the whole installation.
The interesting part is what a plugin can see, which is one header.
shader_abi.h holds cell_t, color_t, shade_ctx_t, shader_t and nothing else:
no libghostty-vt, no pty, no layout, no session. A shader is therefore
unable to reach anything but the cell it was handed, not by rule but because
nothing else is declared where it can find it. cell_t and color_t moved
there from sl0ppty.h for the same reason -- that is the one place they are a
contract with code compiled outside this tree rather than an internal type.
Loading is deliberately narrow:
- refused unless the library reports our ABI version *and* matching struct
sizes. The version says which contract; the sizes catch someone editing
their copy of the header, which a version number alone calls fine and a
running session calls garbled colours;
- refused if it redefines an existing name, because a config naming `dim`
means the `dim` it was written against;
- all-or-nothing per file, and per file: a bad library is a line on stderr
and everything else still loads (D9 fail-open);
- nothing is ever unloaded. A shade_fn may be sitting in a live config or on
a pane, so dlclose() is a jump into an unmapped page. A reload picks up
newly *added* plugins; replacing one needs a new session.
This is the single exception to D9's "a plugin is a subprocess", and it is
argued in D15 rather than drifted into: a shader is called per cell, per
pass, per frame, which no subprocess can be in the path of, and the measured
alternative -- interpreting bytecode per cell -- is 56ns against 8ns for the
compiled function. On trust, `shell` and a layout's `command=` already let a
file in the config directory run anything as you, so a .so beside them is
not a new boundary. The docs say so plainly rather than implying a sandbox.
contrib/shader-plugin is a working skeleton: Makefile, two commented effects
(one positional, one animated), and the three rules a shader has to keep. It
is built and loaded by the test suite, so a broken example is a failing test
rather than someone else's afternoon.
|