Skip to content

Commit 9b734bd

Browse files
committed
Initial commit from verso-templates/textbook
0 parents  commit 9b734bd

9 files changed

Lines changed: 515 additions & 0 deletions

File tree

README.md

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
This is a demonstration of a textbook built in Verso's manual genre.
2+
3+
To build it, run:
4+
```
5+
$ lake exe textbook
6+
```
7+
8+
This textbook is written in the `Manual` genre. It uses the same
9+
version of Lean for the example code as it does for Verso itself;
10+
please see [the package description example](../package-docs) for an
11+
example in which the Lean code is external to the document and written
12+
in a different version of Lean.
13+
14+
# Code Samples
15+
16+
Additionally, this example demonstrates a non-trivial extension to the
17+
manual genre: extraction of Lean modules from the inline examples. This
18+
extension uses [a custom `savedLean` code block](TextbookTemplate/Meta/Lean.lean)
19+
to indicate that an example or exercise should be saved. At elaboration time,
20+
a custom block element saves the original filename and the contents of the
21+
code block. Then, in [`TextbookTemplateMain.lean`](TextbookTemplateMain.lean), the
22+
custom build step `buildExercises` traverses the entire book prior to HTML
23+
generation, collecting the exercise blocks. The collected blocks are assembled
24+
into files and written to the `example-code` subdirectory of the output.
25+
26+

TextbookTemplate.lean

Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
/-
2+
Copyright (c) 2024-2025 Lean FRO LLC. All rights reserved.
3+
Released under Apache 2.0 license as described in the file LICENSE.
4+
Author: David Thrane Christiansen
5+
-/
6+
7+
import VersoManual
8+
import TextbookTemplate.Meta.Lean
9+
import TextbookTemplate.Papers
10+
11+
-- This is a chapter that's included
12+
import TextbookTemplate.Nat
13+
14+
-- This gets access to most of the manual genre (which is also useful for textbooks)
15+
open Verso.Genre Manual
16+
17+
-- This gets access to Lean code that's in code blocks, elaborated in the same process and
18+
-- environment as Verso
19+
open Verso.Genre.Manual.InlineLean
20+
21+
22+
open TextbookTemplate
23+
24+
set_option pp.rawOnError true
25+
26+
27+
#doc (Manual) "A Textbook" =>
28+
29+
%%%
30+
authors := ["David Thrane Christiansen"]
31+
%%%
32+
33+
{index}[example]
34+
Here's an example project showing how to build a certain kind of textbook with Verso.
35+
It's a good idea to read the document's source together with the rendered output, because it demonstrates how to use various features.
36+
37+
38+
# Lean Code
39+
40+
The tools in this section come from the Verso namespace `Verso.Genre.Manual.InlineLean`.
41+
42+
The {lean}`lean` code block allows Lean code to be included in the text.
43+
It is elaborated in the context of the text's elaboration.
44+
45+
```lean
46+
inductive NatList where
47+
| nil
48+
| cons : Nat → NatList → NatList
49+
```
50+
51+
Use the {lean}`leanSection` directive to create a Lean section that delimits scope changes.
52+
The {lean}`lean` role allows Lean terms to be included as inline elements in paragraphs.
53+
Use {lean}`name` to refer to a name that can't be easily elaborated as a term, e.g. due to implicit parameters or type classes.
54+
55+
## Saved Lean Code
56+
57+
The tools in this section come from the Verso namespace `TextbookTemplate` in the module `TextbookTemplate.Meta.Lean`.
58+
59+
The {lean}`savedLean` code block is just like the {lean}`lean` block, except it additionally saves the contents to a file when the book is built.
60+
The code is saved to the output directory, in the subdirectory `example-code` (by default, this is `_out/example-code`), with its filename being that of the file in which it is edited.
61+
Use {lean}`savedImport` to save code for the file header.
62+
63+
```savedComment
64+
Here's some commentary for the file
65+
```
66+
```savedLean
67+
def x : Nat := 15
68+
```
69+
70+
When named, the code block's output is saved.
71+
It can be both checked and included in the document using {lean}`leanOutput`:
72+
73+
```savedLean (name := xVal)
74+
#eval x
75+
```
76+
```leanOutput xVal
77+
15
78+
```
79+
80+
Expected error messages must be indicated explicitly:
81+
```lean +error (name := yVal)
82+
#eval y
83+
```
84+
```leanOutput yVal
85+
Unknown identifier `y`
86+
```
87+
88+
{include 1 TextbookTemplate.Nat}
89+
90+
# Notes
91+
92+
Use {lean}`margin` to create a marginal note.{margin}[Marginal notes should be used like footnotes.]
93+
94+
# Citations
95+
96+
Cite works using {lean}`citet`, {lean}`citep`, or {lean}`citehere`.
97+
They take a name of a citable reference value as a parameter.
98+
References should be defined as values, typically in one module that is imported (similar to the role of a `.bib` file in LaTeX).
99+
100+
Textual citations, as with {citet someThesis}[], look like this.
101+
Parenthetical {citep someArXiv}[] looks like this.
102+
Use {lean}`citehere` to literally include the cite rather than making a margin note, e.g. {citehere somePaper}[].
103+
Literally-included cites are mostly useful when performing citation inside a margin note.
104+
105+
# Section References
106+
%%%
107+
tag := "sec-ref"
108+
%%%
109+
110+
Sections with tags can be cross-referenced.
111+
They additionally gain permalink indicators that can be used to link to them even if the document is reorganized.
112+
Tags are added in section metadata, e.g.
113+
```
114+
%%%
115+
tag := "my-tag"
116+
%%%
117+
```
118+
They can be linked to using {lean}`ref`.
119+
Here's one to {ref "sec-ref"}[this section].
120+
121+
122+
123+
# Viewing the Output
124+
125+
Verso's HTML doesn't presently work correctly when opened directly in a browser, so it should be served via a server.{margin}[This is due to security restrictions on retrieved files: some of the code hovers are deduplicated to a JSON file that's fetched on demand.]
126+
One portable way to do this is documented in the root of this repository.
127+
128+
# Using an Index
129+
130+
{index}[index]
131+
The index should contain an entry for “lorem ipsum”.
132+
{index}[lorem ipsum] foo
133+
{index (subterm := "of lorem")}[ipsum]
134+
{index (subterm := "per se")}[ipsum]
135+
{index}[ipsum]
136+
Lorem ipsum dolor {index}[dolor] sit amet, consectetur adipiscing elit, sed {index}[sed] do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris {index}[laboris] {see "lorem ipsum"}[laboris] {seeAlso "dolor"}[laboris] nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
137+
138+
This is done using the `{index}[term]` syntax. Sub-terms {index (subterm := "sub-term")}[entry] can be added using the `subterm` parameter to `index`.
139+
140+
Multiple index {index}[index] targets for a term also work.
141+
142+
{ref "index"}[Index link]
143+
144+
145+
# Index
146+
%%%
147+
number := false
148+
tag := "index"
149+
%%%
150+
151+
{theIndex}

TextbookTemplate/Meta/Lean.lean

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
/-
2+
Copyright (c) 2025 Lean FRO LLC. All rights reserved.
3+
Released under Apache 2.0 license as described in the file LICENSE.
4+
Author: David Thrane Christiansen
5+
-/
6+
7+
import VersoManual
8+
9+
open Verso.Genre Manual
10+
open Verso.Doc Elab
11+
open Verso.ArgParse
12+
open Lean
13+
14+
namespace TextbookTemplate
15+
16+
block_extension Block.savedLean (file : String) (source : String) where
17+
data := .arr #[.str file, .str source]
18+
19+
traverse _ _ _ := pure none
20+
toTeX := none
21+
toHtml := some fun _ goB _ _ contents =>
22+
contents.mapM goB
23+
24+
block_extension Block.savedImport (file : String) (source : String) where
25+
data := .arr #[.str file, .str source]
26+
27+
traverse _ _ _ := pure none
28+
toTeX := none
29+
toHtml := some fun _ _ _ _ _ =>
30+
pure .empty
31+
32+
/--
33+
Lean code that is saved to the examples file.
34+
-/
35+
@[code_block savedLean]
36+
def savedLean : CodeBlockExpanderOf InlineLean.LeanBlockConfig
37+
| args, code => do
38+
let underlying ← InlineLean.lean args code
39+
``(Block.other (Block.savedLean $(quote (← getFileName)) $(quote (code.getString))) #[$underlying])
40+
41+
/--
42+
An import of some other module, to be located in the saved code. Not rendered.
43+
-/
44+
@[code_block]
45+
def savedImport : CodeBlockExpanderOf Unit
46+
| (), code => do
47+
``(Block.other (Block.savedImport $(quote (← getFileName)) $(quote (code.getString))) #[])
48+
49+
/--
50+
Comments to be added as module docstrings to the examples file.
51+
-/
52+
@[code_block]
53+
def savedComment : CodeBlockExpanderOf Unit
54+
| (), code => do
55+
let str := code.getString.trimAsciiEnd.copy
56+
let comment := s!"/-!\n{str}\n-/"
57+
``(Block.other (Block.savedLean $(quote (← getFileName)) $(quote comment)) #[])

TextbookTemplate/Nat.lean

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
/-
2+
Copyright (c) 2024-2025 Lean FRO LLC. All rights reserved.
3+
Released under Apache 2.0 license as described in the file LICENSE.
4+
Author: David Thrane Christiansen
5+
-/
6+
7+
import VersoManual
8+
import TextbookTemplate.Meta.Lean
9+
import TextbookTemplate.Papers
10+
11+
-- This gets access to most of the manual genre (which is also useful for textbooks)
12+
open Verso.Genre Manual
13+
14+
-- This gets access to Lean code that's in code blocks, elaborated in the same process and
15+
-- environment as Verso
16+
open Verso.Genre.Manual.InlineLean
17+
18+
19+
open TextbookTemplate
20+
21+
set_option pp.rawOnError true
22+
23+
24+
25+
#doc (Manual) "The Natural Numbers" =>
26+
27+
```savedLean
28+
namespace MyNats
29+
```
30+
31+
```savedLean
32+
inductive Nat where
33+
| zero
34+
| succ : Nat → Nat
35+
```
36+
37+
```savedLean
38+
def Nat.ofNat : _root_.Nat → Nat
39+
| 0 => .zero
40+
| n + 1 => .succ (.ofNat n)
41+
```
42+
43+
```savedLean
44+
instance : OfNat Nat n where
45+
ofNat := .ofNat n
46+
```
47+
48+
```savedLean
49+
@[match_pattern]
50+
def Nat.add (n k : Nat) : Nat :=
51+
match k with
52+
| .zero => n
53+
| .succ k' => .succ (n.add k')
54+
```
55+
56+
```savedLean
57+
instance : Add Nat where
58+
add := Nat.add
59+
```
60+
61+
```savedLean
62+
def Nat.toNat : MyNats.Nat → _root_.Nat
63+
| 0 => 0
64+
| n + 1 => toNat n + 1
65+
```
66+
67+
68+
```lean (name := verboseOut)
69+
#eval (4 : MyNats.Nat) + 2
70+
```
71+
```leanOutput verboseOut
72+
MyNats.Nat.succ
73+
(MyNats.Nat.succ (MyNats.Nat.succ (MyNats.Nat.succ (MyNats.Nat.succ (MyNats.Nat.succ (MyNats.Nat.zero))))))
74+
```
75+
76+
```lean
77+
instance : Repr Nat where
78+
reprPrec n _prec := repr n.toNat
79+
80+
instance : ReprAtom Nat where
81+
```
82+
83+
```lean (name := betterOut)
84+
#eval (4 : MyNats.Nat) + 2
85+
```
86+
```leanOutput betterOut
87+
6
88+
```
89+
90+
91+
```savedLean
92+
end MyNats
93+
```

TextbookTemplate/Papers.lean

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
/-
2+
Copyright (c) 2024-2025 Lean FRO LLC. All rights reserved.
3+
Released under Apache 2.0 license as described in the file LICENSE.
4+
Author: David Thrane Christiansen
5+
-/
6+
import VersoManual
7+
open Verso.Genre.Manual
8+
9+
-- Here, `inlines!` is a macro that parses a string constant into Verso inline elements
10+
11+
def someThesis : Thesis where
12+
title := inlines!"A Great Thesis"
13+
author := inlines!"A. Great Student"
14+
year := 2025
15+
university := inlines!"A University"
16+
degree := inlines!"Something"
17+
18+
def somePaper : InProceedings where
19+
title := inlines!"Grommulation of Flying Lambdas"
20+
authors := #[inlines!"A. Great Student"]
21+
year := 2025
22+
booktitle := inlines!"Proceedings of the Best Conference Ever"
23+
24+
def someArXiv : ArXiv where
25+
title := inlines!"Grommulation of Flying Lambdas"
26+
authors := #[inlines!"A. Great Student"]
27+
year := 2025
28+
id := "...insert arXiv id here..."

0 commit comments

Comments
 (0)