WIP: Documentation #1512

Draft
jay wants to merge 128 commits from jay/gerbil:v0.19-documentation into v0.19-staging
Member

very much still WIP, not ready for review
preview hosted at https://gerbil.tungo.org/

  • {.gerbil} inline and gerbil fences link documented identifiers
  • {module=":std/foo"} declares the documented module
  • {.def} generates checked signatures; macros use handwritten grammar
  • gerbil-repl for repl, with outputs in committed _freeze/ files
very much still WIP, not ready for review preview hosted at https://gerbil.tungo.org/ - `{.gerbil}` inline and `gerbil` fences link documented identifiers - `{module=":std/foo"}` declares the documented module - `{.def}` generates checked signatures; macros use handwritten grammar - `gerbil-repl` for repl, with outputs in committed `_freeze/` files
jay added 112 commits 2026-10-15 06:57:45 +00:00
README.md now publishes as index.html. Historical VuePress URLs
and heading identifiers are not compatibility targets.
Each manual's root page lists its chapters in a ::: contents block, and doc/readme.md lists the four manuals in a ::: manuals block. The Guide's installation chapter moves from README.md to installation.md so the README can be the Guide's title page.
Manuals come from ::: contents blocks and start pages from ::: manuals; every page must appear in exactly one contents block. Generated directory indexes, the header bar and breadcrumbs are replaced by a manual rail with numbered contents and prev/up/next links. The default stylesheet moves to gxdoc/gxdoc.css and ships with subset Piazzolla and Fira Mono fonts under the SIL Open Font License.
Heading {module=...} attributes declare the module a section documents,
and {.def} signature blocks define the names it must export.  Scheme code
on every page links each identifier to the definition documenting its
binding, found by following re-exports through compiled module interfaces.
Documentation never loads module source or instantiates a module.
Each reference page beside a compiled module declares it in place of an
import tip, and each heading whose signature names exported bindings
becomes a {.def} block.  Headings for bindings the module does not
export are left unchanged.  Links to removed headings use the new
definition anchors, and an unclosed tip in the JSON page is closed.
Inline code in prose links like code blocks, and shows a definition's
metavariables within its description.  Links to :MODULE or :MODULE#NAME
refer to documentation by module path and must resolve.
Sites that document definitions get doc-index.html, an alphabetical
index, and a search form ranking definitions, modules, pages and
sections.  A small script makes search live and loads its data on first
use; without JavaScript the form opens the index.
Core forms such as if and define-values are bound in the expander's root
context and exported by no module, so :gerbil/core accounts for them.
The prelude's expander page now defines its core forms.
Preludes must be compiled too: the expander imports a module's prelude
without the import hook, so it is now imported first under the same
rule.  Each build refreshes interfaces that changed, so the preview
sees rebuilt packages.  Import filters narrow code context; vector
literals stay unlinked; := inside forms is not grammar; each name's
kind comes from its own signature line.  Duplicate definitions are
reported per module and name, and misplaced attributes on code blocks
and repeated module declarations are reported instead of crashing.
Sites with definitions publish gxdoc-inventory.ss, a data file of their
definitions.  A project's xrefs: configuration names other sites'
inventories and base URLs, so its code links to their definitions.
[term]{.dfn} defines a glossary term and [terms]{.term} refers to it,
matching case and plural forms like Scribble's tech.  gerbil doc
--coverage lists each declared module's undocumented exports.
{.def added=... deprecated=...} notes versions beside a definition's
kind, and a link with empty text shows its target's title, as Scribble's
history and secref do.
{.def name="x"} marks a block such as (define x (make-parameter #t))
as linked code defining x, like Scribble's defthing; the definer implies
its kind.
Headings over a definition form of an exported binding, such as
(defclass Exception ...), become {.def name=...} blocks.
Interface refresh now stamps every loaded interface, imported modules
and preludes included, and full builds retry modules that failed.
Search lists definitions first as documented, filters by page path, and
keeps its live region announced.  Inventory and search URLs encode page
paths; xrefs: bases get a final slash and are validated.  Incremental
previews rewrite search data and re-read inventories.  References inside
links no longer nest links, and nested group-in imports resolve.
Pages are interpreted from the Djot AST into gxdoc's model and rendered
by one HTML module instead of annotating djot->sxml output. Problems are
reported together as FILE:LINE:COLUMN: message: detail, without the
gxdoc: prefix.
The preview now publishes pages despite content problems and keeps the
last good site only for outline and configuration errors; the outline
is a tree even for cyclic contents blocks, so rendering cannot loop.
Code blocks are Gerbil when their language is gerbil and inline code when
it has the class gerbil; gxdoc's classes are errors where they do not
belong, and imports= may precede a Gerbil block.  The pages are converted
mechanically: readable ```scheme blocks and every {.def} block become
```gerbil, and inline code phase 1 linked is marked {.gerbil}.
`gerbil doc --signatures FILE` writes, for each definition, the signature
generated from its module's source and type information beside the one
the page writes, for reviewing before pages switch to generated ones.
Rendering is unchanged.  gxdoc.pkg gains sources:.
Slots show their contracts and defaults; a constructor method, type or
alias that cannot be found is an error instead of an invented signature;
the compiled-interface check covers keywords, values that became
procedures and missing optimizer files.  Caches belong to each build's
source index, unreadable sources are located errors, and the report
code moves to gxdoc/migrate.
Blocks list names for generated kinds; syntax keeps its grammar. Members of exported types are defined on their type's lines. Pages are rewritten to names-only definitions; the migration report is removed.
A type's own constructor method may be defined in another module, where gxc declares only NS#T::METHOD. Constructors, primitive predicates and t::t bindings no longer fail the consistency check; values, parameters and type options are checked too. Alias targets are classified by declaration, and their errors reported. Headers show final:/constructor: as compiled and transparent:/equal: as written.
call-with-temporary-file-name, call-with-temporary-file and call-with-temporary-directory declared => :string but return what PROC returns; optimized callers trusted the declaration ((fixnum? (call-with-temporary-file-name "x" (lambda (f) 42))) gave #f).
Types show their descriptor, unchecked accessors and an interface's instance predicates and constructors; a member with no line is an error; members of unexported types name their role. Own methods are indexed by method and confirmed by type, so a renamed type is found. An alias of syntax shows (defalias A B) with B's kind, and an alias's kind comes first from its own declaration. name= is an error; per-name problems point at their line. The preview watches sources: and the source and optimizer files read; sources: problems are configuration errors. Results are returned as values, not encoded.
Rewrite request.md's options and http-* entries, websocket-connect and websocket-request-handler, and lru-cache-flush! from the source; name keywords as callers write them; rename old parameter names inside code; fix stale defaults, grammar and descriptions; state call-with-temporary-file-name's result.
Unchecked (&) accessors and mutators are implementation names, which
coverage already ignores, so a type's slot lines no longer show them;
listing one alone is the "shows no line for it" error.  A slot line
without its slot is an internal error instead of "slot ?".  The manual
says so, and its problems sentence keeps its parentheticals with the
attributes they qualify.
- actor: ->> to an exited local actor times out (no actor error);
  remove set-default-reply-timeout!, which v0.19 does not define.
- uuid: remove make-uuid, uuid? and uuid=?, which the module does not
  export; UUID's definition covers make-UUID, UUID? and equal?.
- request: request-json and request-cookies are unimplemented stubs
  that always raise; list the default headers in the order sent.
- make-hash-table: describe lock: (a Locker) and check: from hash.ss.
- csv, decimal: name what the source/writer accept
  (with-buffered-reader/-writer).
- json: write-json with #f returns a string (json-test.ss).
- guide: describe read-json's results and write-json's inputs.
- c3: struct: is optional; name get-name: as callers write it.
- process, hash/misc: parameter and keyword names; rwlock: module name.
The owner decided that an identifier macro, used as a bare identifier, is written NAME -> result, as multicall-default -> symbol is; its name alone is not a grammar.
--update numbers objects as the session's matching outputs do; set-id
and sticky bits are masked; check=none partial imports are replayed;
an exited driver is never signalled; a late cleanup failure is the
run's problem; late output joins the last input, malformed output
between frames the next, and a hang after the last input reports its
timeout; --timeout and --jobs need --check-examples again.
std/list now defines unique, which the fixture used as its unbound name.
A pipe's column counts the characters of a string written to it past its
newlines, so a result after output ending in a newline was indented as
if it continued that output.
Laying a result out apart from the port lost the port's readtable, and
with it the #0= labels the REPL prints for shared structure.
freeze.ss reads, writes and replays _freeze recordings; nothing uses it
yet.  The driver frames an entry's error text with !ID, so output and
error text are recorded apart.
Outputs move to recordings; inputs that must raise are marked ; raises,
and blocks whose S5 wildcards hid random output are check=run.
Results go to _freeze/ (freeze-dir:), one file per page; --check
compares without writing, and --manual adds check=manual sessions.
Inputs that must raise are marked ; raises.
Examples that read the reader's files get setups that write them in
the session's directory instead, and are recorded.
Builds replay each page's recording from _freeze and stop on a missing
or stale one; an output line in a transcript is an error.  Page outputs,
wildcards and --update are gone.
The preview watches the freeze directory and renders again the pages
whose recordings changed; it marks an input without a current one.
(cherry picked from commit 6cc169664bc7b4f4558bdcc7329d6b911d459d6c)
Preserve manuals with --no-docs and remove them on named cleanup. Validate documentation destinations and reuse gxdoc dependency discovery.

Correct the pre-existing path-normalize* argument bug as approved: uninstall must remove its target, not the caller directory. Isolated tests preserve caller and sibling sentinels.

(cherry picked from commit d497bd3811944fc847034de10364c627e6510d85)
(cherry picked from commit d32f51531d0d64013a851272c250d24753fbaf85)
(cherry picked from commit 363f73ac181409382f7ed0c702b099f4e7b5179b)
Keep traversal-local completion separate from final module ordering. Repeated acyclic imports otherwise expand exponentially before the clean build can compile libgerbil. Preserve phase selection, exclusions and deterministic dependency order.
Keep newly discovered source watches inside the publication lock. Releasing readers first lets an immediate source edit precede watch registration and lose its event. The unchanged installed preview suite now passes all 18 cases.
Fixture GERBIL_HOME values must isolate manuals without hiding the actual installed core library. This lets the unchanged command assertions run with no GERBIL_LOADPATH overlay.
This pull request has changes conflicting with the target branch.
  • src/build/build-libgerbil-test.ss
  • src/build/build-libgerbil.ss
  • src/std/list/list-test.ss
  • src/std/sync/channel-test.ss
View command line instructions

Manual merge helper

Use this merge commit message when completing the merge manually.

Checkout

From your project repository, check out a new branch and test the changes.
git fetch -u v0.19-documentation:jay-v0.19-documentation
git switch jay-v0.19-documentation

Merge

Merge the changes and update on Forgejo.

Warning: The "Autodetect manual merge" setting is not enabled for this repository, you will have to mark this pull request as manually merged afterwards.

git switch v0.19-staging
git merge --no-ff jay-v0.19-documentation
git switch jay-v0.19-documentation
git rebase v0.19-staging
git switch v0.19-staging
git merge --ff-only jay-v0.19-documentation
git switch jay-v0.19-documentation
git rebase v0.19-staging
git switch v0.19-staging
git merge --no-ff jay-v0.19-documentation
git switch v0.19-staging
git merge --squash jay-v0.19-documentation
git switch v0.19-staging
git merge --ff-only jay-v0.19-documentation
git switch v0.19-staging
git merge jay-v0.19-documentation
git push origin v0.19-staging
Sign in to join this conversation.
No description provided.