Odoc docs

Files
README.md

odd #

Keep an opam switch's HTML documentation continuously up to date.

odd wires opam's post-install-commands, pre-remove-commands, post-remove-commands and post-session-commands hooks so that after every successful opam install / opam upgrade / opam remove, the docs for exactly the packages that changed are regenerated, in dependency order, by odd-driver. The per-package hooks are plain coreutils (a touch to mark a package stale, find -delete/rm -rf to drop a removed one's docs), so they keep working even when odd itself isn't installed in the switch; only the once-per-session worker needs the binary. Documentation artifacts are installed under $OPAM_SWITCH_PREFIX/lib/: a module's .odoc/.odocl files sit next to the .cmt/.cmti they were compiled from, in the library's own directory, and a package's documentation pages live under lib/<package>/, mirroring their ids — for most packages, the same directory. HTML output and indexes are written to $OPAM_SWITCH_PREFIX/odoc/<package>/, with a landing page at $OPAM_SWITCH_PREFIX/odoc/index.html. (This is odd's own tree, kept separate from opam's $OPAM_SWITCH_PREFIX/doc, where packages install their own documentation.)

See doc/DESIGN.md for the full design, and doc/DESIGN_DOC.md / doc/DESIGN_COMPLETE.md for the doc and complete commands.

Setup #

$ odd setup          # show the opam configuration to be added
$ odd setup --apply  # add it to ~/.opam/config via `opam option`
$ odd rebuild --all  # Initial (slow!) build of all the docs

The odoc driver (odd-driver) is bundled with odd (vendored under driver/, built and installed alongside the odd binary), so there's nothing else to install. It drives the odoc, odoc-md and sherlodoc binaries, which must be present in the switch.

Commands #

  • odd sync — session worker (the post-session hook); rebuilds every package marked stale, in dependency order, and regenerates the landing page. Always exits 0; details go to $OPAM_SWITCH_PREFIX/var/cache/odd/log.
  • odd rebuild [--all | PKG...] — mark packages stale and sync. Exits non-zero on failure (user-facing, unlike the hook commands).
  • odd order [PKG...] — print the dependency order that sync would use (debugging aid).
  • odd search [--package PKG]... [--match=name] [-n N] QUERY — search the generated documentation. Queries every package's sherlodoc_db.marshal together (a single query covers the whole switch), printing each match with its owning library and package. The query is space-separated words, optionally followed by a : type annotation (map : list -> _); words match as literal substrings of an entry's name or its doc text — no regexes. Operators are indexed by their bare symbol (odd search '$' finds Cmdliner.Term.($)). --match=name keeps only entries whose name contains every word; --package restricts to named packages; at most -n results are printed (default 25).
  • odd doc REFERENCE — print an item's documentation as Markdown, under a header naming the item and the library/package it comes from, resolving an odoc reference against the whole switch. Stdlib is open, so bare names work (List, print_endline); references may also be qualified (Astring.String) or path-qualified — module units by library (/brr/Brr, /terminal.ansi/Terminal_ansi for a sub-library), pages by package (/brr/web_page_howto). A reference that fails to resolve is retried against the switch's package/library names (brr.Brr → /brr/Brr, /terminal/ansi/… → /terminal.ansi/…) with a note on stderr; a miss naming an installed package whose docs aren't built points at odd rebuild. A module's rendering ends with its submodule references, since their bodies appear only as sig ... end in the parent page, and every rendering ends with the installed source paths (.mli/.ml, a page's .mld) when present. When a reference is ambiguous (e.g. a bare index, a page in every package), it lists the package-qualified alternatives instead of picking one; when a bare name resolves through the Stdlib open (List → Stdlib.List), a note on stderr names the winner.
  • odd complete PARTIAL — list the references PARTIAL could be completed to, one per line: members of what it names so far (List.m → List.map, …; kind tags filter, e.g. module-List.type- → module-List.type-t), package/library names for a leading / (/o → /odoc, /odoc.model, …), or the entries under a /root/ path. A root that is both a package and a library (brr) lists both namespaces: module units (Brr) next to pages and sub-library directories (brr.poke); sub-library modules complete under the dotted root (/terminal.ansi/ → Terminal_ansi). The engine for shell completion.

Shell completion (zsh, bash) #

Completions are shipped for zsh (completions/zsh/_odd) and bash (completions/bash/odd). Both complete the subcommands and, for doc and complete, the reference argument — by calling odd complete, so completion always matches the command's own resolver (Stdlib open, package-qualified /pkg/... paths, kind tags like type-, section labels, …). Type . or / and press TAB again to drill in.

opam install puts both under the package's share dir. Neither directory is consulted by the shell by default, so point at it yourself.

zsh — add to ~/.zshrc, before compinit:

fpath=("$(opam var odd:share)/zsh" $fpath)
autoload -U compinit && compinit

bash — add to ~/.bashrc:

source "$(opam var odd:share)/bash/odd"

(Or use completions/zsh and completions/bash/odd from a source checkout. The bash file is named after the command, so dropping it in ~/.local/share/bash-completion/completions/odd works too, and loads lazily.)

Development #

$ opam install . --deps-only --with-test
$ dune build
$ dune runtest