Skip to content

Add slide-* CLI subcommands for inspecting and rewriting Hazel slides#2282

Open
7h3kk1d wants to merge 1 commit into
devfrom
slide-cli
Open

Add slide-* CLI subcommands for inspecting and rewriting Hazel slides#2282
7h3kk1d wants to merge 1 commit into
devfrom
slide-cli

Conversation

@7h3kk1d
Copy link
Copy Markdown
Contributor

@7h3kk1d 7h3kk1d commented May 9, 2026

Summary

Adds three small hazel CLI subcommands for working with the documentation slides linked into the binary (the let out : ... PersistentSegment.t modules under src/web/init/docs/ and src/b2t2/slides/), plus two supporting tweaks to format and analyze and a small CLI refactor.

The design is deliberately minimal: slides are addressed by name, not by .ml file path, and the only slide-specific operations exposed are decode (slide → plaintext) and encode (plaintext → slide). Every other transformation (prettify, suppress unused-var warnings, static analysis) is done generically on the plaintext via the existing format and analyze commands.

Note

This is intended as a stopgap. Once #1487 ("Build step for building Init.ml editors") lands — replacing the serialized let out : ... PersistentSegment.t modules with plain-text slide files compiled into Init.ml at build time — these commands will likely be obviated or need to be reworked. At that point slide-decode collapses to cat, slide-encode collapses to writing the plain-text file, and only the trigger-syntax round-tripping (which would presumably move into whatever textual syntax #1487 adopts for projectors/refractors) carries over.

New slide commands

  • hazel slide-list — print the names of every slide statically linked into the binary.
  • hazel slide-decode <NAME> — look up a slide by name and print its program as plaintext. Manual refractors are rendered with ^^probe(...) / ^^statics(...) trigger syntax so the output is reparseable.
  • hazel slide-encode --title T <TEXT-or--> — build a slide .ml from a title and plaintext program, emitting the let out : ... PersistentSegment.t module form. Use -o to write to a file (otherwise stdout). Refractors written with trigger syntax in the input are rebuilt by the parser's Triggers module on insertion.

The slides are looked up out of Web.Init.documentation_slides : list((string, PersistentSegment.t)), a new top-level binding extracted from the existing inline list in Init.re. No on-disk .ml parsing is needed.

Supporting changes

  • hazel format now preserves refractors. It parses to a zipper instead of just a segment and threads z.refractors.manuals through Printer.of_segment, so ^^probe(...) / ^^statics(...) trigger syntax survives the pretty-print round-trip.
  • hazel analyze gains -W / --warnings. When set, warnings (currently just unused variables) are reported alongside errors using the same Rust-style source context.
  • Rust-style diagnostic rendering extracted to src/CLI/Diagnostic.re. Shared by analyze's error and warning paths; replaces ~140 lines of duplicated formatting in Cli.re with one helper plus two ~15-line wrappers.
  • src/CLI/README.md updated for the new commands, the --warnings flag, the corrected format / analyze behavior (the README had stale claims about both lacking source locations / preserving comments), and a note recommending NODE_OPTIONS="--max-old-space-size=4096" for analyze on larger inputs.

How they compose

A slide-level pretty-print is now just three commands piped together:

./hazel slide-decode "Probes" \
  | ./hazel format -w 60 - \
  | ./hazel slide-encode --title "Probes" - -o src/web/init/docs/Probes.ml

The same shape (decode → transform → encode) covers every workflow the earlier draft hard-coded into bespoke slide-prettify / slide-update / slide-suppress-warnings subcommands.

Test plan

  • make dev builds cleanly
  • ./hazel slide-list prints all expected names (BasicReference, Probes, etc., plus b2t2 entries)
  • ./hazel slide-decode "Probes" emits plaintext with ^^probe(...) markers intact
  • ./hazel slide-decode "Probes" | ./hazel format -w 60 - preserves refractor count
  • Full decode | format | encode round-trip produces a slide .ml whose re-decode matches refractor count (verified across all 50 docs+b2t2 slides)
  • ./hazel analyze -W on a program with an unused let-binding prints a warning: unused variable: <name> diagnostic with location

🤖 Generated with Claude Code

@codecov
Copy link
Copy Markdown

codecov Bot commented May 9, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 50.92%. Comparing base (d2e85b3) to head (f107e5c).

Additional details and impacted files
@@           Coverage Diff           @@
##              dev    #2282   +/-   ##
=======================================
  Coverage   50.91%   50.92%           
=======================================
  Files         300      300           
  Lines       39867    39867           
=======================================
+ Hits        20300    20302    +2     
+ Misses      19567    19565    -2     
Files with missing lines Coverage Δ
src/web/init/Init.re 34.48% <ø> (ø)

... and 10 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@7h3kk1d 7h3kk1d force-pushed the slide-cli branch 7 times, most recently from 1a582d0 to 0f0a2ba Compare May 14, 2026 19:00
@7h3kk1d 7h3kk1d requested a review from disconcision May 14, 2026 19:00
@7h3kk1d 7h3kk1d marked this pull request as ready for review May 14, 2026 19:00
Replaces the earlier draft slide commands (slide-info, slide-prettify,
slide-update, slide-suppress-warnings) with a smaller surface focused on
the plaintext representation:

- `hazel slide-list` prints the names of every slide statically linked
  into the binary (the docs under `src/web/init/docs/` plus `B2t2.Slides`).
- `hazel slide-decode <name>` looks up a slide by name and prints its
  program as plaintext. Manual refractors are rendered with
  `^^probe(...)` / `^^statics(...)` trigger syntax so the output is
  reparseable.
- `hazel slide-encode --title T <text-or-->` builds a slide `.ml` from a
  title and plaintext program, emitting the `let out : ...
  PersistentSegment.t` module form. Refractors written with trigger
  syntax in the input are rebuilt by the parser's Triggers module on
  insertion.

Other transformations (prettify, suppress unused-var warnings, static
analysis) are no longer slide-specific - they now compose with the
existing `hazel format` / `hazel analyze` commands on plaintext, e.g.

  ./hazel slide-decode "Probes" \
    | ./hazel format -w 60 - \
    | ./hazel slide-encode --title "Probes" - -o src/web/init/docs/Probes.ml

Supporting changes:

- `hazel format` now parses to a zipper and threads `z.refractors.manuals`
  through `Printer.of_segment`, so `^^probe(...)` / `^^statics(...)`
  trigger syntax survives the pretty-print round-trip.
- `hazel analyze` gains `-W` / `--warnings` to also report warnings (e.g.
  unused variables) alongside errors, with the same Rust-style source
  context. README correspondingly updated.
- `src/web/init/Init.re` extracts `documentation_slides : list((string,
  PersistentSegment.t))` as a top-level binding so the CLI can look up
  slides by name without re-reading the on-disk `.ml` source files.
- `src/CLI/Slide.re` shrinks accordingly: the OCaml string-literal
  scanner is gone; only the in-binary lookup and the `.ml` emitter
  remain.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
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