How to Write Papers with Groff
If you’re like me, word processors hate you. You spend more time trying to get the stupid bullet points right then actually writing. Or perhaps you, like me, think that GUIs are useless bloat and overhead. Maybe you would, like me, prefer to use emacs or vi for word processing instead of a primitive, soulless WYSIWYG interface. Or maybe you, like me, just like to scare people who only know how to change the font in Microsoft Word. Either way, groff(1) may be the right choice for you.
A fairly detailed history of groff/troff/nroff/roff is available in roff(7), but allow me to summarize it for you. Let us go back to the days of CTSS in 1961. There was a program called runoff that was the main format for documentation and text processing, although it only become popular when CTSS became MULTICS (1963). runoff was pretty primitive, and was written in PL/1 and later in BCPL. Further on, in the 1970s, the Unix culture developed roff as a shortened version of runoff with more sophisticated features, such as graphical output to a CAT typesetter. This roff system had three formatters:
- troff, or typesetter roff, created graphical output for the CAT typesetter.
- nroff resulted in textual output for terminals and line printers.
- roff was a plain reimplementation of runoff, and was abandoned. These days, roff refers to a complete troff/nroff system.
groff is the GNU roff system. I could carry on, but that’s the basic history.
Now then, as for how it works, allow me to show you the basic pipeline (although groff can automate the pipeline, I prefer to handle that myself):
Input file --> pre-processors --> troff/nroff --> post-processor --> output (printer, whatever)
The input file you may write in your editor of choice (I prefer vim, personally). It is saved generally with a .tr file extension. Pre-processors turn their special syntax in your input file into roff code, to make graphs, pictures, mathematical forumlas, or whatever easier to work with. Troff then produces roff output code that the post-processor turns into the final output format, such as postscript for printing.
The syntax of roff is a programming language complete with loops, conditional blocks, and debugging output. However, to write a paper, you use a macro package to make your life easier. I suggest the “ms” macro set, as that’s fairly general purpose. Rather then bore you further, I’ll give an example file, and then explain it.
.nr PS 12
.nr PO 1i
.nr LL 6.5i.TL
The effect of widgets on a standard business workflow
.AU
John Doe
.AI
Someplace University
.LP
Widgets have a blah blah blah blah blah blah.
Yadda yadda yadda yadda yadda yadda. According to
Jane Roe,
.QP
“Something and some other thing.”
.LP
If this is to be believed, then bla blah bla blah yadda blah
blah blah blah blah blah.
Firstly, .nr sets a register. I believe that acts like a variable, basically. The macro package I’m using here–ms–defines several registers that change how this document is formatted. The PS register defines general font size, PO defines left margin, and LL defines how long the lines can be. Right margin is implied from these two registers in combination. You can use a variaty of units in a roff document, but here are the basic ones:
- i – inch
- c – centimeter
- p – pica
- p – point
- m – em
- M = 100th of an em
- n – en = em/2
Moving along, the ms macro set defines the .TL command to set the title of the document, .AU to set the author’s name, and .AI to set the author’s institution. You can have any number of authors or institutions, each with their own .AU and .AI.
.RP can be called to make a separate title page, .AB begins an abstract, and .AE ends the abstract.
.LP starts a new paragraph with an indentation, and .QP is indented at both margins, like a <blockquote> tag in HTML.
A new unnumbered heading can be defined with .SH [heading level].
.IP [marker [width]] handles lists; marker is the glyph for the bullet; for unnumbered lists, it’s usually going to be “\[bu]“; a number or a number register for numbered lists, and a word or phrase makes it glossary-style. For example:
.IP \[bu]
Something
.IP \[bu]
Something else
.IP \[bu]
Yet more something else
.nr step 1
.IP \n[step]
“It’s not a question of where he grips it; it’s a simple question of weight ratios! A five-ounce bird cannot carry a one-pound coconut!”
.IP \n+[step]
“Oh, king, very nice. And how’d you get that title, eh? By exploitin’ the workers! By hangin’ onto outdated imperialist dogma that perpetuates the economic and social differences in our society!”
.IP \n+[step]
“We’re knights of the round table, we dance when’ver we’re able!”
.IP Intel 0.5i
A CPU company.
.IP AMD
Another CPU company.
.IP VIA
Yet another CPU company.
Note that I haven’t personally used lists yet; the syntax is right out of the info file for groff.
To view your document, run
cat [document name] | nroff -mms
To view your document graphically, run
cat [document name] | groff -mms -TX75
To print your document, run
cat [document name] | troff -mms | grops | lpr -P[printer name]
groff has options to simplify pipelines like that, but I prefer to avoid them when possible. Pipelines are less likely to harbor bugs then complex command line option sets.
-m sets the macro set, and when used with groff, -T sets the output device.
Congratulations, you now know juuust enough groff to write a paper! I’ll probably expand this article when I learn more. Remember that you can write your own macros, too. roff is extremely powerful, and this barely scratches the surface. If you want more advanced details, feel free to read groff(7), or the groff info page.