v0.6.1 aa12db3

layout.md RawHistoryFolder

Logical layout

internal/layout.Layout(root, Options{Width, Height, TextEngine}) accepts a transient tree of Node{ID, Kind, Style, Children, Content, ImageSize, Measure, ScrollX, ScrollY}. Styles are borrowed immutable *css.Style values from css.Engine.Compute (normally compiled with css.UA()). A nil style receives minimal block defaults; use computed CSS for complete visual defaults. IDs are supplied by the frame-tree adapter and should be unique. Input must be acyclic, with depth at most 256; no renderer resources or parent pointers are retained. The caller owns the decoded images: use internal/image.Decode for bounded PNG/JPEG bytes or internal/image.Size for existing Go images, then put the intrinsic size on the node. Byte input must itself be bounded by the reader before decoding.

Kind differentiates image/text intrinsic measurement, Stack overlay, and Scroll clipping. Flex is selected by the computed display:flex, with row/column UA defaults overridable by author CSS. Block children flow vertically; Stack children share the origin, paint in input order, and hit-test in reverse order. Flex supports row/column, wrap, grow/shrink/basis, row/column gaps, align-self/items and justify-content. CSS px is logical; computed em/rem have already become px; % dimensions use the containing content box and padding/margins use containing width. Auto width fills the containing width except images; auto height fits the children. Oversized/negative/nonfinite geometry is clamped to bounded logical coordinates. CSS display:none drops a subtree. Overflow hidden/auto/scroll emits a content clip per axis, leaving visible axes unbounded; only scroll/auto (or Scroll kind) consumes offsets, clamped to the measured content extent. The caller supplies offset; there is no scroll event policy here.

Output.Tree is JSON-safe geometry and measured content extent. Output.Display contains ordered JSON-safe commands (shadow, rect, border, outline, clip-push, text, image, clip-pop). Glyph rune-cluster offsets and shaped glyph positions are copied to text commands. Each display-list Run also borrows its shaped *text.Face for in-process rasterization and carries serializable FaceID and Size (the logical font size used for shaping). Face is omitted from JSON; decoding JSON alone cannot reconstruct a face, so a renderer consuming serialized commands must resolve FaceID to a matching font before rasterizing. The original text.Line values remain on tree nodes for in-process use and are omitted from JSON. Image commands reference node IDs; the renderer adapter resolves their pixels. Hit applies ancestor clips and reverse child order. Pointer capture, focus and tab ordering are separate runtime responsibilities. Physical independently rounds logical rectangle edges using a fractional Wayland scale at the renderer boundary; do not use physical coordinates for hit tests. JSON snapshots under internal/layout/testdata validate tree and list structure, not rendered pixels.

Options.Arena supplies reusable storage for the tree and display list. An Output is valid until its arena is passed to Layout again; the runtime alternates two arenas so the committed layout stays readable while the next frame is laid out. The superseded layout, including its images and text, stays reachable until the next build reuses its arena. Without an arena, Layout returns a detached Output.

Known bounds: layout does not implement CSS margin collapse, absolute positioning, baseline alignment, align-content, or CSS transforms. Shadow and border commands carry geometry/style data for the renderer; decoration rasterization is not owned here. Text requires a provided text.Engine or a synchronous measure callback. Computed line-height repositions shaped baselines, text-align offsets runs within each content line, and letter-spacing is applied to shaped clusters before the text engine wraps (via the additive text.Request.LetterSpacing option). A synchronous callback's result must be immutable for the duration of layout; do not share a mutable shaping engine across goroutines.

source
1# Logical layout
2
3`internal/layout.Layout(root, Options{Width, Height, TextEngine})` accepts a transient tree of `Node{ID, Kind, Style, Children, Content, ImageSize, Measure, ScrollX, ScrollY}`. Styles are borrowed immutable `*css.Style` values from `css.Engine.Compute` (normally compiled with `css.UA()`). A nil style receives minimal block defaults; use computed CSS for complete visual defaults. IDs are supplied by the frame-tree adapter and should be unique. Input must be acyclic, with depth at most 256; no renderer resources or parent pointers are retained. The caller owns the decoded images: use `internal/image.Decode` for bounded PNG/JPEG bytes or `internal/image.Size` for existing Go images, then put the intrinsic size on the node. Byte input must itself be bounded by the reader before decoding.
4
5`Kind` differentiates image/text intrinsic measurement, Stack overlay, and Scroll clipping. Flex is selected by the computed `display:flex`, with row/column UA defaults overridable by author CSS. Block children flow vertically; Stack children share the origin, paint in input order, and hit-test in reverse order. Flex supports row/column, wrap, grow/shrink/basis, row/column gaps, align-self/items and justify-content. CSS `px` is logical; computed `em`/`rem` have already become `px`; `%` dimensions use the containing content box and padding/margins use containing width. Auto width fills the containing width except images; auto height fits the children. Oversized/negative/nonfinite geometry is clamped to bounded logical coordinates. CSS `display:none` drops a subtree. Overflow hidden/auto/scroll emits a content clip per axis, leaving visible axes unbounded; only scroll/auto (or Scroll kind) consumes offsets, clamped to the measured content extent. The caller supplies offset; there is no scroll event policy here.
6
7`Output.Tree` is JSON-safe geometry and measured content extent. `Output.Display` contains ordered JSON-safe commands (`shadow`, `rect`, `border`, `outline`, `clip-push`, `text`, `image`, `clip-pop`). Glyph rune-cluster offsets and shaped glyph positions are copied to text commands. Each display-list `Run` also borrows its shaped `*text.Face` for in-process rasterization and carries serializable `FaceID` and `Size` (the logical font size used for shaping). `Face` is omitted from JSON; decoding JSON alone cannot reconstruct a face, so a renderer consuming serialized commands must resolve `FaceID` to a matching font before rasterizing. The original `text.Line` values remain on tree nodes for in-process use and are omitted from JSON. Image commands reference node IDs; the renderer adapter resolves their pixels. `Hit` applies ancestor clips and reverse child order. Pointer capture, focus and tab ordering are separate runtime responsibilities. `Physical` independently rounds logical rectangle edges using a fractional Wayland scale at the renderer boundary; do not use physical coordinates for hit tests. JSON snapshots under `internal/layout/testdata` validate tree and list structure, not rendered pixels.
8
9`Options.Arena` supplies reusable storage for the tree and display list. An `Output` is valid until its arena is passed to `Layout` again; the runtime alternates two arenas so the committed layout stays readable while the next frame is laid out. The superseded layout, including its images and text, stays reachable until the next build reuses its arena. Without an arena, `Layout` returns a detached `Output`.
10
11Known bounds: layout does not implement CSS margin collapse, absolute positioning, baseline alignment, `align-content`, or CSS transforms. Shadow and border commands carry geometry/style data for the renderer; decoration rasterization is not owned here. Text requires a provided `text.Engine` or a synchronous measure callback. Computed line-height repositions shaped baselines, text-align offsets runs within each content line, and letter-spacing is applied to shaped clusters before the text engine wraps (via the additive `text.Request.LetterSpacing` option). A synchronous callback's result must be immutable for the duration of layout; do not share a mutable shaping engine across goroutines.

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 1

Tags 12

↑↓ moveenter openesc close