groff(7)

๐ŸŽ€ NAME ๐ŸŽ€

This is groff(7) from the Miscellaneous Information Manual. groff โ€” GNU roff language reference. Periodt.

๐Ÿ’– DESCRIPTION ๐Ÿ’–

Okay so bestie, groff is short for GNU roff, a free reimplementation of the AT&T device-independent troff typesetting system. Need the lore? See roff(7) for a survey of and background on roff systems. No cap.

This document is intended as a reference. The primary groff manual, Groff: The GNU Implementation of troff, by Trent A. Fisher and Werner Lemberg, is a better resource for learners, containing many examples and much discussion. It is written in Texinfo; you can browse it interactively with info groff. Additional formats, including plain text, HTML, TeX DVI, and PDF, may be available in /usr/share/doc/groff-1.24.2. Slay.

We apply the term โ€œgroffโ€ to the language documented here, the GNU implementation of the overall system, the project that develops that system, and the command of that name. In the first sense, groff is an extended dialect of the roff language, for which many similar implementations exist. Itโ€™s giving multiverse, lowkey.

GNU troff, installed on this system as troff(1), is the formatter: a program that reads device and font descriptions (groff_font(5)), interprets the groff language expressed in input text, and translates it into a device-independent page description language (groff_out(5)) that is usually then post-processed by an output driver to produce PostScript, PDF, HTML, DVI, or terminal output. We speak of โ€œthe formatterโ€ when describing behavior that is generally true of troff and nroff programs. Main character energy, fr fr.

๐ŸŒˆ INPUT FORMAT ๐ŸŒˆ

Organize input to GNU troff into lines separated by the Unix newline character (U+000A), using the character encoding it recognizes: ISO Latin-1 (8859-1). We recommend use of ISO 646:1991 IRV (US-ASCII) or (equivalently) the Basic Latin subset of ISO 10646 (Unicode); see groff_char(7). ๐Ÿ’…

Some control characters (from the sets โ€œC0 Controlsโ€ and โ€œC1 Controlsโ€ as Unicode describes them) are invalid as input characters. GNU troff discards them upon reading. It also emits a warning in category โ€œinputโ€; see section โ€œWarningsโ€ of troff(1). It processes a character sequence โ€œfooโ€, followed by an invalid character and then โ€œbarโ€, as โ€œfoobarโ€. Like, the bad char gets yeeted and the rest still walks in wearing sunglasses. ๐Ÿ˜ญ

Invalid input characters comprise 0x00, 0x0B, 0x0Dโ€“0x1F, and 0x80โ€“0x9F. Historically, control characters like ASCII STX, ETX, and BEL (Control+B, Control+C, and Control+G, respectively) have been observed in roff documents, particularly in macro packages employing them as delimiters with the output comparison operator to try to avoid collisions with the content of arbitrary user-supplied parameters (see subsection โ€œConditional expressionsโ€ below). We discourage this expedient; in GNU troff it is unnecessary (outside of compatibility mode) because the program parses delimited arguments at a different input level than their surrounding context. See section โ€œMiscellaneousโ€ of groff_diff(7). GNU troff uses some of these code points for internal purposes, making non-trivial the extension of the program to accept UTF-8 or other encodings that use characters from these ranges. Big โ€œhandle with careโ€ energy. ๐Ÿ”ฅ

โœจ SYNTAX CHARACTERS โœจ

Several input characters are syntactically significant to groff. The most important of these distinguish control lines, which instruct the formatter, from text lines that are formatted as output. Quick vibe check: these little guys are load-bearing. ๐Ÿ‘‘

  • . โ€” A dot at the beginning of an input line marks it as a control line. It can also follow the el and nop requests, and the condition in if, ie, and while requests. The control character invokes requests and calls macros by the name that follows it. The cc request can change the control character.
  • ' โ€” The neutral apostrophe is the no-break control character, recognized where the control character is. It suppresses the (first) break implied by the bp, ce, cf, fi, fl, in, nf, rj, sp, ti, and trf requests. The requested operation takes effect at the next break. It makes br and brp nilpotent. The no-break control character can be changed with the c2 request. When formatted, ' may be typeset as a typographical quotation mark; use the \[aq] special character escape sequence to format a neutral apostrophe glyph.
  • " โ€” The neutral double quote can be used to enclose arguments to macros and strings, and is required if those arguments contain space or tab characters. The requests as, as1, cf, char, ds, ds1, fchar, fschar, mso, msoquiet, nx, open, opena, pi, schar, so, soquiet, sy, and trf strip a leading neutral double quote from their final arguments to allow embedding of leading spaces. All such arguments are โ€œstringsโ€ in a general sense, representing character sequences, file names, operating system commands, or parameters to an output device extension command. To include a double quote inside a quoted argument, use the \[dq] special character escape sequence (which also serves to typeset the glyph in text).
  • \ โ€” A backslash introduces an escape sequence. The escape character can be changed with the ec request; eo disables escape sequence recognition. Use the \[rs] special character escape sequence to format a backslash glyph, and \e to typeset the glyph of the current escape character.
  • ( โ€” An opening parenthesis is special only in certain escape sequences; when recognized, it introduces an argument of exactly two characters. groff offers the more flexible square bracket syntax.
  • [ โ€” An opening bracket is special only in certain escape sequences; when recognized, it introduces an argument (list) of any length, not including a closing bracket.
  • ] โ€” A closing bracket is special only when an escape sequence using an opening bracket as an argument delimiter is being interpreted. It ends the argument (list).

Additionally, the Control+A character (U+0001) in text is interpreted as a leader (see below). ๐Ÿซถ

Horizontal whitespace characters are significant to groff, but trailing spaces on text lines are ignored. The way that whitespace behaves is honestly iconic:

  • space โ€” On control lines and within bracketed escape sequences, spaces separate arguments. On text lines, they separate words. Multiple adjacent space characters in text cause groff to attempt end-of-sentence detection on the preceding word (and trailing punctuation). The amount of space between words and sentences is controlled by the ss request. When filling is enabled (the default), a line may be broken at a space. When adjustment is enabled (the default), inter-word spaces are expanded until the output line reaches the configured length. An adjustable but non-breaking space is available with \~. To get a space of fixed width, use one of the escape sequences \ (the escape character followed by a space), \0, \|, \^, or \h; see section โ€œEscape sequencesโ€ below.
  • newline โ€” On text lines, a newline formats an inter-word space and, if filling is enabled, triggers end-of-sentence recognition on the preceding text. See section โ€œLine continuationโ€ below.
  • tab โ€” A tab character on a text line causes the drawing position to advance to the next defined tab stop.

๐ŸŒธ SENTENCES ๐ŸŒธ

Configure the sets of characters that potentially end sentences or are transparent to sentence endings with the cflags request. Use the ss request to changeโ€”or eliminateโ€”supplemental inter-sentence space. Little punctuation gremlins, but make it fashion. ๐ŸŽ€

๐Ÿฆ‹ TABS AND LEADERS ๐Ÿฆ‹

The formatter interprets input horizontal tab characters (โ€œtabsโ€) and Control+A characters (โ€œleadersโ€) into movements to the next tab stop. Tabs simply move to the next tab stop; leaders place enough periods to fill the space. Tab stops are by default located every half inch measured from the drawing position corresponding to the beginning of the input line; see section โ€œPage geometryโ€ of roff(7). Tabs and leaders do not cause breaks and therefore do not interrupt filling. Tab stops can be configured with the ta request, and tab and leader glyphs with the tc and lc requests, respectively. Dotted-line drama, but make it typesetting. ๐Ÿ’œ

๐Ÿงš LINE CONTINUATION ๐Ÿงš

When filling is enabled, input and output line breaks generally do not correspond. The roff language therefore distinguishes input and output line continuation. Bestie, this is the plot twist. ๐Ÿ˜ญ

A backslash \ immediately followed by a newline, sometimes discussed as \newline, suppresses the effects of that newline on the input. The next input line thus retains the classification of its predecessor as a control or text line. \newline is useful for managing line lengths in the input during document maintenance; you can break an input line at a space, or in the middle of a word, request invocation, macro call, or escape sequence. Input line continuation is invisible to the formatter, with two exceptions: the | operator recognizes the new input line, and the input line counter register .c increments. Sneaky little exceptions, iykyk. ๐Ÿ‘€

The \c escape sequence continues an output line. Nothing on the input line after it is formatted. In contrast to \newline, a line after \c is treated as a new input line, so a control character is recognized at its beginning. The visual results depend on whether filling is enabled. An intervening control line that causes a break overrides \c, flushing out the pending output line in the usual way. The register .int interpolates a positive value only if the pending output line has been continued with \c; this datum is associated with the environment. Itโ€™s giving โ€œstill not done talkingโ€ energy. ๐Ÿ’€

๐ŸŒˆ COLORS ๐ŸŒˆ

groff supports color output with a variety of color spaces and up to 16 bits per channel. Some devices, particularly terminals, may be more limited. When color support is enabled, two colors are current at any given time: the stroke color, with which glyphs, rules (lines), and geometric objects like circles and polygons are drawn, and the fill color, which can be used to paint the interior of a closed geometric figure. The color, defcolor, gcolor, and fcolor requests; \m and \M escape sequences; and .color, .m, and .M registers exercise color support. Obsessed with the palette. ๐ŸŽจโœจ

Each output device has a color named โ€œdefaultโ€, which cannot be redefined. A deviceโ€™s default stroke and fill colors are not necessarily the same. For the dvi, html, pdf, ps, and xhtml output devices, troff automatically loads a macro file defining many color names at startup. By the same mechanism, the devices supported by grotty(1) recognize the eight standard ISO 6429/ECMA-48 color names. (These are known vulgarly as โ€œANSIโ€ colors, after its X3.64 standard, now withdrawn.) No cap, the color lore goes deep. ๐ŸŒˆ

๐ŸŒธ Measurements ๐ŸŒธ

Okay bestie, when a numeric parameter is specifying a measurement, you write it as an integer or a decimal fraction with an optional scaling unit suffixed. A scaling unit is literally just a letter that immediately follows the magnitude of the measurement. Digits after the decimal point are optional, no stress. ๐Ÿ’–

The formatter scales measurements by the specified scaling unit, storing them internally (with any fractional part discarded) in basic units. The device resolution can therefore be obtained by storing a value of 1i to a register, then reading the register. Slay, that's actually so useful. โœจ

  • u โ€” Basic unit; it is at least as small as any other unit.
  • i โ€” Inch; defined as 2.54 centimeters.
  • c โ€” Centimeter.
  • p โ€” Point; a typesetter's unit used for measuring type size. There are 72 points to an inch.
  • P โ€” Pica; another typesetter's unit. There are 6 picas to an inch and 12 points to a pica.
  • z โ€” Typographical point; like p, but used only with type sizes, to overcome a limitation of AT&T troff.
  • s โ€” Scaled point.
  • f โ€” Multiplication by 65,536; scales decimal fractions in the interval [0, 1] to 16-bit unsigned integers.

The magnitudes of other scaling units depend on the text formatting parameters in effect. ๐Ÿฆ‹

  • m โ€” Em; an em is equal to the current type size in points.
  • n โ€” En; on typesetters, an en is one-half em, but on terminals an en equals an em.
  • v โ€” Vee; distance between text baselines.
  • M โ€” Hundredth of an em.

๐Ÿฆ‹ Motion quanta ๐Ÿฆ‹

The basic unit u is not necessarily an output device's smallest addressable length; u can be smaller to avoid integer rounding errors. The minimum distances that a device can work with in the horizontal and vertical directions are termed its motion quanta, stored in the .H and .V registers, respectively. The formatter rounds measurements to applicable motion quanta. Half-quantum fractions round toward zero. ๐ŸŽ€

๐ŸŽ€ Default units ๐ŸŽ€

A general-purpose register (one created or updated with the nr request; see section โ€œRegistersโ€ below) is implicitly dimensionless, or reckoned in basic units if interpreted in a measurement context. But it is convenient for many requests and escape sequences to infer a scaling unit for an argument if none is specified. An explicit scaling unit (not after a closing parenthesis) can override an undesirable default. Effectively, the default unit is suffixed to the expression if a scaling unit is not already present. GNU troff's use of integer arithmetic in numeric expressions should also be kept in mind. ๐Ÿซถ


๐Ÿ”ฅ Numeric expressions ๐Ÿ”ฅ

When evaluated, a numeric expression interpolates an integer. GNU troff recognizes the following operators, and yes, there are a lot of them, but we're gonna get through this together. ๐Ÿ’…

  • + โ€” addition
  • - โ€” subtraction
  • * โ€” multiplication
  • / โ€” truncating division
  • % โ€” modulus
  • unary + โ€” assertion, motion, incrementation
  • unary - โ€” negation, motion, decrementation
  • ; โ€” scaling
  • >? โ€” maximum
  • <? โ€” minimum
  • < โ€” less than
  • > โ€” greater than
  • <= โ€” less than or equal
  • >= โ€” greater than or equal
  • = โ€” equal
  • == โ€” equal
  • & โ€” logical conjunction (โ€œandโ€)
  • : โ€” logical disjunction (โ€œorโ€)
  • ! โ€” logical complementation (โ€œnotโ€)
  • ( ) โ€” precedence
  • | โ€” boundary-relative measurement

troff provides a set of mathematical and logical operators familiar to programmersโ€”as well as some unusual onesโ€”but supports only integer arithmetic. (Provision is made for interpreting and reporting decimal fractions in certain cases.) The internal data type used for computing results depends on the host machine but is at least a 32-bit signed integer, which suffices to represent magnitudes within a range of ยฑ2 billion. (If that's not enough, see groff_tmac(5) for the 62bit.tmac macro package.) Arithmetic saturates. (If overflow would occur, GNU troff emits a warning in category โ€œrangeโ€. See section โ€œWarningsโ€ of troff(1).) ๐Ÿ”ฅ

Arithmetic infix operators perform a function on the numeric expressions to their left and right; they are + (addition), - (subtraction), * (multiplication), / (truncating division), and % (modulus). Truncating division rounds to the integer nearer to zero, no matter how large the fractional portion. Division and modulus by zero are errors and abort evaluation of a numeric expression. ๐Ÿšจ

Arithmetic unary operators operate on the numeric expression to their right; they are - (negation) and + (assertionโ€”for completeness; it does nothing). The unary minus must often be used with parentheses to avoid confusion with the decrementation operator, discussed below. ๐Ÿ˜ญ

The sign of the modulus of operands of mixed signs is determined by the sign of the first. Division and modulus operators satisfy the following property: given a dividend a and a divisor b, a quotient q formed by (a / b) and a remainder r by (a % b), then qb + r = a. ๐Ÿงฎ

GNU troff's scaling operator, used with parentheses as (c;e), evaluates a numeric expression e using c as the default scaling unit. If c is omitted, scaling units are ignored in the evaluation of e. GNU troff also provides a pair of operators to compute the extremum of two operands: >? (maximum) and <? (minimum). โœจ

Comparison operators comprise < (less than), > (greater than), <= (less than or equal), >= (greater than or equal), and = (equal, with a synonym ==). When evaluating a comparison, the formatter replaces it with 0 if it is false and 1 if true. In the roff language, positive values are true, others false. ๐Ÿ‘‘

Operate on truth values with the logical operators & (logical conjunction or โ€œandโ€) and : (logical disjunction or โ€œorโ€). They evaluate as comparison operators do. A logical complementation (โ€œnotโ€) operator, !, works only within if, ie, and while requests. Furthermore, the formatter recognizes ! only at the beginning of a numeric expression not contained by another numeric expression. In other words, ! must be the โ€œoutermostโ€ operator. Its presence elsewhere causes the expression to evaluate false. (GNU troff emits a warning in category โ€œnumberโ€. See section โ€œWarningsโ€ of troff(1).) This unfortunate limitation maintains compatibility with AT&T troff. Test a numeric expression for falsity within a complex expression by comparing it to a false value. ๐Ÿ’€

The roff language has no operator precedence: expressions are evaluated strictly from left to right, in contrast to schoolhouse arithmetic. Use parentheses ( ) to impose a desired precedence upon subexpressions. Lowkey iconic of roff to just refuse math class like that. ๐Ÿ™ˆ

For many requests and escape sequences that cause motion on the page, the unary operators + and - work differently when leading a numeric expression. They then indicate a motion relative to the drawing position: positive is down in vertical contexts, right in horizontal ones. ๐ŸŒˆ

+ and - are also treated differently by the following requests and escape sequences: bp, in, ll, pl, pn, po, ps, pvs, rt, ti, \H, \R, and \s. Here, leading plus and minus signs serve as incrementation and decrementation operators, respectively. To negate an expression in these contexts, subtract it from zero or include the unary minus in parentheses with its argument. ๐ŸŽ€

A leading | operator indicates a motion relative not to the drawing position but to a boundary. For horizontal motions, the measurement specifies a distance relative to a drawing position corresponding to the beginning of the input line. By default, tab stops reckon movements in this way. Most escape sequences do not; | tells them to do so. For vertical motions, the | operator specifies a distance from the first text baseline on the page or in the current diversion, using the current vertical spacing. ๐ŸŒธ

The delimited escape sequence \B tests its argument for validity as a numeric expression. ๐Ÿ”

A register interpolated as an operand in a numeric expression must have an Arabic format; luckily, this is the default. โญ

Because spaces separate arguments to requests, spaces are not allowed in numeric expressions unless parentheses surround the (sub)expression containing them. Fr fr, respect the space rules. ๐Ÿซถ

๐Ÿ’… Identifiers ๐Ÿ’…

Okay bestie, an identifier is basically the name tag for a GNU troff datum โ€” think register, name (macro, string, or diversion), typeface, color, special character or character class, hyphenation language code, environment, or stream. Valid identifiers are one or more ordinary characters. An ordinary character is any Unicode Basic Latin character that is not a space and not the escape character; recall section โ€œInput formatโ€ above. โœจ

An identifier with a closing bracket (]) in its name can't be accessed with bracket-form escape sequences that expect an identifier as a parameter. Similarly, the identifier ( can't be interpolated except with bracket forms. ๐Ÿ’…

Beginning a macro, string, or diversion name with [ or ] forecloses use of the refer(1) preprocessor, which recognizes input lines starting with .[ and .] as bibliographic reference delimiters. ๐Ÿซถ

The delimited escape sequence \A tests its argument for validity as an identifier.

The formatter's handling of undefined identifiers is context-dependent. There is no way to invoke an undefined request; such syntax is interpreted as a macro call instead. If the identifier is interpreted as a string, macro, or diversion name, the formatter defines it as empty and interpolates nothing. (GNU troff emits a warning in category mac. See section โ€œWarningsโ€ of troff(1).) Similarly, if the identifier is interpreted as a register name, the formatter initializes it to zero and interpolates that value. GNU troff emits a warning in category reg; see section โ€œWarningsโ€ in troff(1), and subsection โ€œInterpolating registersโ€ and section โ€œStringsโ€ below. Attempting to use an undefined typeface, special character or character class, color, environment, hyphenation language code, or stream generally provokes an error diagnostic. ๐Ÿ˜ญ

Identifiers for requests, macros, strings, and diversions share one name space; special characters and character classes another. No other object types do.


๐ŸŽฎ Control characters ๐ŸŽฎ

The formatter recognizes a control character only at the beginning of an input line, or at the beginning of a branch of a control structure request; see section โ€œControl structuresโ€ below. ๐Ÿ•น๏ธ

A few requests cause a break implicitly; invoke them with the no-break control character to prevent the break. Break suppression is its sole behavioral distinction. Employing the no-break control character to invoke requests that don't cause breaks is harmless but poor style. ๐Ÿ’€

The control character . and the no-break control character ' can be changed with the cc and c2 requests, respectively. Within a macro definition, register .br indicates the control character used to call it.


๐Ÿ“ž Invoking requests ๐Ÿ“ž

A control character is optionally followed by tabs and/or spaces and then an identifier naming a request or macro. The invocation of an unrecognized request is interpreted as a macro call. Defining a macro with the same name as a request replaces the request. Deleting a request name with the rm request makes it unavailable. The als request can alias requests, permitting them to be wrapped or non-destructively replaced. See section โ€œStringsโ€ below. ๐Ÿ‘‘

There is no inherent limit on argument length or quantity. Most requests take one or more arguments, and ignore any they do not expect. A request may be separated from its arguments by tabs or spaces, but only spaces can separate an argument from its successor. Only one separator between arguments is necessary; any excess is ignored. GNU troff does not allow tabs for argument separation. (Plan 9 troff does.) ๐Ÿซ 

Generally, a space within a request argument is not relevant, not meaningful, or is supported by bespoke provisions, as with the tl request's delimiters. Some requests, like ds, interpret the remainder of the control line as a single argument. See section โ€œStringsโ€ below. ๐ŸŽ€

Spaces and tabs immediately after a control character are ignored. Commonly, authors use them to indent the source of documents or macro files.


๐Ÿซถ Calling macros ๐Ÿซถ

If a macro of the desired name does not exist when called, the formatter creates it and assigns it an empty definition. (GNU troff emits a warning in category mac. See section โ€œWarningsโ€ in troff(1).) Calling an undefined macro does end a macro definition naming it as its end macro (see section โ€œWriting macrosโ€ below). ๐Ÿ˜ญ

To embed spaces within a macro argument, enclose the argument in neutral double quotes ". Horizontal motion escape sequences are sometimes a better choice for arguments to be formatted as text. โœจ

The foregoing raises the question of how to embed neutral double quotes or backslashes in macro arguments when those characters are desired as literals. In GNU troff, the special character escape sequence \[rs] produces a backslash and \[dq] a neutral double quote. ๐Ÿช„

In GNU troff's AT&T compatibility mode, these characters remain available as \(rs and \(dq, respectively. AT&T troff did not consistently define these special characters, but its descendants can be made to support them. See groff_font(5). If even that is not feasible, see the โ€œCalling Macrosโ€ section of the groff Texinfo manual for the complex macro argument quoting rules of AT&T troff. ๐Ÿ’–


๐Ÿช„ Using escape sequences ๐Ÿช„

Whereas requests must occur on control lines, escape sequences can occur intermixed with text and may appear in arguments to requests, macros, and other escape sequences. An escape sequence is introduced by the escape character, a backslash \. The next character selects the escape's function. ๐ŸŒˆ

Escape sequences vary in length. Some take an argument, and of those, some have different syntactical forms for a one-character, two-character, or arbitrary-length argument. Others accept only an arbitrary-length argument. In the former scheme, a one-character argument follows the function character immediately, an opening parenthesis ( introduces a two-character argument (no closing parenthesis is used), and an argument of arbitrary length is enclosed in brackets []. In the latter scheme, the user selects a delimiter character. A few escape sequences are idiosyncratic, and support both of the foregoing conventions (\s), designate their own termination sequence (\?), consume input until the next newline (\!, \", \#), or support an additional modifier character (\s again, and \n). In no case can an escape sequence parameter contain an unescaped newline. ๐ŸŒ€

If the character that follows the escape character does not identify a defined operation, the formatter ignores the escape character. (GNU troff emits a warning in category escape. See section โ€œWarningsโ€ in troff(1).) ๐Ÿ™ˆ

Escape sequence interpolation is of higher precedence than escape sequence argument interpretation. This rule affords flexibility in using escape sequences to construct parameters to other escape sequences. ๐Ÿ”ฅ

The escape character can be interpolated (\e). Requests permit the escape mechanism to be deactivated (eo) and restored, or the escape character changed (ec), and to save and restore it (ecs and ecr). ๐Ÿ’…


โœ‚๏ธ Delimiters โœ‚๏ธ

Some escape sequences that require parameters use delimiters. The neutral apostrophe ' is a popular choice and shown in this document. The neutral double quote " is also commonly seen. Punctuation characters are the best choice (and most portable to other troffs, except for those meaningful in numeric expressions; see below). ๐ŸŽ€

The following escape sequences are not themselves delimited, and thus are allowed as delimiters:

\space, \%, \|, \^, \{, \}, \', \`, \-, \_, \!, \?, \), \/, \,, \&, \:, \~, \0, \a, \c, \d, \e, \E, \p, \r, \t, and \u

However, we discourage using them this way; they can make the input confusing to read. (The eqn(1) and tbl(1) preprocessors use parameterized but non-delimited special character escape sequences \( and \[ to bracket portions of their output.) An invalid escape sequence is valid as a delimiter if the character after the escape character would be valid. ๐Ÿฆ‹

The escape sequences \D, \h, \H, \l, \L, \N, \R, \s, \S, \v, and \x prohibit delimiters that are meaningful in numeric expressions, because they accept numeric expressions as (or within) their arguments. For consistency, GNU troff prohibits the same delimiters in the argument to the tl request. The if, ie, and while requests each interpret their first argument as a conditional expression; only characters that are not meaningful as operators in that context can be used as output comparison delimiters. The following inputs are therefore invalid as delimiters in GNU troff. ๐Ÿ’€

  • the numerals 0โ€“9 and the decimal point .
  • the (single-character) operators +-/*%<>=&:()|
  • any escape sequences other than:
\%, \:, \{, \}, \', \`, \-, \_, \!, \/, \c, \e, and \p

Delimiter syntax is flexible (and laborious to describe) primarily for historical reasons; the foregoing restrictions need be kept in mind mainly when using GNU troff in AT&T compatibility mode. Normally, GNU troff keeps track of the nesting depth of escape sequence interpolations, so the only characters you need to avoid using as delimiters are those that appear in the arguments you input, not those that result from interpolation. Typically, ' works fine. See section โ€œImplementation differencesโ€ in groff_diff(7). ๐ŸŒธ


๐Ÿซฅ Dummy characters ๐Ÿซฅ

As discussed in roff(7), the first character on an input line is treated specially. Further, formatting a glyph has many consequences on formatter state (see section โ€œEnvironmentsโ€ below). Occasionally, we want to escape this context or embrace some of those consequences without actually rendering a glyph to the output. \& interpolates a dummy character, which is constitutive of output but invisible. Its presence alters the interpretation context of a subsequent input character, and enjoys several applications: preventing the insertion of extra space after an end-of-sentence character, preventing interpretation of a control character at the beginning of an input line, preventing kerning between two glyphs, and permitting the tr request to remap a character to โ€œnothingโ€. \) works as \& does, except that it does not cancel a pending end-of-sentence state. ๐Ÿงš

๐ŸŽ€ Page control ๐ŸŽ€

Okay so page control is literally about not letting your content get split at the worst possible moment, and discretionary page breaks are the whole vibe here โ€” they can prevent the unwanted separation of content, bestie. A new page number takes effect during page ejection; see subsection โ€œThe implicit page trapโ€ below.

  • bp โ€” breaks the page, incrementing the page number by one (or setting it per the supplied argument). Iconic little page-flip moment.
  • ne โ€” forces a page break if insufficient vertical space is available (it asserts โ€œneededโ€ space).
  • sv โ€” requires vertical space as ne does, but also saves it for later output by the os request.

The nl register interpolates the vertical drawing position as of the most recently typeset output line. It does not necessarily (and often does not) represent that of the pending output line, because the formatter does not determine the position of its baseline until it is output. Assigning a value to nl sets the vertical drawing position in advance of further modifications to baseline positioning arising from alterations to type size, changes to vertical spacing, or application of extra pre- or post-vertical spacing.

When the formatter starts, the transition to the first page has not yet happened โ€” nl is negative. If you plant a page location trap at vertical position โ€œ0โ€ (idiomatically to format a header), you can assign a negative value to nl to spring that trap even if the page has already started (see subsection โ€œPage location trapsโ€ below). Ngl that trick is lowkey main character energy. โœจ


๐Ÿ’– Control structures ๐Ÿ’–

groff has if and while control structures like other languages. However, the syntax for grouping multiple input lines in the branches or bodies of these structures is unusual โ€” not bad, just giving โ€œspecial little syntaxโ€ fr fr.

They have a common form: the request name is (except for el โ€œelseโ€) followed by a conditional expression cond-expr; the remainder of the line, input, is interpreted as if it were an input line. Any quantity of spaces between arguments to requests serves only to separate them; leading spaces in input are therefore not seen. input effectively cannot be omitted; if cond-expr is true and input is empty, the newline at the end of the control line is interpreted as a blank line (and therefore a blank text line). No cap, that newline is doing actual work. ๐Ÿ’€

It is frequently desirable for a control structure to govern more than one request, macro call, or text line, or combination of the foregoing. The opening and closing brace escape sequences \{ and \} perform such grouping. Brace escape sequences outside of control structures have no meaning and produce no output.

\{ should appear (after optional spaces and tabs) immediately subsequent to the request's conditional expression. \} should appear on a line with other occurrences of itself as necessary to match \{ sequences. It can be preceded by a control character, spaces, and tabs. Input after any quantity of \} sequences on the same line is processed only if all the preceding conditions to which they correspond are true. Furthermore, a \} closing the body of a โ€œwhileโ€ request must be the last such escape sequence on an input line.

GNU troff treats the body of a โ€œwhileโ€ request similarly to that of a de request (albeit one not read in copy mode), but stores it under an internal name and deletes it when the loop finishes. The operation of a macro containing a โ€œwhileโ€ request can slow significantly if its body is large. Each time GNU troff interpolates the macro, it parses and stores the โ€œwhileโ€ body again. An often better solution โ€” and one that is more portable, since AT&T troff lacked the โ€œwhileโ€ request โ€” is to instead write a recursive macro, which is parsed only once (unless you redefine it). To prevent infinite loops, GNU troff limits the default number of available recursion levels to 1,000 or somewhat less (because things other than macro calls can be on the input stack). You can disable this protective measure, or alter the limit, by setting the slimit register. See section โ€œDebuggingโ€ below. ๐ŸŒ€

โœจ Conditional expressions โœจ

The if, ie, and while requests test the truth values of numeric expressions. They also support several additional Boolean operators; the members of this expanded class are termed conditional expressions; their truth values are as shown below. Vibe check time:

  • 's1's2' โ€” s1 produces the same formatted output as s2.
  • c g โ€” a character g is defined.
  • d m โ€” a string, macro, diversion, or request m is defined.
  • e โ€” the current page number is even.
  • F f โ€” a font named f is available.
  • m c โ€” a color named c is defined.
  • n โ€” the formatter is in nroff mode.
  • o โ€” the current page number is odd.
  • r n โ€” a register named n is defined.
  • S s โ€” a font style named s is available.
  • t โ€” the formatter is in troff mode.
  • v โ€” n/a (historical artifact; always false).

If the first argument to an if, ie, or while request begins with a non-alphanumeric character apart from โ€œ!โ€ (see below) and is not a numeric expression, the formatter performs an output comparison test. Shown first in the table above, the output comparison operator interpolates a true value if formatting its comparands s1 and s2 produces the same output commands. Other delimiters can be used in place of the neutral apostrophes; see section โ€œDelimitersโ€ above. troff formats s1 and s2 in separate scratch buffers; after comparison, it discards the resulting data. The resulting glyph properties, including font family, style, size, and slant, must match, but not necessarily the requests and/or escape sequences used to obtain them. Motions must match in orientation and magnitude to within the applicable horizontal or vertical motion quantum of the device, after rounding.

Surround the comparands with \? to avoid formatting them; this causes them to be compared character by character, as with string comparisons in other programming languages. Since GNU troff reads comparands protected with \? in copy mode, they need not be syntactically valid. The escape character is still lexically recognized, however, and consumes the next character. Sneaky but valid, iykyk. ๐Ÿฆ‹

The above operators can't be combined with most others, but a leading โ€œ!โ€, not followed immediately by spaces or tabs, complements an expression. Spaces and tabs are optional immediately after the c, d, F, m, r, and S operators, but right after โ€œ!โ€, they end the predicate and the conditional evaluates true. (This bizarre behavior maintains compatibility with AT&T troff.) Not me side-eyeing the AT&T compatibility caveat, but okay periodt. ๐Ÿ™ˆ

Conditional operators do not create roff language objects as interpolations with \n and \* escape sequences do. ๐Ÿ’…

โœจ Syntax reference conventions โœจ

Okay so in the request and escape sequence specs that follow, most argument names were picked to be descriptive. GNU troff reads arguments named character-sequence, command, contents, file, and message in copy mode (see section โ€œCopy Modeโ€ below) until the end of the input line. A character-sequence is one or more ordinary, special, or indexed characters; spaces; or escape sequences that interpolate only these. The remaining arguments are named for clarity, but they are also character-sequences. A neutral double quote " can optionally prefix a character-sequence; the formatter discards one if itโ€™s present, which lets the argument start with embedded spaces. And input means arbitrary character sequences (up to a newline or delimiter) that GNU troff fully interprets, as opposed to copy mode. ๐Ÿ’…

A few denotations are more specific. ๐Ÿ‘‡

  • b โ€” a numerical expression evaluated as a Boolean; positive values are true, everything else is false.
  • c โ€” a single character: ordinary, special, or indexed.
  • command โ€” an instance of contents (see below) that gets passed to the system as a command, potentially with arguments. GNU troff strips a leading neutral double quote, allowing embedded leading spaces.
  • contents โ€” arbitrary input, excluding an unescaped newline, read in copy mode. GNU troff strips a leading neutral double quote, allowing embedded leading spaces.
  • div โ€” a diversion identifier.
  • env โ€” an environment identifier.
  • file โ€” an instance of contents naming a file on the system. GNU troff strips a leading neutral double quote, allowing embedded leading spaces. GNU troff does not accept newlines (line feeds) in file names supplied as arguments to requests.
  • font โ€” a typeface specified as a font identifier, an abstract style, or a mounting position.
  • ident โ€” a valid groff identifier; its use often means the operation creates an object of a type later referred to as mac, reg, str, and so forth.
  • mac โ€” a macro identifier.
  • message โ€” an instance of contents to emit on the standard error stream. GNU troff strips a leading neutral double quote, allowing embedded leading spaces.
  • n โ€” a numeric expression that evaluates to a non-negative integer.
  • ยฑN โ€” a numeric expression whose meaning depends on its sign; see below.
  • name โ€” a macro, string, or diversion identifier, or the name of a request.
  • npl โ€” a numeric expression that counts subsequent productive input lines; that is, lines that directly produce formatted output. Text lines produce output, and so do control lines containing requests like .tl //Page %// or escape sequences like \l'1i'. Macro calls are not themselves productive, but their interpolations can be.
  • reg โ€” a register identifier.
  • str โ€” a string identifier.
  • stream โ€” an output stream identifier.

So if a numeric expression presented as ยฑN starts with a + sign, an increment in the amount of N is applied to the value that applies to the request or escape sequence. If it starts with a - sign, a decrement of magnitude N is applied instead. With no sign, N replaces any existing value. A roff formatter always interprets a leading minus sign in N as a decrementation operator, not an algebraic sign. To assign a register a negative value, or the negated value of another interpolation, you have to force the formatter to interpret โ€œ-โ€ as a negation or minus operator rather than a decrementation operator: enclose the โ€œ-โ€ with its operand in parentheses, or subtract the expression of interest from zero. If a prior value does not exist โ€” the register was undefined โ€” then an increment or decrement applies as if to 0. ๐Ÿซถ


๐ŸŒธ Request short reference ๐ŸŒธ

Not all the details of request behavior are outlined here. See the groff Texinfo manual, or, for features new to GNU troff, groff_diff(7). โœจ

  • .ab โ€” Abort the formatter and bail out with a failure status. ๐Ÿ’€
    • .ab terminal-message โ€” Abort the formatter, write terminal-message to the standard error stream, and still exit with failure status.
  • .ad โ€” Turn output line alignment and adjustment back on, using whatever mode is sitting in \n[.j]. โœจ
    • **.ad *c*** โ€” Turn on alignment and adjustment in mode *c*, where *c* is one of b, c, l, n, r. This sets \n[.j]`.
  • .af reg c โ€” Assign format c to register reg, where c is i, I, a, A, or a run of decimal digits whose quantity denotes the minimum width in digits to use when the register gets interpolated. ๐ŸŽ€ i and a mean Roman numerals and basic Latin alphabetics respectively, in whichever lettercase you specified. The default is 0.
  • .aln new-register existing-register โ€” Make an alias (an extra name) new-register for existing-register, so both names refer to the same stored object. If existing-register is undefined, the formatter just ignores the request. GNU troff emits a warning in category reg. ๐Ÿ‘‘
  • .als new-name existing-name โ€” Make an alias (a whole extra name) new-name for the request, string, macro, or diversion existing-name, so the names refer to the same stored object. If existing-name is undefined, the formatter ignores the request, and GNU troff emits a warning in category mac. โš ๏ธ Heads up: if new-name already exists, its definition is lost unless it's already aliased.
  • .am mac โ€” Append to macro mac until you hit .. at the start of a control line in the current conditional block. ๐Ÿฆ‹
    • .am mac end-mac โ€” Append to macro mac until end-mac is called at the start of a control line in the current conditional block. end-mac can be a request.
  • .am1 mac โ€” Same as .am, but with compatibility mode disabled when the appendment to macro mac is interpreted.
    • .am1 mac end-mac โ€” Same as .am mac, but with compatibility mode disabled when the appendment to macro mac is interpreted.
  • .ami str โ€” Append to a macro indirectly โ€” its name lives inside string str โ€” until you encounter ... ๐Ÿงš
    • .ami str end-mac-str โ€” Append to a macro indirectly. Same as .am, except str and end-mac-str hold the names of the macro being appended to and the one whose call ends the appendment, respectively.
  • .ami1 str โ€” Same as .ami, with compatibility mode disabled when the appendment is interpreted.
    • .ami1 str end-mac-str โ€” Same as .ami, with compatibility mode disabled when the appendment is interpreted.
  • .as ident โ€” Create string ident with empty contents; does absolutely nothing if ident already exists. ๐Ÿ™ˆ
    • .as str contents โ€” Append contents to string str.
  • .as1 ident โ€” Same as .as ident.
    • .as1 str contents โ€” Same as .as, with compatibility mode disabled when the appendment to string str is interpreted.
  • .asciify div โ€” Unformat ordinary characters, spaces, and some escape sequences in diversion div. When transforming a glyph node back into an input sequence that demands expression as a special character escape sequence, GNU troff uses the default escape character. ๐ŸŒˆ
  • .backtrace โ€” Write the state of the input stack to the standard error stream. Peep the -b option of groff(1). ๐Ÿ‘€
  • .bd font โ€” Stop emboldening font font.
    • .bd font n โ€” Embolden font by overstriking its glyphs offset by n-1 units. See register .b.
    • .bd special-font font โ€” Stop emboldening special-font when font is selected. special-font must be a font name, not a mounting position.
    • .bd special-font font n โ€” Embolden special-font, overstriking its glyphs offset by n-1 units when font is selected. See register .b.
  • .blm โ€” Unset the blank line macro (trap). Restores default handling of blank lines.
    • .blm mac โ€” Set the blank line macro (trap) to mac.
  • .box โ€” Stop directing output to the current diversion; any pending output line gets discarded. ๐Ÿ’…
    • .box ident โ€” Direct output to diversion ident, omitting a partially collected line.
  • .boxa โ€” Stop appending output to the current diversion; any pending output line gets discarded.
    • .boxa div โ€” Append output to diversion div, omitting a partially collected line.
  • .bp โ€” Break the page and start a new one. ๐ŸŽ€
    • .bp ยฑN โ€” Break the page, starting a new one numbered ยฑN.
  • .br โ€” Break the output line.
  • .brp โ€” Break and force adjustment of the output line per the current adjustment mode. ๐Ÿ”ฅ
  • .break โ€” Break out of a while loop.
  • .c2 โ€” Reset the no-break control character back to '.
    • .c2 o โ€” Recognize ordinary character o as the no-break control character.
  • .cc โ€” Reset the control character back to ..
    • .cc o โ€” Recognize ordinary character o as the control character.
  • .ce โ€” Break, center the output of the next productive input line without filling, then break again. ๐ŸŒธ
    • .ce npl โ€” Break, center the output of the next npl productive input lines without filling, then break again. If npl โ‰ค 0, stop centering.
  • .cf file โ€” Break and copy the contents of file as "throughput" to GNU troff output (see groff_out(5)). Every line of file is output as if preceded by \!, but is not interpreted by the formatter. ๐Ÿšจ Unsafe request; disabled by default.
  • .cflags n c... โ€” Assign the properties encoded by non-negative integer n to each character or class c. You don't need spaces between the c arguments.
  • .ch mac โ€” Unplant page location trap mac.
    • .ch mac vertical-position โ€” Change page location trap mac (planted by wh) by moving its location to vertical-position (default scaling unit v).
  • .char c โ€” Define an ordinary, special, or indexed character c as empty.
    • .char c contents โ€” Define an ordinary, special, or indexed character c as contents.
  • .chop name โ€” Remove the last character from the macro, string, or diversion name. โœ‚๏ธ
  • .class ident c ... โ€” Define a (character) class ident comprising the characters or range expressions c, where each c is an ordinary, special, or indexed character, or a range expression. A class defined this way can then be referred to in a cflags request instead of listing out every single character inside it. ๐Ÿ’œ
  • .close stream โ€” Close stream, making it unavailable for write requests.
  • .color โ€” Enable output of color-related device-independent output commands. It's enabled by default. ๐ŸŒˆ
    • .color b โ€” Enable or disable output of color-related device-independent output commands per Boolean expression b.
  • .composite c โ€” Remove the composite character mapping for character c.
    • .composite c1 c2 โ€” Map character c1 to c2 when c1 is a combining component in a composite character.
  • .continue โ€” Skip the rest of a while loop's body and immediately retest its conditional expression. โญ
  • .cp โ€” Enable AT&T troff compatibility mode. It's disabled by default.
    • .cp b โ€” Enable or disable AT&T troff compatibility mode per Boolean expression b.
  • .cs f โ€” Disable constant-width glyph spacing mode for font f.
    • .cs f n โ€” Enable constant-width glyph spacing mode for font f at n/36 ems.
    • .cs f n p โ€” Enable constant-width glyph spacing mode for the font at n/36 ems, as if one em equals p scaled points.
  • .cu โ€” Continuously underline the output of the next productive input line.
    • .cu npl โ€” Continuously underline the output of the next npl productive input lines. If npl=0, stop continuously underlining.
  • .da โ€” Stop appending output to the current diversion.
    • .da div โ€” Append output to diversion div.
  • .de ident โ€” Define macro ident until .. occurs at the start of a control line in the current conditional block. ๐Ÿซถ
    • .de ident end-mac โ€” Define macro ident until end-mac is called at the start of a control line in the current conditional block. end-mac can be a request.
  • .de1 ident โ€” Same as de, with compatibility mode disabled when mac is interpreted.
    • .de1 ident end-mac โ€” Same as .de ident end-mac, with compatibility mode disabled when mac is interpreted.
  • .defcolor ident scheme color-component ... โ€” Define a color named ident. scheme identifies a color space and decides how many *color-component*s are required; it must be one of rgb (three components), cmy (three), cmyk (four), or gray (one). grey is accepted as a synonym of gray. The color components can be encoded as a single hexadecimal value starting with # or ## โ€” the former means each component is in the range 0โ€“255 (0โ€“FF), the latter the range 0โ€“65,535 (0โ€“FFFF). Or, alternatively, each color component can be given as a decimal fraction in the range 0โ€“1, interpreted using a default scaling unit of f, which multiplies its value by 65,536 (but clamps it at 65,535). ๐ŸŽจ
  • .dei str โ€” Define a macro indirectly. Same as de, but interpolate string str to get the macro's name. ๐Ÿงš
    • .dei str end-mac-str โ€” Define a macro indirectly. Same as de, except str and end-mac-str hold the names of the macro to be defined and the one whose call ends the definition, respectively.
  • .dei1 str โ€” Same as dei, with compatibility mode disabled when the macro is interpreted.
    • .dei1 str end-mac-str โ€” Same as dei, with compatibility mode disabled when the macro is interpreted.
  • .device character-sequence โ€” Embed character-sequence into GNU troff output as parameters to an xX device extension command; see groff_out(5). The output driver or other postprocessor interprets character-sequence however it sees fit. ๐Ÿ”Œ
  • .devicem name โ€” Write the contents of macro or string name to troff output as the argument to a device extension command.
  • .di โ€” Stop directing output to the current diversion.
    • .di ident โ€” Direct output to diversion ident.
  • .do name argument ... โ€” Interpret the string, request, diversion, or macro name (along with any further arguments) with compatibility mode
Picking up right where we left off mid-sentence, bestie: โ€œโ€ฆdisabled. Compatibility mode is restored (only if it was active) when the interpolation of name is interpreted.โ€ ๐Ÿ’…
  • .ds ident โ€” Create an empty string named ident.
  • .ds ident contents โ€” Create a string named ident that contains contents.
  • .ds1 ident / .ds1 ident contents โ€” Literally .ds but with compatibility mode turned off while the string is being interpreted. Same energy, fewer gremlins ๐Ÿงš
  • .dt โ€” Clear the diversion trap.
  • .dt vertical-position mac โ€” Set the diversion trap to macro mac at vertical-position (default scaling unit v).
  • .ec โ€” Recognize \ as the escape character again.
  • .ec o โ€” Make the ordinary character o the escape character.
  • .ecr โ€” Restore the escape character that you saved with ecs.
  • .ecs โ€” Save the escape character. Snapshot it, basically ๐Ÿ“ธ
  • .el โ€” Interpolate a newline if the conditional expression of the corresponding ie request was false.
  • .el input โ€” Interpret input as if it were an input line, if the conditional expression of the corresponding ie request was false.
  • .em โ€” Unset the end-of-input macro.
  • .em mac โ€” Call macro mac after the end of input. Like a little goodbye ritual ๐Ÿ‘‹
  • .eo โ€” Disable the escape mechanism in interpretation mode.
  • .ev โ€” Pop the environment stack, going back to the previous environment.
  • .ev env โ€” Push the current environment onto the stack and switch to env, creating it if it doesn't exist yet.
  • .evc env โ€” Copy environment env into the current one.
  • .ex โ€” Exit the formatter. Bye bestie, the formatter is done โœจ
  • .fam โ€” Set the default font family back to the previous value.
  • .fam name โ€” Set the default font family to name.
  • .fc โ€” Disable the field mechanism.
  • .fc c โ€” Set the field delimiter to c, and the pad glyph to a space.
  • .fc c1 c2 โ€” Set the field delimiter to c1 and the pad glyph to c2.
  • .fchar c โ€” Define fallback character c as empty.
  • .fchar c contents โ€” Define fallback character c as contents. It's like char, but where that request hides a glyph with the same name in the selected font, fchar definitions only get used if the font has no glyph for c. GNU troff does this test before searching special fonts. Sneaky little priority check, iconic tbh ๐Ÿ‘‘
  • .fcolor โ€” Restore the previous fill color, or the default if there isn't one.
  • .fcolor col โ€” Select col as the fill color.
  • .fi โ€” Enable filling of output lines; a pending output line gets broken. Also sets \n[.u].
  • .fl โ€” Flush any pending output line.
  • .fp pos id โ€” Mount the font whose font description file name is id at the non-negative position pos.
  • .fp pos id font-description-file-name โ€” Mount the font with font-description-file-name as name id at the non-negative position pos.
  • .fschar f c โ€” Define fallback character c, specific to font f, as empty.
  • .fschar f c contents โ€” Define fallback character c, specific to font f, as contents. Like char, but GNU troff locates a character defined by fschar after any fonts named as arguments to fspecial are searched, and before those named as arguments to the "special" request. Order matters, always ๐Ÿซถ
  • .fspecial f โ€” Empty the list of fonts treated as special when f is selected.
  • .fspecial f s ... โ€” Declare each font s as special only when font f is selected. GNU troff searches fonts given as arguments to the "special" request after those given as arguments to the fspecial request.
  • .ft / .ft P โ€” Select the typeface font. If font is an integer, the formatter interprets it as a mounting position, and the font mounted there gets selected. If that position refers to an abstract style, GNU troff combines it with the default family (see fam above and \F below) to make a resolved font name. If font is "DESC", if the mounting position is not an abstract style and no font is mounted there, or if the mounting position is negative, GNU troff just ignores the request โ€” and yes, it also emits a warning in category "font" or "range" as appropriate (see section โ€œWarningsโ€ in troff(1)). Also see \f. So much drama for one request ๐Ÿ˜ญ
  • .ftr f โ€” Remove the translation of the font named f.
  • .ftr f1 f2 โ€” Translate font name f1 to f2.
  • .fzoom font 0 โ€” Stop magnifying the font.
  • .fzoom font zoom โ€” Set the magnification of the mounted font to zoom, a multiplier of the current type size in thousandths (default: 1000).
  • .gcolor โ€” Restore the previous stroke color, or the default if there isn't one.
  • .gcolor col โ€” Select col as the stroke color.
  • .hc โ€” Reset the hyphenation character back to \% (that's the default).
  • .hc c โ€” Change the hyphenation character to c.
  • .hcode dst1 src1 [dst2 src2] ... โ€” Set the hyphenation code of character dst1 to that of src1, and so on for every pair.
  • .hla โ€” Clear the environment's hyphenation language, which disables automatic hyphenation.
  • .hla ident โ€” Set the environment's hyphenation language to ident.
  • .hlm โ€” Set the consecutive automatically hyphenated line limit to -1 (the default), which means โ€œno limitโ€.
  • .hlm n โ€” Set the consecutive automatically hyphenated line limit to n. A negative value means โ€œno limitโ€.
  • .hpf file โ€” Read hyphenation patterns from file.
  • .hpfa file โ€” Append hyphenation patterns from file.
  • .hpfcode a b [c d] ... โ€” Caution: this request will be withdrawn in a future groff release โ€” use hcode instead. It defines mappings for character codes in hyphenation pattern files. (Deprecated, babes, don't get attached ๐Ÿ’€)
  • .hw word ... โ€” Define each argument word (made of ordinary, special, or indexed characters) as a hyphenation exception word, such that each occurrence of a hyphen-minus - in word marks a hyphenation point.
  • .hy โ€” Set the automatic hyphenation mode to the value of the .hydefault register.
  • .hy 0 โ€” Disable automatic hyphenation; same as .nh.
  • .hy mode โ€” Set the automatic hyphenation mode to mode; see section โ€œHyphenationโ€ below.
  • .hydefault mode โ€” Set the hyphenation mode default to mode; see section โ€œHyphenationโ€ below.
  • .hym โ€” Set the (right) hyphenation margin to 0 (the default).
  • .hym length โ€” Set the (right) hyphenation margin to length (default scaling unit m).
  • .hys โ€” Set the hyphenation space to 0 (the default).
  • .hys hyphenation-space โ€” Suppress automatic hyphenation in adjustment modes "b" or "n" if that adjustment can be achieved by adding no more than hyphenation-space to each inter-word space (default scaling unit m).
  • .ie cond-expr โ€” Interpolate a newline if cond-expr is true, otherwise skip ahead to a corresponding el request.
  • .ie cond-expr input โ€” If cond-expr is true, interpret input as if it were an input line; otherwise skip to a corresponding el request.
  • .if cond-expr โ€” Interpolate a newline if cond-expr is true.
  • .if cond-expr input โ€” If cond-expr is true, interpret input as if it were an input line.
  • .ig โ€” Ignore input (except for the side effects of \R on auto-incrementing registers) until .. shows up at the start of a control line in the current conditional block.
  • .ig end-mac โ€” Ignore input (except for the side effects of \R on auto-incrementing registers) until end-mac is called at the start of a control line in the current conditional block. And yes, end-mac can be a request.
  • .in โ€” Set the indentation amount back to the previous value.
  • .in ยฑ*N* โ€” Set the indentation to ยฑ*N* (default scaling unit m).
  • .it โ€” Cancel any pending input line trap.
  • .it npl mac โ€” Set (or replace) an input line trap in the environment, calling mac after the next npl productive input lines have been read. Lines interrupted with the \c escape sequence are counted separately. Fr fr, separate counter ๐Ÿ“
  • .itc โ€” Cancel any pending input line trap.
  • .itc npl mac โ€” Same as it, but lines interrupted with the \c escape sequence don't count toward the line count.
  • .kern โ€” Enable pairwise kerning.
  • .kern b โ€” Enable or disable pairwise kerning according to the Boolean expression b.
  • .lc โ€” Unset the leader repetition character.
  • .lc c โ€” Set the leader repetition character to c (default: ".").
  • .length reg contents โ€” Compute the number of characters in contents and store that count in the register reg.
  • .linetabs โ€” Activate line-tabs in the environment. It's disabled by default.
  • .linetabs b โ€” Activate or deactivate line-tabs in the environment according to the Boolean expression b.
  • .lf input-line-number โ€” Set the input line number the formatter uses when reporting diagnostics. The argument becomes the input line number of the next line the formatter reads.
  • .lf input-line-number character-sequence โ€” Same as lf with one argument, but it also updates the reported file name to character-sequence.
  • .lg โ€” Enable ligature mode 1.
  • .lg m โ€” Set the ligature mode to m (0 = disable, 1 = enable, 2 = enable for two-letter ligatures only).
  • .ll โ€” Set the line length back to the previous value. Does not affect a pending output line.
  • .ll ยฑ*N* โ€” Set the line length to ยฑ*N* (default length 6.5i, default scaling unit m). Still doesn't affect a pending output line, bestie.
  • .lsm โ€” Unset the leading space macro (trap). Restores the default handling of lines with leading spaces.
  • .lsm mac โ€” Set the leading space macro (trap) to mac.
  • .ls โ€” Change to the previous value of the additional intra-line skip.
  • .ls n โ€” Set the additional intra-line skip value to n, i.e. n-1 blank lines get inserted after each text output line.
  • .lt โ€” Set the length of title lines back to the previous value.
  • .lt ยฑ*N*** โ€” Set the length of title lines (default length 6.5i, default scaling unit m).
  • .mc โ€” Cease writing the margin character.
  • .mc c โ€” Start writing margin character c to the right of each output line, at a distance of 10p.
  • .mc c d โ€” Start writing margin character c on each output line at distance d to the right of the right margin (default distance 10p, default scaling unit m).
  • .mk โ€” Mark the vertical drawing position in an internal register; see .rt.
  • .mk reg โ€” Mark the vertical drawing position in register reg.
  • .mso file โ€” Just like so, except GNU troff searches for the specified file in the same directories as macro files; see

...it's GROFF_TMAC_PATH, bestie โ€” tucked in the Environment section of groff(1) โ€” plus -m, which lives in the Options section of that very same page. iykyk ๐Ÿ’…

  • .msoquiet file โ€” literally .mso but it keeps its mouth shut: no warning if file doesn't exist. polite queen behavior ๐ŸŽ€
  • .na โ€” disable output line adjustment. no more stretching lines to fit, we're done with that โœจ
  • .ne โ€” break the page if the distance to the next page location trap is less than one vee.
  • .ne d โ€” break the page if that distance is less than distance d (default scaling unit v).
  • .nf โ€” disable filling of output lines, and any pending output line gets broken. also clears \n[.u], so heads up ๐Ÿ‘€
  • .nh โ€” disable automatic hyphenation; same thing as .hy 0. no more splitting words, we simply refuse ๐Ÿ’…
  • .nm โ€” deactivate output line numbering. numbers? gone. never happened ๐ŸŒธ
  • .nm ยฑN, .nm ยฑN m, .nm ยฑN m s, .nm ยฑN m s i โ€” activate output line numbering, and here's the whole stack: number the next output line ยฑN, write numbers every m lines (default 1), put s numeral widths (\0) between the line number and the output (default 1), and indent the line number by i numeral widths (default 0). full control, we love to see it ๐Ÿ‘‘
  • .nn โ€” suppress numbering of the next output line counted by nm.
  • .nn n โ€” suppress numbering of the next n output lines counted by nm. if n=0, the suppression gets cancelled. undo button, slay ๐Ÿฆ‹
  • .nop โ€” interpolate a newline.
  • .nop input โ€” interpret input as if it were an input line.
  • .nr reg ยฑN โ€” define or update register reg with value N.
  • .nr reg ยฑN I โ€” define or update register reg with value N and auto-increment I, which can be any integer you want, no cap ๐ŸŒˆ
  • .nroff โ€” make the conditional expressions n true and t false. flipping the vibe check for conditionals ๐Ÿ˜Œ
  • .ns โ€” enable no-space mode, which ignores .sp requests until a glyph or a \D primitive actually gets output. see .rs for the escape hatch ๐Ÿซถ
  • .nx โ€” stop processing the input file and read the next one, if there is one.
  • .nx file โ€” stop processing the input file and read file instead. switching lanes, periodt ๐Ÿš—
  • .open ident file โ€” open file for writing and associate a stream named ident with it, so it's available for "write" requests. unsafe request; disabled by default, so don't come crying to me ๐Ÿ˜ญ
  • .opena ident file โ€” same as open, but if file already exists it appends instead of overwriting. unsafe request; disabled by default ๐Ÿซฃ
  • .os โ€” output the vertical space that was saved by the sv request.
  • .output character-sequence โ€” emit character-sequence "transparently" (like, directly) to troff's output. no filter, no middleman, main character energy โญ
  • .pc โ€” reset the page number character back to %.
  • .pc c โ€” change the page number character used in titles to c.
  • .pchar c ... โ€” report info about each character (ordinary, special, or indexed) or character class c to the standard error stream. a character defined by a request (char, fchar, fschar, or schar) reports its contents as a JSON-encoded string โ€” but the output is not otherwise in JSON format, so don't get it twisted ๐Ÿ’€
  • .pcolor โ€” report every defined color name, its color space identifier, and channel value assignments to the standard error stream. a device's default stroke and/or fill colors, default, are not listed, because they're immutable and the formatter doesn't even know their details. mysterious icons ๐Ÿ™ˆ
  • .pcolor col ... โ€” report the name, color space identifier, and channel value assignments of each color col to the standard error stream.
  • .pcomposite โ€” report the list of configured composite character mappings to the standard error stream. see the composite request. the "from" code point gets listed first, followed by its "to" mapping. order matters, bestie ๐ŸŽ€
  • .pev โ€” report the state of the current environment, followed by that of all the other environments, to the standard error stream. the whole group chat, exposed ๐Ÿ’…
  • .pfp โ€” report the list of occupied font mounting positions to the standard error stream. occupied positions are listed one per line, in increasing order, followed by the typeface name. if that name corresponds to an abstract style, the entry just ends there. otherwise, the name of the font description file and the font's "internal name" datum โ€” whose meaning varies by output device โ€” follow. it's giving lore drop ๐Ÿ“œ
  • .pftr โ€” report the list of font translations to the standard error stream.
  • .phw โ€” report the list of hyphenation exception words associated with the hyphenation language selected by the hla request, to the standard error stream. a - marks each hyphenation point, and a word prefixed with - isn't hyphenated at all. bonus: the report suffixes words that automatic hyphenation applies to (meaning those defined in a hyphenation pattern file rather than with the hw request) with a tab and an asterisk *. little star sticker for the auto ones โญ
  • .pi command โ€” pipe GNU troff output through command (which is read in copy mode) by passing it to popen(3). multiple pi requests construct a multi-stage pipeline in the same order as the formatter encounters the requests. unsafe request; disabled by default ๐ŸŒŠ
  • .pl โ€” set page length to the default 11i. the current page length is stored in register .p, so peek there whenever ๐Ÿ’–
  • .pl ยฑN โ€” change page length to ยฑN (default scaling unit v).
  • .pline โ€” report the list of output nodes corresponding to the pending output line, in JSON syntax, to the standard error stream. in JSON, a pair of empty brackets [ ] represents an empty list. a pending output line hasn't undergone adjustment yet, and lacks a line number and margin character (all as applicable). not finished yet, don't judge her ๐Ÿ˜ญ
  • .pm โ€” report the names of all defined macros, strings, and diversions, plus their lengths in characters or nodes, to the standard error stream.
  • .pm name ... โ€” report the JSON-encoded name and contents of each macro, string, or diversion name to the standard error stream.
  • .pn ยฑN โ€” set the next page number.
  • .pnr โ€” report the names, values, and (as applicable) autoincrement amounts and assigned formats of all defined registers to the standard error stream. full registry dump, we're nosy ๐Ÿ•ต๏ธโ€โ™€๏ธ
  • .pnr reg ... โ€” report the name and value of each register reg to the standard error stream, plus โ€” if its type is numeric โ€” the autoincrement amount and assigned format. conditional info, live a little โœจ
  • .po โ€” change to the previous page offset. the current page offset is available in register .o.
  • .po ยฑN โ€” alter the page offset (default scaling unit m).
  • .ps โ€” restore the previous type size. back to how it was, no drama ๐Ÿฆ‹
  • .ps ยฑN โ€” set/increase/decrease the type size to/by N scaled points (a non-positive resulting type size gets set to 1 u โ€” the code said absolutely not ๐Ÿ’€); also see \s[ยฑN].
  • .psbb postscript-file โ€” retrieve the bounding box of the PostScript image found in postscript-file, which must conform to Adobe's Document Structuring Conventions (DSC). see registers llx, lly, urx, ury. non-negotiable requirement, bestie ๐Ÿ“
  • .pso command โ€” like so, except the input comes from the standard output stream of command, which gets passed to popen(3). unsafe request; disabled by default ๐Ÿ”ฅ
  • .pstream โ€” report the list of open streams, in JSON syntax, to the standard error stream โ€” including the name of each open stream, the name of the file backing it, and its mode (writing or appending). stream status: exposed ๐ŸŒˆ
  • .pwh โ€” report the names and positions of all page location traps to the standard error stream.
  • .pvs โ€” change to the previous post-vertical line spacing.
  • .pvs ยฑN โ€” change post-vertical line spacing according to ยฑN (default scaling unit p).
  • .rchar c... โ€” remove the definition of each ordinary, special, or indexed character c, undoing the effect of a char, fchar, or schar request. spaces need not separate the c arguments. the character definition removed (if any) is the first one encountered in the resolution process documented in section "Using Symbols" of Groff: The GNU Implementation of troff. glyphs โ€” which are defined by font description files โ€” cannot be removed, so don't even try ๐Ÿ˜ค
  • .rd โ€” read an insertion from the standard input stream, ringing the terminal bell as the prompt. ding! ๐Ÿ””
  • .rd terminal-message โ€” read an insertion from the standard input stream, writing terminal-message to the standard error stream as the prompt. custom prompt, fancy ๐Ÿ’…
  • .return โ€” stop interpreting an interpolated macro, skipping the remainder of its definition. exit, stage left ๐ŸŽญ
  • .return input โ€” same as return, but the skip happens twice โ€” once within the macro being interpreted and once in an enclosing macro. double skip, double slay โœŒ๏ธ
  • .rfschar f c... โ€” remove each fallback special character c for font f. spaces need not separate the c arguments. see fschar.
  • .rj โ€” break, right-align the output of the next productive input line without filling, then break again.
  • .rj npl โ€” break, right-align the output of the next npl productive input lines without filling, then break again. if npl โ‰ค 0, stop right-aligning. alignment era over ๐Ÿšซ
  • .rm name ... โ€” remove each request, macro, diversion, or string name. gone, deleted, blocked ๐Ÿ’€
  • .rn old new โ€” rename request, macro, diversion, or string old to new. rebrand โœจ
  • .rnn reg1 reg2 โ€” rename register reg1 to reg2.
  • .rr reg ... โ€” remove each register reg.
  • .rs โ€” restore spacing; disable no-space mode. see .ns. we're back, baby ๐Ÿซถ
  • .rt โ€” return (upward only โฌ†๏ธ) to the vertical position marked by .mk on the current page.
  • .rt N โ€” return (upward only โฌ†๏ธ) to vertical position N (default scaling unit v). upward only, no downward trips, don't ask ๐Ÿ˜Œ
  • .schar c โ€” define global fallback character c as empty.
  • .schar c contents โ€” define global fallback character c as contents. it works like char, except GNU troff locates a character defined with schar after any fonts named as arguments to the special request and before any mounted special fonts. placement is everything, bestie ๐ŸŽ€
  • .shc โ€” reset the soft hyphen character back to \[hy].
  • .shc c โ€” set the soft hyphen character to c.
  • .shift โ€” shift macro or string parameters one place n places: argument i becomes argument i-1; argument 1 becomes unavailable. everybody slide down one seat ๐Ÿช‘
  • .shift n โ€” shift macro or string parameters n places: argument i becomes argument i-n; arguments 1 to n become unavailable.
  • .sizes s1 s2 ... sn [0] โ€” set available type sizes to the list of values or ranges; each si is interpreted in units of scaled points (s). GNU troff strips a leading neutral double quote from s1; it reads
  • .so file โ€” swaps the request's control line out for the contents of file, aka "sourcing" it ๐Ÿ’…. GNU troff hunts for file in any directories you gave with -I command-line options first, then the current working directory. If file doesn't exist, the formatter just ignores the request (GNU troff does drop a warning in category "file", bestie, so check your stderr ๐Ÿ‘€).
  • .soquiet file โ€” same energy as .so, but no warning gets emitted if file doesn't exist. silent treatment, iconic ๐ŸŽ€
  • .sp โ€” breaks and moves the next text baseline down by one vee, or keeps going until it springs a page location trap. ngl if you invoke it with the no-break control character, sp moves the text baseline that applies to the entire pending output line ๐Ÿซถ
  • .sp vertical-distance โ€” like sp, but it moves by vertical-distance instead of 1v. Inside a diversion, the formatter ignores any argument (rude but ok ๐Ÿ˜ญ). A negative vertical-distance can't push the text baseline below zero โ€” that's the floor, periodt. And if you apply the boundary-relative measurement operator | to vertical-distance, like in |N, it moves to a position relative to the page top for positive N, and the bottom if N is negative โœจ
  • .special โ€” empties the list of special fonts designated by this request when you give it arguments. clear the roster ๐Ÿ’€
  • .special s ... โ€” declares each font s as special, irrespective of its description file, populating a list that GNU troff searches in order to find the glyph you're demanding ๐Ÿ‘‘. GNU troff searches fonts specified as arguments to the special request after those given as arguments to the fspecial request โ€” order matters, iykyk
  • .spreadwarn โ€” toggles the spread warning on and off (default is off) without changing its value ๐ŸŒธ
  • .spreadwarn N โ€” emits a break warning if the additional space inserted for each space between words in an adjusted output line is greater than or equal to N. A negative N is treated as 0. The default scaling unit is m. At startup, spreadwarn is inactive and N is 3 m. so generous of it ๐Ÿ’–
  • .ss n โ€” sets minimum inter-word space and supplemental inter-sentence space sizes to n 12ths of the selected font's spacewidth parameter (default: 12) ๐Ÿงš
  • .ss n m โ€” as .ss n, but sets the supplemental inter-sentence space size to m 12ths of the selected font's spacewidth parameter. two knobs, one request โœจ
  • .stringdown str โ€” replaces each byte in the string named str with its lowercase version ๐Ÿ”ก
  • .stringup str โ€” replaces each byte in the string named str with its uppercase version ๐Ÿ” 
  • .sty pos style โ€” associates abstract style with non-negative font position pos ๐ŸŽจ
  • .substring str start [end] โ€” replaces the string named str with its substring bounded by the indices start and end, inclusive. Negative indices count backward from the end of the string, which is honestly such a slay ๐Ÿฆ‹
  • .sv โ€” as ne, but saves 1 v for output with the os request ๐Ÿ’พ
  • .sv d โ€” as ne, but saves distance d for later output with the os request (default scaling unit v) ๐Ÿซถ
  • .sy command โ€” executes command (which gets read in copy mode) in the operating environment by passing it to system(3). see register systat. Unsafe request; disabled by default. โš ๏ธ no cap, be careful with that one
  • .ta โ€” clears tab stops. bye tabs ๐Ÿ‘‹
  • .ta n1 n2 ... nn T r1 r2 ... rn โ€” sets tabs at positions n1, n2, ..., nn, then sets tabs at nn+mร—*rn*+r1 through nn+mร—*rn*+rn, where m increments from 0, 1, 2, ... up to the output line length ๐Ÿ“. Each n argument can be prefixed with a + to place the tab stop ni at a distance relative to the previous one, n(i-1). Each argument ni or ri can be suffixed with a letter to align text within the tab column bounded by tab stops i and i+1: L for left-aligned (the default), C for centered, and R for right-aligned ๐Ÿ’… alignment queen
  • .tag โ€” Reserved for internal use. ๐Ÿ”’ hands off
  • .taga โ€” Reserved for internal use. ๐Ÿ”’ also hands off
  • .tc โ€” unsets the tab repetition character ๐Ÿšซ
  • .tc c โ€” sets the tab repetition character to c (default: none) ๐Ÿฉท
  • .ti ยฑN โ€” temporarily indents the next output line (default scaling unit m) โžก๏ธ
  • .tkf font s1 n1 s2 n2 โ€” enables track kerning for font ๐Ÿ”คโœจ
  • .tl 'left'center'right' โ€” formats a three-part title ๐ŸŽ€
  • .tm โ€” writes a newline to the standard error stream ๐Ÿ“
  • .tm terminal-message โ€” sends terminal-message, followed by a newline, to the standard error stream. The formatter reads the argument to the end of the input line in copy mode, but does not remove a leading double quote; contrast .tm1 ๐Ÿ™ˆ
  • .tm1 โ€” as tm. ๐Ÿซถ
  • .tm1 message โ€” as tm, but removes a leading neutral double quote " from message, permitting initial embedded spaces in it, and reads it to the end of the input line in copy mode โœจ
  • .tmc โ€” No operation. literally nothing. a vibe ๐Ÿ’€
  • .tmc message โ€” as tm1, but does not append a newline ๐ŸŒธ
  • .tr abcd... โ€” translates ordinary or special characters a to b, c to d, and so on prior to output ๐Ÿ”
  • .trf file โ€” breaks and copies the contents of file as "throughput" to GNU troff output (see groff_out(5)). Unlike cf, characters invalid as input to GNU troff are discarded ๐Ÿ—‘๏ธ. If file's contents don't end with a newline, trf appends one โœ…
  • .trin abcd... โ€” as tr, except that asciify ignores the translation when a diversion is interpolated ๐ŸŒ€
  • .trnt abcd... โ€” as tr, except that translations are suppressed in the argument to \! ๐Ÿค
  • .troff โ€” makes the conditional expressions t true and n false โš–๏ธ
  • .uf font โ€” sets the underline font used by ul to font โœ๏ธ
  • .ul โ€” underlines (italicizes in troff mode) the output of the next productive input line ๐Ÿ–Š๏ธ
  • .ul npl โ€” underlines (italicizes in troff mode) the output of the next npl productive input lines. If npl=0, stop underlining ๐Ÿ›‘
  • .unformat div โ€” unformats space characters and tabs in diversion div, preserving font information ๐Ÿ”
  • .vpt โ€” enables vertical position traps. They're enabled by default already, so this is just a little reminder ๐Ÿชค
  • .vpt b โ€” enables or disables vertical position traps per Boolean expression b ๐Ÿ”˜
  • .vs โ€” changes to the previous vertical spacing โช
  • .vs ยฑN โ€” sets vertical spacing to ยฑN (default scaling unit p) ๐Ÿ“
  • .warn โ€” enables all warning categories ๐Ÿšจ
  • .warn 0 โ€” disables all warning categories ๐Ÿคซ
  • .warn n โ€” enables warnings in categories whose codes sum to n; see troff(1) ๐Ÿงฎ
  • .warnscale scaling-unit โ€” selects the scaling unit used in certain warnings (one of u, i, c, p, or P; default: i). Ignored on nroff-mode output devices, for which these diagnostics report the vertical page location in lines, and the horizontal page location in ens ๐Ÿ“Š
  • .wh vertical-position โ€” removes the visible page location trap at vertical-position (default scaling unit v) ๐Ÿงน
  • .wh vertical-position mac โ€” plants macro mac as a page location trap at vertical-position (default scaling unit v), removing any visible trap already there ๐Ÿชด
  • .while cond-expr โ€” interpolates newlines unless and until cond-expr evaluates false ๐Ÿ”
  • .while cond-expr input โ€” repeatedly executes input unless and until cond-expr evaluates false ๐ŸŒ€
  • .write stream character-sequence โ€” writes character-sequence, a sequence of ordinary characters, spaces, or tabs, to stream, which must previously have been the subject of an open (or opena) request, followed by a newline. GNU troff flushes the stream after writing to it ๐Ÿšฐ
  • .writec stream character-sequence โ€” as write, but does not write a newline to the output โœ๏ธ
  • .writem stream name โ€” writes the contents of the macro or string name to stream, which must previously have been the subject of an open (or opena) request. GNU troff reads the contents of name in copy mode ๐Ÿ“–

โœจ Escape sequence short reference โœจ

okay so the escape sequences \", \#, \$, \*, \?, \a, \e, \n, \t, \g, \V, and \newline are interpreted even in copy mode ๐Ÿ‘€ like they don't wait their turn, they're main character energy.

The escape sequences \f, \F, \H, \m, \M, \R, \s, and \S are not tokenized when GNU troff reads its input ๐Ÿ“ฅ. \R updates only the formatter's register dictionary, and does not contribute (directly) to output. The others alter the environment (see section "Environments" below) ๐ŸŒˆ. See the "GNU troff Internals" section of the groff Texinfo manual for the deep lore ๐Ÿงš

  • \" โ€” comment era ๐Ÿ’ฌ reads everything up to the next newline in copy mode and discards it. Bye.
  • \# โ€” whole-line comment, bestie: reads everything up to and including the next newline in copy mode and discards it.
  • \*s โ€” interpolate the string with one-character name s.
  • \*(st โ€” interpolate the string with two-character name st.
  • \*[string] โ€” interpolate the string with name string (of arbitrary length).
  • \*[string arg ...] โ€” interpolate the string with name string (of arbitrary length), taking arg ... as arguments.
  • \$0 โ€” interpolate the name by which the currently executing macro was invoked.
  • \$n โ€” interpolate macro or string parameter numbered n (1โ‰คnโ‰ค9).
  • \$(nn โ€” interpolate macro or string parameter numbered nn (01โ‰คnnโ‰ค99).
  • \$[nnn] โ€” interpolate macro or string parameter numbered nnn (nnnโ‰ฅ1).
  • \$* โ€” interpolate the catenation of all macro or string parameters, separated by spaces.
  • \$@ โ€” interpolate the catenation of all macro or string parameters, with each surrounded by double quotes and separated by spaces.
  • \$^ โ€” interpolate the catenation of all macro or string parameters as if they were arguments to the ds request.
  • \' โ€” synonym for \[aa], the acute accent special character.
  • \` โ€” synonym for \[ga], the grave accent special character.
  • \- โ€” synonym for \[-], the minus sign special character.
  • \_ โ€” synonym for \[ul], the underrule special character.
  • \% โ€” mark a hyphenation point within a word. At the beginning of a word, prevent it from being otherwise hyphenated.
  • \!character-sequence โ€” transparently embed character-sequence, up to and including the end of the line, into the current diversion, requests, macro calls, and escape sequences when reading them into a diversion. Doing so prevents them from taking effect until the diverted text is actually output.
  • \?character-sequence\? โ€” transparently embed character-sequence, up to its own next occurrence on the input line, into a diversion, or unformatted as an output comparand in a conditional expression. Ignored in the top-level diversion.
  • \space โ€” move right one inter-word space.
  • \~ โ€” insert an unbreakable, adjustable space.
  • \0 โ€” move right by the width of a numeral in the current font.
  • \| โ€” move one-sixth em to the right on typesetters.
  • \^ โ€” move one-twelfth em to the right on typesetters.
  • \& โ€” interpolate a dummy character.
  • \) โ€” interpolate a dummy character that is transparent to end-of-sentence recognition.
  • \/ โ€” apply italic correction. Use between an immediately adjacent oblique glyph on the left and an upright glyph on the right.
  • \, โ€” apply left italic correction. Use between an immediately adjacent upright glyph on the left and an oblique glyph on the right.
  • \: โ€” non-printing break point (similar to \%, but never produces a hyphen glyph).
  • \newline โ€” continue the current input line on the next.
  • \{ โ€” begin conditional input.
  • \} โ€” end conditional input.
  • \(sc โ€” interpolate the glyph of the special character with two-character identifier sc.
  • \[spchar] โ€” interpolate the glyph of the special character with identifier spchar (of arbitrary length).
  • \[base-char comp ...] โ€” interpolate the composite glyph constructed from base-char and each component comp.
  • \[charnnn] โ€” interpolate the glyph of eight-bit encoded character nnn, where 0โ‰คnnnโ‰ค255.
  • \[unnnn[n[n]]] โ€” interpolate the glyph of the Unicode character with code point nnnn[n[n]] in uppercase hexadecimal.
  • \[ubase-char[_combining-component]...] โ€” interpolate the composite glyph from Unicode character base-char and combining-components.
  • \a โ€” interpolate a leader in copy mode.
  • \A'input' โ€” interpolate 1 if input is a valid identifier, and 0 otherwise. Heads up: because GNU troff ignores any input character with an invalid code when reading it, invalid identifiers are empty or contain spaces, tabs, newlines, or escape sequences that interpolate something other than a sequence of ordinary characters.
  • \b'string' โ€” build bracket: pile a sequence of glyphs corresponding to each character in string vertically, and center it vertically on the output line.
  • \B'input' โ€” interpolate 1 if input is a valid numeric expression, and 0 otherwise.
  • \c โ€” continue the output line at the next input line.
  • \C'glyph' โ€” as \[glyph], but compatible with other troff implementations.
  • \d โ€” move downward ยฝ em on typesetters.
  • \D'drawing-command' โ€” see subsection โ€œDrawing commandsโ€ below.
  • \e โ€” interpolate the escape character.
  • \E โ€” as \e, but not interpreted in copy mode.
  • \fP โ€” select previous font mounting position (abstract style or font); same as โ€œ.ftโ€ or โ€œ.ft Pโ€.
  • \fF โ€” select font mounting position, abstract style, or font with one-character name or one-digit position F. F cannot be P.
  • \f(ft โ€” select font mounting position, abstract style, or font with two-character name or two-digit position ft.
  • \f[font] โ€” select font mounting position, abstract style, or font with arbitrarily long name or position font. font cannot be P.
  • \f[] โ€” select previous font mounting position (abstract style or font).
  • \Ff โ€” set default font family to that with one-character name f.
  • \F(fm โ€” set default font family to that with two-character name fm.
  • \F[fam] โ€” set default font family to that with arbitrarily long name fam.
  • \F[] โ€” set default font family to previous value.
  • \gr โ€” interpolate format of register with one-character name r.
  • \g(rg โ€” interpolate format of register with two-character name rg.
  • \g[reg] โ€” interpolate format of register with arbitrarily long name reg.
  • \h'N' โ€” horizontally move the drawing position by N ems (or specified units); | may be used. Positive motion is rightward.
  • \H'N' โ€” set (increment, decrement) the height of the current font, but not its width. If N is zero, the formatter uses the font's inherent height for its type size default scaling unit z).
  • \kr โ€” store the horizontal drawing position, relative to that corresponding to the start of the input line (ignoring page offset and indentation), in register name r.
  • \k(rg โ€” store the horizontal drawing position, relative to that corresponding to the start of the input line (ignoring page offset and indentation), in register name rg.
  • \k[reg] โ€” store the horizontal drawing position, relative to that corresponding to the start of the input line (ignoring page offset and indentation), in register name reg.
  • \l'N[c]' โ€” draw horizontal line of length N with character c (default: \[ru]; default scaling unit m).
  • \L'N[c]' โ€” draw vertical line of length N with character c (default: \[br]; default scaling unit v).
  • \mc โ€” select stroke color with one-character name c.
  • \m(cl โ€” select stroke color with two-character name cl.
  • \m[color] โ€” select stroke color with arbitrarily long name color.
  • \m[] โ€” restore previous stroke color.
  • \Mc โ€” select fill color with one-character name c.
  • \M(cl โ€” select fill color with two-character name cl.
  • \M[color] โ€” select fill color with arbitrarily long name color.
  • \M[] โ€” restore previous fill color.
  • \nr โ€” interpolate value of register with one-character name r.
  • \n(rg โ€” interpolate value of register with two-character name rg.
  • \n[reg] โ€” interpolate value of register with arbitrarily long name reg.
  • \N'n' โ€” format indexed character numbered n in the current font.
  • \o'abc...' โ€” overstrike centered glyphs of characters a, b, c, and so on.
  • \O0 โ€” at the outermost suppression level, disable emission of glyphs and geometric objects to the output driver.
  • \O1 โ€” at the outermost suppression level, enable emission of glyphs and geometric objects to the output driver.
  • \O2 โ€” this one is iconic and also a lot ๐Ÿ˜ญ at the outermost suppression level, enable glyph and geometric primitive emission to the output driver and write to the standard error stream the page number, four bounding box registers enclosing glyphs written since the previous \O escape sequence, the page offset, line length, image file name (if any), horizontal and vertical device motion quanta, and input file name.
  • \O3 โ€” begin a nested suppression level.
  • \O4 โ€” end a nested suppression level.
  • \O[5Pfile] โ€” at the outermost suppression level, write the name file to the standard error stream at position P, which must be one of l, r, c, or i.
  • \p โ€” break output line at next word boundary; adjust if applicable.
  • \r โ€” move โ€œin reverseโ€ (upward) 1 em.
  • \R'name ยฑN' โ€” set, increment, or decrement register name by N.
  • \sยฑN โ€” set/increase/decrease the type size to/by N scaled points. N must be a single digit. If n is an unsigned โ€œ0โ€, restore the previous size. (In compatibility mode only, a non-zero N must be in the range 4โ€“39.) Otherwise, as ps request.
  • \s(ยฑN, \sยฑ(N โ€” set/increase/decrease the type size to/by N scaled points; N is a two-digit number โ‰ฅ1. If n is an unsigned โ€œ00โ€, restore the previous size. Otherwise, as ps request.
  • \s[ยฑN], \sยฑ[N], \s'ยฑN', \sยฑ'N' โ€” set/increase/decrease the type size to/by N scaled points. If n is an unsigned โ€œ0โ€ (with any number of leading zeroes), restore the previous size. Otherwise, as ps request.
  • \S'N' โ€” slant the glyphs of the currently selected font by @var{N} degrees. Positive values slant in the direction of text flow. Only integer values are possible.
  • \t โ€” interpolate a tab in copy mode.
  • \u โ€” move upward ยฝ em on typesetters.
  • \v'N' โ€” vertically move the drawing position by N vees (or specified units); | may be used. Positive motion is downward.
  • \Ve โ€” interpolate value of system environment variable with one-character name e as returned by getenv(3).
  • \V(ev โ€” interpolate value of system environment variable with two-character name ev as returned by getenv(3).
  • \V[env] โ€” interpolate value of system environment variable with arbitrarily long name env as returned by getenv(3).
  • \w'input' โ€” interpolate the width of input, as interpreted, in basic units. This escape sequence allows several properties of formatted output to be measured without writing it out. The formatter processes input in a dummy environment: this means that font and

โ€ฆtype size changes, for example, may occur within it without affecting subsequent output. ๐Ÿ’…

Okay so next up in the escape-sequence lineup, bestie:

  • \x'N' โ€” increase vertical spacing of pending output line by N vees (or specified units; negative before, positive after).
  • \X'character-sequence' โ€” write character-sequence to troff output as a device extension command.

Okay so here's the lore: the groff special character repertoire is unknown to output drivers outside of glyphs named in a device's fonts, and even then they may not possess complete coverage of the names documented in groff_char(7). Further, escape sequences that produce horizontal or vertical motions, hyphenation breaks, or that are dummy characters may appear in strings or be converted to nodes, particularly in diversions. These are not representable when interpolated directly into device-independent output, as might be done when writing out tag names for PDF bookmarks, which can appear in a viewer's navigation pane.

So that documents or macro packages do not have to laboriously โ€œsanitizeโ€ strings destined for interpolation in device extension commands, this escape sequence performs certain transformations on its argument. For these transformations, character translations and definitions are ignored.

GNU troff converts several ordinary characters that typeset as non-basic Latin code points to code points outside that range so that they are used consistently whether they are formatted as glyphs or used in a device control command argument. These ordinary characters are ', -, ^, `, and ~; others are written as-is.

Special characters that typeset as Unicode basic Latin characters are translated to basic Latin characters accordingly. So that any Unicode code point can be represented in device extension commands, for example in an author's name in document metadata or as a usefully named bookmark or hyperlink anchor, GNU troff maps other special characters to Unicode special character notation. Special characters without a Unicode representation, and escape sequences that do not interpolate a sequence of ordinary and/or special characters, produce warnings in category โ€œcharโ€. ๐Ÿšจ

  • \Yn โ€” write contents of macro or string n to troff output as a device extension command.
  • \Y(nm โ€” write contents of macro or string nm to troff output as a device extension command.
  • \Y[name] โ€” write contents of macro or string name to troff output as a device extension command.
  • \zc โ€” format character c with zero widthโ€”without advancing the drawing position.
  • \Z'input' โ€” save the drawing position, format input, then restore it. GNU troff ignores tabs and leaders in input with an error diagnostic.

๐ŸŽจ Drawing commands

Drawing commands direct the output device to render geometrical objects rather than glyphs. Specific devices may support only a subset, or may feature additional ones; consult the man page for the output driver in use. Terminals in particular implement almost none. ๐Ÿ˜ญ

Rendering starts at the drawing position; when finished, the drawing position is left at the rightmost point of the object, even for closed figures, except where noted. GNU troff draws stroked (outlined) objects with the stroke color, and shades filled ones with the fill color. See section โ€œColorsโ€ above. Coordinates h and v are horizontal and vertical motions relative to the drawing position or previous point in the command. The default scaling unit for horizontal measurements (and diameters of circles) is m; for vertical ones, v.

Circles, ellipses, and polygons can be drawn stroked or filled. These are independent properties; if you want a filled, stroked figure, you must draw the same figure twice using each drawing command. A filled figure is always smaller than an outlined one because the former is drawn only within its defined area, whereas strokes have a line thickness (set with \D't').

  • \D'~ h1 v1 ... hn vn' โ€” draw B-spline to each point in sequence, leaving drawing position at (hn, vn).
  • \D'a hc vc h v' โ€” draw circular arc centered at (hc, vc) counterclockwise from the drawing position to a point (h, v) relative to the center. (hc, vc) is adjusted to the point nearest the perpendicular bisector of the arc's chord.
  • \D'c d' โ€” draw circle of diameter d with its leftmost point at the drawing position.
  • \D'C d' โ€” as \D'C', but the circle is filled.
  • \D'e h v' โ€” draw ellipse of width h and height v with its leftmost point at the drawing position.
  • \D'E h v' โ€” as \D'e', but the ellipse is filled.
  • \D'l h v' โ€” draw line from the drawing position to (h, v).
  • \D'p h1 v1 ... hn vn' โ€” draw polygon with vertices at the drawing position and each point in sequence. GNU troff closes the polygon by drawing a line from (hn, vn) back to the initial drawing position. Afterward, the drawing position is left at (hn, vn).
  • \D'P h1 v1 ... hn vn' โ€” as \D'p', but the polygon is filled.
  • \D't n' โ€” set stroke thickness of geometric objects to to n basic units. (Yep, โ€œto toโ€. Iconic.) A zero n selects the minimum supported thickness. A negative n selects a thickness proportional to the type size; this is the default. ๐Ÿ”ฅ

๐Ÿงต Strings

groff supports strings primarily for user convenience. Conventionally, if one would define a macro only to interpolate a small amount of text, without invoking requests or calling any other macros, one defines a string instead. Only one string is predefined by the language.

  • \*[.T] โ€” contains the name of the output device (for example, utf8 or pdf).

The ds request creates a string with a specified name and contents. If the identifier named by ds already exists as an alias, the target of the alias is redefined. If ds is invoked with only one argument, the named string becomes empty. The formatter removes a leading neutral double quote " from contents to permit the embedding of leading spaces. It interprets any other " literally, but the wise author uses the special character escape sequence \[dq] instead if the string might be interpolated as part of a macro argument; see section โ€œCalling macrosโ€ above. ๐ŸŽ€

The \* escape sequence dereferences a string's name, interpolating its contents. If the name does not exist, the formatter defines it as empty, interpolates nothing, and emits a warning in category โ€œmacโ€. See section โ€œWarningsโ€ in troff(1). The bracketed interpolation form accepts arguments that are handled as macro arguments are; see section โ€œCalling macrosโ€ above. In contrast to macro calls, an argument containing a closing bracket ] must be enclosed in double quotes. When defining strings, argument interpolations must be escaped if they are to reference parameters from the calling context; see section โ€œParametersโ€ below. Any non-initial neutral double quote " is interpreted literally, but it is wise to use the special character escape sequence \[dq] instead if the string might be interpolated as part of a macro argument; see section โ€œCalling macrosโ€ above. Strings are not limited to a single input line of text. \newline works just as it does elsewhere. The resulting string is stored without the newlines. When filling is disabled, care is required to avoid overrunning the line length when interpolating strings. Conversely, when filling is enabled, it is not necessary to append \c to a string interpolation to prevent a break afterward, as might be required in a macro argument. Nor does a string require use of the GNU troff chop request to excise a trailing newline as is often done with diversions. It is not possible to embed a newline in a string that will be interpreted as such when the string is interpolated. To achieve that effect, use \* to interpolate a macro instead; see section โ€œPunning namesโ€ below.

The as request is similar to ds but appends to a string instead of redefining it. If as is invoked with only one argument, no operation is performed (beyond dereferencing the string).

Because strings are similar to macros, they too can be defined to suppress AT&T troff compatibility mode enablement when interpolated; see section โ€œCompatibility modeโ€ below. The ds1 request defines a string that suspends compatibility mode when the string is later interpolated. as1 is likewise similar to as, with compatibility mode suspended when the appended portion of the string is later interpolated.

Caution, bestie: these requests treat the remainder of the input line as their second argument, including any spaces, up to a newline or comment escape sequence. Ending string definitions (and appendments) with a comment, even an empty one, prevents unwanted space from creeping into them during source document maintenance. This rule and suggestion also applies to the second argument of the length request, to requests that define characters (char, fchar, fschar, and schar), and to the file name or command arguments of the cf, hpf, hpfa, mso, msoquiet, nx, open, opena, pi, pso, so, soquiet, and trf requests. ๐Ÿšจ

Several requests exist to perform rudimentary string operations. Strings can be queried (length) and modified (chop, substring, stringup, stringdown), and their names can be manipulated through renaming, removal, and aliasing (rn, rm, als).

Redefinitions and appendments โ€œwrite throughโ€ request, macro, string, and diversion names. To replace an aliased object with a separately defined one, you must use the rm request on its name first.

๐Ÿ”ข Registers

In the roff language, numbers and measurements can be stored in registers. Many built-in registers exist, supplying anything from components of the date to details of formatting parameters; some of these are read-only. You can also define your own. See section โ€œIdentifiersโ€ above regarding the construction of valid names for registers. ๐Ÿ—‚๏ธ

Each register (except read-only ones) can be assigned a format, causing its value to interpolate with leading zeroes, in Roman numerals, or alphabetically. Some read-only registers are string-valued, meaning that they interpolate text and lack a format.

Define registers and update their values with the nr request or the \R escape sequence. ๐Ÿ‘‘

So like, user-defined registers can also get bumped up or down by a set amount at the exact moment you interpolate them ๐Ÿ‘€. You set that increment with a third argument to the nr request, and there's a special interpolation syntax, \nยฑ, that changes the register's value and then hands it to you. Together? These features are called auto-increment. (And yeah, a negative auto-increment is basically an "auto-decrement" โ€” math is math bestie ๐Ÿ’….)

There are so many predefined registers, it's giving infinite closet. In the list below we write register interpolation syntax \n[name] to refer to a register name, so you can clearly tell it apart from a string or request name โ€” the symbols \n[] are not part of the register name, they're just the outfit it's wearing. And important: the register name space is separate from the one used for requests, macros, strings, and diversions. Different worlds, no crossover drama ๐Ÿฆ‹.

โœจ Read-only registers โœจ

Predefined registers whose identifiers start with a dot are read-only. Many are Boolean-valued, which is just fancy talk for "it's a yes/no situation."

Caution: Built-in registers are subject to removal like others; once removed, they can be recreated only as normal writable registers and will not otherwise reflect the configuration of the formatter. So like... don't delete the furniture unless you're ready to live with an IKEA box, okay? ๐Ÿ˜ญ

A register name is often associated with a request of the same name (without the dot); exceptions are noted.

  • \n[.$] โ€” Count of arguments passed to currently interpolated macro or string.
  • \n[.a] โ€” Amount of extra post-vertical line space; see \x.
  • \n[.A] โ€” Approximate output is being formatted (Boolean-valued); see troff -a option.
  • \n[.b] โ€” Font emboldening offset; see bd.
  • \n[.br] โ€” The normal control character was used to call the macro being interpreted (Boolean-valued).
  • \n[.c] โ€” Input line number; see lf and register "c.".
  • \n[.C] โ€” AT&T troff compatibility mode is enabled (Boolean-valued); see cp. Always false when processing do; see register .cp.
  • \n[.cdp] โ€” Depth of last glyph formatted in the environment; positive if glyph extends below the baseline.
  • \n[.ce] โ€” Count of input lines remaining to be centered in the environment.
  • \n[.cht] โ€” Height of last glyph formatted in the environment; positive if glyph extends above the baseline.
  • \n[.color] โ€” Color output is enabled (Boolean-valued).
  • \n[.cp] โ€” Within do, the saved value of compatibility mode; see register .C.
  • \n[.csk] โ€” Skew of the last glyph formatted in the environment; see register skw.
  • \n[.d] โ€” Vertical drawing position in diversion.
  • \n[.ev] โ€” Name of environment (string-valued).
  • \n[.f] โ€” Mounting position of selected font; see ft and \f.
  • \n[.F] โ€” Name of input file (string-valued); see lf.
  • \n[.fam] โ€” Name of the environment's default font family (string-valued).
  • \n[.fn] โ€” Resolved name of font selected in the environment (string-valued); see ft and \f.
  • \n[.fp] โ€” Next non-zero free font mounting position index.
  • \n[.g] โ€” Always true in GNU troff (Boolean-valued). Iconic, never lies.
  • \n[.h] โ€” Text baseline high-water mark on page or in diversion.
  • \n[.H] โ€” Horizontal motion quantum of output device in basic units.
  • \n[.height] โ€” Height of the environment's selected font; see \H.
  • \n[.hla] โ€” Hyphenation language in environment (string-valued).
  • \n[.hlc] โ€” Count of immediately preceding consecutive hyphenated lines in environment.
  • \n[.hlm] โ€” Maximum quantity of consecutive hyphenated lines allowed in environment.
  • \n[.hy] โ€” Automatic hyphenation mode in environment.
  • \n[.hydefault] โ€” Hyphenation mode default in environment.
  • \n[.hym] โ€” Hyphenation margin in environment.
  • \n[.hys] โ€” Hyphenation space adjustment threshold in environment.
  • \n[.i] โ€” Environment's indentation amount; see in.
  • \n[.in] โ€” Indentation amount applicable to the output line pending in the environment; see ti.
  • \n[.int] โ€” The text most recently formatted in the environment was "interrupted" or continued with \c (Boolean-valued).
  • \n[.it] โ€” Count of input lines remaining in the environment's pending input trap.
  • \n[.itc] โ€” The environment's pending input trap honors output line continuation with \c (Boolean-valued).
  • \n[.itm] โ€” Name of the macro associated with the pending input trap (string-valued).
  • \n[.j] โ€” The environment's adjustment mode encoded as an integer; see ad and na. Do not interpret or perform arithmetic on its value. Like, do not, bestie, it's not that kind of number ๐Ÿ™ˆ.
  • \n[.k] โ€” The environment's horizontal drawing position relative to indentation.
  • \n[.kern] โ€” Pairwise kerning is enabled (Boolean-valued).
  • \n[.l] โ€” Line length; see ll.
  • \n[.L] โ€” Line spacing; see ls.
  • \n[.lg] โ€” Ligature mode.
  • \n[.linetabs] โ€” Line-tabs mode is enabled in the environment (Boolean-valued).
  • \n[.ll] โ€” Line length applicable to the environment's pending output line.
  • \n[.lt] โ€” Environment's title line length.
  • \n[.m] โ€” Stroke color (string-valued); see gcolor and \m. The default stroke color is named "default".
  • \n[.M] โ€” Fill color (string-valued); see fcolor and \M. The default fill color is named "default".
  • \n[.n] โ€” Length of formatted output on previous output line.
  • \n[.ne] โ€” Amount of vertical space required by last ne that caused a trap to be sprung; also see register .trunc.
  • \n[.nm] โ€” Output line numbering is enabled in the environment (Boolean-valued).
  • \n[.nn] โ€” Count of lines remaining in the environment for which numbering is suppressed while output line numbering is enabled.
  • \n[.ns] โ€” No-space mode is enabled (Boolean-valued).
  • \n[.o] โ€” Page offset; see po.
  • \n[.O] โ€” Output suppression nesting level; see \O.
  • \n[.p] โ€” Page length; see pl.
  • \n[.P] โ€” The page is selected for output (Boolean-valued); see troff -o option.
  • \n[.pe] โ€” Page ejection is in progress (Boolean-valued).
  • \n[.pn] โ€” Number of the next page.
  • \n[.ps] โ€” The environment's type size in scaled points.
  • \n[.psr] โ€” The environment's most recently requested type size in scaled points; see ps and \s.
  • \n[.pvs] โ€” The environment's post-vertical line spacing.
  • \n[.R] โ€” Maximum representable integer in GNU troff.
  • \n[.rj] โ€” Count of input lines remaining to be right-aligned in the environment.
  • \n[.s] โ€” The environment's type size in points as a decimal fraction (string-valued); see ps and \s.
  • \n[.S] โ€” Reserved. Plan 9 troff uses this name for roughly the same purpose as GNU troff's \n[.tabs].
  • \n[.slant] โ€” Slant in degrees of the environment's selected font; see \S.
  • \n[.sr] โ€” The environment's most recently requested type size in points as a decimal fraction (string-valued); see ps and \s.
  • \n[.ss] โ€” Size of the environment's minimum inter-word space in twelfths of the space width of the selected font.
  • \n[.sss] โ€” Size of the environment's supplemental inter-sentence space in twelfths of the space width of the selected font.
  • \n[.sty] โ€” The environment's selected abstract style (string-valued); see ft and \f.
  • \n[.t] โ€” Distance to next vertical position trap; see wh and ch. If no such traps exist between the drawing position and the bottom of the page, troff interpolates the distance to the page bottom. Within a diversion, in the absence of a diversion trap, this distance is the maximum possible vertical position supported by the output device. It's giving "how much runway do I have left" โœˆ๏ธ.
  • \n[.T] โ€” An output device was explicitly selected (Boolean-valued); see troff -T option.
  • \n[.tabs] โ€” The environment's tab stop settings (if any) suitable for use as argument to ta (string-valued).
  • \n[.trap] โ€” Name of the next vertical position trap after the vertical drawing position (string-valued); see wh, ch, and dt.
  • \n[.trunc] โ€” Amount of vertical space truncated by the most recently sprung vertical position trap, or, if the trap was sprung by an ne, minus the amount of vertical motion produced by ne; also see register .ne.
  • \n[.u] โ€” Filling is enabled in the environment (Boolean-valued); see fi and nf.
  • \n[.U] โ€” Unsafe mode is enabled (Boolean-valued); see troff -U option.
  • \n[.v] โ€” The environment's vertical line spacing; see vs.
  • \n[.V] โ€” Vertical motion quantum of the output device in basic units.
  • \n[.vpt] โ€” Vertical position traps are enabled (Boolean-valued).
  • \n[.w] โ€” Width of last glyph formatted in the environment.
  • \n[.warn] โ€” Sum of the numeric codes of enabled warning categories.
  • \n[.x] โ€” Major version number of the running troff formatter.
  • \n[.y] โ€” Minor version number of the running troff formatter.
  • \n[.Y] โ€” Revision number of the running troff formatter.
  • \n[.z] โ€” Name of diversion (string-valued). Empty if output is directed to the top-level diversion.
  • \n[.zoom] โ€” Magnification of the environment's selected font (in thousandths; zero if no magnification); see fzoom.

๐ŸŒธ Writable predefined registers ๐ŸŒธ

Several registers are predefined but also modifiable โ€” yes, they're โœจeditableโœจ; some of them get updated the moment certain requests or escape sequences are interpreted. Date- and time-related registers are set to the local time as determined by localtime(3) when the formatter launches. And this initialization can be overridden by SOURCE_DATE_EPOCH and TZ; see section "Environment" of groff(1). Your clock, your rules ๐Ÿซถ.

  • \n[$$] โ€” the process ID of troff, bestie. your fave formatter's actual PID. iconic.
  • \n[%] โ€” the page number. yes queen, the one you keep checking ๐Ÿ’…
  • \n[c.] โ€” input line number. so you always know where you are in the source, no cap.
  • \n[ct] โ€” the union of character types of every glyph rendered into the dummy environment by \w. like a little personality readout for the characters, ngl.
  • \n[dl] โ€” width of the last closed diversion. the moment it closes, you get the receipt ๐Ÿงพ
  • \n[dn] โ€” height of the last closed diversion. same vibe, vertical edition.
  • \n[dw] โ€” day of the week, in the range 1โ€“7, where 1 is Sunday. yes, Sunday is #1, she's the main character of the week apparently ๐Ÿ™ˆ
  • \n[dy] โ€” day of the month, 1โ€“31. calendar girlie stuff ๐ŸŽ€
  • \n[hours] โ€” count of hours elapsed since midnight, 0โ€“23. the "how late am I staying up formatting" register, lowkey ๐Ÿ’€
  • \n[hp] โ€” horizontal drawing position relative to the position at the start of the input line. relative, not absolute โ€” she's giving context-dependent energy.
  • \n[llx] โ€” lower-left x coordinate of the PostScript image, in PostScript units; see psbb.
  • \n[lly] โ€” lower-left y coordinate of the PostScript image, in PostScript units; see psbb. those two are a matching set, obsessed.
  • \n[ln] โ€” output line number; see nm. so you can actually cite yourself.
  • \n[lsn] โ€” count of leading spaces on the input line. she counted them. every single one. ๐Ÿ”ฅ
  • \n[lss] โ€” the amount of horizontal space that corresponds to those leading spaces on the input line. so not just how many spaces, but how wide they land. two different registers, two different jobs, periodt.
  • \n[minutes] โ€” count of minutes elapsed in the hour, 0โ€“59.
  • \n[mo] โ€” month of the year, 1โ€“12.
  • \n[nl] โ€” vertical drawing position.
  • \n[opmaxx], \n[opmaxy], \n[opminx], \n[opminy] โ€” okay so these four are a set ๐Ÿซถ they mark the top left-hand and bottom right-hand corners of a rectangle that encompasses all formatted output on the page. and here's the tea: they get reset to -1 by \O0 or \O1. so if you see -1 in there, that's why, don't panic.
  • \n[rsb] โ€” same as register sb, except it adds the maximum glyph height to the measurement. so it's sb but taller, literally.
  • \n[rst] โ€” same as register st, except it adds the maximum glyph depth to the measurement. sibling energy to rsb.
  • \n[sb] โ€” the maximum displacement of the text baseline below its original position after rendering into the dummy environment by \w. a whole sentence but like, she's exact and we respect her for it.
  • \n[seconds] โ€” count of seconds elapsed in the minute, 0โ€“60. and yes bestie, it does go to 60 โ€” that's not a typo, the original says 0โ€“60. take it up with the manpage ๐Ÿ’€
  • \n[skw] โ€” skew of the last glyph rendered into the dummy environment by \w. she's a little tilted, and honestly? same.
  • \n[slimit] โ€” the maximum depth of troff's internal input stack. this one matters: if it's โ‰ค0, there's no limit, and recursion can continue until available memory is exhausted ๐Ÿ˜ญ so like, that's the risky setting, be aware. the default is 1,000.
  • \n[ssc] โ€” subscript correction of the last glyph rendered into the dummy environment by \w. tiny adjustment, huge impact โœจ
  • \n[st] โ€” the maximum displacement of the text baseline above its original position after rendering into the dummy environment by \w. so sb goes down, st goes up, they're a duo ๐Ÿฆ‹
  • \n[systat] โ€” the return value of system(3); see sy. your shell command's whole mood, recorded.
  • \n[urx] โ€” upper-right x coordinate of the PostScript image, in PostScript units; see psbb.
  • \n[ury] โ€” upper-right y coordinate of the PostScript image, in PostScript units; see psbb. completing the corner collection, we love a complete set ๐Ÿ‘‘
  • \n[year] โ€” Gregorian year. full four digits, she's not doing abbreviations.
  • \n[yr] โ€” Gregorian year minus 1900. the shorthand version, for when you're feeling lazy ๐ŸŒธ

โœจ USING FONTS โœจ

Okay so in digital typography, a font is a collection of characters in a specific typeface that a device can render as glyphs at a desired size. (Terminals and some typesetters have fonts that render at only one or two sizes โ€” examples? the groff lj4 device's Lineprinter, and lbp's Courier and Elite faces. Very "one size fits all" of them. ๐Ÿ™ˆ)

A roff formatter can switch typefaces at literally any point in the text. The basic faces are a set of styles that combine upright and slanted shapes with normal and heavy stroke weights: R, I, B, and BI โ€” standing for roman, bold, italic, and bold-italic, slay. ๐Ÿ’… For linguistic text, GNU troff groups typefaces into families containing each of these styles (font designers build families so the styles share esthetic properties โ€” the vibe check must pass across the whole family โœจ). So a text font is often a family combined with a style, but bestie, it does not have to be: look at the ps and pdf devices' ZCMI (Zapf Chancery Medium italic) โ€” often there's just no other style of Zapf Chancery Medium provided. Main character font, no supporting cast. ๐Ÿ‘‘

On typesetters, at least one special font is available, comprising unstyled glyphs for mathematical operators and other purposes.

Like the AT&T troff formatter, GNU troff does not itself load or manipulate a digital font file โ€” instead it works with a font description file that characterizes it, including its glyph repertoire and the metrics (dimensions) of each glyph. This info lets the formatter accurately place glyphs relative to each other. ๐ŸŽฏ Before using a font description, the formatter associates it with a mounting position โ€” a place in an ordered list of available typefaces.

So that a document need not be strongly coupled to one specific font family, in GNU troff an output device can associate a style in the abstract sense with a mounting position. That way the default family can be combined with a style dynamically, producing a resolved font name. And a user-specified font name that already combines family and style, or that refers to a font that isn't a member of a family, is already "resolved" โ€” it came out of the group chat ready to go. ๐Ÿซถ

Fonts often have trademarked names, and even Free Software fonts can require renaming upon modification. groff keeps a convention that a device's serif font family is named T ("Times"), its sans-serif family H ("Helvetica"), and its monospaced family C ("Courier"). Historical inertia has straight-up driven groff's font identifiers to short uppercase abbreviations of font names, as with TR, TB, TI, TBI, and a special font S. It's giving acronym era and we respect it. ๐Ÿ’€

The default family used with abstract styles can be changed at any time; initially, it's T. Typically abstract styles are arranged in the first four mounting positions in the order shown above. The default mounting position โ€” and therefore the default style โ€” is always 1 (R). By issuing the appropriate formatter instructions, you can override these defaults before your document writes its first glyph. Plan ahead, bestie, first impressions are forever. ๐ŸŽ€

Terminals cannot change font families and lack special fonts. They support style changes by overstriking, or by altering ISO 6429/ECMA-48 graphic renditions (character cell attributes) โ€” hack the attributes, iconic.

The ft request and \f escape sequence select a typeface by name, abstract style, or mounting position. The fam request and \F escape sequence set the default font family. The ftr request translates one font name to another; fzoom magnifies or reduces the typeface corresponding to a resolved one. And sty and fp associate abstract styles and font names with mounting positions. Teamwork, no cap. ๐ŸŒˆ


๐Ÿฆ‹ CHARACTERS AND GLYPHS ๐Ÿฆ‹

A glyph is a graphical representation of a character. Whereas a character is an abstraction of semantic information, a glyph is an intelligible mark you can actually see on screen or paper. ๐Ÿ‘€ A character has many possible representation forms โ€” for example, the character A can be written in an upright or a slanted typeface, producing distinct glyphs. Sometimes a sequence of characters maps to a single glyph: that's a ligature โ€” the most common one is fi.

Space characters never become glyphs in GNU troff. If they aren't discarded (as when they're trailing text lines), horizontal motions represent them in the output. Ghost vibes only. ๐Ÿงš

The formatter supports three kinds of character:

  • An ordinary character (see section "Identifiers" above) is the most commonly used one, has no special syntax, and typically represents itself. (Depending on the breadth of the output device's glyph repertoire, the characters ', -, ^, the backtick, and ~ can be exceptions to this rule. " and \ are not exceptions, but because they're syntactically meaningful to the formatter, getting at their glyphs may require special characters โ€” or changing or disabling the escape character. See groff_char(7).) ๐Ÿ“
  • A special character gets interpolated with the \[xxx] or \C'xxx' escape sequence syntax, where xxx is an identifier.
  • An indexed character bypasses most of the character-to-glyph resolution logic, uses the \N'i' syntax, and picks a glyph out of the currently selected font by its integer-valued position i in the output device's representation of that font. (A device's fonts don't necessarily arrange their glyphs according to a standard character encoding โ€” do not assume, bestie. ๐Ÿ’€)

User-defined characters are similar to string definitions (see section "Strings" above) and let you extend or substitute within the character repertoire. Any ordinary, special, or indexed character can be user-defined. The char, fchar, schar, and fschar requests create user-defined characters that get employed at various stages of the character-to-glyph resolution process. Build-a-font workshop. ๐Ÿ› ๏ธ

In a troff system, a font description file lists all the glyphs a particular font provides. If the user requests a glyph that isn't available in the currently selected font, the formatter looks it up in an ordered list of special fonts. By default, the ps (PostScript) and pdf output devices support the two special fonts SS (slanted symbol) and S (symbol); and these devices' DESC files arrange them so the formatter searches the former before the latter. Other output devices use different names for special fonts. Fonts mounted with the fonts keyword in the DESC file are globally available. GNU troff's special and fspecial requests alter the list of fonts treated as special โ€” on a general basis, or only when a certain font is currently selected, respectively. ๐Ÿ”ฅ

GNU troff employs the following procedure to resolve an input character into a glyph. User-defined characters make this resolution process recursive. The first step that succeeds ends the resolution procedure for the character being formatted โ€” which may not be the last in the sequence interpolated by a user-defined character. So don't assume it went all the way down. ๐Ÿ™ˆ

  1. Interpolate the definition of any character defined by the char request and apply this procedure to each character in its definition.
  2. Check the current font for a glyph corresponding to the character.
  3. Interpolate the definition of any user-defined character matching, defined by the fchar request, and apply this procedure to each character in its definition.
  4. Check whether the current font has a font-specific list of special fonts; if so, check each font therein, in the order determined by the last applicable fspecial request, for a glyph corresponding to the character.
  5. Interpolate the definition of any character defined by the fschar request for the currently selected font, and apply this procedure to each character in its definition.
  6. Check each font in the list configured by the most recently issued special request for a glyph corresponding to the character.
  7. Interpolate the definition of any character defined by the sschar request and apply this procedure to each character in its definition.
  8. Finally, iterate through the list of mounted fonts by position. For each mounted font, if that font bears the special directive (see groff_font(5)), check it for a glyph corresponding to the character. This stage of the resolution process can sometimes lead to surprising results, since the fonts directive in the DESC file often contains empty positions that get filled by a macro file or document employing the fp request after the formatter initializes. Plot twist at step eight, literally. ๐Ÿ˜ญ

๐ŸŒธ SPECIAL FONTS ๐ŸŒธ

Special fonts are those the formatter searches โ€” in mounting position order โ€” when it can't find a requested glyph in the selected font. Typically they're declared as such in their description files (see groff_font(5)), and they contain unstyled glyphs. The "Symbol" and "Zapf Dingbats" fonts of the PostScript and PDF standards are the classic examples. Ordinarily, only typesetters have special fonts. ๐Ÿ’…

GNU troff's special and fspecial requests let a document supplement the set of fonts the device configures for glyph search without having to use the fp request to mess with the list of mounting positions โ€” which can be tedious, ngl โ€” by default, GNU troff mounts 40 fonts at startup when using the ps device. Forty. Iconic behavior. ๐Ÿ‘‘

๐ŸŒธ Hyphenation ๐ŸŒธ

Okay so when groff is filling (you know, packing words onto lines), it hyphenates words as needed at user-specified and automatically determined hyphenation points. Words that already have hyphens in them โ€” like โ€œmother-in-lawโ€ โ€” are always eligible for breaking after each of their hyphens. No cap. The hyphenation character \% and the non-printing break point \: escape sequences may be used to control the hyphenation and breaking of individual words. The hw request sets user-defined hyphenation points for specified words at any subsequent occurrence. Otherwise? groff figures out hyphenation points automatically by default. main character energy. ๐Ÿ’…

A bunch of requests influence automatic hyphenation. Because conventions vary, the hy request has a whole menu of hyphenation modes. These modes decide whether hyphenation will apply to a word prior to breaking a line at the end of a page (more or less; see below for details), and at which positions within that word automatically determined hyphenation points are permissible. The localization macro files loaded by troffrc configure a default hyphenation mode appropriate to the language.

  • 0 โ€” disables hyphenation, periodt.
  • 1 โ€” enables hyphenation except after the first and before the last character of a word.

The remaining values โ€œimplyโ€ 1; that is, they enable hyphenation under the same conditions as .hy 1, and then apply or lift restrictions relative to that basis.

  • 2 โ€” disables hyphenation of the last word on a page or column, even for explicitly hyphenated words. (Hyphenation is prevented if the next page location trap is closer to the vertical drawing position than the next text baseline would be. See section โ€œTrapsโ€ below.)
  • 4 โ€” disables hyphenation before the last two characters of a word.
  • 8 โ€” disables hyphenation after the first two characters of a word.
  • 16 โ€” enables hyphenation before the last character of a word.
  • 32 โ€” enables hyphenation after the first character of a word.

Apart from value 2, restrictions imposed by the hyphenation mode are not respected for words whose hyphenations have been specified with the hyphenation character (\% by default) or the .hw request. iykyk.

Nonzero values are additive. For example, mode 12 causes groff to hyphenate neither the last two nor the first two characters of a word. Some values cannot be used together because they contradict; for instance, values 4 and 16, and values 8 and 32. As noted, it is superfluous to add 1 to any non-zero even mode.

The places within a word that are eligible for hyphenation are determined by language-specific data (hla, hpf, and hpfa) and lettercase relationships (hcode and hpfcode). Furthermore, hyphenation of a word might be suppressed due to a limit on consecutive hyphenated lines (hlm), a minimum line length threshold (hym), or because the line can instead be adjusted with additional inter-word space (hys). ๐Ÿฆ‹


๐Ÿฆ‹ Localization ๐Ÿฆ‹

GNU troff ties the set of hyphenation patterns to the hyphenation language code selected by the hla request. The hpf request is usually invoked by a localization file loaded by the troffrc file. groff provides localization files for several languages; See subsection โ€œLocalization packagesโ€ of groff_tmac(5). For Western languages, the localization file sets the default hyphenation mode and loads hyphenation patterns and exceptions. By default, troffrc loads the localization file for English. ๐ŸŒ


๐ŸŽ€ Writing macros ๐ŸŽ€

The .de request defines a macro named for its argument. If that name already exists as an alias, the target of the alias is redefined; see section โ€œStringsโ€ above. troff enters โ€œcopy modeโ€ (see below), storing subsequent input lines as the definition. If the optional second argument is not specified, the definition ends with the control line .. (two dots). Tabs and spaces are permitted between the dots. Alternatively, a second argument to .de names a macro whose call (or request whose invocation) syntax ends the definition; this end macro is then interpreted normally. Spaces or tabs are permitted after the first control character in the line containing this ending token, but a tab immediately after the token prevents its recognition as the end of a macro definition. Macro definitions can be nested if they use distinct end macros or if their ending tokens are sufficiently escaped. An end macro need not be defined until it is called. This fact enables a nested macro definition to begin inside one macro and end inside another. โœจ

Variants of .de disable compatibility mode and/or indirect the names of the macros specified for definition or termination: these are .de1, .dei, and .dei1. Append to macro definitions with .am, .am1, .ami, and .ami1. The .als, .rm, and .rn requests create an alias of, remove, and rename a macro, respectively. .return stops the execution of a macro immediately, returning to the enclosing context. slay.

๐Ÿ’– Parameters ๐Ÿ’–

Macro call and string interpolation parameters can be accessed using escape sequences starting with \$. The \n[.$] read-only register stores the count of parameters available to a macro or string; change its value with the .shift request, which dequeues parameters from the current list. The \$0 escape sequence interpolates the name by which a macro was called. Applying string interpolation to a macro does not change this name. lowkey useful. ๐Ÿซถ

๐Ÿงš Copy mode ๐Ÿงš

GNU troff processes certain requests in copy mode: it copies ordinary, special, and indexed characters as-is; interpolates the escape sequences \n, \g, \$, \*, \V, and \? normally; discards comments \" and \#; interpolates \a, \e, and \t, as the current leader, escape, or tab character with respectively; represents these in an encoded form:

\newline \& \_ \| \^ \{ \} \` \' \- \! \c \% \space \E \) \~ \:

and copies other escape sequences as-is. The term โ€œcopy modeโ€ reflects its most visible application in requests that populate macros and strings, but other requests also use it when interpreting arguments that can't meaningfully represent typesetting operations. For example, a font selection escape sequence has no meaning in a hyphenation pattern file name (hpf) or a diagnostic message written to the terminal (tm). The complement of copy modeโ€”a roff formatter's behavior when not defining or appending to a macro, string, or diversionโ€”where all macros are interpolated, requests invoked, and valid escape sequences processed immediately upon recognition, can be termed interpretation mode. highkey a mouthful, but iconic. ๐Ÿ”ฅ

The escape character (\ by default) when used before itself quotes an escape character for later interpretation in an enclosing context. Escape character quotation enables you to control whether the formatter interprets a given \n, \g, \$, \*, \V, or \? escape sequence at the time the macro containing it is defined, or later when the macro is called. ๐Ÿ’€

You can think of \\ as a โ€œdelayedโ€ backslash; it is the escape character followed by a backslash from which the escape character has removed its special meaning. Consequently, \\ is not best considered an escape sequence, but a quoted escape character. In any escape sequence \X that troff does not recognize, the formatter discards the escape character and outputs X. An unrecognized escape sequence causes a warning in category โ€œescapeโ€, with two exceptions, \\ being one. The other is \., which quotes the control character. It is used to permit nested macro definitions to end without a named macro call to conclude them. Without a syntax for quoting the control character, this would not be possible. Outside of copy mode, roff documents should not use the \\ or \. character sequences; they serve only to obfuscate the input. Use \e to represent the escape character, \[rs] to obtain a backslash glyph, and \& before . and ' where troff expects them as control characters if you mean to use them literally. ๐Ÿซถ

Warning bestie: those \\ and \. sequences outside copy mode? Not the vibe. They just obfuscate your input. Use \e, \[rs], and \& as described. ๐Ÿซถ

Macro definitions can be nested to arbitrary depth. Given the input character sequence \\ in a macro or string definition, the formatter interprets each escape character in multiple contexts; once, when populating the macro or string, where the first \ serves its quotation functionโ€”thus only one \ is stored in the definition. (Verify this fact with the pm request.) The formatter interprets the second \ as an escape character (assuming the escape character hasn't been changed in the meantime) each time it interpolates the macro or string definition. This fact leads to exponential growth in the quantity of escape characters required to quote and thereby delay interpolation of \n, \g, \$, \*, \V, and \? at each nesting level. An alternative is to use \E, which represents an escape character that is not interpreted in copy mode. Because \. is not a true escape sequence, we can't use \E to keep .. from ending a macro definition prematurely. If the multiplicity of backslashes complicates maintenance, use end macros. ๐Ÿงš

Traps ๐Ÿชค

okay so a trap is a spot in the output โ€” or a condition on the input โ€” that, the moment it gets reached or fulfilled, calls a macro you picked. โœจ

A vertical position trap calls its macro when the formatter's vertical drawing position reaches or passes (going downward, obviously) a certain location on the output page or inside a diversion. What's it for? page headers and footers, body text in multiple columns, footnotes โ€” the whole aesthetic. ๐Ÿ’… These traps can sit at a given location either on the page (wh, ch) or in the current diversion (dt) โ€” together those are the vertical position traps, and yes they can be disabled and reรซnabled (vpt).

A diversion isn't formatted in the context of a page, so it has no page location traps โ€” but it can have a diversion trap. And there can be at most one such vertical position trap per diversion. One. That's the rule. ๐ŸŽ€

Other trap flavors can be planted:

  • at a blank line (blm)
  • at a line with leading space characters (lsm)
  • after a certain number of productive input lines (it, itc)
  • at the end of input (em)

Setting a trap is also called planting one (very gardening of us ๐ŸŒฑ), and a trap is said to be sprung when its condition is fulfilled. Also important: the formatter passes no arguments to macros called by traps. zero. nada. ๐Ÿ˜Œ

Registers that ride along with trap management, bestie:

  • vertical position trap enablement status: \n[.vpt]
  • distance to the next trap: \n[.t]
  • the name of that trap: \n[.trap]
  • count of lines remaining in the pending input trap: \n[.it]
  • name of the macro associated with it: \n[.itm]
  • whether that input trap honors the \c output line continuation escape sequence: \n[.itc]
  • amount of needed (.ne-requested) space that caused the most recent vertical position trap to be sprung: \n[.ne]
  • amount of needed space truncated from the amount requested: \n[.trunc]
  • page ejection status: \n[.pe]
  • leading space count \n[lsn], plus its corresponding amount of motion \n[lss]

Page location traps ๐Ÿ“

A page location trap is a vertical position trap that applies to the page โ€” meaning the top-level diversion. You can have a bunch of them hanging out at once; manage them with the wh and ch requests. ๐ŸŒธ

Non-negative page locations you give these requests set the trap relative to the top of the page; negative values set it relative to the bottom. One thing you literally cannot do: plant a trap less than one basic unit from the page bottom โ€” a location of "-0" is interpreted as "0", i.e. the top of the page. ๐Ÿ™ˆ An existing visible trap at the same location gets removed; and that's wh's sole function if you leave off its second argument.

A trap is only sprung if it is visible, meaning its location is actually reachable on the page and it isn't hidden by another trap already planted at that same location. (A trap planted at "20i" or "-30i" will not be sprung on a page of length "11i" โ€” like, it's just not on the page, babe. ๐Ÿ’€)

A trap above the top, or at/below the bottom, of the page can be made visible either by moving it into the page area or by increasing the page length so the trap is on the page. And a negative trap value always uses the current page length โ€” the formatter does not convert it to an absolute vertical position. fr fr. โœจ

We can use the pwh request to dump page location traps to the standard error stream; peep the "Debugging" section below. GNU troff reports their positions in basic units and includes empty slots in the list โ€” you know, spots where a trap had been planted and then subsequently (re)moved โ€” because those empty slots can still affect the visibility of traps planted after them. ๐Ÿ‘‘

The implicit page trap ๐ŸŽ€

There's an implicit page trap that always exists in the top-level diversion (see below); its whole job is to eject the current page and start the next one. It works like a trap in some ways but not in others, which is very main-character of it:

  • It has no name, so you can't move or delete it with wh or ch requests.
  • You can't hide it by placing another trap at its location.
  • You can move it only by redefining the page length with pl.
  • Its operation is suppressed when vertical page traps are disabled with GNU troff's vpt request.

Diversions ๐ŸŒ€

So in roff systems you can format text as if it were going to output โ€” but instead of writing it immediately, you divert the formatted text into a named storage area. Later you retrieve it by specifying its name after a control character. The formatter uses the same name space for these diversions as for strings and macros; see "Identifiers" above. ๐Ÿฆ‹

People sometimes say this text is "stored in a macro", but that coinage obscures a super important distinction: macros and strings store unformatted input text, while diversions capture formatted output. Different beasts entirely. Diversions also don't interpret arguments. ๐ŸŒˆ

Applications of diversions include footnotes, tables of contents, indices, and "keeps" โ€” preventing a page break at an inconvenient place by forcing a set of output lines to be set as a group. And for orthogonality, GNU troff is said to populate the top-level diversion if no diversion is active (that is, formatted output is being "diverted" directly to the output device). The top-level diversion has no name. ๐Ÿ’–

Dereferencing an undefined diversion creates an empty one of that name. (GNU troff also emits a warning in category "mac"; see section "Warnings" of troff(1).) And heads up: a diversion does not exist for the purpose of testing with the d conditional expression operator until its initial definition ends; see subsection "Conditional expressions" above. ๐Ÿ˜ญ

The di request creates a diversion, including any partially collected line. da appends to a diversion, creating one if it doesn't already exist. If the diversion's name already exists as an alias, the target of the alias is replaced or appended to; see section "Strings" above. The pending output line is diverted as well. And switching to another environment (with the ev request) before invoking di or da avoids including any pending output line in the diversion. (See section "Environments" below.) ๐Ÿซถ

Invoking di or da without an argument stops diverting output to the diversion named by the most recent corresponding request. Invoking di or da without an argument when no diversion is being populated does nothing at all. (GNU troff emits a warning in category "di"; see section "Warnings" of troff(1).) ๐Ÿ’€

box and boxa work similarly, but they ignore partially collected lines. Call any of these macros again without an argument to end the diversion. โœจ

Diversion requests can be nested, because of course they can. The registers .d and .z report information about the current diversion, and dn and dl report on the most recently closed one. .h is meaningful in diversions, including the top-level one. ๐ŸŒธ

After output to a (named) diversion stops, the formatter stores its vertical and horizontal sizes into the writable registers dn and dl, respectively. Only the lines just processed get counted: for the computation of dn and dl, the requests da and boxa are handled as if di and box had been used, respectively โ€” so lines that have already been stored in the diversion (box) are not taken into account. ๐ŸŽฏ

The \! and \? escape sequences and the output request escape from a diversion โ€” the first two to the enclosing level, and the last to the top level. This facility is termed transparent embedding. ๐Ÿ‘‘

The asciify and "unformat" requests reprocess diversions.

Punning names ๐ŸŽญ

Macros, strings, and diversions share a name space; see section "Identifiers" above. Internally, the exact same mechanism stores them all. Which means you can call a macro with string interpolation syntax and vice versa โ€” iconic, honestly. ๐Ÿ’… Interpolating a string does not hide existing macro arguments. And here's the trick: place the sequence \\ at the end of a line in a macro definition, or (within a macro definition) immediately after the interpolation of a macro as a string, to suppress the effect of a newline. ๐Ÿ˜Œ

Environments ๐ŸŒ

Environments store most of the parameters that control text processing. A default environment named "0" (zero) exists when the formatter starts up; formatting-related requests and escape sequences modify its properties. โœจ

You can create new environments and switch among them โ€” only one is current at any given time. Active environments are managed using a stack, a data structure supporting "push" and "pop" operations. The current environment is at the top of the stack. ๐Ÿฅž

The same environment name can be pushed onto the stack multiple times, possibly interleaved with others. Popping the environment stack does not destroy the current environment; it stays accessible by name and can be made current again by pushing it whenever. Environments cannot be renamed or deleted, and they can only be modified when current. To inspect the environment stack, use the pev request; see section "Debugging" below. ๐Ÿ‘‘

Environments store the following info:

  • a partially collected line, if any
  • data about the most recently output glyph and line (registers .cdp, .cht, .csk, .n, .w)
  • typeface parameters (size, family, style, height and slant, inter-word and inter-sentence space sizes)
  • page parameters (line length, title length, vertical spacing, line spacing, indentation, line numbering, centering, right-alignment, underlining, hyphenation parameters)
  • filling enablement; adjustment enablement and mode
  • tab stops; tab, leader, escape, control, no-break control, hyphenation, and margin characters
  • input line traps
  • stroke and fill colors

The ev request (with an argument) pushes to, and (without one) pops from, the environment stack โ€” while evc copies a named environment's parameters to the current one. ๐Ÿฆ‹

๐Ÿ’… POSTPROCESSOR ACCESS ๐Ÿ’…

Okay so beyond the cf and trf requests, you have two escape sequences and two requests that let documents pass information straight to a postprocessor. These are for exercising device-specific capabilities that the groff language does not abstract or generalize; examples include embedding hyperlinks and image files. Device-specific functions are documented in each output driver's man page, such as gropdf(1), grops(1), or grotty(1). โœจ

  • The device request and the \X escape sequence embed their arguments into GNU troff output as parameters to an x X device extension command (see groff_out(5)). The interpretation of such parameters is determined by the output driver or other postprocessor.
  • GNU troff also permits the interpolation of macro or string contents as a device extension command. The devicem request and \Y escape sequence correspond to .device \*[name] and \X'\*[name], respectively. They differ from their counterparts in that GNU troff does not interpret the contents of the string or macro name; further, name may be a macro and thus contain newlines. (There is no way to embed a newline in the arguments to device or \X.) The inclusion of newlines requires an extension to the AT&T troff device-independent page description language, and their presence confuses drivers that do not know about it (see subsection โ€œDevice control commandsโ€ of groff_out(5)).
โš ๏ธ Use of device extension commands early in a document โ€” before the first text is formatted โ€” can interfere with processing of page location traps. If you experience problems when placing them early, precede the first with a dummy character escape sequence \&; recall section โ€œDummy Charactersโ€ above. ๐Ÿ‘€

The tag and taga requests are reserved for internal use. Don't touch, bestie. ๐Ÿ™ˆ


๐ŸŽ€ UNDERLINING ๐ŸŽ€

In RUNOFF (see roff(7)), underlining, even of lengthy passages, was straightforward because only fixed-pitch printing devices were targeted. Typesetter output posed a greater challenge. There exists a groff request .ul (see above) that underlines subsequent source lines on terminals, but on typesetters, it selects an italic font style instead. The ms macro package (see groff_ms(7)) offers a macro .UL, but it too produces the desired effect only on typesetters, and has other limitations.

One could adapt ms's approach to the construction of a macro as follows. ๐Ÿงš

.de UNDERLINE
. ie n \\$1\f[I]\\$2\f[P]\\$3
. el \\$1\Z'\\$2'\v'.25m'\D'l \w'\\$2'u 0'\v'-.25m'\\$3
..

If doclifter(1) makes trouble, change the macro name UNDERLINE into some 2-letter word, like Ul. Moreover, change the form of the font selection escape sequence from \f[P] to \fP.

โœจ Underlining without macro definitions โœจ

If one does not want to use macro definitions, e.g., when doclifter gets lost, use the following. ๐Ÿซถ

.ds u1 before
.ds u2 in
.ds u3 after
.ie n \*[u1]\f[I]\*[u2]\f[P]\*[u3]
.el \*[u1]\Z'\*[u2]'\v'.25m'\D'l \w'\*[u2]'u 0'\v'-.25m'\*[u3]

When using doclifter, it might be necessary to change syntax forms such as \[xy] and \*[xy] to those supported by AT&T troff: \*(xy and \(xy, and so on.

Then these lines could look like:

.ds u1 before
.ds u2 in
.ds u3 after
.ie n \*[u1]\fI\*(u2\fP\*(u3
.el \*(u1\Z'\*(u2'\v'.25m'\D'l \w'\*(u2'u 0'\v'-.25m'\*(u3

The result looks like:

before in after

๐Ÿ’€ Underlining by overstriking with (ul ๐Ÿ’€

The \z escape sequence writes a glyph without advancing the drawing position, enabling overstriking. Thus, \zc\(ul formats c with an underrule glyph on top of it. Video terminals implement the underrule by setting a character cell's underline attribute, so this technique works in both nroff and troff modes. Slay. ๐Ÿ’…

Long words may then look intimidating in the input; a clarifying approach might be to use the input line continuation escape sequence \newline to place each underlined character on its own input line. Thus,

.nf
\&\fB: ${\fIvar\fR\c
\zo\(ul\
\zp\(ul\c
\&\fIvalue\fB}
.fi

produces

: ${var__value}

as output.


๐Ÿฆ‹ COMPATIBILITY MODE ๐Ÿฆ‹

groff_diff(7) documents differences between the roff language recognized by GNU troff and that of AT&T troff, as well as the device, font, and device-independent page description formats described by CSTR #54. GNU troff provides an AT&T troff compatibility mode. The cp request and registers .C and .cp set and test the enablement of this mode.


๐Ÿ” DEBUGGING ๐Ÿ”

Preprocessors use the lf request to preserve the identities of line numbers and names of input files. groff emits a variety of error diagnostics and supports several categories of warning; the output of these can be selectively suppressed with โ€œwarnโ€ (and see the -E, -w, and -W options of troff(1)). A trace of the formatter's input processing stack can be emitted when errors or warnings occur by means of troff(1)'s -b option, or produced on demand with the backtrace request. tm, tmc, and tm1 can be used to emit customized diagnostic messages or for instrumentation while troubleshooting. ex and ab cause early termination with successful and error exit codes respectively, to halt further processing when continuing would be fruitless. Examine the state of the formatter with requests that write lists of defined names โ€” macros, strings, and diversions โ€” (pm); characters (pchar; experimental); colors (pcolor); composite character mappings (pcomposite); environments (pev); occupied font mounting positions (pfp); font translations (pftr); automatic hyphenation codes (pchar) and exceptions (phw); registers (pnr); open streams (pstream); and page location traps (pwh). Requests can also disclose to the standard error stream the internal properties and representations of characters and classes (pchar), macros (and strings and diversions) (pm), and the list of output nodes corresponding to the pending input line (pline).


๐Ÿ‘‘ AUTHORS ๐Ÿ‘‘

This document was written by Trent A. Fisher, Werner Lemberg, and G. Branden Robinson. Section โ€œUnderliningโ€ was primarily written by Bernd Warken.


๐ŸŒˆ SEE ALSO ๐ŸŒˆ

Groff: The GNU Implementation of troff, by Trent A. Fisher and Werner Lemberg, is the primary groff manual. You can browse it interactively with info groff. ๐Ÿ“š

โ€œTroff User's Manualโ€ by Joseph F. Ossanna, 1976 (revised by Brian W. Kernighan, 1992), AT&T Bell Laboratories Computing Science Technical Report No. 54, widely called simply โ€œCSTR #54โ€, documents the language, device and font description file formats, and device-independent page description language referred to collectively in groff documentation as โ€œAT&T troffโ€.

โ€œA Typesetter-independent TROFFโ€ by Brian W. Kernighan, 1982, AT&T Bell Laboratories Computing Science Technical Report No. 97 (CSTR #97), provides additional insights into the device and font description file formats and device-independent page description language.

  • groff(1) โ€” is the preferred interface to the groff system; it manages the pipeline that carries a source document through preprocessors, the troff formatter, and an output driver to viewable or printable form. It also exhaustively lists the man pages provided with the GNU roff system.
  • groff_char(7) โ€” discusses character encoding issues and escape sequences that produce glyphs.
  • groff_diff(7) โ€” covers differences between the GNU troff formatter, its device and font description file formats, its device-independent page description language, and those of AT&T troff.
  • groff_font(5) โ€” describes the formats of the files that describe devices (DESC) and fonts.
  • groff_tmac(5) โ€” surveys macro packages provided with groff, describes how documents can take advantage of them, offers guidance on writing macro packages and using diversions, and includes historical information.
  • roff(7) โ€” presents a detailed history of roff systems and summarizes concepts common to them.

That's the whole groff(7) page, bestie! ๐Ÿ’– It's from groff 1.24.2, dated 2026-10-01, and yes โ€” it's the groff(7) manual. ๐ŸŽ€โœจ

๐Ÿ“ฆ where this page comes from