<feed xmlns='http://www.w3.org/2005/Atom'>
<title>slosh.git/tests/test_scroll.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_scroll.py?h=docs-new</id>
<link rel='self' href='https://git.sl0p.foo/slosh.git/atom/tests/test_scroll.py?h=docs-new'/>
<link rel='alternate' type='text/html' href='https://git.sl0p.foo/slosh.git/'/>
<updated>2026-08-26T14:11:42Z</updated>
<entry>
<title>macos: the kernel still knows, it just spells /proc differently</title>
<updated>2026-08-26T14:11:42Z</updated>
<author>
<name>user</name>
<email>user@clank</email>
</author>
<published>2026-08-26T14:11:42Z</published>
<link rel='alternate' type='text/html' href='https://git.sl0p.foo/slosh.git/commit/?id=087b2bd1d31dac24f8b0ffe79c33f4ebf1f60bd3'/>
<id>urn:sha1:087b2bd1d31dac24f8b0ffe79c33f4ebf1f60bd3</id>
<content type='text'>
Portability fixes contributed by our macOS developer, applied with one
hardening tweak (below).

Darwin has no /proc, so everything that read one gets the native answer:
live_cwd via proc_pidinfo(PROC_PIDVNODEPATHINFO), the foreground command
via sysctl(KERN_PROCARGS2) parsed back into the NUL-separated shape
/proc/&lt;pid&gt;/cmdline gives, and SLOSH_BIN via _NSGetExecutablePath plus
realpath. The pty gets its winsize set on the slave after opening it,
because Darwin attaches no line discipline to the master until then and
the earlier TIOCSWINSZ was silently dropped -- a pane born 0x0. The
shader repl binds tab in libedit's own words, since macOS ships Python's
readline as a libedit wrapper that accepts GNU syntax in silence.

Two finds are cross-platform bugs: a toast wider than the screen minus
the gap computed a negative x that uint16_t made ~65533, drawing the
longest messages -- the ones most worth reading -- off screen; now the
middle is elided (a path's tail is the half you needed) and x clamps.
And a pane label was 128 bytes, which a Homebrew interpreter's full path
exceeds before its arguments even start; dump-layout wrote the
truncation down and a restore ran it, so it is 1024 now.

Saving a layout learned cwd_as_named: the kernel answers with the
physical path, and on macOS /tmp is a symlink to /private/tmp, so a
layout that said cwd="/tmp" stopped round-tripping through a save.
If realpath(named) is where the pane still is, the named spelling wins.

Tests follow: realpath'd tmpdirs, the scroll test reads the shell's
first prompt instead of spelling out bash 5.3, and wrapped pane text is
joined before matching a long path.

One tweak on top of the contribution: the elision needs five columns
for a head, the dots and a tail -- below that `avail - 3` goes
negative, and negative as size_t is a pointer into the weeds; a
terminal that narrow gets a plain clip.
</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: give the scroll arrow room to breathe</title>
<updated>2026-08-14T17:02:36Z</updated>
<author>
<name>user</name>
<email>user@clank</email>
</author>
<published>2026-08-14T17:02:36Z</published>
<link rel='alternate' type='text/html' href='https://git.sl0p.foo/slosh.git/commit/?id=8c8940a07c7883b34eccd55bdd7c7e947fcf9c06'/>
<id>urn:sha1:8c8940a07c7883b34eccd55bdd7c7e947fcf9c06</id>
<content type='text'>
"▲12" ran the arrow into the first digit. U+25B2 is drawn wide enough in plenty
of fonts to touch whatever follows it, and the pair then reads as one smudged
token instead of an arrow and a number. Both places that draw it — the pane
frame and the status line — now put a space between.

Both were also measuring the indicator in bytes. The arrow is three bytes and
one column, so strlen reserved two columns that were never drawn, holding the
whole thing further from the edge than it needed to be. The frame now counts
cells arithmetically and hit-tests the width screen_text actually drew; the
status line counts codepoints, which is exact for a string whose only non-ASCII
is that arrow.

Fixing the measurement immediately made the bottom line worse, which is a
pleasing kind of bug: the two-column overcount had been supplying the gap
between "scrolled" and "pane 1/1" by accident, and correcting it left them
adjacent and reading as one phrase. The separation between right-hand clusters
is now deliberate and two columns wide, rather than however much the arithmetic
happened to be wrong by.
</content>
</entry>
<entry>
<title>sl0ptty: scrollback — wheel, keyboard, and a clickable indicator</title>
<updated>2026-08-13T21:50:24Z</updated>
<author>
<name>sl0p</name>
<email>sl0p@sl0p.foo</email>
</author>
<published>2026-08-13T21:50:24Z</published>
<link rel='alternate' type='text/html' href='https://git.sl0p.foo/slosh.git/commit/?id=b514f68d9535e0ee882eecbbac217486f999f538'/>
<id>urn:sha1:b514f68d9535e0ee882eecbbac217486f999f538</id>
<content type='text'>
libghostty-vt already keeps the scrollback, so the work was deciding whose
wheel it is:

  - a program tracking the mouse gets the wheel events themselves;
  - a full-screen program without mouse tracking (vim, less) has no scrollback
    of ours to show, so the wheel becomes arrow keys, which is what it means
    to that program;
  - anything else scrolls our viewport.

All three are tested against real programs rather than asserted in principle.

C-a PageUp/PageDown/Home/End, and scroll_lines in the config for the wheel.
Typing snaps back to the live view, because reading scrollback and then typing
into a screen you are not looking at is a trap. New output does not yank the
viewport back — it just grows the gap, which the indicator shows.

The indicator is compact, right-aligned, budgeted after the split button and
before the title (a title is the thing you can most afford to lose), and
clicking it returns to the bottom.

Three test failures on the way, all mine and all instructive: the top of the
scrollback is the shell's first prompt rather than the first line of output;
typing without a newline types rather than runs; and two side-by-side panes
share a screen row, so asserting on line(y) reads both frames at once.

341 checks green.
</content>
</entry>
</feed>
