feat(viz): number mbtx source lines in both HTML renders - #1108
Conversation
An mbtx run's compiler diagnostics cite line:column positions into the submitted source, but neither the desktop transcript card nor the static viz export numbered the program - following a diagnostic meant counting lines by hand. Add a shared @syntax_html.moonbit_numbered_source helper that pairs each highlighted line with a right-aligned gutter, space-padded to the last line's number width so the per-row grids stay aligned across digit boundaries. Both mbtx render paths use it; the gutter reuses the read card's grid styling under shared moonbit-line/gutter/code classes and is user-select: none, so copied text stays pure source. The card also stops clamping the source through truncate_output: a clamp would misnumber every line after its skip marker, and card_fields' 128k-unit ceiling already bounds the payload (recorded calls top out at 37 lines / ~1.5k units against 101-line / 20k-unit thresholds). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EgSh3EMeThZdTLxfyHjC9a
One entry point with `numbered? : Bool = false` instead of a separate moonbit_numbered_source: the transcript card and viz export opt in, the composer's approval body keeps the un-numbered default - there are no diagnostics to match at approval time, and its comment now records that choice instead of claiming identity with the transcript render. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EgSh3EMeThZdTLxfyHjC9a
Codex review of #1108 flagged that dropping truncate_output left the numbered render unbounded: the 128k-unit card ceiling still admits tens of thousands of two-character lines, and the viz export path had no ceiling at all. Bound it inside the numbered renderer, where numbering stays honest: past 501 lines the head 400 and tail 100 rows keep their true numbers around one unnumbered "lines skipped" row. Recorded programs top out near 40 lines, so the clamp is display-invisible in practice. Also per that review, add the missing regression coverage: a >101-line program renders every numbered line in both the card and the export (so reintroducing the transcript clamp would fail), one enormous line stays a single numbered row, and the degenerate clamp elides the middle under true tail numbers. The numbered branch moves to a private helper so the consolidated entry point stays a thin dispatch. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EgSh3EMeThZdTLxfyHjC9a
Codex CLI review (xhigh reasoning)An initial review pass requested two changes, addressed in c95a227:
Re-review verdict, verbatim:
Codex's read-only sandbox couldn't execute the test suite; run separately: 🤖 Generated with Claude Code |
The numbered? flag made one name return two structurally different DOM shapes - a single code element or a fragment of gutter-grid rows - and the caller must know which it asked for anyway to style it. Two named functions state that honestly; the tokenization stays shared through moonbit_source_lines. Rendering behavior is unchanged. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EgSh3EMeThZdTLxfyHjC9a
A fresh Codex review of #1108 flagged that the degenerate clamp decided what to keep only after moonbit_source_lines had materialized fragments for every line, and that the skip row's empty gutter collapsed its own grid's max-content column, shoving the marker out from under the code. Tokenization now takes a keep predicate: every line is still lexed so state flows across the skipped middle, but only kept lines inflate tokens and build spans. The skip row's gutter pads to the shared width, asserted by the clamp test. Rendered output is otherwise unchanged. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EgSh3EMeThZdTLxfyHjC9a
Fresh Codex CLI review (xhigh reasoning) — second passAn independent fresh-eyes pass at 14a8039 requested two fixes, addressed in 95d3459:
Final verdict, verbatim:
Run separately (Codex's sandbox is read-only): 🤖 Generated with Claude Code |
Summary
An
mbtxrun's compiler diagnostics citeline:columnpositions into the submitted source, but neither the desktop transcript card nor the static viz export numbered the program — following a diagnostic meant counting lines by hand.@syntax_html.moonbit_numbered_sourcehelper: each highlighted line gets a right-aligned gutter, space-padded to the last line's number width so per-row grids stay aligned across digit boundaries (line 9 →· 9, line 10 →10).moonbit-line/moonbit-gutter/moonbit-codeclasses and isuser-select: none, so copied text stays pure source.truncate_output: a clamp would misnumber every line after its skip marker, andcard_fields' 128k-unit ceiling already bounds the payload. Empirically (171 recorded calls), sources top out at 37 lines / ~1.5k UTF-16 units against the 101-line / 20k-unit truncation thresholds, so the clamp had never fired.Display-only: nothing under
agent_tool/mbtx/, the protocol, or prompts changed.Test plan
moon checkclean; fullmoon testpasses (2065 native + 34 js).🤖 Generated with Claude Code
https://claude.ai/code/session_01EgSh3EMeThZdTLxfyHjC9a