feat(rust): honor width / height / fill on row + column scene layouts#1000
Merged
Conversation
Schema already had `width` / `height` as `Dim::Cells(n) | Dim::Fill` on box children, but the Rust render layer ignored both — every row child fell back to its intrinsic width and every column child to its intrinsic height. That made the schema's `direction: row` only useful for content-packed rows, never for sized panes. ## Algorithm Walk children once; classify each: - explicit `Dim::Cells(n)` → reserve exactly n cells (capped at the remaining axis space, in source order) - explicit `Dim::Fill` → defer - unsized → reserve intrinsic size, capped at remaining After the first pass, split whatever's left equally among the deferred Fill children, distributing any pixel remainder to the leading ones so the total adds up to exactly the gap-adjusted axis budget. Gaps between siblings come off the top. ## Visible use `titleRow` is now a row box: brand on the left, model name on the right, with a `width: "fill"` spacer between them. Sets up the producer-side pattern that the upcoming three-pane layout PR (Sidebar / Main / ContextPanel) will reuse — sidebar gets a fixed cell width, main gets `Dim::Fill`, ctx panel gets its own fixed. ## Tests 9 new Rust cases on the layout algorithm (fixed reservation order, single Fill, multiple Fill, uneven remainder distribution, fixed clamped at remaining, intrinsic fallback for unsized, gap subtraction, column height variants). 2 new JS cases on the producer-side titleRow restructure (row box with brand + fill spacer + model; spacer-only row when no model). Refs #868
esengine
added a commit
that referenced
this pull request
May 16, 2026
…#1001) First concrete consumer of the new flex layout primitive (#1000) and the smallest visible step toward the multi-segment status bar the design mock points at. Wallet balance is the most direct visible signal of reasonix's cheap-positioning claim — users see how slowly the number goes down across a session. - New SceneTraceInput.walletBalance + walletCurrency scalars, primitives so effect deps stay stable. - statusRow upgrades from a single text node to a row box only when the balance is present: left segments (cardCount · busy/idle · activity) + fill spacer + right segment (`wallet ¥184.20`). When balance is null/undefined the row stays a single text node — back-compat with the existing test that asserts `kind === "text"` on the status row. - Currency rendering: ¥ for CNY/RMB/JPY, $ for USD, € EUR, £ GBP; unknown codes fall back to `CODE 5.00` so nothing silently looks like the wrong currency. - App.tsx forwards `balance.total` and `balance.currency` from useSessionInfo — both null until the first successful getBalance() call, so the wallet segment appears once the endpoint responds and stays hidden offline. Cache-hit %, branch, spent (this session), jobs count all also belong in this row; each is a small isolated wiring step from here. Refs #868 Co-authored-by: reasonix <reasonix@deepseek.com>
esengine
added a commit
that referenced
this pull request
May 16, 2026
…/ContextPanel layout (#1003) Stage 1 toward the user's design mock — restructure from a flat column of rows to the classic IDE three-pane shape: ┌───────────── title (full width) ─────────────┐ │ SIDEBAR (24) │ MAIN (fill) │ CTX (32) │ └───────────── status (full width) ────────────┘ The middle band is a `direction: "row"` box with `height: "fill"`, made possible by the flex-sizing infra from #1000. Sidebar and ctx pane have fixed cell widths; main pane fills the remainder. Both side panes auto-hide on narrow terminals — sidebar below 60 cols, ctx pane below 100 cols — so an 80-col terminal still works the way it did before, just with a sessions-rail on the left. ## Main pane content (unchanged) The cards stack, composer / approval / sessions-picker takeover, slash overlay — exactly the same nodes as before, now living inside the main pane's column instead of inline in the root. ## Sidebar (stage-1 placeholder) Just a `─ SESSIONS ─` header + `use /sessions to browse` hint. The real session list goes here in stage 2 once App.tsx surfaces a permanently-loaded list (today it's loaded only when the picker is open). ## Context pane (uses what's wired) `─ CONTEXT ─` + `model · cards · wallet`. Wallet moves from the status row into the ctx pane when both are visible — avoids duplicating it. At cols < 100 the ctx pane is hidden and wallet stays on the right of the status row (as in #1001). ## Test rewrite The flat-children shape was load-bearing in 15 tests. Added two helpers — `mainOf(f)` / `statusOf(f)` / `titleOf(f)` — and rewrote each test to drill through the new structure. Coverage is identical in spirit (still asserts behavior of card rows, composer, approval modal, sessions picker, slash overlay, status segments) but expressed in terms of the new hierarchy. 3 new shape tests: - root is now `[title, middle, status]` (3 children, not 4-7) - sidebar hidden below 60 cols - ctx pane hidden below 100 cols Refs #868 Co-authored-by: reasonix <reasonix@deepseek.com>
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.
Unblocks multi-pane scene layouts. Foundation PR for the
`Sidebar / Main / ContextPanel` three-pane layout the user's
design mock points at.
Why
The scene schema already declared `width` / `height` on
`BoxLayout` as `Dim::Cells(n) | Dim::Fill`, but the Rust render
layer ignored both — every row child fell back to its intrinsic
width and every column child to its intrinsic height. That made
`direction: row` only useful for content-packed rows, never for
sized panes (244-cell sidebar + fluid main + 320-cell context panel
was literally not expressible end-to-end).
Algorithm
Single-pass distribution per axis:
(first-come basis, source order).
Pixel remainder goes to the leading Fill children so the total
adds up to exactly the gap-adjusted axis budget.
Backward compatible — every existing scene (column with unsized
children, row with intrinsic-width chips) keeps rendering identically.
Visible use
`titleRow` is now a row box: brand on the left, model name on the
right, `width: "fill"` spacer between them. Same pattern the
upcoming three-pane layout PR will use — sidebar with
`Dim::Cells(n)`, main with `Dim::Fill`, ctx panel with its own
fixed cell width.
Tests
`crates/reasonix-render/tests/render.rs` — 9 new cases:
`tests/scene-trace-frame.test.ts` — 2 new cases on the producer-side
`titleRow` restructure.
`cargo test -p reasonix-render --test render` → 17/17 green.
`npm run verify` → green via prepush gate.
What still doesn't work
still ignores them. `Dim::Fill` is the primary way to grow.
currently done by inserting a Fill spacer before the right-aligned
child, as the new `titleRow` does.)
Each of these is a small isolated follow-up; `width` / `height`
was the highest-impact one because it unlocks fixed-sized panes.
Refs #868