# Writing Man Pages with AsciiDoc A workflow for authoring Unix man pages in AsciiDoc and installing them into the local man database on Debian (and Debian-derived) systems. ## Why AsciiDoc Native `roff` is terse and unforgiving. AsciiDoc is plain-text, version-control friendly, and `asciidoctor` ships a dedicated `manpage` backend that produces groff source indistinguishable from a hand-written page. ## Prerequisites ```sh sudo apt install asciidoctor ``` Confirm the manpage backend is available: ```sh asciidoctor --backend=manpage --help >/dev/null && echo OK ``` ## Source File Structure Name the source `.
.adoc`, where the section is one of: | Section | Contents | |---------|--------------------------------| | 1 | User commands | | 5 | File formats and conventions | | 7 | Miscellaneous / overviews | | 8 | System administration commands | A minimal template (`foo.1.adoc`): ```adoc = foo(1) Author Name :doctype: manpage :manmanual: FOO Manual :mansource: FOO 1.0 == NAME foo - one-line summary of what foo does == SYNOPSIS *foo* [_OPTIONS_] _ARGUMENT_ == DESCRIPTION Longer prose description of the command. == OPTIONS *-h*, *--help*:: Print help and exit. *-v*, *--version*:: Print version and exit. *-f* _FILE_, *--file*=_FILE_:: Read input from _FILE_. == EXIT STATUS *0*:: Success. *1*:: General error. == EXAMPLES Run foo against a file: foo -f /etc/hosts == ENVIRONMENT *FOO_CONFIG*:: Path to the configuration file. == FILES _~/.config/foo/config_:: User configuration. == SEE ALSO *bar*(1), *baz*(5) == AUTHORS Author Name == BUGS Report bugs at https://example.org/foo/issues ``` ### Mandatory elements - **Title line** `= name(section)` sets the page name and section number. - **`:doctype: manpage`** selects the manpage backend. - **`NAME`, `SYNOPSIS`, `DESCRIPTION`** headers (uppercase, `==`) are required. ### Useful conventions - `*bold*` renders as bold (commands, flags). - `_italic_` renders as underline in terminals (variables, arguments, file paths). - `*cmd*(N)` for cross-references to other man pages. - `::` after a term starts a definition list (options, environment vars). - Indented lines in `EXAMPLES` are preformatted blocks. ## Building Convert AsciiDoc to groff man source: ```sh asciidoctor -b manpage foo.1.adoc ``` Output: `foo.1` in the same directory. Preview without installing: ```sh man -l ./foo.1 ``` ## Installing Locally Debian's `man-db` reads `~/.local/share/man` automatically (it is part of the default `MANPATH` derivation). No `manpath` edit required. ```sh mkdir -p ~/.local/share/man/man1 cp foo.1 ~/.local/share/man/man1/ ``` After installation: ```sh man foo # works immediately ``` For `apropos` and `whatis` to find the new page, rebuild the index: ```sh mandb -u # incremental update of the user index ``` The user-level index lives in `~/.local/share/man/index.db`; no root needed. ## System-Wide Installation (optional) For pages that should be visible to all users: ```sh sudo cp foo.1 /usr/local/share/man/man1/ sudo mandb ``` Use `/usr/local/share/man`, not `/usr/share/man` (the latter is reserved for distribution-packaged pages). ## Verification ```sh man -w foo # prints the path man would open man -k 'one-line summary' # apropos search; requires mandb update whatis foo ``` ## Automating with Make A minimal `Makefile`: ```makefile PREFIX ?= $(HOME)/.local MAN1DIR := $(PREFIX)/share/man/man1 SOURCES := $(wildcard *.1.adoc) PAGES := $(SOURCES:.adoc=) all: $(PAGES) %.1: %.1.adoc asciidoctor -b manpage $< install: all install -d $(MAN1DIR) install -m 644 $(PAGES) $(MAN1DIR)/ mandb -u clean: rm -f $(PAGES) .PHONY: all install clean ``` Usage: `make`, `make install`, `make clean`. ## Troubleshooting | Symptom | Cause / Fix | |-------------------------------------------|------------------------------------------------------------------| | `man foo` reports "No manual entry" | File not in MANPATH; check `manpath` and `man -w foo` | | `apropos foo` finds nothing | Run `mandb -u` | | Page renders but options look misaligned | Ensure `::` is on the same logical line as the term it defines | | Cross-references not linked in HTML build | Manpage backend renders them as `name(N)` text only; this is OK | | Asciidoctor warns about missing `NAME` | The required headers must be uppercase and start with `==` | ## References - `asciidoctor(1)`, `man(1)`, `man-pages(7)`, `mandb(8)` - Asciidoctor manpage backend: - File Hierarchy Standard, ยง4.11 (manual pages)