an9wer's

Forming a Labelled and Indented Paragraph in troff

posted:

2025-05-26

A labelled and indented paragraph is a paragraph that begins with a label, followed by text that is indented. As described in the "Paragraphs" section of the groff manual, there are typically two common forms:

  1. The label and the paragraph text appear on separated lines. For example:

    Note
            This is the paragraph text that is separated from the label
            "Note". Here is some dummy text, and then comes some more dummy
            text.
  2. The label and the paragraph body appear on the same line. For example:

    Note    This is the paragraph text that is on the same line as the label
            "Note". Here is some dummy text, and then comes some more dummy
            text.

The first form can be implemented simply by starting with the label "Note", followed by a new line using the request .br, and setting a desired indentation width (in this case, 8m) for the subsequent line using the request .in 8m:

$ groff > form1.ps
Note
.br
.in 8m
This is the paragraph text that is separated from the label "Note".
Here is some dummy text, and then comes some more dummy text.

The second form is more challenging because the label and the paragraph text share the same line, which prevents the use of indentation request .in. Fortunately, the "ms" package provides a macro called ".IP" specifically for this purpose:

$ groff -ms > form2-with-ms.ps
.IP Note
This is the paragraph text that is on the same line as the label "Note".
Here is some dummy text, and then comes some more dummy text.

But how to implement it without using any macro packages? - an intelligent trick is to place a tab character right after the label "Note", with the tab stop set to match the indentation width:

$ groff > form2.ps
.in 8m
.ta 8m
.ti 0
Note    \c
This is the paragraph text that is on the same line as the label "Note".
Here is some dummy text, and then comes some more dummy text.

Let's break down how this works. First, both the indentation width and the tab stop are set to 8m using the requests .in 8m and .ta 8m. The request .ti 0 is then used to cancel automatic indentation for the next line, which is the first line of output.

The first line of output begins with the label "Note" at the left margin, followed by a tab character. The escape sequence "\c" tells troff to continue the output with the next input line, so the paragraph text follows immediately after the tab. Because the tab stop matches the indentation width, the paragraph text is aligned as if it were indented. The remaining of the paragraph appears on the next output lines, which is automatically indented.

If looking into the source code of the macro ".IP" in the "ms" package, you will see it uses the similiar method. Below is a simplified version of the macro ".IP":

.de IP
.ie \\n(.$>1 .nr I \\$2
.el .nr I 8
.in \\nIm
.ta \\nIm
.ti 0
\\$1\t\c
..

The first argument is the label, and the second argument (optional) specifies the indentation width. Here are some examples of how to use it:

Thanks for reading :)