Work in progress — public development preview. This project implements a documented subset of roff/man; it is not a replacement for the full GNU groff toolchain. The CLI and APIs may change, and no stable binary release is available yet. See documentation and the planned GitHub Pages site (available after publication is enabled).
Read Linux man-page source, inspect its structure, export HTML or paginated PNG/JPEG, convert a supported HTML/man subset, and browse a local collection. The headless CLI and libraries use pure Go with bundled Go fonts. They need no groff, browser process, fontconfig, C compiler or installed man database.
Example input → HTML, PNG, dark JPEG, OPTIONS AST, validation and canonical roff.
These commands remain unreleased development features. There are no published binary releases yet. Check the release page for future archives; older revisions may not contain these commands. The release/install guide describes checksum verification, archive/package contents and the publication gates. Snapshot candidates are available as CI artifacts after successful builds; they are development builds.
From a checkout containing the merged features, use Go 1.26 or newer (tested: 1.26.10):
go build -o gtroff ./cmd/gtroffOr install this feature revision directly, with Go's bin directory on PATH:
go install github.com/arran4/golang-gtroff/cmd/gtroff@mainA tagged release can replace the branch suffix once published. For library use,
use go get github.com/arran4/golang-gtroff with an appropriate reviewed revision.
The optional desktop command has a separate module and build below.
The small synthetic page contains NAME, SYNOPSIS,
DESCRIPTION, repeated formatting styles, OPTIONS, EXAMPLES and links. All commands
below run from this checkout. # smoke blocks are executed against a real binary
in tests; generated files go into a temporary directory there.
# smoke
./gtroff validate --strict examples/man-tool.1
./gtroff ast --select section:OPTIONS examples/man-tool.1 > options.json
./gtroff man render > gtroff-render.1
./gtroff completion bash > gtroff.bash
./gtroff render --format html -o page.html examples/man-tool.1
./gtroff render --format png -o page.png examples/man-tool.1
./gtroff render --format jpg --theme dark -o page.jpg examples/man-tool.1Validation reports accepted syntax. Open page.html or either image to read the
result. options.json contains the selected nodes and the complete original
source snapshot, including original line endings. IDs are stable within that
snapshot. Omit FILE or use - to read stdin.
validate checks syntax rather than typesetting or semantic support. Unknown
requests produce warnings; malformed input fails. --strict rejects warnings.
Diagnostics go to stderr, or inside JSON for validate --format json and ast.
Exit codes are 0 success (possibly warnings), 1 invalid/strict, 2 usage/selection,
and 3 I/O/resource failure. CLI details.
# smoke
./gtroff ast --select section:OPTIONS --format text examples/man-tool.1
./gtroff render --section OPTIONS --theme dark -o options.html examples/man-tool.1
./gtroff render --format png --section OPTIONS --single -o options.png examples/man-tool.1
./gtroff render --format png --width 600 --page-height 400 -o pages.png examples/man-tool.1
./gtroff help renderThe last render writes pages-001.png, pages-002.png, and so on. Single-page
output uses the exact requested name. Images on stdout require one page.
--single derives height within guarded limits; it does not crop overflow.
--width, --margin and --page-height use pixels. Image --font-size uses
points at --dpi (default 96); HTML font size uses CSS pixels.
AST selectors also accept node:ID and path:/0/1. Render --node ID takes an
AST source ID. Repeated matching headings select every matching section.
HTML --fragment emits a styled article; --assets omit-fonts makes a smaller
file that uses reader-side font fallback.
Four bundled Go faces are the default. To use an explicit font file:
./gtroff render --font-regular /path/to/regular.ttf --font-mono /path/to/mono.ttf -o custom.html examples/man-tool.1Other faces retain bundled defaults. No font discovery runs automatically. Missing raster glyphs are displayed as code-point labels and diagnosed. HTML options · image layout and limits.
# smoke
./gtroff convert --from html --to roff --strict -i examples/convert.html -o converted.1
./gtroff convert --from roff --to html -i converted.1 -o converted.htmlCompare the HTML input with its canonical roff result. Headings, paragraphs, emphasis, definitions, nested lists, preformatted text and safe links have semantic loop contracts. Canonical output changes source spelling. Original bytes and normalized semantics remain separate. Unsupported tags/CSS/scripts become visible literal fallback with diagnostics; strict mode rejects them before writing. Supported profile and conversion contracts.
./gtroff serve --root examples --listen 127.0.0.1:8080Open http://127.0.0.1:8080, search for man-tool, then follow OPTIONS or EXAMPLES.
The server indexes explicit directories once and serves a read-only snapshot;
restart to refresh. Plain and gzip man files work. Built-in search needs no system
utilities. To supplement it with an installed apropos/whatis, opt in:
./gtroff serve --root /usr/share/man/man1 --root /usr/share/man/man3 --system-searchUnavailable system search falls back to internal search with a notice. The server defaults to loopback; remote listening requires explicit opt-in. Includes and request parameters never resolve arbitrary files. Server guide.
cd desktop
CGO_ENABLED=0 go build -o gtroff-view ./cmd/gtroff-view
./gtroff-view ../examples/man-tool.1Scroll or drag, zoom with +/-, fit with f, switch pages with n/p, and
close with Escape. The separate module keeps Shiny out of headless dependencies.
--section OPTIONS opens a selection. On macOS use a native CGO/toolchain build.
Controls, build options and native smoke procedure.
| Surface | Linux | Windows | macOS |
|---|---|---|---|
| Headless CLI, HTML, raster, server | Native CGO-free tests | Cross-built; native CI configured | Cross-built; native CI configured |
| Optional viewer | X11 / CGO=0 executed under Xvfb | Win32 / CGO=0 cross-built; runtime unverified | Native CGO backend configured; runtime unverified |
Hosted CI currently fails before running any steps; native Windows/macOS test results are not established. Tracked release/CI work.
This is a bounded Linux-man subset, not full groff typesetting. Tables, equations, macro evaluation, arbitrary CSS, complex shaping and all Unicode glyph coverage are not promised. Unsupported content remains visible with diagnostics. Source includes, commands and remote resources are never loaded by these workflows. The opt-in legacy evaluator is separate from render/convert/serve.
Parser/evaluator/include/generator findings under #3–#17 remain separate contracts. Specific parser dependencies. Named outputs stage before per-file replacement; multipage replacement is not atomic as a collection. Resource and strict failures preserve existing outputs.
Library guide · AST · semantic model ·
executable AST example. cmd/lex remains the legacy token
inspection utility. Generated catalogue coverage is not semantic support.
go test ./...
go vet ./...
go generate ./...Generation rebuilds macro/request definitions, dispatchers and catalogue from
cmd/gen/in.json, schema.go and templates, regenerates
man pages and completions, and checks committed CLI examples.
It does not refresh example expectations. To approve a refresh:
go run ./cmd/examples --write
go test . -run '^TestIntegrationScenarios$' -update-integrationRun ordinary tests again and inspect text and images before committing. The
shared scenario guide explains cross-feature checks, both
conversion loops, binary snapshots and focused update commands. The semantic
model JSON uses -update-man; the viewer screenshot requires the explicit native
smoke capture documented in its guide. Neither is silently regenerated.
For coordinated reporting, secret-handling policies and security boundaries, see SECURITY.md.
Project-authored code is offered under GPL-3.0-or-later. Third-party fonts, fixtures, and GNU groff documentation retain their applicable original terms. See LICENSE, Licensing and provenance, and the bundled GFDL text.
Publication clearance remains under review in issue #67 until source-by-source coverage of descriptions embedded in generated Go is verified.