0.4.0: collapse across a wrapping container, in all seven implementations - #84
Merged
Conversation
Closing the gaps was necessary and not sufficient. Panels then touched but still drew two borders, because a seam merges only where two *bordered siblings* meet -- and the only way to put a stack of panels beside one tall panel is to wrap the stack in a column, which is not itself bordered. So the seam down the middle of every screen was the one seam that could never merge, and a grid never merged at all. The dashboard looked right only because its panels happen to be direct children of the row. Containers now take a `bordered` flag that says their own edges are panel borders, and a grid of panels merges its tracks. It is declared rather than inferred: the children are built only once the layout has been solved, and the seam has to be known before that, so there is nothing to inspect at the moment the question is asked. The other half was a panel with a background. `box` filled the whole rect before drawing its border, which erased the neighbour's border out of the shared column -- so the merge found a blank cell and overwrote it, leaving a corner where a junction belonged. Filling under collapsing now stops at the border ring, which the border then paints in the same background. Uncollapsed rendering is untouched, and the regenerated fixture proves it: of 240 cases, all 120 open frames are byte-identical and 90 of the 120 collapsed ones changed. Rust and Zig widened their grid gap arithmetic to signed, since a merged track seam is minus one. In C++ the flag has to be copied into the panel body: those lambdas are stored and run by flush() after the enclosing function returns, so a captured-by-reference `gap` was a dangling local, which is exactly how the dashboard's sub-panels kept their gap while everything around them merged. Verified: TypeScript 356 tests; Go, Python 36, Rust 17 demo-parity, Zig 17, C++ 9/9 including its own 240-case parity; Ruby and Perl bindings each report 240 exact reference frames in both border modes. Rendering all eleven screens both ways and counting seams that stayed open gives zero on every one. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VhrgsHr1C5BYxXDpN1mahf
Bumps the library, the demo, the COBOL adapter and every workspace range that points at them, plus the two hand-written strings no build step touches — the CLI's VERSION and the demo's --version — and the site's badge. The demo has to move with the library rather than after it: it now calls `worldMap`, which does not exist in the published 0.3.0, so a demo published against `^0.3.0` would resolve the old library and crash on the world screen. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VhrgsHr1C5BYxXDpN1mahf
The test ran green under `bun test`, which does not typecheck, and failed `bun run typecheck` on all three platforms. `Color` is a `number` in hqtui, and a "#202020" string only looked right. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VhrgsHr1C5BYxXDpN1mahf
`col` gained a `bordered` argument and two callers were missed: the read and write graphs inside the dashboard's I/O Summary, which are graphs rather than panels and so pass false. They compile only under the `test-demo` target. `zig build test` alone leaves the demo out, which is why this reached CI: the command to run is `zig build test test-demo`, the one mise's `test:zig` task uses. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VhrgsHr1C5BYxXDpN1mahf
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Follow-up to #83, which landed the first half. This is the rest.
What #83 left unfinished
#83 closed the gaps so every seam could touch. But the panels then touched while still drawing two borders, because a seam merges only where two bordered siblings meet — and the only way to put a stack of panels beside one tall panel is to wrap the stack in a column, which is not itself bordered. So the seam down the middle of every screen was the one seam that could never merge, and a grid never merged at all. The dashboard looked right only because its panels happen to be direct children of the row.
Containers now take a
borderedflag saying their own edges are panel borders, and a grid of panels merges its tracks. It is declared rather than inferred: the children are built only once the layout has been solved, and the seam has to be known before that, so there is nothing to inspect at the moment the question is asked.And panels with a background
boxfilled its whole rect before drawing its border, which erased the neighbour's border out of the shared column — so the merge found a blank cell and overwrote it, leaving a corner where a junction belonged. That is why the themes grid showed╭where a┬was due. Filling under collapsing now stops at the border ring, which the border then paints in the same background.All seven implementations
TypeScript, Rust, Go, Python, Zig and C/C++, plus the Ruby/PHP/Perl bindings that ride on the C++ demo.
flush()after the enclosing function returns, so a captured-by-referencegapwas a dangling local — which is exactly how the dashboard's sub-panels kept their gap while everything around them merged.Uncollapsed rendering is untouched
The regenerated
demo-parity.jsonproves it: of 240 cases, all 120 open frames are byte-identical, and 90 of the 120 collapsed ones changed.0.4.0
The demo has to move with the library rather than after it: it calls
worldMap, which does not exist in the published 0.3.0, so a demo published against^0.3.0would resolve the old library and crash on the world screen.Checks
bun testandnode --testphpize, built in CI)bun install --frozen-lockfileclean;node apps/demo/bin/hqtui-demo.mjs --versionprintshqtui-demo 0.4.0🤖 Generated with Claude Code
https://claude.ai/code/session_01VhrgsHr1C5BYxXDpN1mahf