Skip to content

refactor: split codegen/preview.zig into focused sub-modules (behavior-preserving) - #547

Merged
apotema merged 1 commit into
mainfrom
refactor/split-preview
Jul 5, 2026
Merged

apotema merged 1 commit into
mainfrom
refactor/split-preview

Conversation

@apotema

@apotema apotema commented Jul 5, 2026 •

Copy link
Copy Markdown
Contributor

What

Pure, behavior-preserving extraction of the 1310-line preview-mode codegen string-template module src/codegen/preview.zig into a preview/ sub-package + thin barrel. Follows the proven #539/#541 pattern (barrel re-exports the full public surface by name; sub-files path-@imported; no build.zig change).

The whole module is pub const string literals (no logic, no functions, no cross-references), so the seams are clean and there are no shared helpers to hoist.

Sections extracted (name / responsibility / original line-range)

Sub-module Responsibility orig lines
preview/wasm_workaround.zig Zig 0.16 wasm32-emscripten panic/debug-io workarounds (WASM_PANIC_WORKAROUND, WASM_DEBUG_IO_WORKAROUND) 31–101
preview/helpers.zig module-scope clock/getenv helper + raylib desktop PBO readback bridges (PREVIEW_HELPERS, PREVIEW_READBACK_HELPERS) 103–176
preview/loop.zig loop-backend snippets (raylib/sdl/bgfx/wgpu): setup, readback, heartbeat, input dispatch (6 consts) 178–346
preview/callback.zig callback-backend snippets (sokol, raylib wasm): init/cleanup/heartbeat (3 consts) 348–424
preview/sokol_gl.zig sokol GL PBO readback (4 consts) 426–657
preview/sokol_d3d11.zig sokol D3D11 staging-texture readback (4 consts) 659–838, 934–945, 961–1124, 1183–1207
preview/sokol_metal.zig sokol Metal/IOSurface readback, Path A (5 consts) 840–932, 947–959, 1126–1225
preview/editor.zig editor-preview codegen, labelle-studio Play mode (3 consts) 1227–1310

The D3D11/Metal decls were interleaved in the original (helpers → init → frame → cleanup, alternating backend); the split groups them by backend, so each sub-module reads top-to-bottom as one story.

Unchanged public surface

All 28 pub const snippets are re-exported from the barrel under their original names/identities. preview.<Name> call sites (main_zig.zig, codegen/lifecycle/render.zig, codegen/blocks/imports.zig) are untouched.

Verification

  • zig build compiles on 0.16.0
  • zig build test green (exit 0; benign --listen=- expected-error stderr)
  • Golden suite (main_zig_tests, incl. bgfx_wasm_editor_preview_main.zig) + preview_mode_tests pass — zero golden diff, no golden file changed per git status (only preview.zig modified + preview/ added)
  • zig fmt --check clean

Line counts

  • Before: preview.zig = 1310 lines
  • After: barrel preview.zig = 79; sub-modules 74–387 each (largest sokol_d3d11.zig = 387); total 1376 (delta = per-file headers/barrel boilerplate)

Pure extraction — any bug a reviewer spots in the moved code is pre-existing (copied verbatim); flag for follow-up rather than fixing here.

https://claude.ai/code/session_017pW3ifKf9wgxNg4viy6okw

Summary by CodeRabbit

  • New Features

    • Expanded preview support across more rendering paths, including desktop, WebAssembly, and multiple graphics backends.
    • Added editor-preview integration so preview builds can sync simulation and editor state during runtime.
    • Improved preview connection and frame-stream handling for smoother live updates.
  • Bug Fixes

    • Added platform-specific safeguards to keep preview builds working on unsupported targets.
    • Improved cleanup and heartbeat handling to reduce preview disconnects and stale input events.

…r-preserving)

Pure extraction of the 1310-line preview-mode codegen string-template
module into a `preview/` sub-package + thin barrel. Every `pub const`
keeps its original name/identity; `preview.<Name>` call sites unchanged.

Sub-modules:
  - preview/wasm_workaround.zig  Zig 0.16 wasm32-emscripten panic/debug-io
  - preview/helpers.zig          clock/getenv helper + raylib PBO bridges
  - preview/loop.zig             loop-backend setup/readback/heartbeat/input
  - preview/callback.zig         callback-backend init/cleanup/heartbeat
  - preview/sokol_gl.zig         sokol GL PBO readback
  - preview/sokol_d3d11.zig      sokol D3D11 staging-texture readback
  - preview/sokol_metal.zig      sokol Metal/IOSurface readback (Path A)
  - preview/editor.zig           editor-preview codegen (labelle-studio)

Byte-identical output: golden suite (main_zig_tests) + preview_mode_tests
green, no golden file changed. zig build + zig fmt --check clean on 0.16.0.

Claude-Session: https://claude.ai/code/session_017pW3ifKf9wgxNg4viy6okw
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@coderabbitai

coderabbitai Bot commented Jul 5, 2026 •

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The monolithic src/codegen/preview.zig template module is split into focused sub-modules under src/codegen/preview/ (wasm workaround, helpers, loop, callback, editor, sokol_gl, sokol_metal, sokol_d3d11). The barrel file now imports these and re-exports the same public template constants with no behavior changes.

Changes

Preview codegen modularization

Layer / File(s) Summary
Barrel module re-exports
src/codegen/preview.zig
The monolithic module is reduced to imports of new sub-modules and re-exports of all previously inline template constants.
Wasm panic/debug-io workarounds
src/codegen/preview/wasm_workaround.zig
Adds WASM_PANIC_WORKAROUND and WASM_DEBUG_IO_WORKAROUND snippets overriding std_options_debug_io/panic for Zig 0.16 wasm32-emscripten builds.
Core preview/readback helpers
src/codegen/preview/helpers.zig
Adds PREVIEW_HELPERS (getenv/clock_gettime timestamp) and PREVIEW_READBACK_HELPERS (raylib desktop PBO bridge functions).
Callback-style backend templates
src/codegen/preview/callback.zig
Adds PREVIEW_INIT_CALLBACK, PREVIEW_CLEANUP_CALLBACK, PREVIEW_HEARTBEAT_CALLBACK for connect/hello, bye, and per-frame input dispatch.
Loop-style backend templates
src/codegen/preview/loop.zig
Adds PREVIEW_LOOP_SETUP, PREVIEW_READBACK_SETUP, PREVIEW_HEARTBEAT_LOOP, PREVIEW_INPUT_DISPATCH(_STUB), and PREVIEW_READBACK_LOOP for raylib desktop loop backends.
Sokol GL readback backend
src/codegen/preview/sokol_gl.zig
Adds PBO-ring based GL readback helper, init, per-frame, and cleanup templates gated by OS.
Sokol Metal/IOSurface readback backend
src/codegen/preview/sokol_metal.zig
Adds Metal/IOSurface bridge, init, pre/post-render, and cleanup templates for Path-A preview readback.
Sokol D3D11 readback backend
src/codegen/preview/sokol_d3d11.zig
Adds COM/vtable dispatch helpers plus init, per-frame staging-texture readback, and cleanup templates for Windows.
Editor-preview binding templates
src/codegen/preview/editor.zig
Adds EDITOR_PREVIEW_BIND, EDITOR_PREVIEW_SIM_OPEN, EDITOR_PREVIEW_SIM_CLOSE snippets for editor-preview build wiring.

Estimated code review effort: 3 (Moderate) | ~30 minutes

Possibly related PRs

Poem

A thousand lines once tangled tight,
now hop apart, each snippet right.
Metal, GL, and D3D11 too,
each burrow small, each purpose true.
🐇 Thump! The barrel file stands neat—
modular code, a rabbit's treat.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the main refactor and correctly notes the behavior-preserving module split.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch refactor/split-preview

Comment @coderabbitai help to get the list of available commands.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request refactors src/codegen/preview.zig by splitting the large ~1300-line module into several smaller, focused sub-modules under the preview/ directory, including wasm_workaround.zig, helpers.zig, loop.zig, callback.zig, sokol_gl.zig, sokol_d3d11.zig, sokol_metal.zig, and editor.zig. The original preview.zig file has been converted into a thin barrel file that re-exports all public constants, preserving behavior and keeping existing call sites unchanged. There are no review comments to evaluate, and I have no feedback to provide.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (3)
src/codegen/preview/helpers.zig (1)

29-77: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Doc comment no longer matches the body it documents.

The /// doc comment (lines 29-38) advertises "Raw GL externs + constants" and "GL 2.1 / 3.3 core values", but the actual PREVIEW_READBACK_HELPERS string only contains engine.Preview bridge wrapper functions — no GL externs or constants at all. The inline comment inside the string (lines 41-47) correctly describes this bridge-only design ("All GL state + PBO ring... now lives in the external labelle-raylib package"), which suggests the outer doc comment is stale from before that refactor and wasn't updated when this content was carried into the new sub-module.

✏️ Suggested doc fix
-/// Raw GL externs + constants needed for the raylib desktop PBO-based
-/// async readback path. Raylib links the platform's OpenGL loader on
-/// desktop (CGL / GLX / WGL), so PBO entry points are present as
-/// regular `extern "c"` symbols — `@extern` here resolves them at link
-/// time without any extra dependency.
-///
-/// Concatenated into `module_vars` for raylib-desktop only. Other
+/// Tiny `*anyopaque`-boundary bridge functions wrapping `engine.Preview`
+/// readback methods (PBO + IOSurface variants) for the raylib desktop
+/// backend. All actual GL state / PBO ring / IOSurface machinery now
+/// lives in the external labelle-raylib package.
+///
+/// Concatenated into `module_vars` for raylib-desktop only. Other
 /// loop backends (sdl/bgfx/wgpu) don't use these and don't ship them
-/// (their readback story is a separate ticket). The constants are GL
-/// 2.1 / 3.3 core values — stable across drivers and platforms.
+/// (their readback story is a separate ticket).
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/codegen/preview/helpers.zig` around lines 29 - 77, Update the doc comment
above PREVIEW_READBACK_HELPERS so it matches the current body: it no longer
contains raw GL externs/constants, only the bridge wrappers around
engine.Preview methods. Remove the stale GL 2.1/3.3 wording and describe this
constant as the preview readback bridge helpers used by the raylib-desktop path,
keeping the comment aligned with the existing inline notes and the
_preview_pbo_* bridge functions.
src/codegen/preview/callback.zig (1)

60-80: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Indentation-vs-doc-comment mismatch (cosmetic).

The doc comment says this heartbeat has "one extra indent level vs. the loop variant", but the string body actually starts at 4 spaces here vs. 8 spaces in PREVIEW_HEARTBEAT_LOOP — i.e. the loop variant has more indentation, not less. Since zig fmt normalizes the final generated output, this has no functional impact — just a confusing comment for future maintainers reasoning about paste-site indentation.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/codegen/preview/callback.zig` around lines 60 - 80, The doc comment on
PREVIEW_HEARTBEAT_CALLBACK describes the indentation relationship backwards
relative to PREVIEW_HEARTBEAT_LOOP, so update the comment to match the actual
generated string bodies. Keep the explanation aligned with the callback
generator’s real paste-site indentation and make sure the comparison to the loop
variant is stated consistently in PREVIEW_HEARTBEAT_CALLBACK and the related
PREVIEW_HEARTBEAT_LOOP constant.
src/codegen/preview/loop.zig (1)

39-77: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Doc comments describe an older, more elaborate PBO-ring design than the code below actually implements.

The doc block above PREVIEW_READBACK_SETUP (lines 39-57) still talks about "the PBO ring + CPU staging buffer locals that PREVIEW_READBACK_LOOP uses" and a deferred "GL/SHM teardown" with an _gl_delete_buffers symbol — none of which appear in the actual template body (lines 58-77), which just wires bridge functions into window.preview_pbo and defers window.preview_pbo.deinit(). Likewise, the doc above PREVIEW_READBACK_LOOP (lines 133-165) extensively describes a "3-deep PBO ring" / glMapBuffer / resize-handling algorithm that the actual body (lines 166-172) no longer implements — it just calls window.preview_pbo.frame(), delegating everything to the backend package per the labelle-assembler#140 refactor mentioned inline at line 59-62.

These are internal doc comments only (no functional impact), but they're actively misleading about where the readback logic now lives, which could send a future maintainer down the wrong path when debugging.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/codegen/preview/loop.zig` around lines 39 - 77, Update the doc comments
for PREVIEW_READBACK_SETUP and PREVIEW_READBACK_LOOP so they match the current
implementation: remove references to the old PBO ring, CPU staging buffer
locals, GL/SHM teardown, _gl_delete_buffers, glMapBuffer, and resize-handling
logic. Keep the docs focused on the actual behavior in PREVIEW_READBACK_SETUP
(wiring window.preview_pbo bridges and deferring window.preview_pbo.deinit())
and PREVIEW_READBACK_LOOP (delegating to window.preview_pbo.frame() via the
backend package).
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/codegen/preview/editor.zig`:
- Around line 54-55: The generated comment text in editor preview is
grammatically broken because the string in the editor-preview emitter is used
verbatim in generated main.zig. Update the comment text near the editor_* export
handling in the editor-preview code path so it reads naturally (fix “this arms”
and the awkward “emcc link’s” phrasing) while preserving the same meaning about
EXPORTED_FUNCTIONS keeping the exports alive.

In `@src/codegen/preview/wasm_workaround.zig`:
- Around line 4-12: The stray PID note is misplaced in wasm_workaround.zig; this
file should only contain the two wasm workaround snippets. Remove the comment
block from this module and move any PID/hello-message explanation to the
handshake-related code that actually uses it, or delete it if it is no longer
needed. Use the existing snippet definitions in wasm_workaround.zig to keep the
file focused on workaround strings only.

---

Nitpick comments:
In `@src/codegen/preview/callback.zig`:
- Around line 60-80: The doc comment on PREVIEW_HEARTBEAT_CALLBACK describes the
indentation relationship backwards relative to PREVIEW_HEARTBEAT_LOOP, so update
the comment to match the actual generated string bodies. Keep the explanation
aligned with the callback generator’s real paste-site indentation and make sure
the comparison to the loop variant is stated consistently in
PREVIEW_HEARTBEAT_CALLBACK and the related PREVIEW_HEARTBEAT_LOOP constant.

In `@src/codegen/preview/helpers.zig`:
- Around line 29-77: Update the doc comment above PREVIEW_READBACK_HELPERS so it
matches the current body: it no longer contains raw GL externs/constants, only
the bridge wrappers around engine.Preview methods. Remove the stale GL 2.1/3.3
wording and describe this constant as the preview readback bridge helpers used
by the raylib-desktop path, keeping the comment aligned with the existing inline
notes and the _preview_pbo_* bridge functions.

In `@src/codegen/preview/loop.zig`:
- Around line 39-77: Update the doc comments for PREVIEW_READBACK_SETUP and
PREVIEW_READBACK_LOOP so they match the current implementation: remove
references to the old PBO ring, CPU staging buffer locals, GL/SHM teardown,
_gl_delete_buffers, glMapBuffer, and resize-handling logic. Keep the docs
focused on the actual behavior in PREVIEW_READBACK_SETUP (wiring
window.preview_pbo bridges and deferring window.preview_pbo.deinit()) and
PREVIEW_READBACK_LOOP (delegating to window.preview_pbo.frame() via the backend
package).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 3fe639e0-1f48-4a82-afaf-fb66e287d3d9

📥 Commits

Reviewing files that changed from the base of the PR and between cd062ec and e2102c4.

📒 Files selected for processing (9)
  • src/codegen/preview.zig
  • src/codegen/preview/callback.zig
  • src/codegen/preview/editor.zig
  • src/codegen/preview/helpers.zig
  • src/codegen/preview/loop.zig
  • src/codegen/preview/sokol_d3d11.zig
  • src/codegen/preview/sokol_gl.zig
  • src/codegen/preview/sokol_metal.zig
  • src/codegen/preview/wasm_workaround.zig

Comment on lines +54 to +55
\\ // The `editor_*` C exports this arms are kept alive by the emcc
\\ // link's -sEXPORTED_FUNCTIONS list (backend hook, editor-preview arm).

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Grammar error in generated comment string.

"The editor_* C exports this arms are kept alive by the emcc link's..." is garbled — this comment text is emitted verbatim into generated main.zig for editor-preview builds.

✏️ Proposed fix
-    \\    // The `editor_*` C exports this arms are kept alive by the emcc
-    \\    // link's -sEXPORTED_FUNCTIONS list (backend hook, editor-preview arm).
+    \\    // The `editor_*` C exports are kept alive by the emcc link's
+    \\    // -sEXPORTED_FUNCTIONS list (backend hook, editor-preview arm).
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
\\ // The `editor_*` C exports this arms are kept alive by the emcc
\\ // link's -sEXPORTED_FUNCTIONS list (backend hook, editor-preview arm).
\\ // The `editor_*` C exports are kept alive by the emcc link's
\\ // -sEXPORTED_FUNCTIONS list (backend hook, editor-preview arm).
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/codegen/preview/editor.zig` around lines 54 - 55, The generated comment
text in editor preview is grammatically broken because the string in the
editor-preview emitter is used verbatim in generated main.zig. Update the
comment text near the editor_* export handling in the editor-preview code path
so it reads naturally (fix “this arms” and the awkward “emcc link’s” phrasing)
while preserving the same meaning about EXPORTED_FUNCTIONS keeping the exports
alive.

Comment on lines +4 to +12
// PID is purely informational in the `hello` message — the editor
// uses it for UI display, not for any process management. Earlier
// snippets tried a per-OS comptime branch (`std.posix.getpid()` on
// POSIX, kernel32 on Windows) but `std.posix.getpid` isn't exposed
// in Zig 0.15.2's stdlib (only `std.os.linux.getpid` and
// `std.c.getpid` exist, and the latter requires linking libc which
// not every backend does). Simplest portable fix: send 0. A
// follow-up can wire the real PID once we settle on a stdlib import
// that's universal across our backends.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '--- wasm_workaround.zig ---'
git ls-files src/codegen/preview/wasm_workaround.zig
cat -n src/codegen/preview/wasm_workaround.zig

echo
echo '--- search for PID / hello references in preview codegen ---'
rg -n --hidden --glob '!**/.git/**' -S 'getpid|PID|hello message|hello|handshake|kernel32|std\.posix\.getpid|std\.os\.linux\.getpid|std\.c\.getpid' src/codegen src || true

Repository: labelle-toolkit/labelle-assembler

Length of output: 7684


Remove the stray PID comment block
This note about the hello message/PID doesn’t belong in src/codegen/preview/wasm_workaround.zig; the file only defines the two wasm workaround snippets. Move it to the handshake code or delete it.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/codegen/preview/wasm_workaround.zig` around lines 4 - 12, The stray PID
note is misplaced in wasm_workaround.zig; this file should only contain the two
wasm workaround snippets. Remove the comment block from this module and move any
PID/hello-message explanation to the handshake-related code that actually uses
it, or delete it if it is no longer needed. Use the existing snippet definitions
in wasm_workaround.zig to keep the file focused on workaround strings only.

@apotema
apotema merged commit fec1e0d into main Jul 5, 2026
4 checks passed
@apotema
apotema deleted the refactor/split-preview branch July 5, 2026 15:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant