Background ---------- mmroff(1) pdfmom(1)
...and today's dispute between Deri and myself. https://lists.gnu.org/archive/html/groff/2026-07/msg00094.html https://lists.gnu.org/archive/html/groff/2026-07/msg00095.html Summary ------- For purposes of this proposal, a "reference" is an internal reference within a document that may be discussed in formatted text and/or hyperlinked. Let's add reference tracking inside the formatter itself. The scope is as minimal as possible: we want to know if any forward reference "promises" that a document makes have gone unfulfilled--"unkept" by the time the formatter exits. Management of auxiliary reference-related information, such as section or page numbers, or human-readable text to accompany it, is beyond the scope of this proposal; a macro package can use the unique reference identifiers supported here, however, as scaffolding to perform their own data management by constructing their own register and string names. Sketch of UI ------------ Two new requests respectively manipulate and query or dump a dictionary of reference identifiers. Here's a sketch of changes to the groff(7) man page. .ref {link|mark} identifier Register a reference _identifier_. GNU troff maintains a dictionary of references. The request populates the dictionary with an entry for _identifier_ if it does not already exist. If the first argument is "mark", then the reference's datum is assigned with a true value: the reference is fulfilled within the document. If the first argument is "link", the datum is not manipulated. If the first argument is neither "link" nor "mark", GNU troff diagnoses an error and the reference dictionary is not affected. It is not an error to mark the same _identifier_ multiple times. (To be determined: should we warn in that event? Should we employ a new warning category for this scenario?) .pref [identifier ...] Report, to the standard error stream in JSON format, any match in the reference dictionary for each _identifier_. If no arguments are specified, report all entries in the reference dictionary. Here's a sketch of changes to the groff(1) man page. Exit status ... If any reference identifier was linked before it was marked, GNU troff exits with status 3 and issues a list of all such references to file descriptor 3 (but see the -Q option) as a sequence of `ref mark` requests. If the reference was subsequently marked in the input, a comment follows the request on the same line reporting the file name and line number where the mark actually occurred. After these requests, GNU troff then emits an `.lf 1` request. Options ... Transparent options The following options are passed as‐is to the formatter program troff(1) and described in more detail in its man page. ... -Q fd Emit _troff_ requests recording “forward” and unfulfilled reference links to file descriptor _fd_ instead of 3. How to use this reference system -------------------------------- The idea is that you'd run groff(1) or troff(1) repeatedly (up to twice, except possibly in the case of documents that emit reference links or marks only conditionally). A forward reference causes the formatter to exit with status 3 and dump out GNU troff input like the following to file descriptor 3. .ref mark footnote-1 \" 45 "chapter1.me .ref mark footnote-2 \" 206 "chapter6.me .lf 1 (Why the neutral double quotation mark before "chapter"? See [1].) You can then re-run groff(1) or troff(1) with the foregoing input prepended to your originally specified input, and since every `ref link` request encountered will be preceded by a corresponding `ref mark` for the same identifier, GNU troff will exit with status 0 if the document encounters no other formatting problems. Consider a case where the document was composed erroneously, with a reference link that was never fulfilled with a corresponding mark. Say our previous example never actually populated "footnote-1". We'd then see something like this. .ref mark footnote-2 \" 206 "chapter6.me .lf 1 ...and attempting to format the foregoing prepended to the original input stream to troff(1) would still exit with status 3. Notes ----- The comment after the synthesized `ref mark` requests is not an essential aspect of this proposal, and can be discarded. However I'm, say, 75% sure that it would be easy to support; GNU troff's input stack is designed such that it always knows the file name and line number associated with the top of the stack. Tracking this information would require using an `object_dictionary` rather than a "plain" `dictionary` for the reference dictionary structure, but I don't think that would be a challenge. I already had to learn my way around these when working on stream management functions and implementing the `pstream` request new to groff 1.24.0. https://cgit.git.savannah.gnu.org/cgit/groff.git/tree/src/roff/troff/dictionary.cpp?h=1.24.1 https://cgit.git.savannah.gnu.org/cgit/groff.git/tree/src/roff/troff/dictionary.h?h=1.24.1 (If you're wondering why GNU troff doesn't use an STL container for this sort of thing, you're right to do so. It's technical debt from ~1990, and is on my list of issues to resolve.) This sketch owes a great deal to the existing design of mmroff(1) and to the principle of operation of a one-pass assembler (where references to symbols "unresolved" at the time they are encountered are emitted after assembly as "errata"), which is no accident. The shape of the problem is an old and familiar one. Anti-goal --------- Having references that are `mark`ed but not `link`ed is not an error condition. I can easily imagine _ms_(7) or _mm_(7) documents producing automatic `ref mark` requests for every section heading macro call. Whether any of these ever get `ref link`ed is up to the document author, who might never have inbound links to some sections, and/or may never call `TC` to produce a table of contents. Some macro packages have a "threshold" on the table of contents, such that section headings nested beyond a certain depth do not show up in the table of contents. So I don't think there is any need to track whether a "mark"ed reference was ever "link"ed. Conclusion ---------- I reckon I can do this for groff 1.26. Who wants to see it? Comments? "I can dream up schemes when I'm sitting in my seat; I don't see any flaws 'til I get to my feet." -- The Police, "Darkness" Regards, Branden [1] https://cgit.git.savannah.gnu.org/cgit/groff.git/tree/NEWS?h=1.24.1#n20
signature.asc
Description: PGP signature
