Skip to content

clikae v0.26.1 — the board did not fit, and the diagnosis was right

Choose a tag to compare

@cverorg cverorg released this 16 Aug 04:45
· 77 commits to main since this release

The board did not fit, and the reporter's diagnosis was right

Reported from a PineNote over ssh: opening clikae does not fit in the
terminal, and it looks like the layout is hardcoded rather than fluid.

Measured on the repo: it overflowed at every width below 72 columns.

69 cols more clikae status · clikae doctor · clikae demo · clikae help
45 cols the tank rows — 4 lead + dot + 3 spaces + 7 + 8 + 22, all literals
38 cols the interactive frame's autonomy legend
34 cols the wordmark + summary header

There is a fluid layer — _home_cols, _home_row_budget,
_home_wrap_prefixed, _home_trunc — and a set of rows that bypassed it.
The more row is the one you see first: a bare printf of a hardcoded string,
not even a call to _home_cols, and the last line of the board.

Three causes, not one

Literal column widths, written out twice. The tank row's 7 / 8 / 22 lived
at both tank-row sites — the static board and the interactive one — and neither
asked the terminal's width. They share one _home_tank_fields now: the account
column is what is left after the fixed chrome (capped at the old 22, so a wide
terminal is unchanged), truncated to it rather than only padded to it, and
padded only when something follows. Otherwise the padding is trailing
whitespace that still counts as width — which is how a row whose account was
the single character - measured 45 columns.

An escape hatch that produced the overflow it prevented. When the hanging
indent left under 12 columns to wrap into, _home_wrap_prefixed widened the
budget to the whole terminal — and still printed the prefix. Every line came
out exactly hang columns too wide. At 30 columns with a 19-column prefix it
wrapped text to 29 and printed 48.

Every tmux session was born 80x24, whatever terminal you were on.
tmux new-session -d is detached, and a detached session has no client to take
its size from, so tmux used default-size. Measured on a pty at 60, 100 and
140 columns: 80x24 every time. The engine paints its first frame for 80 columns
and only afterwards do we attach and tmux resizes — so the first screen you see
was laid out for a terminal you are not using, and that applies to the
engine's own TUI as much as to our board.

And it never repainted when you resized

tui_read_key blocks — its argument is a file descriptor, not a timeout — so
the loop sat there until a key arrived, while every layout figure was already
being read per draw. The board was always capable of reflowing; nothing asked
it to.

A trap … WINCH does not fix that. Bash installs handlers with SA_RESTART,
so the blocked read resumes and the flag the trap set is never looked at —
measured on a pty, SIGWINCH after the first frame produced zero bytes of
repaint. The wait polls once a second instead, and repaints only when the size
actually changed.

🔴 And it cannot branch on the read's exit code. macOS's stock bash 3.2
the shell clikae runs on — returns 1 for a read -t timeout, where bash 4+
returns >128. Two consecutive one-second timeouts both came back 1,
indistinguishable from EOF. So the loop asks something independent: a terminal
that is gone has no size, and that is the only case that should quit.

Gated on the path that actually breaks

tests/bats/board-width.bats renders the whole board at ten widths and measures
every line — on both paths. clikae with no tty draws the static board,
so a gate that only ran the binary would have missed the interactive frame the
reporter was looking at. The existing width test called _home_wrap_prefixed
directly and proved the helper wraps, which says nothing about the 35 printf
sites that never call it. The new gate caught four defects while the fix was
being written.

pty-smoke.py size and pty-smoke.py resize cover what needs a controlling
terminal — in bats they would pass by not looking. Before the fix: 80x24 at
every width, and nothing drawn after a resize.

Checked, and NOT a bug

Attaching a smaller client to a larger existing session. window-size latest
resizes correctly, 140x40 → 60x29. The first probe said otherwise — it used
tmux attach &, which never attaches at all, because a background process
group cannot own the tty. list-clients was empty and the reading was worthless.