Skip to content

PDF set: the PDFs of a docset link to each other (2/3) - #22

Merged
tobiaskaestner merged 8 commits into
mainfrom
tkaestner/pdf-set
Oct 31, 2026
Merged

tobiaskaestner merged 8 commits into
mainfrom
tkaestner/pdf-set

Conversation

@tobiaskaestner

@tobiaskaestner tobiaskaestner commented Oct 29, 2026 •

Copy link
Copy Markdown
Contributor

The second of three stacked PRs for the PDF output (base: #21). The PDFs of a docset become one set that links to itself and works offline.

deploy/pdf is the PDF set. Each document with a latex builder gives one <title>_<version>.pdf in deploy/pdf (the registry title with - for white space, and the version that the document shows). docrefs.py pdf-deliver copies the PDF there after latexmk and removes the other versions of the same document. pdf-remove is the clean step. Two documents with the same title part give an error at configure time. The LaTeX build directory is now a work area at <build>/<doc>/latex.

Links between the PDFs. zdocs_conf sets the hyperref option destlabel, so each LaTeX label (<page>:<anchor>, one per need, section and page) is also a named destination. pdf_links changes a link to a document of the set into <title>_<version>.pdf#<page>:<anchor>, which hyperref writes as a "go to remote" action. Links to documents outside the set use the rules of #21.

doc-check reads the set (check C). It fails on a link to a PDF that is not in the set, or to a destination that the target PDF does not have. It needs pypdf, which is now pinned in requirements-doc.txt (6.15.0).

Docs. ADR 0013 records the decision. The publishing how-to tells how to give the set to readers: one folder, the file names unchanged, built and released together. The deploy layout, the registry title: and the doc-check reference are updated.

Checks: unit 533, zdocs docs 0 warnings. safety-toolbox: 4 PDFs, 687 links between them, 0 broken, with the published and with the development base URL. Before the engine change, a manual click test of a prototype set in Evince found all links working. Not done yet: click tests in Firefox and Chromium, and an acceptance test with two linked PDFs. The matching acceptance changes (test_15, test_18, test_22) come in a separate zdocs-tests PR.

🤖 Generated with Claude Code

tobiaskaestner and others added 8 commits October 29, 2026 11:37
A PDF's links to other documents went to the HTML site (base_url), or
became text in a development build. deploy/pdf/<doc>/ held the whole
LaTeX build directory, and the PDF had the name of the project title.

Now the PDFs of a set are one deliverable that works offline:

- deploy/pdf is the PDF set: one <title>_<version>.pdf per document
  with a latex builder (registry title, white space as "-"; the version
  the document shows). `docrefs.py pdf-deliver` copies latexmk's PDF
  there after the build and removes the other versions of the same
  document; `pdf-remove` is the clean step. Two documents with the same
  title part are a configure-time error.
- The LaTeX build directory is a work area at <build>/<doc>/latex.
  docrefs takes the build root and the doc id from ZDOCS_DOC_BUILD_DIR
  and ZDOCS_DOC_ID, as the path of OUTPUT_DIR no longer gives them.
- zdocs_conf sets hyperref's destlabel: each LaTeX label (Sphinx writes
  one per need, section and page, "<page>:<anchor>") is a named
  destination of the same name.
- pdf_links turns a link to a document of the set into a link to its
  PDF, <title>_<version>.pdf#<page>:<anchor>, which hyperref writes as a
  "go to remote" action. docrefs gives the map (zdocs_pdf_peers) in a
  non-HTML build only. Links to other documents keep the rules before.

Checked on the four safety-toolbox PDFs: 687 links between them, all
with a target (a spike with Evince and pdf.js before), with the
published and with a development base URL.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tobias Kaestner <tobias.kaestner@inovex.de>
A link from one PDF of deploy/pdf into another names a file and a named
destination. If either is missing, the link is dead, and a PDF is
mailed and filed as it is.

doccheck now reads the PDFs of deploy/pdf (check C) and fails on a link
into a PDF that is not in the set, or into a destination that the PDF
does not have. It reads "go to remote" actions and relative URI links
to <file>.pdf#[nameddest=]<dest>. It needs pypdf, now pinned in
requirements-doc.txt (6.15.0); without it, a set with PDFs is a
finding. Without PDFs, the check has nothing to read.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tobias Kaestner <tobias.kaestner@inovex.de>
ADR 0013 records the decision: deploy/pdf is a set of
<title>_<version>.pdf that link to each other, the LaTeX build
directory is a work area, and doc-check checks the links. The how-to
for publishing says how to distribute the set (one folder, file names
kept, built and released together); the deploy layout, the registry
`title:` and the doc-check reference follow.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tobias Kaestner <tobias.kaestner@inovex.de>
The LaTeX preamble was strings in zdocs_conf. It is now a style file,
sphinx/_latex/zdocs.sty, that Sphinx copies next to the .tex and that
the preamble loads after Sphinx's own package. zdocs_conf only sets the
values of the build with \zdsetup{title, version, footer}.

A consumer can give its own style file: configure(latex_style=...). The
PDF loads it last, so it can set the same keys, colors and fonts again.

zdocs.sty loads no package that a Sphinx xelatex build does not load.
It changes the layout only through what Sphinx documents: the page
styles "normal" and "plain" and \sphinxtableofcontents.

Changes in the PDF:
- one font family: the body text uses the sans-serif font of the
  headings (FreeSans), not FreeSerif;
- the running header gives the title and the version, not the doc id;
- the footer says "Copyright <year> <holder>", without "All rights
  reserved";
- the contents follow the title page under a section-size heading, and
  the text starts on the same page (no fncychap, no roman page numbers),
  so the page count in the footer is right.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tobias Kaestner <tobias.kaestner@inovex.de>
CSS does not reach LaTeX, so in a PDF a zdocs card was the sphinx-needs
table: grey bands, the fields before the text, labels that look like
the values ("Tags:detection"), and an empty line before the links.

In a LaTeX build, need_cards now replaces the table of each zdocs card
with a zd_need node and writes it with new macros of zdocs.sty
(zdneed, \zdneedhead, \zdneedtitle, \zdneedfield):
- no background, so the card prints well: a bar on the left in the
  accent color of the type (the same OKLCH rule as --zd-accent);
- the head: type, ID and the status as a framed badge in the color of
  the HTML pill (good, bad, gap, none, or the type accent);
- the title in bold, then the text, then the fields and links;
- each field and link with a grey label in one aligned column;
- a long ID also breaks after an underscore;
- the card breaks across pages (framed, which Sphinx loads already).

The label of the need stays at the top of the card, so links into the
card, and between the PDFs of the set, keep their target.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tobias Kaestner <tobias.kaestner@inovex.de>
In a PDF, a needtable without :colwidths: had the fixed widths of
sphinx-needs (15 parts for the title, 5 for each other column): the
need IDs broke in two, and long tags and Kconfig names ran past the
edge of the page. A table of 30 rows or fewer was a tabular, which
does not break across pages: a long one moved to the next page and
left an empty page.

The new extension pdf_tables gives each such table, in a LaTeX build:
- column widths from the content: each column as wide as its longest
  word (a need ID stays on one line), the rest of the line to the
  columns with the most text;
- the class longtable, so it breaks across pages;
- ragged-right cells (class zd-needtable);
- a smaller font and less padding (zd-table-small, zd-table-smaller)
  for a table with too many columns for the line;
- a line break after a slash, and after a dot before a letter.

zdocs.sty: in a table and in a need card, a line can break after an
underscore (penalty 100, so TeX still breaks at a space if it can); in
the text of a page a name stays one word. A tabulary column is at
least 5.5em wide.

The toolbox test report: 960 overfull lines -> 2, 50 pages -> 37.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tobias Kaestner <tobias.kaestner@inovex.de>
The Sphinx title page had the title, "Release <version>", the author
and the date, right-aligned on an otherwise empty page.

zdocs.sty defines \sphinxmaketitle again: the title and the version,
then the document ID, the date and the author. If the PDF links to
other PDFs of its set, the title page names their files and says that
the links work only while the files are in one folder with these names.

zdocs_conf gives the values: \zdsetup{docid, set}.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tobias Kaestner <tobias.kaestner@inovex.de>
ADR 0014: the PDF layout is a LaTeX package that changes Sphinx only
through its documented hooks, loads no package that Sphinx does not
load, and that a consumer's style file can change.

A how-to for a consumer's style file (configure(latex_style=...), the
\zdsetup keys, colors, fonts, the label width of a card), the card in
a PDF in the directives reference, and pdf_tables in the API reference.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tobias Kaestner <tobias.kaestner@inovex.de>
@tobiaskaestner
tobiaskaestner changed the base branch from tkaestner/pdf-links to main October 31, 2026 09:42
@tobiaskaestner
tobiaskaestner merged commit 5bc5def into main Oct 31, 2026
3 of 5 checks passed

This branch was successfully deployed

1 active deployment
github-pages — 5bc5def5 Deployed Oct 31, 2026 by tobiaskaestner via Deploy to GitHub Pages #51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants