5.27 Deferring Output

A few roff language elements are generally not used in simple documents, but arise as page layouts become more sophisticated and demanding. Environments collect formatting parameters like line length and typeface. A diversion stores formatted output for later use. A trap is a condition on the input or output, tested automatically by the formatter, that is associated with a macro: fulfilling the condition springs the trap—calls the macro.

Footnote support often exercises all three of the foregoing features. A simple implementation might work as follows. The author writes a pair of macros: one starts a footnote and the other ends it. They further set a trap a small distance above the page bottom, reserving a footnote area. The author calls the first macro where a footnote marker is desired. The macro establishes a diversion so that the footnote text is collected at the place in the body text where its corresponding marker appears. It further creates an environment for the footnote so that it sets at a smaller typeface. The footnote text is formatted in the diversion using that environment, but it does not yet appear in the output. The document author calls the footnote end macro, which returns to the previous environment and ends the diversion. Later, after body text nearly fills the page, the trap springs. The macro called by the trap draws a line across the page and emits the stored diversion. Thus, the footnote renders.

Diversions and traps make the text formatting process non-linear. Let us imagine a set of text lines or paragraphs labelled ‘A’, ‘B’, and so on. If we set up a trap that produces text ‘T’ (as a page footer, say), and we also use a diversion to store the formatted text ‘D’, then a document with input text in the order ‘A B C D E F’ might render as ‘A B C E T F’. The diversion ‘D’ will never be output if we do not call for it.

Environments of themselves are not a source of non-linearity in document formatting: environment switches have immediate effect. One could always write a macro to change as many formatting parameters as desired with a single convenient call. But because diversions can be nested and macros called by traps that are sprung by other trap-called macros, they may be called upon in varying contexts. For example, consider a page header that is always to be set in Helvetica. A document that uses Times for most of its body text, but Courier for displayed code examples, poses a challenge if a page break occurs in the middle of a code display; if the header trap assumes that the “previous font” is always Times, the rest of the example will be formatted in the wrong typeface. One could carefully save all formatting parameters upon entering the trap and restore them upon leaving it, but this is verbose, error-prone, and not future-proof as the groff language develops. Environments save us considerable effort.