<feed xmlns='http://www.w3.org/2005/Atom'>
<title>slosh.git/docs/panes.md, branch v0.1.0</title>
<subtitle>an opinionated terminal multiplexer in C with programmable pane chrome</subtitle>
<id>https://git.sl0p.foo/slosh.git/atom/docs/panes.md?h=v0.1.0</id>
<link rel='self' href='https://git.sl0p.foo/slosh.git/atom/docs/panes.md?h=v0.1.0'/>
<link rel='alternate' type='text/html' href='https://git.sl0p.foo/slosh.git/'/>
<updated>2026-08-27T14:11:26Z</updated>
<entry>
<title>README/docs: stop leaning on the aside dash</title>
<updated>2026-08-27T14:11:26Z</updated>
<author>
<name>user</name>
<email>user@clank</email>
</author>
<published>2026-08-27T14:11:26Z</published>
<link rel='alternate' type='text/html' href='https://git.sl0p.foo/slosh.git/commit/?id=238b1a7eb51c576254537705597f8a039e1d9c86'/>
<id>urn:sha1:238b1a7eb51c576254537705597f8a039e1d9c86</id>
<content type='text'>
Some 230 sentences hung their qualifications between dashes, and at that
density the tic reads as the writing's signature rather than a tool it
occasionally picks up. Each one is now the punctuation the sentence
actually wanted: a colon where the aside defines, parentheses where it
whispers, a comma where it barely pauses, a full stop where two thoughts
were pretending to be one. Definition lists and reference tables take
colons throughout.

Two double hyphens remain on purpose, both literal: the argv separator
in a shell example, and a table cell that means 'takes nothing'.
</content>
</entry>
<entry>
<title>README/docs: spell the dash --, as the rest of the tree does</title>
<updated>2026-08-27T14:04:37Z</updated>
<author>
<name>user</name>
<email>user@clank</email>
</author>
<published>2026-08-27T14:04:37Z</published>
<link rel='alternate' type='text/html' href='https://git.sl0p.foo/slosh.git/commit/?id=5151e42f22b404cf41dc8b409bcdfcd4b39444ea'/>
<id>urn:sha1:5151e42f22b404cf41dc8b409bcdfcd4b39444ea</id>
<content type='text'>
Every C comment, commit message and generated config in this repo
writes the aside dash as a spaced double hyphen; the Markdown alone
used U+2014, some 220 of them. One spelling, and the ASCII one -- the
prose now matches the code it documents.

Mechanical (every occurrence was the spaced form, checked including
the one inside a code fence, where it was comment text), so the words
themselves are untouched.
</content>
</entry>
<entry>
<title>compact: shared borders instead of gaps (D23)</title>
<updated>2026-08-25T12:23:33Z</updated>
<author>
<name>user</name>
<email>user@clank</email>
</author>
<published>2026-08-25T12:23:33Z</published>
<link rel='alternate' type='text/html' href='https://git.sl0p.foo/slosh.git/commit/?id=b744a90859bf248bfbea97f990668301b5fa9537'/>
<id>urn:sha1:b744a90859bf248bfbea97f990668301b5fa9537</id>
<content type='text'>
One knob, `compact true`: panes pack flush against 1-cell divider lines
that meet in real junctions, one frame rings the tab, and a pane's title
rides the line above it -- a boundary costs one cell where the default
look spends four. The lines are strokes: each write says which edges of
its cell it needs, unions with what is there, and never clobbers text,
so ├ ┬ ┼ fall out of paint order and the focus ring recolours without
inventing arms. The divider *is* the gap (eff_gap, one answer for the
layout, split_fits and the resize clamp), so gap hits, hover hints and
corner drags work unchanged. Interior edges give up click-to-split --
one cell cannot hold two verbs -- and a pane's status row overlays its
last content row. Floats, zoom and the D6 flatten keep classic frames
through place_hidden: zero new tree cases.

Underneath it, mode or no mode: a border drag now moves the boundary on
that side, converted on the first motion so the press that never moves
keeps its old meaning -- the handle's click still splits, the rim's is
still deliberately nothing (drag.rim). Which is also the fix for gap 0,
where flush panes leave no gap cell to grab and the resize gesture had
silently vanished with it.
</content>
</entry>
<entry>
<title>slosh: put-away panes are miniature pane frames</title>
<updated>2026-08-20T22:42:01Z</updated>
<author>
<name>user</name>
<email>user@clank</email>
</author>
<published>2026-08-20T22:42:01Z</published>
<link rel='alternate' type='text/html' href='https://git.sl0p.foo/slosh.git/commit/?id=54dc47f801a444fe0d710f393b04c684df8fa31d'/>
<id>urn:sha1:54dc47f801a444fe0d710f393b04c684df8fa31d</id>
<content type='text'>
Brackets were tried and still read as text. Each min-bar entry is now a
three-row chip wearing a real pane frame -- the same corners, because a
frame is what a pane *looks like* in this program, so a shrunken one reads
as exactly what it is: a pane, clickable. The put-away mark rides inside
each chip and the lone legend is gone; a rung pane's bell mark keeps its
own colour inside the frame; hover lights the whole chip and the whole
chip is the hit. The bar costs three rows instead of one while anything
is minimised (and nothing when nothing is), which is what an affordance
that works is worth.
</content>
</entry>
<entry>
<title>slosh: minimized panes wear buttons in the strip</title>
<updated>2026-08-20T22:33:35Z</updated>
<author>
<name>user</name>
<email>user@clank</email>
</author>
<published>2026-08-20T22:33:35Z</published>
<link rel='alternate' type='text/html' href='https://git.sl0p.foo/slosh.git/commit/?id=0615f09fe885a2a6b136c45931aa500f6e810d19'/>
<id>urn:sha1:0615f09fe885a2a6b136c45931aa500f6e810d19</id>
<content type='text'>
A row of dim bare names read as a caption, and nobody clicks a caption.
Each entry now wears square brackets -- [▬ name] -- because that is what
clickable already looks like in this program: [re-run], [close], the
buttons a pane's own row offers. The put-away mark rides inside each entry
instead of standing at the head of the row as a legend: a legend explains
the row once, a mark per entry says what each button is. A rung pane's
bell mark keeps its own colour inside the brackets, and the whole bracket
is the hit, as one geometry demands.
</content>
</entry>
<entry>
<title>slosh: M10c, the memory -- floats survive being written down</title>
<updated>2026-08-20T21:53:43Z</updated>
<author>
<name>user</name>
<email>user@clank</email>
</author>
<published>2026-08-20T21:53:43Z</published>
<link rel='alternate' type='text/html' href='https://git.sl0p.foo/slosh.git/commit/?id=64db2051192a6a6f5a9333f503d14b1ccccd699d'/>
<id>urn:sha1:64db2051192a6a6f5a9333f503d14b1ccccd699d</id>
<content type='text'>
A dumped session quietly re-tiled its floats, which was the one data-loss
gap left in D22. dump-layout now records `floating=true x= y= w= h=` -- the
*wanted* rect, because intent is what survives a session and the next
screen's layout clamps it like any frame -- layout files declare the same
(linted: floating is a bool, x/y/w/h mean nothing without it), and a file
whose every pane floats self-heals through ensure_tiled: the top float
lands, the same rule closing the last tiled pane follows, no lint required.
save-workspace inherits all of it from the shared dumper.

`float` over the API takes x/y/w/h and then *places* rather than toggles --
a placement is a statement about where, not about whether -- floating the
pane first when it is tiled, re-placing when it already floats, with
omitted fields meaning "keep". The intent is stored exactly as asked: the
write-back rule is for hands, whose drags need the clamp to agree with the
eye; a script means what it typed.

And kitty graphics respect the stack. The cell compositor gets occlusion
free from paint order, but placements are sent after the diff and would
paint an image straight over a float covering it. Each pane's placements
are now clipped by the float rects above it -- every float for a tiled
pane, the higher-raised for a float -- cropping what one clean edge can
express (the pane-edge source-rectangle arithmetic aimed at another
clipper, including from the top and left, where the source origin moves and
the sub-cell offset is consumed) and suppressing what it cannot: a strip
across the middle or a corner overlap leaves a shape one placement cannot
say, and the image returns whole when the float moves. No z= needed --
clipping is the z-order, since nothing is ever allowed to overlap.

D22's "still owed" paragraph is paid and rewritten; M10 is fully checked.
</content>
</entry>
<entry>
<title>slosh: floating panes and the drop grammar</title>
<updated>2026-08-20T21:22:33Z</updated>
<author>
<name>user</name>
<email>user@clank</email>
</author>
<published>2026-08-20T21:22:33Z</published>
<link rel='alternate' type='text/html' href='https://git.sl0p.foo/slosh.git/commit/?id=b33e8c13ff7981effc7ec2735e6aeaaaf1705af7'/>
<id>urn:sha1:b33e8c13ff7981effc7ec2735e6aeaaaf1705af7</id>
<content type='text'>
A pane can float: lifted out of the layout, drawn over the tiled panes and
under the modals, freely moved and shaped. The model is a flag and a rect on
the leaf, exactly like `minimized` -- the seat in the tree is kept, layout
skips it, the siblings absorb its share, and un-floating returns it home.
The drawn rect is the wanted one clamped to the tab every frame, never
written back, so a terminal squeeze round-trips exactly; an explicit move or
resize *does* write back, because the hand is the author of the intent.
Floating pops the pane to the centre: the jump is what says it happened.
Painted after everything tiled, so the hit list -- searched backwards --
resolves an overlap to the float you can see: the z-order and the click
order are the same list. It casts a shadow (float_shadow, one number), and
`floating` joins the states table above `unfocused`, so a float is never
dimmed as merely-unfocused.

The hands: the title moves it, any other border resizes it (a bottom corner
on both axes; the grabbed edge pins at walls and floors, never sliding the
window), H J K L move a focused float, the =/+ key grows it about its
centre, `-` shrinks it (its split was a refusal anyway), and hovering shows
which edges a grab would take, from the same derivation the press uses.
Equalize moved to `0` to free the key; `C-a f` floats (finder went to `s`,
where it reads as search); `C-a F` opens a new floating shell -- the
throwaway terminal; the function row f1..f12 became nameable in configs
along the way. Guards throughout: the last tiled pane cannot float or
minimize away, closing it lands the top float, splits are refused with
their own words, floats are not swap targets.

Dropping got a grammar: while a pane is carried, the pane under the pointer
subdivides into a swap centre and four edge bands meaning "insert me beside
this pane, on this side" -- detach_leaf + place_beside, the surgery
cross-tab moves already had. Bands are thirds (the first map of quarters
showed the swap owning half of each axis), the hovered band fills the half
the drop would hand over, the release resolves against the painted frame's
hits so it cannot disagree with the fill, and a drop between siblings along
the axis is a reorder that always fits -- refusing it was refusing the most
ordinary drag there is.

Also: rename-pane/rename-tab as palette actions (renaming was a
double-click and nothing else, the one verb the palette could not reach),
and C-u clears the rename editor like it clears the picker's query.

Design log in PLAN-FLOATING-PANES.md; to fold into DESIGN.md as D22/M10-11.
</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: aim the top handle at the middle, and stop ruling through the row</title>
<updated>2026-08-18T14:20:37Z</updated>
<author>
<name>user</name>
<email>user@clank</email>
</author>
<published>2026-08-18T14:20:37Z</published>
<link rel='alternate' type='text/html' href='https://git.sl0p.foo/slosh.git/commit/?id=13967ce08d440a850665c81d407e710c1c77394d'/>
<id>urn:sha1:13967ce08d440a850665c81d407e710c1c77394d</id>
<content type='text'>
Two faults that fed each other, and only the second one made the first visible.

The handle went to the **widest** free run of the top row. A centred title leaves
two runs of nearly the same width, so a one-cell difference nobody can see threw
the handle out toward a corner: on a 116-column pane whose row middle is 60, it
sat at 85. Placement should be stated in terms of where the thing wants to be,
not of the leftovers it is allowed to occupy -- so it now aims at the middle of
the row and slides into the nearest run that is free. Nothing in the way: centred,
like the other three sides. A title holding the middle: hard against the title,
where the eye already is. That same pane now puts it at 64.

The armed edge also ruled the heavy line straight across the whole border, over
the pane's name, its buttons, its scroll indicator and a dead pane's epitaph. The
row went unreadable exactly while the pointer was on it -- and the title the
handle had just been placed beside was wiped, which is what turned a merely-off
position into an apparently random one. Each cell of the edge is now painted only
if the hit list says the edge still owns it: the same question the handle asks,
and the one the click will ask.

The epitaph had to start claiming its cells to take part. It answers
`panestatus:` and does nothing when clicked, because an epitaph is not a button;
what it buys is that ` exited: status 3 ` survives a hover over the border it
lives on, next to `[re-run]` and `[close]`, which already survived because they
were buttons.

Verified: `make retest`, **1877 checks measured**, all green. Four new: the handle
is centred on the row when the row is empty, sits against the title when the
title holds the middle, and the armed top edge leaves both the name and the three
buttons legible.

Live on a 116x36 pane, hovering the far left of the top row -- deliberately the
rim, so this is the first stage doing all of it:

  ╭━━━━━━━━━━━━━━━━━━━ sl0ppty ███▲███━━━━━━━━━━━━━━━━━▬ □ ✕ ╮

and on a dead pane, hovering the bottom handle:

  ╰ exited: status 3 ━━━━━━━━━━███▼███━━━━━━━━[re-run]━[close]━╯
</content>
</entry>
<entry>
<title>sl0ppty: the split arrow belongs on the button</title>
<updated>2026-08-18T14:10:10Z</updated>
<author>
<name>user</name>
<email>user@clank</email>
</author>
<published>2026-08-18T14:10:10Z</published>
<link rel='alternate' type='text/html' href='https://git.sl0p.foo/slosh.git/commit/?id=14dad660036e34a899a406f09195f790bb60709c'/>
<id>urn:sha1:14dad660036e34a899a406f09195f790bb60709c</id>
<content type='text'>
The arrow rode the middle of the dashed boundary line, which put the two halves
of one message in two places: the handle said *press here* and a glyph out in the
middle of the pane said *this is what happens*. It also meant the direction was
unreadable until you were already on the target, since the dashed line is stage
two of the hover.

So the arrow moves into the handle and the boundary line goes back to being a
plain boundary -- which is the honest shape for it anyway: it is the *edge* of the
pane you are about to make, and an edge has no middle worth marking. The handle
is now one object that explains itself, and because the handle is drawn from the
first stage, brushing any part of an edge tells you where its button is and which
way that button splits, without previewing a boundary nobody asked about.

Knocked out with ATTR_INVERSE rather than drawn in a second colour: the bar is
solid `guide`, so a `guide` glyph on top of it would have been invisible, and
inverting gets contrast that follows whatever colour the theme sets for no new
knob. Along the handle the arrow sits in the middle, where the pointer is aiming.
Across it -- a distinction only the upright pair has, being the two that grow a
second cell -- it sits on the edge's own cell rather than the one over the
content, because it marks a boundary and the boundary lands on the frame.

Verified: `make retest`, **1873 checks measured** (`test_split_ux.py` 100 of
them), all green. The test that pinned the arrow to the dashed line is now the
test that pins it to the handle, on all four sides, plus one that it is legible
from the first stage with no boundary drawn.

Checked live on a 116x36 pane: `◄█` at column 2 and `█►` at column 117 on the
middle row of their bars, `━━━███▼███━━━` on the bottom border's single row, and
-- the case that shows why this is worth it -- hovering the *far left* of the top
row draws `███▲███` at column 85, where the handle actually is, having dodged a
centred title.

A note on the two commits before this one: their messages quote 1801 and 1807
checks, which were carried over from earlier in the session rather than measured.
The figure was 1865 at that point. The code and the tests were right; the numbers
in those two messages were not.
</content>
</entry>
</feed>
