<feed xmlns='http://www.w3.org/2005/Atom'>
<title>slosh.git/docs, branch docs-new</title>
<subtitle>an opinionated terminal multiplexer in C with programmable pane chrome</subtitle>
<id>https://git.sl0p.foo/slosh.git/atom/docs?h=docs-new</id>
<link rel='self' href='https://git.sl0p.foo/slosh.git/atom/docs?h=docs-new'/>
<link rel='alternate' type='text/html' href='https://git.sl0p.foo/slosh.git/'/>
<updated>2026-09-02T10:34:31Z</updated>
<entry>
<title>docs: chore</title>
<updated>2026-09-02T10:34:31Z</updated>
<author>
<name>Peter Geissler</name>
<email>peter@haxx.in</email>
</author>
<published>2026-09-02T10:34:31Z</published>
<link rel='alternate' type='text/html' href='https://git.sl0p.foo/slosh.git/commit/?id=5f5f0aaf5ef3f86b6345d26d0abc9dc37f4acbf3'/>
<id>urn:sha1:5f5f0aaf5ef3f86b6345d26d0abc9dc37f4acbf3</id>
<content type='text'>
</content>
</entry>
<entry>
<title>docs: deprecate boring design narrative, more trimming and culling</title>
<updated>2026-09-02T10:32:45Z</updated>
<author>
<name>Peter Geissler</name>
<email>peter@haxx.in</email>
</author>
<published>2026-09-02T10:32:45Z</published>
<link rel='alternate' type='text/html' href='https://git.sl0p.foo/slosh.git/commit/?id=794e22914666775cab0b1b730a000b2529cec6b5'/>
<id>urn:sha1:794e22914666775cab0b1b730a000b2529cec6b5</id>
<content type='text'>
</content>
</entry>
<entry>
<title>docs: big overhaul</title>
<updated>2026-09-02T09:55:35Z</updated>
<author>
<name>Peter Geissler</name>
<email>peter@haxx.in</email>
</author>
<published>2026-09-02T09:55:35Z</published>
<link rel='alternate' type='text/html' href='https://git.sl0p.foo/slosh.git/commit/?id=93e8b6a98de3f9e8f3176199e7974f4bc8a66a1f'/>
<id>urn:sha1:93e8b6a98de3f9e8f3176199e7974f4bc8a66a1f</id>
<content type='text'>
</content>
</entry>
<entry>
<title>layout: a float sized but not positioned is centred, per axis</title>
<updated>2026-08-30T13:22:51Z</updated>
<author>
<name>user</name>
<email>user@clank</email>
</author>
<published>2026-08-30T13:22:51Z</published>
<link rel='alternate' type='text/html' href='https://git.sl0p.foo/slosh.git/commit/?id=ea83e7ee521d1430f6b0c3b619b390337924a066'/>
<id>urn:sha1:ea83e7ee521d1430f6b0c3b619b390337924a066</id>
<content type='text'>
docs/layouts.md always said an absent coordinate takes the centred
default; the loader said 0, and a layout float with only w= h= landed
in the top-left corner. Now an axis the file does not name is
FLOAT_CENTRE, a sentinel no real coordinate can reach, and float_clamp
answers it with the middle -- every frame, at whatever size the
terminal is by then, until an explicit move or resize writes a real
number over it. The webdemo's welcome float is the customer: it must
sit centred on a terminal whose size the layout file cannot know.

The dump writes a still-centred axis by omission, because the number
it happened to land on would pin to this screen's size the one intent
that deliberately has none. Every mutating verb already writes back
from the drawn rect, so the sentinel survives nothing it should not.
</content>
</entry>
<entry>
<title>graphics: a frame the client never got must be said again</title>
<updated>2026-08-29T19:31:41Z</updated>
<author>
<name>user</name>
<email>user@clank</email>
</author>
<published>2026-08-29T19:31:41Z</published>
<link rel='alternate' type='text/html' href='https://git.sl0p.foo/slosh.git/commit/?id=8a8b5e1c7acd269d4a639a40712412a84480ad18'/>
<id>urn:sha1:8a8b5e1c7acd269d4a639a40712412a84480ad18</id>
<content type='text'>
A pane image is re-emitted to the client as decoded RGBA, which for one
screenshot is ~4MB of base64 in a single indivisible message -- and
conn_send silently dropped anything that would overflow the 4MB outbox,
while push_graphics ignored the refusal and the model advanced anyway.
Everything stateful in that dropped frame was lost for good: the image
was marked sent (so its placements drew nothing, forever), and the
deletions rode out with it (so a placement the client had was never
revoked). Reported as screenshots in a recovered pi transcript parked
at a fixed spot on the screen, immune to scrolling and pane swaps --
those were placements whose deletion left with a dropped frame. The
1000x800 one could never be delivered at all: its transmission alone
was bigger than the cap.

So the frame is now transactional. Deletions queue and are repeated
every flush until gfx_commit() confirms the client heard them;
transmissions recorded in a frame are unwound by an undelivered commit
so they are sent again. A flush nobody commits counts as undelivered at
the next gfx_begin(), which is what the `graphics` control command is:
bytes rendered for a CLI, not the client. The server reports the
verdict and keeps the paint pending until it lands.

The outbox cap now bounds the backlog rather than backlog-plus-message,
so one big transmission on a drained queue always fits -- and that
surfaced a second way to lose: a queued image legitimately holds the
backlog over the cap until the client swallows it, and push_frame read
that as a dead client and closed the connection. The session
auto-detached every time a screenshot crossed the wire. A full outbox
is a client that is *behind*, not gone: push_frame now marks the screen
for a full repaint (the dropped diff means the client's cells are
unknown) and retries as POLLOUT drains the queue; a client that truly
left still shows up as a write error there.

The headless suite pins the owed-until-committed contract; the new
tests/live_graphics.py drives the real socket with a
bigger-than-the-cap image and a reader that stalls, and would have
caught both bugs: the flood must not detach, the transmission must
arrive whole, and a placement scrolled away must be deleted -- then
come back on scroll without a second copy of the pixels.
</content>
</entry>
<entry>
<title>docs: less wordy</title>
<updated>2026-08-29T18:25:39Z</updated>
<author>
<name>user</name>
<email>user@clank</email>
</author>
<published>2026-08-29T18:25:39Z</published>
<link rel='alternate' type='text/html' href='https://git.sl0p.foo/slosh.git/commit/?id=31c32f9c20e3dd5045fa053fc8e7e606a8139397'/>
<id>urn:sha1:31c32f9c20e3dd5045fa053fc8e7e606a8139397</id>
<content type='text'>
</content>
</entry>
<entry>
<title>gitignore: DESIGN.md and .fastfeedback are local, not the project</title>
<updated>2026-08-28T13:38:41Z</updated>
<author>
<name>user</name>
<email>user@clank</email>
</author>
<published>2026-08-28T13:38:41Z</published>
<link rel='alternate' type='text/html' href='https://git.sl0p.foo/slosh.git/commit/?id=a7a20bc026488928b6b65f44924b31615b898263'/>
<id>urn:sha1:a7a20bc026488928b6b65f44924b31615b898263</id>
<content type='text'>
DESIGN.md was a scratch design doc and .fastfeedback a per-repo tool cache;
neither belongs in the tree. Both stay on disk, ignored. Everything that
pointed at DESIGN.md now points at docs/design.md, and the decision counts
quoted from it (which had already drifted: the README said twenty-one, the
docs said twenty-two) are gone with it.
</content>
</entry>
<entry>
<title>windows release: a zip in dist/, built beside the linux tarballs</title>
<updated>2026-08-28T13:38:27Z</updated>
<author>
<name>user</name>
<email>user@clank</email>
</author>
<published>2026-08-28T13:38:27Z</published>
<link rel='alternate' type='text/html' href='https://git.sl0p.foo/slosh.git/commit/?id=67e0330e5f18e4fe7f87db978071c6afa77ee91b'/>
<id>urn:sha1:67e0330e5f18e4fe7f87db978071c6afa77ee91b</id>
<content type='text'>
make -f Makefile.windows dist stages slosh.exe as
slosh-&lt;version&gt;-windows-&lt;arch&gt;.zip -- a zip, not a tarball, because Windows
is the machine that will open it -- carrying the same licensing paperwork as
the linux tarballs, with docs/windows.md riding along instead of the
manpages. `make release` now builds both architectures via release-windows,
so the windows zips land under the same SHA256SUMS as everything else.
</content>
</entry>
<entry>
<title>ctrl_d_exits: Ctrl-D at a prompt, where the tty cannot do it</title>
<updated>2026-08-28T12:41:42Z</updated>
<author>
<name>Peter Geissler</name>
<email>peter@haxx.in</email>
</author>
<published>2026-08-28T12:41:42Z</published>
<link rel='alternate' type='text/html' href='https://git.sl0p.foo/slosh.git/commit/?id=2fbd36c1cef6ea6c9fcf9c36afb5209089288257'/>
<id>urn:sha1:2fbd36c1cef6ea6c9fcf9c36afb5209089288257</id>
<content type='text'>
Windows has no VEOF. The console driver does not know the character, so
^D arrives at cmd.exe and PowerShell as an ordinary keystroke and they
ignore it -- it even echoes, which is how you find out: the line reads
`echo hello^D`. The one key that closes a pane on every other platform
does nothing at all, and closing a pane becomes a word you have to type.

That you can type `exit` instead is the tell: the intent was never
ambiguous, only unspoken. So slosh speaks it. What goes to the pane is
the word, not a signal and not a close from outside -- the shell runs
its own cleanup, returns its own status, and keep_dead decides what is
left behind, all three of which reaching past it would skip. It is also
what the user would have typed, so there is nothing new to explain.

The knob is what makes it honest, because a wrong guess costs a pane.
It fires only with the shell itself in the foreground (a program that
is running may want the EOF for itself -- `cat` reading to end is the
whole job), only on the primary screen (in an editor or a pager ^D is
half a page down, and the alternate screen is the pane stating that
rather than us matching process names), and only on an empty line
(POSIX sends EOF there; what it does not do is discard what you typed).

The line is an estimate. The shell's editor is on the far side of a
pty, so pane_send_key counts what it forwarded since the last Enter.
Editing it does not model -- a recalled history entry, ^U, completion
-- leaves the count too high, which forgets to exit. That is the
direction to be wrong in; the other one throws away a half-typed
command.

Default true on Windows, false on POSIX, where the line discipline
already does this and does it properly: ^D there is also EOF for `cat`
and every REPL, none of which is ours to intercept. A knob rather than
an #ifdef so the guards are the same code everywhere and can be tested
where the test suite runs -- test_ctrl_d.py turns it on and drives all
four decisions, plus the case that does exit.

Telling trapped from forwarded needs a program that reports what it
received: on POSIX a forwarded ^D also ends an idle shell, and looking
for the word `exit` cannot separate them either, because bash prints
`exit` itself on EOF.

Verified on the Windows box as well, where it is the default: ^D at an
idle cmd.exe prompt takes the pane (and with it the session, having no
panes left), `more` in the foreground keeps its own EOF, and a
half-typed line survives with the line still on screen.
</content>
</entry>
<entry>
<title>docs: the Windows build is a cross-compile, and only that</title>
<updated>2026-08-28T12:22:57Z</updated>
<author>
<name>Peter Geissler</name>
<email>peter@haxx.in</email>
</author>
<published>2026-08-28T12:22:57Z</published>
<link rel='alternate' type='text/html' href='https://git.sl0p.foo/slosh.git/commit/?id=7941820413d82b3d62d7fc2ac15ef0e1b3b69ee4'/>
<id>urn:sha1:7941820413d82b3d62d7fc2ac15ef0e1b3b69ee4</id>
<content type='text'>
The docs offered a native build as an equal alternative -- "the same
command builds natively on the Windows box itself, with zig on PATH and
a make" -- and it does not work. Makefile.windows needs sed, cat,
mkdir -p and shell grouping, none of which cmd.exe has; and on ARM64
`zig cc` in zig 0.16.0 dies with an access violation on a one-line C
file, so the compiler cannot run there at all. The zip that does it
matches the published shasum, so this is upstream rather than a bad
download.

Nobody following those two sentences reached a binary. So they are
gone, along with the "# host arch, native" usage line in the makefile
and the "cross-compiles too" aside in the two install sections, which
both implied that building on the box was the normal path and the
cross-compile a bonus. It is the other way round, and now the pages
say so once, in the same words each time.

`builds and runs natively` on the doc's first line loses `builds`:
what is native about slosh.exe is the binary, not where it was made.
</content>
</entry>
</feed>
