Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Build documentation

The book is mdBook, built from docs/. Parts of it are generated from the code, and every code block in it is checked.

python3 scripts/docs/build_single_version_docs.py preview
python3 scripts/docs/rebuild_index.py
python3 -m http.server 8000 --directory book

Open http://localhost:8000 for the landing page and the book. Install the prerequisites first:

cargo install mdbook --version 0.5.2 --locked
python3 -m pip install -r scripts/requirements.txt

The scripts find mdBook on PATH or in ~/.cargo/bin/.

Where to edit

FilePurpose
docs/SUMMARY.mdSidebar order and page titles
docs/getting-started/Start: install, quick start
docs/user-guide/Use datui: one page per task
docs/formats/Formats: the overview, then one page per family
docs/reference/Reference: options, keys, settings, syntax, Python API
docs/for-developers/Contribute
book.tomlmdBook settings, and a redirect for every moved page and heading
README.md, python/README.mdThe GitHub and PyPI pages
scripts/docs/index.html.j2The landing page at the site root
docs/night-market.cssColors and layout

Style

Rule
TitleThe H1 is the page’s title in SUMMARY.md, in sentence case
LeadOne sentence, then the command or the key, then a table
ProseOnly for what a table cannot say. No design rationale in user pages
One home per factSampling, what gets read, light and dark, cloud logins: one page says it, the others link to it
LengthAbout 250 lines for a guide page; a reference page of tables may run longer
WordsThe glossary; tests/wording_test.rs fails on a retired word
ClaimsVerified against the code. No speed claim that was not measured
LinksRelative, with .md. Never to plans/ or another unpublished path

A moved page or heading gets a redirect in book.toml, and the README and landing page links move in the same change.

Generated pages

Do not edit these by hand. Change the code they come from, then write them:

cargo run -p datui-cli --bin gen_docs -- write
Page or regionFrom
reference/command-line-options.mdThe clap Args and examples.toml in crates/datui-cli
reference/settings.mdThe option registry, SETTINGS in crates/datui-cli/src/settings.rs
reference/environment.mdENVIRONMENT in the same file
reference/keyboard-shortcuts.md, region keysThe key registry, crates/datui-cli/src/keys.rs
formats/index.md, region formatsThe format descriptors in crates/datui-cli/src/formats.rs
Region format-count in formats/index.mdThe same: how many formats, and their names
Region pitch in introduction.md and README.mdsite::PITCH in crates/datui-cli/src/docgen/site.rs
reference/python-api.md, region optionsThe registry’s Python keywords
Region install in README.md and the landing page; install-script, install-table and install-apt in getting-started/installation.mdscripts/docs/install.toml, one entry per install channel
Region formats in the landing pageThe format descriptors: the formats strip by family
The package descriptions: description in Cargo.toml and python/pyproject.toml, the deb’s extended-description, Homebrew’s desc, the desktop entry’s Commentsite::summary and site::description in crates/datui-cli/src/docgen/site.rs
reference/manual-pages.md, region pagesThe list of manpages, PAGES in crates/datui-cli/src/man/mod.rs
crates/datui-cli/man/* (the manpages)All of the above, plus long_about.txt, query-syntax.md, formats/index.md and the format-spec pages (Build and publish packages)

GENERATED in crates/datui-cli/src/docgen.rs lists them. A region sits between two comments, which mdBook and GitHub hide; the text around it is written by hand:

<!-- generated: keys -->
<!-- end generated: keys -->

In the landing page the comments are Jinja’s, {# generated: NAME #}; in TOML, Ruby and desktop files, # generated: NAME.

the_generated_docs_are_current (scripts/dev/test.sh cli) fails while a committed copy differs. gen_docs with no argument prints the command-line reference; with settings, environment or keys, that page.

Code blocks

Every fenced block in docs/, the READMEs and the next release’s notes is one of three kinds, named in its info string. On the landing page every <pre> names it in data-example (<pre data-example="bash,network">), and the runner checks and runs those the same way:

KindInfo stringChecked
Runnablebash, toml, python, sql, q, …Run, as a reader would paste it on a fresh install
Shape to fill inbash,template, toml,templateNot run. Placeholders are <UPPER_CASE>, and the sentence before the block says what to replace. Its flags must exist; TOML must parse once filled in
Outputtext, consoleNot run: what a command prints, or a screen

Code shown from the source (rust, yaml, json) is not run. More attributes go after the language, comma-separated:

AttributeMeans
networkReads public data; runs in the Nightly job
interactiveIts producer never ends; stopped once the first rows show
continueRuns in the directory the page’s previous block ran in
expect=rows, screen or exitWhat its datui command must do: show rows (the default with a path), stay up (the home screen, the hex view), or print and exit
specA TOML format spec, checked with datui formats check
catalogA catalog file, checked with datui catalog check
dataset=NAMEA sql or q block’s data, from scripts/docs/doc_datasets.toml
rows=NThe rows a sql or q block returns
repoRun from a checkout of this repository; its scripts/ paths must exist, and it is not run
installInstalls datui; test-install.yml covers it
file=NAMEA file the page’s next runnable block uses by name; written into its directory before it runs, not run itself

A runnable block stands alone: it uses the built-in catalog’s public data, real commands (seq, printf, journalctl), or the file blocks above it. Files an example needs are titled file blocks, never heredocs; sample-data generators are readable scripts. Each file is its own block, its name in bold on the line above, and the command block runs it by name:

**`make_day_l2.py`**

```python,file=make_day_l2.py
...
```

```bash
python3 make_day_l2.py
datui day.l2
```

The lint fails a heredoc or a python -c in a shell block, and a file block the next runnable block does not name. A binary generator lays out its records with ctypes.LittleEndianStructure (_pack_ = 1, _layout_ = "ms"), a field per field of the format. A bash or toml block never starts a line with a # comment; say it in the text, or at the end of a command.

The examples datui --help, the manpages and the command-line reference show are crates/datui-cli/examples.toml: each entry’s command, description, test (run, network or interactive), an optional expect, and the pages whose EXAMPLES show it (datui.1 when not given; datui COMMAND --help shows those of datui-COMMAND.1). Every command page needs one. Files a command reads are a files list ([{ name, text }]): the runner writes them and the pages show each under its name, never a printf into a file. Each runs with HOME set to its own directory, so an example may install into ~.

Run the checks

CommandChecks
.venv/bin/python scripts/docs/doc_examples.py --lintEvery block’s label, placeholders and flags. Needs no binary
.venv/bin/python scripts/docs/doc_examples.py --bin target/debug/datuiRuns the runnable shell and TOML blocks, and examples.toml’s entries, that need no network
... --bin target/debug/datui --networkThe network ones instead
.venv/bin/python scripts/docs/doc_examples.py --pythonThe python blocks, with the wheel installed (Build Python bindings)
... -k quick-startOnly the blocks whose file:line or text holds the word
scripts/dev/test.sh unit doc_queriesEvery q block parses; sql and q blocks on data that ships with the docs run
python3 scripts/docs/lint_docs.pyH1s against SUMMARY.md, headings in sentence case, links, redirects
python3 scripts/docs/lint_manpages.pyThe manpages: no mandoc -T lint or groff -ww warning at 78 or 60 columns, and a NAME line lexgrog reads. Skips a tool that is missing; CI passes --require
./scripts/docs/check_doc_links.sh book/previewEvery link in the built book, with lychee; --online adds external URLs

A shell block runs in an empty directory with its own DATUI_CONFIG_DIR and DATUI_CACHE_DIR. scripts/docs/datui_shim.py stands in for the reader: it runs datui on a pseudo-terminal, passes once the table shows rows, answers a download question, and otherwise fails with the screen’s last text. A failure names the file and line.

The queries on public data run once the datasets are downloaded:

.venv/bin/python scripts/docs/doc_examples.py --fetch-datasets ~/tmp/doc-data
DATUI_DOC_DATA=~/tmp/doc-data cargo test -p datui-lib --lib doc_queries -- --ignored

CI runs the lints and the local blocks on every pull request. Nightly runs the network blocks, the network Python blocks and the queries on public data. Check the examples covers the numbers the guides quote.

Build choices

CommandOutput
python3 scripts/docs/build_single_version_docs.pyThe current checkout, under its branch name
python3 scripts/docs/build_single_version_docs.py previewThe current checkout, to book/preview/; the argument only names the output
python3 scripts/docs/build_single_version_docs.py vX.Y.ZChecks out the tag, builds it, restores the checkout; use a clean worktree
python3 scripts/docs/build_all_docs_local.pyEvery tag in temporary worktrees, then latest/ and the landing page
python3 scripts/docs/rebuild_index.pyOnly the landing page, from the books already built
python3 -m unittest discover -s scripts/docs -p 'test_*.py'The build scripts’ tests

A branch build writes the command-line reference into a temporary copy; a tag build uses the one committed with the tag. The landing page lists release and development books. It stays a landing page; it does not redirect into a book. Check it in light and dark, at phone and desktop widths, with the keyboard and with JavaScript off.

Publishing

PathContentsBuilt
/Landing page, from scripts/docs/index.html.j2Every deploy
/latest/A copy of the newest tagged bookOn a v* tag (release.yml)
/vX.Y.Z/That tag’s bookOn its tag, then from cache by the tag’s SHA
/dev/main’s bookOn every push to main that touches the docs (build-and-publish-docs.yml), and on a release

A deploy replaces the whole site, so both workflows build every tag (from cache), /latest/ and /dev/. A merged docs change shows at /dev/ within minutes and reaches /latest/ with the next release. Build and publish docs can also be run by hand. A tag’s cached book is marked by book/<tag>/.built_sha; remove the marker to rebuild it locally.