Skip to content

Commit 0459295

Browse files
Improve the (PDF) Manual (#989)
* manual: Fix Heading Levels * manual: Some improvements * changes: Update changelog
1 parent d78e66f commit 0459295

9 files changed

Lines changed: 192 additions & 169 deletions

File tree

.github/workflows/ci.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,4 +36,5 @@ jobs:
3636
just install @local
3737
just install @preview
3838
just test
39+
just manual
3940
just docs

CHANGES.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
- Added a new `content.wrap` style key that takes a function to wrap content in, useful for applying Typst styling, such as text color (#964)
55
- Fixed a division by zero bug when shortening paths to zero length (#962)
66
- The content element now supports the `wrap:` style to apply a function to they Typst content (e.g. applying text attributes) (#964)
7+
- The PDF API-Reference is back: manual.pdf (#974)
8+
- All docstrings are now written in Typst (#974)
79

810
# 0.4.2
911
- The `tree` element now has a `anchor:` argument to position the tree (#929)

docs/style.typ

Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
#import "/src/lib.typ" as cetz
2+
13
#let colors = (
24
"any": rgb("#eff0f3"),
35
"content": rgb("#a6ebe6"),
@@ -23,3 +25,146 @@
2325
box(raw(name), inset: 2pt, baseline: 2pt, radius: 2pt,
2426
fill: colors.at(name, default: colors.at("any")), stroke: none)
2527
}
28+
29+
#let show-docstring(comment, level) = {
30+
let text = comment.text
31+
let arguments = comment.arguments
32+
let result = comment.result
33+
34+
set heading(outlined: false, offset: level)
35+
36+
block([
37+
#eval(text, mode: "markup", scope: (
38+
cetz: cetz,
39+
))
40+
])
41+
42+
if arguments != () {
43+
heading("Parameters")
44+
list(..arguments.map(arg => {
45+
let types = arg.types
46+
if types == none { types = ("any",) }
47+
block(
48+
strong(raw(arg.name)) + [ ]
49+
+ types.map(show-type).join([ ]) + [\ ]
50+
+ eval(arg.text, mode: "markup")
51+
)
52+
}))
53+
}
54+
55+
if result.any(r => r.text != "") {
56+
heading("Result")
57+
58+
let show-result(r) = if r.text != "" {
59+
let type = r.type
60+
if type == none { type = "any" }
61+
block(
62+
show-type(type) + [\ ] + eval(r.text, mode: "markup")
63+
)
64+
}
65+
66+
if result.len() > 1 {
67+
list(..result.map(show-result))
68+
} else {
69+
show-result(result.first())
70+
}
71+
}
72+
}
73+
74+
/// Show a function signature annoted with types from the docstring
75+
#let show-annotated-signature(signature, comment) = block({
76+
set par(leading: 0.35em)
77+
78+
let name = signature.name
79+
80+
let arguments = signature.arguments.map(arg => {
81+
let comment-arg = comment.arguments.find(comment-arg => {
82+
comment-arg.name == arg.name
83+
})
84+
if comment-arg == none {
85+
comment-arg = (types: (), name: name)
86+
}
87+
88+
let types = comment-arg.types
89+
if types == none { types = () }
90+
91+
if arg.has-default {
92+
raw(arg.name + ":") + [ ] + types.map(show-type).join([ ])
93+
} else {
94+
raw(arg.name) + [ ] + types.map(show-type).join([ ])
95+
}
96+
})
97+
98+
let result = if comment.result != () {
99+
[ #sym.arrow.r ] + comment.result.map(r => show-type(r.type)).join([ or ])
100+
} else {
101+
[]
102+
}
103+
104+
text(blue, raw(name)) + raw("(") + [\ ] + arguments.map(v => h(1em) + v).join([,\ ]) + [\ ] + raw(")") + result
105+
})
106+
107+
/// Show a single module/file
108+
#let show-module(docs, name, level: 3) = {
109+
for item in docs.at(name) {
110+
if item.at("signature", default: none) == none {
111+
continue
112+
}
113+
114+
let function-name = item.signature.name
115+
if function-name.starts-with("_") {
116+
continue
117+
}
118+
119+
[#heading(function-name, level: level) #label(function-name)]
120+
show-annotated-signature(item.signature, item.comment)
121+
show-docstring(item.comment, level)
122+
}
123+
}
124+
125+
// Root show function for manual.typ
126+
#let setup(body) = {
127+
set heading(numbering: (..nums) => {
128+
let nums = nums.pos()
129+
if nums.len() <= 2 {
130+
return nums.map(n => [#n]).join([.])
131+
}
132+
}, hanging-indent: 0cm)
133+
134+
/// Render an example side-by-side with its source code.
135+
let render-example(code, vertical: false) = {
136+
let columns = if vertical {
137+
(1fr,)
138+
} else {
139+
(1fr, 2fr,)
140+
}
141+
142+
let align = if vertical {
143+
(x, y) => (center + top, left + top).at(y)
144+
} else {
145+
(x, y) => (center + horizon, left + top).at(x)
146+
}
147+
148+
let stroke = 1pt + gray
149+
let line = if vertical { table.hline } else { table.vline }
150+
151+
block(radius: 2pt, stroke: stroke, breakable: false, {
152+
table(columns: columns, align: align, stroke: none,
153+
cetz.canvas({
154+
let preamble = "import cetz.draw: *\n"
155+
eval(preamble + code, mode: "code", scope: (
156+
cetz: cetz,
157+
))
158+
}),
159+
line(stroke: (paint: gray, thickness: 1pt, dash: "dashed")),
160+
raw(code, lang: "typc"),
161+
)
162+
})
163+
}
164+
165+
show raw.where(lang: "example"): it => render-example(it.text)
166+
show raw.where(lang: "example-vertical"): it => render-example(it.text, vertical: true)
167+
show regex("type:([\w-]+)"): it => show-type(it.text.replace("type:", ""))
168+
169+
body
170+
}

justfile

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ update-test *filter: build
2424
gallery: build
2525
for f in "{{gallery_dir}}"/*.typ; do typst c "$f" "${f/typ/png}"; done
2626

27-
docs: build
27+
manual: build
2828
typst compile --root . manual.typ
29+
30+
docs: build
2931
typst query --root . manual.typ "<metadata>" --field value | python ./docs/genhtml.py -o ./docs/_generated

manual.pdf

-2.15 KB
Binary file not shown.

manual.typ

Lines changed: 20 additions & 154 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,7 @@
1-
#import "/src/lib.typ" as cetz
2-
3-
#import "/docs/style.typ": show-type
1+
#import "/docs/style.typ": show-type, show-module, setup, cetz
42
#import "/docs/typlodocus/extractor.typ"
53

6-
#set heading(numbering: (..nums) => {
7-
let nums = nums.pos()
8-
if nums.len() <= 2 {
9-
return nums.map(n => [#n]).join([.])
10-
}
11-
}, hanging-indent: 0cm)
4+
#show: setup
125

136
#let modules = (
147
[Canvas],
@@ -28,17 +21,18 @@
2821
"src/draw/util.typ",
2922

3023
[Libraries], 1,
31-
[Angle],
32-
"src/lib/angle.typ",
33-
[Tree],
34-
"src/lib/tree.typ",
35-
[Decorations],
36-
[Path],
37-
"src/lib/decorations/path.typ",
38-
[Brace],
39-
"src/lib/decorations/brace.typ",
40-
[Palette],
41-
"src/lib/palette.typ",
24+
[Angle],
25+
"src/lib/angle.typ",
26+
[Tree],
27+
"src/lib/tree.typ",
28+
[Decorations], 2,
29+
[Path],
30+
"src/lib/decorations/path.typ",
31+
[Brace],
32+
"src/lib/decorations/brace.typ",
33+
1,
34+
[Palette],
35+
"src/lib/palette.typ",
4236
0,
4337

4438
[Internals], 1,
@@ -82,138 +76,7 @@
8276
// Generate query metadata
8377
#metadata(docs) <metadata>
8478

85-
/// Show a function signature annoted with types from the docstring
86-
#let show-annotated-signature(signature, comment) = block({
87-
set par(leading: 0.35em)
88-
89-
let name = signature.name
90-
91-
let arguments = signature.arguments.map(arg => {
92-
let comment-arg = comment.arguments.find(comment-arg => {
93-
comment-arg.name == arg.name
94-
})
95-
if comment-arg == none {
96-
comment-arg = (types: (), name: name)
97-
}
98-
99-
let types = comment-arg.types
100-
if types == none { types = () }
101-
102-
if arg.has-default {
103-
raw(arg.name + ":") + [ ] + types.map(show-type).join([ ])
104-
} else {
105-
raw(arg.name) + [ ] + types.map(show-type).join([ ])
106-
}
107-
})
108-
109-
let result = if comment.result != () {
110-
[ #sym.arrow.r ] + comment.result.map(r => show-type(r.type)).join([ or ])
111-
} else {
112-
[]
113-
}
114-
115-
text(blue, raw(name)) + raw("(") + [\ ] + arguments.map(v => h(1em) + v).join([,\ ]) + [\ ] + raw(")") + result
116-
})
117-
118-
/// Render an example side-by-side with its source code.
119-
#let render-example(code, vertical: false) = {
120-
let columns = if vertical {
121-
(1fr,)
122-
} else {
123-
(1fr, 2fr,)
124-
}
125-
126-
let align = if vertical {
127-
(x, y) => (center + top, left + top).at(y)
128-
} else {
129-
(x, y) => (center + horizon, left + top).at(x)
130-
}
131-
132-
let stroke = 1pt + gray
133-
let line = if vertical { table.hline } else { table.vline }
134-
135-
block(radius: 2pt, stroke: stroke, {
136-
table(columns: columns, align: align, stroke: none,
137-
cetz.canvas({
138-
let preamble = "import cetz.draw: *\n"
139-
eval(preamble + code, mode: "code", scope: (
140-
cetz: cetz,
141-
))
142-
}),
143-
line(stroke: (paint: gray, thickness: 1pt, dash: "dashed")),
144-
raw(code, lang: "typc"),
145-
)
146-
})
147-
}
148-
149-
#show raw.where(lang: "example"): it => render-example(it.text)
150-
#show raw.where(lang: "example-vertical"): it => render-example(it.text, vertical: true)
151-
#show regex("type:([\w-]+)"): it => show-type(it.text.replace("type:", ""))
152-
153-
#let show-docstring(comment, level) = {
154-
let text = comment.text
155-
let arguments = comment.arguments
156-
let result = comment.result
157-
158-
set heading(outlined: false, offset: level)
159-
160-
block([
161-
#eval(text, mode: "markup", scope: (
162-
cetz: cetz,
163-
))
164-
])
165-
166-
if arguments != () {
167-
heading("Parameters")
168-
list(..arguments.map(arg => {
169-
let types = arg.types
170-
if types == none { types = ("any",) }
171-
block(
172-
strong(raw(arg.name)) + [ ]
173-
+ types.map(show-type).join([ ]) + [\ ]
174-
+ eval(arg.text, mode: "markup")
175-
)
176-
}))
177-
}
178-
179-
if result.any(r => r.text != "") {
180-
heading("Result")
181-
182-
let show-result(r) = if r.text != "" {
183-
let type = r.type
184-
if type == none { type = "any" }
185-
block(
186-
show-type(type) + [\ ] + eval(r.text, mode: "markup")
187-
)
188-
}
189-
190-
if result.len() > 1 {
191-
list(..result.map(show-result))
192-
} else {
193-
show-result(result.first())
194-
}
195-
}
196-
}
197-
198-
/// Show a single module/file
199-
#let show-module(name, level: 3) = {
200-
for item in docs.at(name) {
201-
if item.at("signature", default: none) == none {
202-
continue
203-
}
204-
205-
let function-name = item.signature.name
206-
if function-name.starts-with("_") {
207-
continue
208-
}
209-
210-
[#heading(function-name, level: level) #label(function-name)]
211-
show-annotated-signature(item.signature, item.comment)
212-
show-docstring(item.comment, level)
213-
}
214-
}
215-
216-
79+
// Outline
21780
#columns(2, outline(depth: 4))
21881
#pagebreak()
21982

@@ -244,7 +107,10 @@ From this point on only the code inside the
244107
canvas block will be shown in examples unless specified otherwise.
245108

246109
```example
110+
// Draw a circle
247111
circle((0, 0))
112+
113+
// Draw a line
248114
line((1,-1), (2,1))
249115
```
250116

@@ -297,13 +163,13 @@ stroke and fill styling unless said otherwise.
297163
How to stroke the border or the path of the draw element. #link("https://typst.app/docs/reference/visualize/line/#parameters-stroke")[See Typst's line documentation for more details.]
298164

299165
= API
166+
#let heading-offset = 1
300167
#for item in modules {
301-
let heading-offset = 1
302168
if type(item) == int {
303169
heading-offset = 1 + item
304170
} else if type(item) != str {
305171
heading(item, offset: heading-offset)
306172
} else {
307-
show-module(item, level: 2 + heading-offset)
173+
show-module(docs, item, level: 2 + heading-offset)
308174
}
309175
}

0 commit comments

Comments
 (0)