The docs commands
What torb docs check, index, skill and bundle each do, which rules they decide, and which rules only a reviewer can decide.
Diese Seite gibt es noch nicht auf Deutsch, deshalb steht sie hier auf Englisch. Zur englischen Seite
The documentation has a gate. torb docs check decides everything about a page that a program can decide: the front
matter, the sections, the headings, the links, the anchors, the summaries, a short list of words that say nothing
exactly, and every code block. What it cannot decide is whether a page is true and useful, which is what a review is
for.
Synopsis#
torb docs check [root] Check the documentation (default root: docs)
--standard-library <path> Where std/ is. Default: <root>/../std
--no-snippets Do not type check the snippets, which is the slow part
--no-native Do not build the snippets: for a machine without a C compiler
torb docs index [root] Write the generated part of every index.md
--check Report instead of writing, for the gate
torb docs declarations [root] Write the marked signature blocks of the package pages, from std/
--standard-library <path> Where std/ is. Default: <root>/../std
--check Report the stale blocks instead of writing, for the gate
torb docs skill <root> <out> Write the Agent Skills of <root>/skills/ below <out> (fails on a dangling link)
--check Report the stale files instead of writing, for the gate
torb docs bundle <root> <out> Write llms.txt and llms-full.txt
torb docs site <root> --output <dir> Write the website: the front page, every page, the search
--version <v> The version the documentation is of (default: latest)
--check Build it and check its links, and write nothing
torb docs source <path>... Check the doc comments of the code itselfEvery command exits with 1 when it reports a problem and with 0 when it does not, and both run from the repository root:
torb docs check docs
torb docs index --check docs
torb docs declarations --check docsAll three are gates of every change. docs site writes the website from the same tree and has its own page,
torb docs site. docs source is about the doc comments of std/, compiler/ and examples/
instead of about these pages, it has rules of its own, and it is not a gate yet - it has its own page,
torb docs source.
What it does#
The shape of the tree#
- Every folder has an
index.md, and a folder that has nothing but its index is an error. - Every
.mdfile that starts with a---line is a page. One that does not is a plain design document and has to be named in thedocumentsfield of some index, so it is reachable and nothing is silently ignored. - Every page is reachable from
docs/index.md, which follows from the two rules above: the body of an index is generated from its children. - A file name is lowercase and uses hyphens.
The front matter#
- The opening
---is the first line, and the front matter is closed by a second one. - Only the nine known fields, each at most once, in the legal subset described in front-matter.md. A value that needs quotes and does not have them is an error, not a guess.
title,summary,kindandstatusare present.kindandstatusare in their vocabularies. Areferenceorpackagepage has asource.- A
titleis at most 60 characters and has no full stop. Asummaryis 40 to 240 characters, ends a sentence, and does not containthis page. documentsonly on an index,prerequisitesonly on a guide, andskillonly asskill: omit.
The body#
- No
#heading: thetitleis the heading of the page, so a body starts at##. - Sentence case, no full stop and no colon at the end of a heading, and no skipped heading level.
- Two headings of one page may not produce the same anchor.
- The
##sections thekindrequires are present, in the required relative order. Other sections may stand between them. - A
plannedordraftpage opens its body with the banner of its status. - The words
usually,simply,obviously,basically,easily,of course,as mentioned,see above,and so on,please noteandetc.are errors in prose. What stands between backticks is not prose, so a page about the rule can quote the word.
The links#
- An internal link resolves to a page of the tree or to a plain document of it, and an anchor resolves to a heading of the page it names. Both are errors when they do not: an agent follows a path instead of guessing.
- A link that leaves the tree (
../../CONCEPT.md) has to exist on disk. - A link that starts with
http://orhttps://is not followed at all. A gate has to answer the same offline as online, and an unreachable host is not a defect of the documentation. - A link inside the documentation is relative and names a
.mdfile.
The code blocks#
A fence is at least three backticks and names its language: trb, text, console, json, md, yaml or diff.
A closing fence is at least as long as the one it closes, so a block that shows a fence opens with four backticks. A
trb fence may carry one marker, and the marker decides how hard the block is checked.
| Fence | What is checked |
|---|---|
trb | Lexes and parses without a diagnostic, and is in the formatter canon |
trb check | The same, and type checks against the real std/ as the entry file of a package |
trb run | The same, and is built natively and run; its output has to be what its // prints comments say |
trb fragment | Lexes without a diagnostic. For a signature or a shape that is not a whole program |
trb error | Produces exactly the diagnostics the block declares in its // error: lines, and no other |
trb exercise | Parses, is in the canon and type checks: the starting code of an exercise, whose output is not compared |
trb exercise incomplete | Lexes without a diagnostic: the starting code of an exercise, with a gap on purpose |
trb skip <reason> | Nothing. The reason is required and the gate prints every skip |
An exercise is followed by its solution: the first trb run block after it and before the next exercise, whose
// prints comments are the output the exercise asks for. An exercise without one is a problem
(the contract).
A trb error block writes what it expects into the code, as a comment:
```trb error
const small: Int8 = 300
// error: `300` does not fit into `Int8`
```The comment stays in the block, because it parses like any other comment and because an expectation that sits next to
the line it belongs to cannot drift away from it. Every expectation has to appear in some diagnostic of the block,
and every diagnostic has to contain one of the expectations: a block that is also wrong for a second reason
teaches a second wrong line, and a block whose intended diagnostic went away would otherwise pass on the incidental
one. A block that legitimately produces several diagnostics - two unknown trait names, a parse error and what follows
from it - writes one // error: line per diagnostic. A trb error block that produces no diagnostic at all is an
error itself.
A trb run block writes its output the same way, one // prints <line> comment per line of output, behind the
statement that prints or on a line of its own:
```trb run
const text = "Grüße"
print text.byteLength() // prints 7
```The program has to end with exit code 0. A claim about what a program prints belongs in such a block rather than in
the prose around a trb check block, because only the block is compared with what the program does.
Type checking happens in one run of the front end for the whole documentation: the standard library is read and
resolved once, and every block that asked for it becomes the entry file of a package of its own,
snippets/<name>/src/main.trb, which is a member of a synthetic workspace next to std/ - the way examples/<name>
is a member of the repository. A block sees std/ through its imports, not as files of its own package, and sees no
other block. One run costs seconds; one run per block would cost minutes.
What the native back end says#
A block that the back end refuses is a block a reader cannot run, in the VM of torb run or natively. Two blocks are asked, each lowered on its own so that a refusal belongs to it:
- Every
trb runblock. A refusal is an error. The blocks that are not refused become the entries of one program, compiled once with the C compiler at-O0intobuild/docs/beside the documentation root and run; a marker line before each entry cuts the output back into one piece per block. - Every
trb checkblock of astablepage. Astablepage promises that what it shows works. When the back end refuses a block of it, the page either shows a form that builds or says so in a paragraph that opens with> **Not built natively yet.**and names what is refused. The note is held to the truth the other way as well: a page that has it and whose blocks all build is reported, so the note goes away when the back end catches up. Adraftorplannedpage is not asked, because its banner already says it may not work.
The C runtime is $TORB_RUNTIME, or the runtime/ beside the standard library.
The canon#
Two of the rules of the formatter canon are decided on every block that parses:
- calls: a call is a command wherever the grammar allows it, and has parentheses everywhere else. Both directions
are reported. A call of a field that holds a function is left alone, because there the parentheses are meaning and
not style:
debugger.stop(event)calls the field, anddebugger.stop eventwould write it. Only the type checker knows what a callee is, so atrb checkand atrb runblock are held to this rule in the type check, with what the checker resolved - a call of a field, and one whose callee it did not resolve, keeps the way it is written, astorb formatkeeps it. Atrbblock, which nothing type checks, leaves alone a callee that names a field of the type it stands in. - strings: a multi-line
"""orraw"""is indented two spaces deeper than the line its statement starts on, with a closing"""that stands alone aligned with the content.
What is not checked is the layout torb format adds to the canon: indentation, spaces and blank lines. A snippet
that passes here is in the canon; whether it is in the layout of torb format is not promised.
The declarations of a package page#
torb docs declarations writes the signature blocks of the ## Declarations section of a std/ page. A line
<!-- torb:declaration: <Name> --> directly above a trb fragment block names the construct the block shows, and the
command replaces the block with what the model of torb doc says of it:
- the signature, the way the source writes it and without
public, - every member that is not
private, one per line and indented, - the
extendblocks of the package that target it: the header of one that implements a trait, whose members the trait documents, and the whole block of one that adds members of its own.
The package is the one the title of a kind: package page names (title: std/uri). Several markers above one block
show several constructs in it, in their order, and a name that is no construct of the package but a type its extend
blocks add to (Bytes, String) shows those blocks. Everything else of the page is untouched, byte for byte: the
headings, the prose, and every block without a marker.
A marker that names nothing of the package, one that stands above no trb fragment block and one on a page whose title
is no package are problems at their line, and so is a std/ that does not type check. --check writes nothing and
reports every block that is not what std/ declares, with the constructs it shows and its first line that differs.
The indexes#
torb docs index writes the lines between <!-- torb:index:begin --> and <!-- torb:index:end --> of every
index.md, from the title, summary, order and status of the children. Everything above the first marker is
untouched, byte for byte. Below the closing marker nothing is allowed.
The generated body has up to three sections: ## Sections for the folders below, ## Pages for the pages of the
folder, and ## Design documents for what the documents field names. A child with status: planned or
status: draft is marked in its entry.
--check reports every index whose body is not what it would write, and writes nothing. That is the form the gate uses.
The translations#
A page below translations/<language>/ translates the English page at the rest of its path, and is checked beside it:
its front matter, with the kind of its original and a translates field; its headings, but not the English names of
the sections a kind requires; its links, resolved from the folder of its original; and its trb blocks. The
strings.json of a language is one JSON object of texts whose keys are the keys of the site's interface, with the
language's own name as language.
A translation whose original changed since it was made is no problem. The check lists it after the problems, on a line
that starts with outdated: and names the value translates gets once the translation is brought up to date.
Examples#
A green run names the numbers, so a change in them is visible in a diff:
$ torb docs check docs
224 pages, 24 folders, 979 snippets, no problemsA problem names the file, the line and the rule:
$ torb docs check docs
../docs/language/types/values.md:31: A call is a command wherever the grammar allows it. Write `Ok ...` without parentheses
../docs/language/types/values.md:52: `soon` is not a status. One of: stable, draft, planned
2 problems in 42 pagesWhat no command decides#
These are the reviewer's, and they are the ones that matter:
- Whether a claim is true of the compiler as it is today.
- Whether the example is the smallest one that shows the construct.
- Whether
## What this is notnames the mistake a reader will actually make. - Whether the
summaryis enough to decide whether to open the page. - Whether the page is understandable when it is the only page loaded.
Related#
- How this documentation is structured - the tree and the kinds.
- The front matter - the nine fields and the YAML subset.
- How to write here - the rules the reviewer checks.
- Add a page - the steps and the templates.
- The Agent Skills - what
docs skillproduces.