-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathconfig.mld
More file actions
279 lines (227 loc) · 12.9 KB
/
Copy pathconfig.mld
File metadata and controls
279 lines (227 loc) · 12.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
{0 Configuration: the [doc/wodoc] file}
The turn-key {{!page-"commands"}[wodoc build]} command is driven by one
declarative file per project, conventionally [doc/wodoc]. It is a dune-style
S-expression, read by {!Wodoc.Config}, and it replaces a project's old
[build.sh] {e and} its hand-written navigation — there is no [menu.wiki],
[nav.html], [leftnav.html] or [template.html] any more: the left navigation is
declared here, in the [(nav …)] stanza, and the page template is generated by
{!Wodoc.Build}.
A minimal config (wodoc's own — this very site):
{@text[
(project wodoc)
(title Wodoc)
(url-prefix /wodoc)
(packages wodoc)
(landing wodoc/index.html)
(nav
(section "Manual"
(link "Overview" wodoc/index.html index)
(link "Commands" wodoc/commands.html commands))
(api-section "API"
(link "API overview" wodoc/api.html api)))
]}
Build it with:
{@text[
wodoc build --config doc/wodoc --out <site>/<label> \
--menu https://ocsigen.org/doc/menu.html --label <label> [--latest] [--local]
]}
{1 Core stanzas}
{t
| Stanza | Meaning |
|--------|---------|
| [(project <id>)] | {b required} — package / project id, e.g. [ocsipersist] |
| [(title <label>)] | sub-project label shown by the logo (default: the project id) |
| [(url-prefix <path>)] | absolute publish base for the version selector, e.g. [/ocsipersist] (default [/<project>]) |
| [(menu-current <id>)] | which project to highlight in the shared top menu (default: the project id) |
| [(packages <p> …)] | the odoc output subtrees to assemble, in order; empty = every subtree odoc produced |
| [(landing <path>)] | where the version-root [index.html] redirects, e.g. [ocsipersist/index.html] |
}
{1 Navigation: the [(nav …)] stanza}
The left-column navigation is described declaratively here — {b this is the only
way to define navigation}; the old wikicréole [menu.wiki] is gone. [(nav …)]
holds an ordered list of sections:
{@text[
(nav
(section "Manual"
(link "Overview" index.html index)
(link "Tutorial" tutorial.html tutorial))
(api-section "API"
(link "Modules" pkg/index.html pkg)))
]}
- [(section <heading> <item> …)] — a {b manual} block, rendered as
[<nav class="api-nav manual-nav">]. Several sections stack in order, each
with its own [<h3>] heading.
- [(api-section <heading> <item> …)] — an {b API} block
([<nav class="api-nav">]); use it for hand-curated API links. (A client/server
project's per-module API nav is generated automatically instead — see below.)
- [(link <label> <path> [<current>])] — one entry. [<path>] is taken relative
to the version root (the per-page [base] is prefixed automatically), {e unless}
it is absolute ([/talks/…]) or a URL ([https://…]), in which case it is emitted
verbatim. [<current>] is an optional [data-wodoc-page] id: the entry is
highlighted on the page whose id matches (an API subtree's top directory, or a
manual page's own basename). Omit it for a link that never needs highlighting.
- [(group <heading> <item> …)] — a {b sub-heading} ([<h4>]) and its nested
items, indented one level deeper. Groups nest, so a section can reproduce a
multi-level menu (section → subsection → page links).
To point at an {b in-page anchor} (a one-page manual), put the fragment in the
path: [(link "Section 2" index.html#sec2 index)].
A nested example (one [<h3>] section, an [<h4>] subsection, indented links):
{@text[
(section "Server-side programming"
(group "Services"
(link "Service parameters" server-params.html server-params)
(link "Service handlers" server-outputs.html server-outputs))
(link "Sessions" server-state.html server-state))
]}
{2 Per-version navigation — [--nav]}
The [(nav …)] stanza lives in the one [doc/wodoc], so it is the same for every
version a project builds. A project whose versions have {e different} manuals
(e.g. a manual-only project that builds several version directories from the
same checkout) instead passes the nav per build, with the same syntax in a
separate file:
{@text[
wodoc build --config doc/wodoc --out <site>/<v> --label <v> \
--mld-dir manual/<v> --nav manual/<v>/nav --menu <…>
]}
[--nav <file>] reads a [(nav …)] stanza from [<file>] and uses it instead of the
config's. (This replaces the older per-version [menu.wiki].)
{1 Cross-reference resolution}
odoc leaves some references dead in the HTML; these stanzas rewrite them (see
{{!page-"commands"}[resolve-refs]} and {!Wodoc.Resolve}).
- [(sibling <Module> <seg/seg/…>) …] — cross-{e package} references to a
sibling library built in the same tree; maps a top module to its odoc
directory path.
- [(hosted (<pkg> <dir> <layout> <Wrapper>) …)] — cross-{e project} references
to another hosted Ocsigen project. odoc points these at [ocaml.org]; wodoc
rewrites them to relative links into the sibling project's wodoc docs.
[<layout>] is how that project is deployed: [multilib] (one [<pkg>.<lib>/]
subtree per library, e.g. eliom), [root] (a single package at the version
root) or [subdir] (a [<pkg>/] subtree per package, e.g. js_of_ocaml, tyxml);
[true]/[false] are accepted as legacy aliases for [multilib]/[root].
[<Wrapper>] is its wrapper module (or [""]).
{1 Build inputs and assets}
{t
| Stanza | Meaning |
|--------|---------|
| [(odoc-driver <pkg>)] | build the API with [odoc_driver <pkg> --remap] (the engine ocaml.org uses) instead of [dune build @doc]; needed when [<pkg>.server]/[<pkg>.client] share module names |
| [(profile <p>)] | dune build profile (e.g. [release]) for the [dune build @doc] |
| [(doc-manual true)] | also build the [@doc-manual] alias (examples) |
| [(manual-files <pkg>)] | package dir that receives [manual/files] (examples, images) |
| [(highlight <file>)] | a project-specific syntax-highlight starter to ship as [wodoc-highlight.js]; without it, wodoc ships a built-in default covering eliom / lwt / js_of_ocaml syntax |
| [(markdown false)] | turn off the Markdown twins and [llms.txt] index (on by default; see {{!page-"commands"}Commands}) |
| [(css <href> …)] | the page stylesheets. A relative href is copied into the build and linked per-version (self-contained, works at any path); an absolute ([/…]) or URL href is emitted verbatim. Omitted → wodoc ships its built-in default theme as [wodoc.css] |
}
{1 Layout variants}
{2 Manual at the version root — [(manual-root)]}
A single-package [dune build @doc] project puts both its manual and its API
under a [<package>/] subdirectory. [(manual-root)] strips that leading segment
from output paths, the [(landing …)] and the [(nav …)] links, so the package
deploys at the version root ([ocsigen.org/<project>/<v>/page.html]) — matching
the layout of odoc-driver projects (eliom) so cross-project links resolve.
{2 Manual-only / archived projects — [(mld-dir …)]}
A project with no buildable library API (an archived project, or a tool whose
libraries are internal) has nothing for [dune build @doc] to render. Point
[(mld-dir <dir> [<package>])] at a directory of [.mld] pages and wodoc compiles
them straight with odoc (preprocess → compile → link → html-generate, no dune);
the optional second atom is the odoc [--package]. (When the directory is passed on
the CLI with [--mld-dir] — for a per-version manual — set the package with a
standalone [(mld-package <pkg>)] instead.) The pages {e are} the manual, so
the landing [index.html] is a real page (no redirect). Add [(flat)] when the
first content straddles odoc's preamble boundary. [(static-copy <src> [<dest>])]
(repeatable) copies a tree in verbatim — e.g. a frozen API snapshot that can no
longer be recompiled, or a manual image.
{1 Client/server projects — [(client-server …)]}
A client/server project (eliom, ocsigen-toolkit, ocsigen-start) builds its API
as two or three libraries of one package that share module names
([<pkg>.server] / [<pkg>.client] / [<pkg>.ppx]). Declaring [(client-server …)]
implies [(odoc-driver <project>)] (these shared names would collide under
[dune build @doc]), so you need not repeat it. The block lists one side per
library:
{@text[
(client-server
(server (lib eliom.server) (indexdoc doc/server.indexdoc)
(heading "Server API") (wrapper Eliom) (skip "Index"))
(client (lib eliom.client) (indexdoc doc/client.indexdoc)
(heading "Client API") (wrapper Eliom)))
]}
Each side gives its [(lib <pkg>.<side>)], a curated [(indexdoc <file>)] (a
section-grouped odoc index — [{N title}] + [{!modules: …}] — turned into the
side's module nav via {!Wodoc.Nav.api}), a [(heading …)] (the API-nav title and
switch-button label), the [(wrapper <Module>)] its modules sit under, and any
[(skip <title>)…] section titles to drop. wodoc then gives every page its
side's API nav, a body colour ([wodoc-server] / [wodoc-client] / …) and a
client/server switch button. The {b manual nav is shared} across the sides and
comes from this config's [(section …)] blocks, exactly like a normal project.
List the sibling Ocsigen projects in [(hosted …)] so their cross-references
resolve.
{1 An ultra-simple blog — [(blog …)]}
A wodoc site can carry a blog with no extra tooling: a blog post is just a [.mld]
page. Point [(blog …)] at a directory of posts and wodoc builds each like any
other page, auto-lists them in a generated left-nav section (newest first) and
expands a marker on the landing into a styled "latest posts" list.
{@text[
(blog
(dir doc/blog) ; directory of post sources (default "blog")
(out blog) ; output subdirectory under the version root (default "blog")
(heading "Blog") ; the generated left-nav section heading (default "Blog")
(latest 5)) ; how many recent posts {%wodoc:blog-latest%} shows (default 5)
]}
{2 Writing a post}
A post is a plain [.mld] in [(dir …)], named [YYYY-MM-DD-slug.mld]:
{@text[
doc/blog/2026-06-14-hello-world.mld
]}
- the {b publication date} is the file-name prefix — no metadata file, and posts
sort newest-first on it automatically;
- the {b title} is the post's [{0 …}] / [{1 …}] heading;
- the {b author} is odoc's native [@author] tag (so it also shows on ocaml.org).
odoc warns {e "Tags are not allowed in pages"} for [@author] in a [.mld] page,
but still renders it; the warning is harmless;
- the {b excerpt} shown in listings is the first body paragraph (markup stripped).
Posts deploy at [<out>/<slug>.html] and get the full site chrome, the shared
menu and the blog-augmented left navigation, like every other page.
{2 Latest posts on the landing}
Place a marker where the recent-posts list should appear (typically the landing
[index.mld]):
{@text[
{%html:<!--wodoc-blog-latest-->%}
]}
This [{%html:…%}] form is honoured by stock odoc as an invisible HTML comment
(so it is harmless on ocaml.org) and substituted by wodoc with the list. In a
{e preprocessed} build (a [(mld-dir …)] or [(odoc-driver …)] project) you may
instead write the friendlier [{%wodoc:blog-latest%}]; both reach the same
sentinel. The list is a [<ul class="wodoc-blog-list">] of
[<li class="wodoc-blog-card">], each with a [.wodoc-blog-title] link, a
[.wodoc-blog-meta] line (date — author) and a [.wodoc-blog-excerpt]. wodoc emits
only this semantic markup; style it from your theme's stylesheet.
A page built through the low-level {{!page-"commands"}[wodoc assemble]} path
(rather than [wodoc build]) — typically a separately built site home — can carry
the same listing with
[wodoc assemble … --blog-config <this config> --blog-base <path to the blog root>].
For such a build, {{!page-"commands"}[wodoc blog-nav]} prints the left-nav block
and {{!page-"commands"}[wodoc blog-feed]} prints an Atom feed of the posts (for
syndication, e.g. OCaml Planet).
{1 The version selector and [versions.json]}
Every page carries a version [<select>] in its left column. Both [wodoc build]
and {{!page-"commands"}[wodoc release]} (re)write a [versions.json] manifest at
the {b project root} (the parent of the version directories, e.g.
[<site>/<project>/versions.json]) — the single source of truth the page script
reads to rebuild the menu on load. So even an old frozen page lists the current
version set without being rewritten, and a release only has to touch this one
file.
The format is small:
{@text[
{"latest":"2.3","list":["dev","10.0.0","2.3","2.0"]}
]}
- ["list"] is the ordered menu: [dev] first, then the version directories
newest-first (numeric, so [10.0.0] sorts above [2.0.0]). A directory counts as
a version only if it is itself a wodoc build (it carries
[wodoc-highlight.js]), so the [latest] symlink and stray asset dirs are
skipped.
- ["latest"] records the directory the [latest] symlink points at (or [null]
before the first release). That entry is labelled {e "[<v>] (latest)"} and
keeps the canonical [/<project>/latest/] URL when chosen; other versions
navigate to their own numbered URL.
The menu is also baked statically into each page as a fallback, so it still
works if the manifest cannot be fetched. You never write [versions.json] by
hand — it is generated. See {!Wodoc.Build.write_manifest}.