<feed xmlns='http://www.w3.org/2005/Atom'>
<title>slosh.git/tests/test_session.py, branch v0.1.7</title>
<subtitle>an opinionated terminal multiplexer in C with programmable pane chrome</subtitle>
<id>https://git.sl0p.foo/slosh.git/atom/tests/test_session.py?h=v0.1.7</id>
<link rel='self' href='https://git.sl0p.foo/slosh.git/atom/tests/test_session.py?h=v0.1.7'/>
<link rel='alternate' type='text/html' href='https://git.sl0p.foo/slosh.git/'/>
<updated>2026-09-02T13:09:36Z</updated>
<entry>
<title>attach tag: just the count, in theme colours</title>
<updated>2026-09-02T13:09:36Z</updated>
<author>
<name>user</name>
<email>user@clank</email>
</author>
<published>2026-09-02T13:09:36Z</published>
<link rel='alternate' type='text/html' href='https://git.sl0p.foo/slosh.git/commit/?id=cafa48e0a7e1eb48a783bfde6862c5fd82c7aede'/>
<id>urn:sha1:cafa48e0a7e1eb48a783bfde6862c5fd82c7aede</id>
<content type='text'>
The +x+y offset goes -- 'N clients' says the thing that matters. The
inverse-video chip goes with it: the tag now draws in attach_fg /
attach_bg from the theme, defaulting to gray ink on the terminal's
own background. Standing information, not an announcement.
</content>
</entry>
<entry>
<title>multi-attach: say who else is watching, and where you are</title>
<updated>2026-09-02T13:03:53Z</updated>
<author>
<name>user</name>
<email>user@clank</email>
</author>
<published>2026-09-02T13:03:53Z</published>
<link rel='alternate' type='text/html' href='https://git.sl0p.foo/slosh.git/commit/?id=1a3ba183ae8f2613cae847c8f6460782512acc40'/>
<id>urn:sha1:1a3ba183ae8f2613cae847c8f6460782512acc40</id>
<content type='text'>
A small tag in each client's own top-right corner when several
terminals share the session: the viewer count, and on a view that is
a crop being panned by somebody else's cursor, the crop's offset into
the shared screen ("2 clients +12+4") -- which is exactly the moment
a screen moving on its own needs explaining. Stamped per client after
projection, because every terminal has its own count of others and
its own offset; the shared status bar is composed once and can be
cropped out of a panned view anyway. attach_indicator false hides
it.
</content>
</entry>
<entry>
<title>multi-attach: the config knobs</title>
<updated>2026-09-02T12:57:13Z</updated>
<author>
<name>user</name>
<email>user@clank</email>
</author>
<published>2026-09-02T12:57:13Z</published>
<link rel='alternate' type='text/html' href='https://git.sl0p.foo/slosh.git/commit/?id=d698946464f25a0eb43730ffad15656f3247f56b'/>
<id>urn:sha1:d698946464f25a0eb43730ffad15656f3247f56b</id>
<content type='text'>
The patch made shared attach unconditional; these make it a policy.
multi_attach false restores the classic displacing attach
(EXIT_REPLACED, which old clients already understand). size_follows
picks whose size the shared screen takes: active (the patch's rule),
smallest (the tmux rule: filler, never a crop), or largest. The size
fold lives in apply_canvas, so any attach, resize or departure can
move the canvas under the folding policies -- including a non-active
client leaving, which under smallest may have been the very client
holding the floor down. A config reload re-applies both knobs to the
running session.
</content>
</entry>
<entry>
<title>Add competitive multiplayer support.</title>
<updated>2026-09-02T12:51:02Z</updated>
<author>
<name>Ingmar Steen</name>
<email>iksteen@gmail.com</email>
</author>
<published>2026-08-31T12:43:32Z</published>
<link rel='alternate' type='text/html' href='https://git.sl0p.foo/slosh.git/commit/?id=29061a4aca5e3d645c0e23b885342036ac48f97b'/>
<id>urn:sha1:29061a4aca5e3d645c0e23b885342036ac48f97b</id>
<content type='text'>
Last input wins, canvas size is adjusted to active connection.
</content>
</entry>
<entry>
<title>tests: the greeting is not what the reattach test is about</title>
<updated>2026-08-26T14:48:17Z</updated>
<author>
<name>Peter Geissler</name>
<email>peter@haxx.in</email>
</author>
<published>2026-08-26T14:44:40Z</published>
<link rel='alternate' type='text/html' href='https://git.sl0p.foo/slosh.git/commit/?id=4c1f7f8ebd47ac7906ba9629fc67b53fd317fb5f'/>
<id>urn:sha1:4c1f7f8ebd47ac7906ba9629fc67b53fd317fb5f</id>
<content type='text'>
"reattaching repaints the whole screen" greps the client's byte stream
for the text a pane was holding, and failed about half the time.

The splash assembles from particles scattered over the entire screen, so
for the first few hundred milliseconds of an attach any cell can be
holding a fragment of the logo. The full repaint that a reattach
triggers goes out during exactly that window, so it can carry

    │marker-alp▄a

with a particle where the "h" should be. What restores that cell when
the greeting ends is a one-cell diff, cursor-addressed, so the string is
never contiguous in the stream again and the substring check fails.

Nothing about slosh is wrong here -- the model has the text throughout,
and `snapshot text` shows it -- so the fix is to stop asking this file to
assert about the bytes of an animation it is not testing. The session
under test gets a config with splash_ms 0. The greeting has test_splash.

5/5 where it was roughly half.
</content>
</entry>
<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>make coverage: a number, cheaply</title>
<updated>2026-08-15T14:07:32Z</updated>
<author>
<name>user</name>
<email>user@clank</email>
</author>
<published>2026-08-15T14:07:32Z</published>
<link rel='alternate' type='text/html' href='https://git.sl0p.foo/slosh.git/commit/?id=5585c0736e876c9c54ec4feb5139a8607139daa7'/>
<id>urn:sha1:5585c0736e876c9c54ec4feb5139a8607139daa7</id>
<content type='text'>
`make coverage` builds a second binary with gcc's --coverage into build/cov,
runs every suite against it, and prints a per-file table from gcov. About a
minute. Nothing installed, nothing about the normal zig build changed.

gcc rather than clang because the counters need a gcov that matches the
compiler, and gcov is what this machine has -- no llvm-profdata, no llvm-cov,
no lcov, no gcovr. The aggregation is forty lines of python reading gcov's own
summaries, which is the whole reason this was cheap.

The suites drive it through $SL0PPTY_BIN, one line in the harness, so there is
no second copy of the test code and no risk of the coverage run testing
something else.

Two things about the result, both in the report itself:

- the C unit tests link the *same* instrumented objects, so input.c, kdl.c,
  shader.c and expr.c are credited for the tests that exercise them. Built
  separately, input.c read 54% while having a dedicated decoder test -- a lie
  about where the tests are rather than about the code.
- server.c reads ~8% and is not untested. The session server is a daemonised
  child ending in _exit(), which is right there and skips the flush gcov needs.
  The counters are lost, not the tests. Said in the output, because an
  unexplained low number invites someone to "fix" working code -- and changing
  correct code to make a tool happier is the wrong trade.

Where it lands today: 85.4% of 6298 lines. The gaps that are real rather than
mechanical are jsonval.c (58%), screen.c (64%) and pty.c (59%) -- error paths
and the parts of the diff emitter that only a resize or a weird terminal
reaches.
</content>
</entry>
<entry>
<title>sl0ppty: a floor under splitting, and an arrow saying which way</title>
<updated>2026-08-14T12:45:49Z</updated>
<author>
<name>user</name>
<email>user@clank</email>
</author>
<published>2026-08-14T12:45:49Z</published>
<link rel='alternate' type='text/html' href='https://git.sl0p.foo/slosh.git/commit/?id=037c3550f075ff78e680e5a1f1508d4c292ffcb1'/>
<id>urn:sha1:037c3550f075ff78e680e5a1f1508d4c292ffcb1</id>
<content type='text'>
Two changes to the same affordance.

A border stops being a button below `min_split cols=32 rows=8`. This is a
different question from min_pane, which is where the layout gives up and
collapses a pane: two twenty-five column panes technically fit and are not
worth having, so the number that decides whether to *offer* a split is larger
than the one that decides whether a pane can survive. It is clamped to never
go below min_pane, because refusing to offer what the layout would collapse
anyway is the floor under the floor.

The test is the layout's own arithmetic rather than an approximation of it:
the same floor, the same gap, and the same child count the split would create
— which is one more sibling when the parent already splits that way and two
when it does not. The guide's standing claim is that drawing and the layout
cannot disagree, and a guide promising a split that immediately collapsed
would be exactly that.

The keyboard obeys the same floor, with a toast. A rule only the mouse
followed would mean the same session splits or refuses depending on how you
asked, and whether there is room cannot depend on that. The control API and
layout files are *not* bound by it: a script asking for a pane is declaring
what it wants rather than being offered something, and D6's responsive
collapse is what catches it there. That distinction was not free — app_split_pane
went through the same helper as the keybinding, so the API was silently bound
too until a test noticed, and the interactive path is now its own function.

The guide also gained an arrow on the dashed line, pointing at the half the
new pane will take. The line already said where the boundary lands and left
which side to be inferred from which border you happened to be touching.

Pointers for left and right rather than the matching triangles: U+25C0 and
U+25B6 carry emoji presentation and are widely rendered double-width, while
screen_text books every chrome glyph as exactly one cell — so one that drew as
two would shift the rest of the row. U+25B2 is already the scroll indicator,
so the vertical pair is known good here.

Raising a floor invalidates every test that quietly relied on the old one, and
nine of them did: sessions sized for a world where a sixty-column terminal
could be split into columns. They are sized for the rule now, and the two that
were really about *layout* collapse rather than the affordance now split over
the API, which is the path that still means "do it anyway".
</content>
</entry>
<entry>
<title>sl0ppty: rename from sl0ptty</title>
<updated>2026-08-14T10:13:18Z</updated>
<author>
<name>user</name>
<email>user@clank</email>
</author>
<published>2026-08-14T10:13:18Z</published>
<link rel='alternate' type='text/html' href='https://git.sl0p.foo/slosh.git/commit/?id=20f269a0cdf65f196aea09f0279f5927f26d8192'/>
<id>urn:sha1:20f269a0cdf65f196aea09f0279f5927f26d8192</id>
<content type='text'>
A pty is a pseudo-terminal, and that is what this multiplexes: the extra t
was never standing for anything. Renaming now, while the only users are the
people who typed the old name on purpose, is cheaper than renaming later.

Mechanical, but not only cosmetic. The name is also the runtime contract, so
this moves $SL0PTTY and $SL0PTTY_CONFIG, ~/.config/sl0ptty/config.kdl, the
socket directory ($XDG_RUNTIME_DIR/sl0ptty, /tmp/sl0ptty-&lt;uid&gt;), and the
identity string a program gets back from an OSC 5577 hello. A session left
running under the old binary keeps its old socket directory and is invisible
to the new one; there is no migration and it does not seem worth writing one.

The sl0ppi fork keeps its name: it is a different thing, and D1 still points
at it.
</content>
</entry>
</feed>
