<feed xmlns='http://www.w3.org/2005/Atom'>
<title>slosh.git/tests/test_reload.py, branch docs-new</title>
<subtitle>an opinionated terminal multiplexer in C with programmable pane chrome</subtitle>
<id>https://git.sl0p.foo/slosh.git/atom/tests/test_reload.py?h=docs-new</id>
<link rel='self' href='https://git.sl0p.foo/slosh.git/atom/tests/test_reload.py?h=docs-new'/>
<link rel='alternate' type='text/html' href='https://git.sl0p.foo/slosh.git/'/>
<updated>2026-08-18T19:26:00Z</updated>
<entry>
<title>slosh: rename the project from sl0ppty</title>
<updated>2026-08-18T19:26:00Z</updated>
<author>
<name>user</name>
<email>user@clank</email>
</author>
<published>2026-08-18T19:26:00Z</published>
<link rel='alternate' type='text/html' href='https://git.sl0p.foo/slosh.git/commit/?id=b9e53cace4eb75263077df8623b011e66f5f2241'/>
<id>urn:sha1:b9e53cace4eb75263077df8623b011e66f5f2241</id>
<content type='text'>
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-&lt;uid&gt;,
$XDG_RUNTIME_DIR/slosh), config path (~/.config/slosh), header guards,
src/sl0ppty.h -&gt; src/slosh.h, contrib/sl0ppty-dev -&gt; 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.
</content>
</entry>
<entry>
<title>sl0ppty: ruff format the Python</title>
<updated>2026-08-17T12:36:59Z</updated>
<author>
<name>user</name>
<email>user@clank</email>
</author>
<published>2026-08-17T12:36:59Z</published>
<link rel='alternate' type='text/html' href='https://git.sl0p.foo/slosh.git/commit/?id=c0022776d0912042819e4ea330cf7491a8196b45'/>
<id>urn:sha1:c0022776d0912042819e4ea330cf7491a8196b45</id>
<content type='text'>
The bumpy one, again. Every `.py` outside `vendor/` plus the three `contrib/`
scripts that are Python with no extension: 60 files, 6,714 lines rewritten, no
behaviour changed. Nothing here is worth reading -- the next commit adds it to
`.git-blame-ignore-revs` so `git blame` walks past it.

It is a bigger reformat than the C was, 60% of the lines against 17%, and for a
reason worth writing down rather than tuning away: ruff and black break a call that
does not fit onto one argument per line, where this code aligned the continuation
under the opening paren. The test suite is thousands of `check("some prose", cond,
detail)` calls, so nearly every one of them changed shape and the suite grew 3,308
lines. Line length was the one lever that moved it -- 120 columns would have been a
40% reformat and no growth at all -- and it was left at 88, because picking an
unusual width to dodge a one-time diff is paying forever to avoid paying once.

Import sorting came with it. Two files had `import os, pty, uuid, select, struct,
sys, termios, time, fcntl, signal` on one line and now have ten.

Verified after, not before, because a formatter that alters behaviour would be
worse than none:

- `make retest`, 1801 checks green -- and this reformats the suite that does the
  checking, including `harness.py`, which every one of those files imports.
- `make test-live`, the tty tests the fast suite skips. They matter here more than
  usual: `live_input.py` and `live_m0.py` are two of the files whose comma-imports
  were split, and nothing in the fast suite would have noticed if that broke them.
- All 60 files still compile, `make fmt` twice in a row changes nothing the second
  time, and `ruff check --select I` has nothing left to say.
</content>
</entry>
<entry>
<title>sl0ppty: a race in the reload test, caught at one in eight</title>
<updated>2026-08-16T14:25:36Z</updated>
<author>
<name>user</name>
<email>user@clank</email>
</author>
<published>2026-08-16T14:25:36Z</published>
<link rel='alternate' type='text/html' href='https://git.sl0p.foo/slosh.git/commit/?id=814a2e52757060237e8354f138dc3e4e3d13fd90'/>
<id>urn:sha1:814a2e52757060237e8354f138dc3e4e3d13fd90</id>
<content type='text'>
`test_a_config_written_after_the_session_started_is_noticed` starts a session
whose config directory does not exist, then writes a config into it. The session
is what *creates* that directory -- the whole point of the test is that a file
appearing later gets noticed -- and `sl0ppty -s` returning means the session was
asked for, not that it has got that far. So the write could land first, and did:

    FileNotFoundError: /tmp/sl0ppty-home-rl_q8peu/.config/sl0ppty/config.kdl

Once in about eight full-suite runs, never on its own, never under load I could
synthesise -- which is why it took ten runs in a row to catch and why it has been
sitting there since the watcher work. Nothing to do with what is around it in
this branch; found because I was hunting a flake I had caused elsewhere and this
one answered instead.

Fixed by waiting for the directory, which turns the thing the test *depended* on
into something it *states*: "the session created the directory it needs to
watch". The include test's startup check is polled for the same reason, since it
too read a screen the session had not necessarily drawn yet.

Verified the only way this kind of thing can be: ten consecutive clean runs of
the whole suite, and the file's own eleven checks green in isolation.
</content>
</entry>
<entry>
<title>sl0ppty: watch what the config was built from, not just what it was called</title>
<updated>2026-08-15T21:18:00Z</updated>
<author>
<name>user</name>
<email>user@clank</email>
</author>
<published>2026-08-15T21:18:00Z</published>
<link rel='alternate' type='text/html' href='https://git.sl0p.foo/slosh.git/commit/?id=930f8f04f0b3b487031514615ca7ace7ad7bbe9c'/>
<id>urn:sha1:930f8f04f0b3b487031514615ca7ace7ad7bbe9c</id>
<content type='text'>
An included theme that does not reload when you save it is half a
feature, and the half that is missing is the one the file headers in
contrib/themes have been promising all along ("a running session re-reads
it the moment you save"). That was true while a theme was something you
pasted; the moment it became something you include, the watch was on the
wrong file.

So a config now remembers every file it was read from -- itself and
everything it included -- and the watcher watches all of them. Recorded
before each parse rather than after, because a file that is not there yet
is exactly the file worth watching: writing it is the next thing that
will happen, and that is the same reason the watch is on directories
rather than on files. Deduplicated, so a cycle does not fill the list
with two names twice.

The set is rebuilt after every successful load, because it is a property
of the config that just loaded: an include can be added, pointed
somewhere else, or taken out, and the watch has to follow. One inotify
watch per directory, deduplicated by the descriptor inotify hands back
for a directory it is already watching; names are matched against the
whole set rather than against the directory whose watch fired, which
means two directories holding a file of the same name reload for each
other's save. That costs a debounced re-read of a config that has not
changed, and is not worth a second data structure to avoid.

Only the main config's directory is created if missing. An include's is
not: a mistyped path should not leave a directory behind.

tests/test_reload.py drives a real session for this one -- the watcher is
the thing under test and the headless driver has none. It writes a config
that includes a theme, checks the theme applied at startup, then edits
*only the included file* and waits for the session to change colour.
</content>
</entry>
<entry>
<title>sl0ppty: watch the config directory even when it is not there yet</title>
<updated>2026-08-15T14:27:50Z</updated>
<author>
<name>user</name>
<email>user@clank</email>
</author>
<published>2026-08-15T14:27:50Z</published>
<link rel='alternate' type='text/html' href='https://git.sl0p.foo/slosh.git/commit/?id=4f64774f910347ce8a27c3aecc7f1c2ac167301b'/>
<id>urn:sha1:4f64774f910347ce8a27c3aecc7f1c2ac167301b</id>
<content type='text'>
You were right. The watch is on the *directory* -- editors write a new file
and rename it over the old one, so watching the file stops working the first
time you save -- but a directory that does not exist cannot be watched at
all. inotify_add_watch failed, the session gave up on watching for good, and
writing a config later did nothing until a restart. Which is exactly the
state a fresh machine is in, and exactly the state C-a e leaves you in.

sl0ppty creates its own config directory at startup now, so there is always
something to watch and a file appearing later is picked up. Tested from a home
directory with no .config at all.

Answering the other half of the question -- which settings actually reload --
turned up one that never worked at all: `shell`. main.c read $SHELL directly
and nobody read the config's value, so the setting parsed, rendered in
--dump-config, and did nothing. It is resolved per pane now, which fixes it and
makes it live: edit it, save, and the next pane you open uses it.

Everything else measured rather than assumed, and it is nearly everything:
colours, geometry, the status bar and line, frame marks, shader chains and
their states, and the keys including the leader itself. The two exceptions are
about *when* a value is read, not reluctance -- `shell` at pane creation, and
shader plugins which load on reload but never unload. Both are now written
down where someone would look.

One test needed rescuing from itself: it asserted the new leader worked by
splitting, in panes that were by then too narrow to split. A test that fails on
geometry while claiming to be about the prefix is worse than no test; it opens
a tab instead.
</content>
</entry>
</feed>
