Expand description
Background cell-builder worker — replaces per-frame shape_line
with an off-thread cell matrix build.
S2.2 (2026-05-26).
§Why this exists
Per paramount goal #1 in CLAUDE.md:
Performance. UI thread does no I/O, no parsing, no shaping.
The cell-grid renderer (see
docs/dev/architecture/cell-grid-renderer.md) replaces the per-
frame shape_line path for code-class buffers. The matrix
producer must run off the UI thread; this module owns it.
§S2.2 scope — minimal
S2.2 lands the worker shell with the simplest possible build:
- one whole-doc
lattice_cells::CellMatrixper published document, - rows materialised from
snapshot.buffer.line(i)line-by-line, - cells carry the raw codepoint only (no syntax fg, no bg, no flags),
- no inlay splicing, no fold elision,
- no chunking (S2.4 lands that).
S2.3 will fold in syntax colour + inlays + folds; S2.4 will
switch to chunked mode once the input is above 4 × viewport_height
lines.
§Design (mirrors overlay_worker)
- Dispatch’s
publish_render_statepopulatescrate::render_state::CellsRenderStateinputs (snapshot,version, …) and firescrate::editor::CellsWake’sNotify. - The worker
notified().awaits the wake signal.Notifyis permit-style: a burst of publishes wakes the worker exactly once, after which the worker re-reads the latest snapshot. - On wake the worker reads
render_state.load_full().cells, compares itsversionagainst the currently-publishedlattice_cells::CellMatrix::version, and short-circuits on cache-hit. On miss it builds a fresh matrix and stores it via the sharedcells_matrix_cell: Arc<ArcSwap<CellMatrix>>.
§Renderer contract (S2.2 — not consumed yet)
Renderers will read with:
let rs = editor.render_state.load_full();
let matrix = rs.cells.matrix.load();
// matrix.slice(scroll, viewport_height) → CellSlice over &CellRowS3 (TUI) and S4 (GPU) are the cutover slices that begin consuming the matrix. S2.2 keeps the producer in place so the consumer slices land against a populated cell, not a stub.
Structs§
- Cell
Theme - T.5 (theme-system): the resolved theme read table + builtin ids the
cell builder threads in place of the old
&Theme.Copy(two refs), so it passes through the build chain for free. The builder uses it only for syntax-category + whitespace-marker styling. - Whitespace
Config - 2026-05-27:
display.whitespace.*snapshot consumed by the cell-builder when emitting cells. Mirrors theoption_cache.whitespace_*shape but lives here so the worker can be written without a config-crate import cycle.
Enums§
- Worker
Decision - Recompute decision the worker takes on a wake. Visible for
testing; the production loop calls
recomputedirectly.
Functions§
- gutter_
cols - Non-body columns a document pane reserves for its gutter:
line-number column + diagnostic + diff-sign cells. Mirrors the
TUI renderer’s
gutter_width + DIAG + DIFF(lattice-ui-tui:: render) and the GPUI peer’s gutter, reducing todigits + 5with line numbers on (leading pad 1 + digits + trailing pad 2 + DIAG 1 + DIFF 1) or a bare4with them off (2-cell margin + DIAG 1 + DIFF 1). - recompute
- Pure synchronous recompute. Reads the current published
CellsRenderState, iterates over every visible Document pane (cells.panes), and updates each pane’smatrixindependently. Returns the aggregate decision used to gate the rendererpaint_requestwake: - recompute_
pane - run
- Worker entry point spawned at boot. Loops forever, awaiting
the wake
Notify. Each wake re-reads the latestRenderState.cellsinputs and callsrecompute. - sync_
rebuild_ pane_ on_ edit - B2.3 (2026-06-04): the synchronous, edit-path-only
DisplayMatrixrebuild the actor runs in the publish tail (crate::dispatch’spublish_render_state) before the render state is stored, so the publisheddisplay_matrixis text-current the instant the renderer paints —version.textnever lags the snapshot, which is what retires the per-keystroke whole-viewport stale-guard flicker.