Follow-up to #31: the doc/lint/grammar checks moved to Ludic there; this ports the remaining docgen piece (gen.py / check.py / palette.py) so nothing in the documentation pipeline is Python any more. Three new `x` subcommands, all in Ludic and compiled by Ludic: - x docs-gen [--out DIR] the static-site generator: parses docs/language/** front-matter + bodies (fences, Parameters:), builds the section/symbol model, reads the asset templates, and emits every page + ns/color/api pages + the landing page + ludic-highlight.js + symbols.json + .nojekyll. - x docs-check [DIR] the coverage / integrity guard (required files, a page per inventory.json symbol, duplicate-token and one-dir-per-namespace guards, highlighter link targets). - x docs-palette the named-colour source of truth: the palette table moved into tools/x/docgen.ludic, emitting emit_color.ludic (pointer, not ptr) + palette.json. Verified against the Python oracle: `x docs-gen` reproduces all 466 output files BYTE-FOR-BYTE (a Ludic json.dumps/html.escape/front-matter port — ordered dicts, indent=2 vs compact, ensure_ascii \uXXXX, codepoint-aware truncation), and `x docs-check` matches check.py's pass/fail output. Wired into `x test` as a gate (docs-gen -> docs-check on a fresh site; docs-palette stays byte-identical). CI swap: ci.yml and docs.yml call the Ludic generator; docs.yml drops the python:3.12 container and bootstraps the toolchain from the IR seed instead. tools/docgen/{gen,check,palette}.py deleted; only assets/ + inventory.json remain. Completes #31's criterion 3. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
||
|---|---|---|
| .. | ||
| assets | ||
| inventory.json | ||
| README.md | ||
Ludic documentation generator
Generates the public documentation site (the pages branch) from a single
source of truth, so the site can never drift from the language.
Source of truth
docs/
language/<category>/<id>.md one file per symbol — keyword, type, phase,
builtin, namespace method, operator, annotation
language/<category>/_section.md section title + blurb + order
language/colors/palette.json the 221 named colors (generated by `x docs-palette`)
site/site.json landing-page messaging (hero, features, …)
site/snippets/*.ludic the code shown on the landing page (real programs)
tools/docgen/inventory.json the authoritative symbol set the coverage guard checks
A symbol file
---
id: screen-fill_rectangle # anchor + page name (screen-fill_rectangle.html)
name: Screen.fill_rectangle
category: screen
kind: namespace-method # keyword|type|phase|namespace-method|builtin|annotation|operator
tokens: Screen.fill_rectangle # literal token(s) the highlighter matches & links
sig: Screen.fill_rectangle(x, y, width, height, color)
tip: Draw a solid, filled rectangle. # one sentence — the hover-card summary
order: 1
ns: Screen # namespace-method only
member: fill_rectangle # namespace-method only
related: screen-clear screen-draw_rectangle
---
Rich description — inline `<code>`/`backticks`, "model instance" language.
Parameters: # for anything that takes arguments
- `x` — the left edge, in pixels
- `color` — the fill color, e.g. a `Color.*` name
```ludic
program Example { … descriptive-named, compilable … }
```
What it produces
One page per symbol (<id>.html), a namespace overview page per namespace
(ns-screen.html … ns-color.html), a searchable index (api.html, fuzzy
search over every symbol), the landing page (index.html), the
ludic-highlight.js highlighter (all its symbol tables, tips, per-item link
targets, per-parameter anchors and hover-card data generated from the sources
above), symbols.json, and .nojekyll.
In any code sample: keywords/types/builtins/annotations link to their page;
Screen.fill_rectangle links Screen → the namespace page and fill_rectangle
→ the method page separately; a named argument like width: links to that
parameter's anchor; Color.Charcoal links Color and Charcoal separately;
hovering any token shows a summary card from the real API data.
Build & check
The generator and its guards are written in Ludic and run through x — there is
no Python in the pipeline. assets/ (the CSS/HTML/JS templates) and
inventory.json are the only inputs the tools here still read directly.
bin/x docs-gen --out build/pages # generate the whole site
bin/x docs-check build/pages # coverage + duplicate-token + link guard
bin/x check-docs # parse every ```ludic doc fence
docs-check fails CI if any symbol in inventory.json lacks a page, if a token
is documented on two pages, or if a highlighter link points at a missing page —
so "every symbol is documented, autogenerated each time" is enforced. It needs a
built bin/x (bootstrapped from the IR seed with clang alone).
Publish
.forgejo/workflows/docs.yml bootstraps the toolchain from the IR seed and runs
x docs-gen + x docs-check on every push to main that touches docs/**,
tools/docgen/** or tools/x/**, and publishes the result to the pages branch
root. index.html + .nojekyll always stay at the root.
Colors
palette.json and selfhost/backend/stdlib/emit_color.ludic are both generated
by bin/x docs-palette from a single palette table — the pal_add(...) rows in
tools/x/docgen.ludic. Edit the table there and regenerate; do not hand-edit the
generated files.