-
Notifications
You must be signed in to change notification settings - Fork 123
feat: much more documentation #505
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
2 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,104 @@ | ||
| /- | ||
| Copyright (c) 2023-2025 Lean FRO LLC. All rights reserved. | ||
| Released under Apache 2.0 license as described in the file LICENSE. | ||
| Author: David Thrane Christiansen | ||
| -/ | ||
|
|
||
| import Verso.Syntax | ||
| import VersoManual | ||
|
|
||
| open Verso Genre Manual | ||
|
|
||
| open Verso.Genre.Manual.InlineLean | ||
|
|
||
| #doc (Manual) "Building Documents" => | ||
| %%% | ||
| tag := "build-process" | ||
| %%% | ||
|
|
||
|
|
||
| Verso is a general framework for implementing documentation tools, and this flexibility means that the details of the process described in this section may differ for specific tools. | ||
|
|
||
| A Verso document passes through the following steps on its way from its author to its readers: | ||
| 1. The author writes the document's text in {ref "verso-markup"}[Verso's markup language], which is parsed to Lean's own {name Lean.Syntax}`Syntax` type | ||
| 2. The document is elaborated to a representation as a Lean data structure | ||
| 3. The resulting Lean code is compiled to an executable | ||
| 4. When run, the executable resolves cross-references and computes other globally-scoped metadata in a step referred to as the traversal pass | ||
| 5. Next, the executable generates the output | ||
|
|
||
|
|
||
| # Elaboration | ||
| %%% | ||
| tag := "elaboration" | ||
| %%% | ||
|
|
||
| During the elaboration process, Verso's markup language is converted into its internal representation as a Lean inductive type. | ||
| When Verso's elaborator encounters an {ref "elab-extensions"}[extension point], it consults an internal table to select an implementation of the extension, and delegates to it. | ||
| Other syntax is translated into the appropriate constructors of Verso's data. | ||
|
|
||
| All Verso documents are parameterized by their {tech}[genre]: | ||
|
|
||
| {docstring Verso.Doc.Genre} | ||
|
|
||
| Each document consists of a {name Verso.Doc.Part}`Part`. | ||
| The part's title is the title of the entire document. | ||
|
|
||
| {docstring Verso.Doc.Part} | ||
|
|
||
| {name Verso.Doc.Part}`Part`s contain {name Verso.Doc.Block}`Block`s: | ||
|
|
||
| {docstring Verso.Doc.Block} | ||
|
|
||
| {name Verso.Doc.Block}`Block`s contain {name Verso.Doc.Inline}`Inline`s: | ||
|
|
||
| {docstring Verso.Doc.Inline} | ||
|
|
||
| The {name Verso.Doc.Part.metadata}`metadata` field of {name Verso.Doc.Part}`Part` typically gets its value from a metadata block written by the author, though it may be assigned more information during traversal. | ||
| The {name Verso.Doc.Block.other}`Block.other` and {name Verso.Doc.Inline.other}`Inline.other` constructors typically result from elaborating {ref "elab-extensions"}[extension points]. | ||
|
|
||
| # Compilation | ||
| %%% | ||
| tag := "compilation" | ||
| %%% | ||
|
|
||
| After elaboration, the document is compiled into an executable program. | ||
| Each genre provides a `main` function that will carry out the remainder of the steps. | ||
| Usually, this `main` function can be applied to the part that represents the whole document; however, genres that don't have a strict linear order (such as the {ref "website"}[website genre]) will provide their own means of configuring the document's layout. | ||
| The `main` function typically also takes configuration parameters both in the code and on the command line, such as which output formats to generate or customizations to the generated output. | ||
|
|
||
| # Traversal | ||
| %%% | ||
| tag := "traversal" | ||
| %%% | ||
|
|
||
| Because they are Lean values, Verso documents adhere to the structure of Lean programs in general. | ||
| In particular, Lean doesn't support cyclic import graphs. | ||
| It's common, however, for technical writing to include cyclic references; two sections that describe different aspects of something will frequently refer to one another. | ||
| Similarly, a bibliography that's generated from a database needs a global view of a document to include only those works which are, in fact, cited. | ||
|
|
||
| The {deftech}_traversal_ phase occurs at runtime, before generating output. | ||
| During the traversal phase, the document is repeatedly traversed from beginning to end, and metadata is accumulated into a table. | ||
| The document may also be modified during traversal; this allows the title of a section to be inserted into a cross-reference. | ||
| This traversal is repeated until the resulting document and metadata tables are not modified; it fails if a set number of passes are executed that result in modifications each time. | ||
|
|
||
| Verso provides a general-purpose traversal mechanism for {name Verso.Doc.Part}`Part`, {name Verso.Doc.Block}`Block`, and {name Verso.Doc.Inline}`Inline` that genres may use. | ||
| {name Verso.Doc.Genre.TraverseState}`Genre.TraverseState` contains the genre-specific information that's accumulated during traversal, while {name Verso.Doc.Genre.TraverseContext}`Genre.TraverseContext` provides a means of tracking the surrounding document context. | ||
| To use this framework, genres should define instances of {name Verso.Doc.Traverse}`Traverse`, which specifies the traversal of a genre's custom elements. | ||
| Additionally, instances of {name Verso.Doc.TraversePart}`GenrePart` and {name Verso.Doc.TraverseBlock}`GenreBlock` specify how traversal keeps track of the current position in a document. | ||
|
|
||
| {docstring Verso.Doc.Traverse} | ||
|
|
||
| {docstring Verso.Doc.TraversePart} | ||
|
|
||
| {docstring Verso.Doc.TraverseBlock} | ||
|
|
||
| # Output Generation | ||
| %%% | ||
| tag := "output-gen" | ||
| %%% | ||
|
|
||
| Following traversal, the readable version of the document is generated. | ||
| This may be in any format; each {tech}[genre] defines its supported formats. | ||
|
|
||
| Additionally, genres that emit HTML may generate a serialized version of their cross-reference database. | ||
| This can be used to automatically maintain the links that implement cross-references between Verso documents: if content moves, rebuilding the linking document is sufficient to fix the link. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,106 @@ | ||
| /- | ||
| Copyright (c) 2023-2025 Lean FRO LLC. All rights reserved. | ||
| Released under Apache 2.0 license as described in the file LICENSE. | ||
| Author: David Thrane Christiansen | ||
| -/ | ||
| import Verso.Syntax | ||
| import VersoManual | ||
|
|
||
| open Verso Genre Manual | ||
| open InlineLean | ||
|
|
||
| #doc (Manual) "Extensions" => | ||
| %%% | ||
| tag := "extensions" | ||
| htmlSplit := .never | ||
| %%% | ||
|
|
||
| Verso's markup language features four extension points: | ||
| * {tech}[Roles] | ||
| * {tech}[Directives] | ||
| * {tech}[Code blocks] | ||
| * {tech}[Commands] | ||
|
|
||
| These can be used to extend Verso to support new documentation features. | ||
|
|
||
| # Syntax | ||
| %%% | ||
| tag := "extension-syntax" | ||
| %%% | ||
|
|
||
| All four extension points share a common syntax. | ||
| They are invoked by name, with a sequence of arguments. | ||
| These arguments may be positional or by name, and their values may be identifiers, string literals, or numbers. | ||
|
|
||
| :::paragraph | ||
| In this example, the directive `syntax` is invoked with the positional argument `term` and the named argument `title` set to `"Example"`. | ||
| It contains a descriptive paragraph and the code block `grammar`, which is invoked with no arguments: | ||
| ```` | ||
| :::syntax term (title := example) | ||
| This is an example grammar: | ||
| ```grammar | ||
| term ::= term "<+-+>" term | ||
| ``` | ||
| ::: | ||
| ```` | ||
| ::: | ||
|
|
||
| :::paragraph | ||
| More formally, an invocation of an extension should match this grammar: | ||
| ``` | ||
| CALL := IDENT ARG* | ||
| ARG := VAL | "(" IDENT ":=" VAL ")" | ||
| VAL := IDENT | STRING | NUM | ||
| ``` | ||
| A `CALL` may occur after an opening fence on a code block. | ||
| It is mandatory after the opening colons of a directive, in the opening curly braces of a role, or in a command. | ||
| ::: | ||
|
|
||
| # Elaborating Extensions | ||
| %%% | ||
| tag := "elab-extensions" | ||
| %%% | ||
|
|
||
| Each kind of extension has a table that maps names to expanders. | ||
| An {deftech}_expander_ converts Verso's syntax to Lean terms. | ||
| When the elaborator encounters a code block, role, directive, or command invocation, it resolves the name and looks up an expander in the table. | ||
| Expanders are attempted until one of them either throws an error or succeeds. | ||
| Expanders use the monad {name Verso.Doc.Elab.DocElabM}`DocElabM`, which is an extension of Lean's term elaboration monad {name Lean.Elab.Term.TermElabM}`TermElabM` with document-specific features. | ||
| Expanders first {ref "ArgParse"}[parse] their arguments into a suitable configuration type, typically via a {name Verso.ArgParse.FromArgs}`FromArgs` instance, after which they return Lean syntax. | ||
|
|
||
| There are two ways to associate an expander with a name: the `@[code_block]`, `@[role]`, `@[directive]`, and `@[block_command]` attributes (preferred) or the `@[code_block_expander]`, `@[role_expander]`, and `@[directive_expander]` attributes. | ||
| Using the former attributes results in an expander that invokes the argument parser automatically, and they enable Verso to automatically compute usage information from a {name Verso.ArgParse.FromArgs}`FromArgs` instance. | ||
| The latter are lower-level, and require manual parsing of arguments. | ||
|
|
||
| ## Parsing Arguments | ||
| %%% | ||
| tag := "ArgParse" | ||
| %%% | ||
|
|
||
| This grammar is fairly restrictive, so each extension is responsible for parsing their arguments in order to afford sufficient flexibility. | ||
| Arguments are parsed via instances of {name Verso.ArgParse.FromArgs}`FromArgs`: | ||
|
|
||
| {docstring Verso.ArgParse.FromArgs} | ||
|
|
||
| Implementations of {name Verso.ArgParse.FromArgs.fromArgs}`FromArgs.fromArgs` specify parsers written using {name Verso.ArgParse}`ArgParse`: | ||
|
|
||
| {docstring Verso.ArgParse} | ||
|
|
||
| Individual argument values are matched using {name Verso.ArgParse.ValDesc}`ValDesc`: | ||
|
|
||
| {docstring Verso.ArgParse.ValDesc} | ||
|
|
||
| A canonical value description for a Lean type can be registered via an instance of {name Verso.ArgParse.FromArgVal}`FromArgVal`: | ||
|
|
||
| {docstring Verso.ArgParse.FromArgVal} | ||
|
|
||
|
|
||
| In addition to the constructors of {name Verso.ArgParse}`ArgParse`, the {name}`Applicative` and {name}`Functor` instances are important, as well as the following helpers: | ||
|
|
||
| {docstring Verso.ArgParse.namedD} | ||
|
|
||
| {docstring Verso.ArgParse.positional'} | ||
|
|
||
| {docstring Verso.ArgParse.named'} | ||
|
|
||
| {docstring Verso.ArgParse.namedD'} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
“, or books”?