Guide to APA with groff ms and refer
This guide explains why and how I used groff with the ms and refer macros to write my college essay in Neovim.
Table of Contents
Preface
Many colleges give students a mandatory class where they learn how to cite and do referencing in essays.
For my essay, I wrote it using Neovim, the same terminal text-editor I code on and write blogs for my website with, and that would not have been possible without a word processor that can compile documents from plaintext (unlike What-You-See-Is-What-You-Get (WYSIWYG) word processors, such as LibreOffice Writer). As you could tell from the title of this blog post, I used groff to accomplish this.
Although some of the modifications detailed in this guide are specific to APA, you do not have to be writing in APA to find this guide helpful. Just adapt some of the specific changes made in this guide to suit your style guide.
This blog guide mainly just serves to compile all the relevant research I had done into a simple step-by-step solution I can easily follow when I want to use groff to write essays in APA again, but it also hopes to help others who were in the same spot I was save themselves some time and frustration that I had to go through when figuring things out by myself for the first time.
I made a Github repository as a companion to this guide. It gives an example of the final generated output so you know exactly what you are going to get out of this. The source files included in the repository have some extra comments to help readability and can also be used as a template to quickly set things up to just get started writing.
A fun fact about this blog post: this is actually my second time writing this whole thing because I frustratingly lost the first one in the dumbest way possible. I accidentally deleted the folder containing it because I forgot that I put it in the folder. Unfortunately, it was already gone by the time I realised due to the auto-emptying routine of my Trash folder scheduled to run once every hour.
Introduction
The American Psychological Association (APA) 7th Edition style guide is the most popular for formatting references and citations in college-level essays (at least that was what my lecturer said when they gave out the writing assignment).
GNU (t)roff (abbreviated as groff) is an older and more lightweight but less well-known typesetting alternative to LaTeX (which is popular for writing academic papers) that comes preinstalled in most GNU/Linux distributions. If it was not for the massive size of a LaTeX install (>2GB vs. groff’s <10MB), I likely would not have used groff. groff also has a simpler syntax and compiles in an instant compared to LaTeX, which are some of the things that further convinced me to stick with groff even when I got stuck and lost at times.
The ms (“manuscript”) macros were the earliest and are largely seen as the “default” set of macros for writing in groff, so it should have the most documentation out of any other macro packages. That was the main reason I chose to use the it instead of other macros, as well as having already experimented with writing basic documents with ms previously.
However, groff by itself cannot do citations and referencing out-of-the-box. Fortunately, it does come with a preprocessor called refer that does the citing and referencing for it. Although the defaults for refer do not conform to APA guidelines, it is not too complex to change those defaults to match any style guide as long as you know where to find the right things to change.
Prerequisites
This guide assumes you are using a Unix-based system (e.g. GNU/Linux, *BSD, macOS, etc.) and already know how to write and compile basic groff ms
documents to Portable Document Format (PDF). If not, do not worry. There are many resources online for getting started, such as Luke Smith’s videos on groff and refer. For more detail, see GNU’s official manual or troff
’s HOWTO.
Cover Page
My assignment did not require me to include a cover page, but yours might. By default, groff puts cover page information on the same page as the essay. Luckily, the ms macros contain a convenient way to change this. Just put .RP no
as the first line of your document (.RP
stands for “report”; the no
argument tells it to not repeat the cover page information on the next page):
.RP no
This is also needed for the next section on page numbering.
Page Numbering
The first page does not have any headers (including page numbering) because groff expects it to include cover page information (i.e. the title of the paper; optionally author(s), institution(s), date, and abstract).
If you followed the steps on the previous section on the cover page, you might be confused as to why the first page after the cover page still does not have any page numbering while the page after it starts with the page numbering of ‘2’. This is because although groff started counting page numbers on the first page after the cover page, it still suppresses the first page by default.
When we used the .RP no
macro (also needed for this section) to move the cover page information into its own page, we simply created a new “page 0” that groff does not know about (which is also why groff does not count it in the page numbering).
There is another macro we can use to fix this. Place .P1
below .RP no
to unsuppress the first page header (page numbering):
.RP no
.P1
The .RP no
macro is needed for this, but it produces a cover page. Use PDF-editing software to delete it if it is unwanted. Any tool can be used for this, but the best one I found is PDFArranger.
.P1
does not work by itself without .RP no
likely because groff suppresses headers on any page with cover page information, even if you make them empty by doing this:
.TL
.AB no
.AE
which works because even though the title (.TL
) is required, it stops at the abstract (.AB
, which ends at .AE
; the no
argument suppresses the “Abstract” heading).
Font
Many lecturers demand assignments to be submitted in double-spaced Times New Roman in 12 point size. This section covers how to change the font family, size, style, and line spacing.
Font Family
By default, groff already outputs text in your device’s default serif font family (typically Times New Roman), but sometimes (very rarely, in my experience) lecturers prefer sans-serif or even monospace in some cases.
Default Fonts
Changing to another one of the default fonts in groff is simple.
This is how to change it to device’s default sans-serif,
.fam H \" Helvetica
monospace,
.fam C \" Courier
and (back to) serif font family:
.fam T \" Times New Roman
There are many other default fonts in groff listed in this post.
Custom Fonts
Installing custom fonts for groff is a little bit trickier; I have not been able to get it to work on my device yet. I did find a guide that seemed promising though. Maybe I will revisit this if I get it working in the future.
Font Size
The default font size in groff is a little bit less than 12pt (10pt, to be exact), but it is very easy to change. Simply add this line to your plaintext document to change the font size to 12pt:
.nr PS 12
As for what PS
stands for, it probably means something like “Point Size”; .nr
stands for “Number Registers”.
Line Spacing
All parts of an APA-styled paper should be double-spaced. By default, groff uses 120% of font size as vertical spacing. Fortunately, changing this to double-spacing is just as simple as changing the font size: just set the vertical spacing (.nr VS
) to double your font size (.nr PS
).
.nr VS 24
Font Style
Here is how to make your text bold,
.ft B
or italicised.
.ft I
And to set it back to normal:
.ft R \" Stands for Regular or Roman
In-text Citation
Now that everything is set up, we can start to get into the citations.
refer uses numbered footnotes by default, but APA wants the author(s) and date included in their in-text citations. This section will cover how to do exactly as APA says.
Parenthetical Citation
After some research, I found a blog post “no-tears” guide, 2 Github repositories, and a post from the GNU mailing list archive (which I cannot seem to find anymore). I extracted the refer block (denoted by .R1
and .R2
) from all those sources and combined them to make a frankenstein that works perfectly for most APA parenthetical citations:
.R1 \" Refer block start
database ref.bib # Path to refer bibliography file from current working directory (can also be absolute directory)
accumulate # Prints References at end of the document (same as `-e` argument for refer)
move-punctuation # Ensures citations appear before punctuations (same as `-P` argument for refer)
sort A+ # Sorts References in alphabetical order
label "(A1?(A1.n(A3?' et al.':A2&' & 'A2.n)):Q)', '(D.y|D)" # "Author(s), Date" format for parenthetical citation (joins author names using '&' if 2 authors; appends 'et. al.' if 3 or more)
bracket-label " (" ) "; " # (same as `-S` argument for refer)
no-label-in-reference # Do not display (Author(s), Date) like footnotes in reference list
join-authors " & " ", " " & " # Change default "and" to ampersand (&) when joining author names in reference entry
.R2 \" Refer block end
Narrative Citation
My lecturer luckily did not require me to use narrative citations, but yours might. If you do have to use narrative citation, unfortunately, refer does not have any support for narrative citations being alongside parenthetical citations. While it is possible to repurpose the citation formatting part of the refer block to change it from parenthetical to narrative, it would still not be possible to have both narrative and parenthetical citation on the same page.
The only practical solution I can think of for this problem is to keep the refer block as-is and write the narrative citations manually. This will require you to have a separate document for producing the referencing for the narrative citations, because refer will not make entries for them in the reference list as it will not recognise the narrative citations that you manually typed in, treating them like ordinary text. This also means that you need to generate 2 separate output PDFs and extract the correct reference list from the one without narrative citations to merge (using PDF-editing software) with the other one that does.
Reference List
This section is where we start to dive into refer’s code (usually located inside either /usr/share/groff/current/tmac
or /usr/local/share/groff/current/tmac
). Rest assured, the changes that will be made will not be difficult as long as you know 3 things: what to change, what to change them to, and where to find them (all 3 being what I had to figure out on my own by reading and tinkering with the source code).
Formatting the Heading
The “References” heading is left-aligned by default, whereas APA wants it centered. Some extra changes not specified by APA my lecturer wanted were to make the Heading a little bigger and add an extra line of space below it.
On lines 75–79 of refer-ms.tmac
, you will find this:
.de ref*biblio-start-hook
. SH
. nop \&\\*[REFERENCES]
. par@reset
..
And this is what it will look like fixing the issues (lines that are commented out (denoted by \"
) do not strictly conform to APA, uncomment them to use them):
.de ref*biblio-start-hook
.\" nr PS 14
. SH
. ce
. nop \&\\*[REFERENCES]
.\" sp
.\" nr PS 12
. par@reset
..
Below is a list explaining each change made:
- To make the heading centered, put
.ce
above where the heading is rendered (.nop \%\\*[REFERENCES]
). - (Optional)
.nr PS 14
above it increases the font size to 14pt, just remember to reset it back to normal (12pt) with.nr PS 12
after. - (Optional)
.sp
adds an extra line of space below it.
Space Between Entries
There is no space between reference entries by default. This is already conforming to APA, but my lecturer wanted extra padding between the entries (even if that meant breaking APA guidelines) and maybe yours might too.
Inside refer-ms.tmac
on lines 44–45, you can find this:
.de ref*biblio-item-end
..
(Optional) Just like how we added a space below the “References” heading, use .sp
to add a line of space between each entry in the reference list:
.de ref*biblio-item-end
. sp
..
Field Ordering
The way refer orders the fields of each reference entry is hard-coded and different from what APA desires. More specifically, the date field is placed after the title field instead of being in between it and the author(s) field.
There will be these 5 lines that dictate the order of the fields of each entry on lines 53–57 of refer-ms.tmac
:
.ds ref*spec!0 Q A T S V N P I C D O
.ds ref*spec!1 Q A T J S V N P I C D O
.ds ref*spec!2 Q A T S V P I C D O
.ds ref*spec!3 Q A T B E S V P I C D O
.ds ref*spec!4 Q A T R G P I C D O
Documentation for what each of the ref*spec!N
mean can be found in the comments at the top of refer.tmac
on lines 67–71:
.\" ref*spec!0 Q A T S V N P I C D O -- other
.\" ref*spec!1 Q A T J S V N P I C D O -- journal article
.\" ref*spec!2 Q A T S V P I C D O -- book
.\" ref*spec!3 Q A T B E S V P I C D O -- article within book
.\" ref*spec!4 Q A T R G P I C D O -- technical report
The values for the letters after the ref*spec!N
are specified in the bibliography file linked in the refer block (ref.bib
).
Rearranging D
(date) into the correct order (right after A
(author(s)) and before T
(title)):
.ds ref*spec!0 Q A D T S V N P I C O
.ds ref*spec!1 Q A D T J S V N P I C O
.ds ref*spec!2 Q A D T S V P I C O
.ds ref*spec!3 Q A D T B E S V P I C O
.ds ref*spec!4 Q A D T R G P I C O
Punctuation
Switching the order of the fields messes up the hard-coded punctuation order, but there are also some defaults that do not follow APA guidelines.
Go to lines 59–73 of refer-ms.tmac
, where you will find this:
.ds ref*spec!A ", " "
.ds ref*spec!B """ " " "in \fI" "" "\fP"
.ds ref*spec!D """ " " "(" ")"
.ds ref*spec!E ", " " "ed. "
.ds ref*spec!G """ " " "(" ")"
.ds ref*spec!J ", " " "\fI" "" "\fP"
.ds ref*spec!N """ "(" "" ")"
.ds ref*spec!O ". " "
.ds ref*spec!P ", " " "p.\~"
.ds ref*spec!PP ", " " "pp.\~"
.ds ref*spec!T ", " " "\\*Q" "" "\\*U"
.ds ref*spec!T:0 ", " " "\fI" "" "\fP"
.ds ref*spec!T:2 ", " " "\fI" "" "\fP"
.ds ref*spec!V """ " " "\fB" "\fR"
.ds ref*spec!dflt ", " "
It will look like nonsense at first, but documentation can be found in the comments of refer.tmac
on lines 84–110:
.\" arg 1 the punctuation character to use to separate this field
.\" from the previous field
.\" arg 2 a string to insert after the punctuation character of the
.\" previous field (normally a space)
.\" arg 3 a string with which to prefix this field
.\" arg 4 a string with which to postfix this field
.\" arg 5 a string to add after the punctuation character supplied
.\" by the next field
.\"
.\" 1 2 3 4 5
.\" ------------------------------------------------------------------
.\" ref*spec!A , " " -- author name
.\" ref*spec!B "" " " "in \fI" "" "\fP" -- bk title of article
.\" ref*spec!D "" " " "(" ")" -- date of publication
.\" ref*spec!E , " " "ed. " -- editor
.\" ref*spec!G "" " " "(" ")" -- US Gov. ordering #
.\" ref*spec!J , " " "\fI" "" "\fP" -- journal name
.\" ref*spec!N "" "(" "" ")" -- issue number
.\" ref*spec!O . " " -- other information
.\" ref*spec!P , " " "p.\~" -- page
.\" ref*spec!PP , " " "pp.\~" -- page range
.\" ref*spec!T , " " "\\*Q" "" "\\*U" -- journal title
.\" ref*spec!T:0 , " " "\fI" "" "\fP" -- book title (other)
.\" ref*spec!T:2 , " " "\fI" "" "\fP" -- book title (book)
.\" ref*spec!V "" " " "\fB" "\fR" -- volume number
.\"
.\" ref*spec!dflt , " " -- all other entries
This is how it looks like after some changes:
.ds ref*spec!A ", " "
.ds ref*spec!B """ " " "in \fI" "\fP"
.ds ref*spec!D """ " " "(" ")"
.ds ref*spec!E ", " " "ed. " ""
.ds ref*spec!G """ " " "(" ")"
.ds ref*spec!J ". " " "\fI" "\fP"
.ds ref*spec!N """ "(" "" ")"
.ds ref*spec!O ". " "
.ds ref*spec!P ", " " "p.\~"
.ds ref*spec!PP ", " " "pp.\~"
.ds ref*spec!T ". " "
.ds ref*spec!T:0 ". " "
.ds ref*spec!T:2 ". " "
.ds ref*spec!V ", " " "\fI" "\fR"
.ds ref*spec!dflt ", " "
The list below details the changes:
- In the
.ds ref*spec!J
row, itsarg 1
is changed from a comma (,
) to a period (.
) to add a period after the title field. - In the
.ds ref*spec!T
row,\\*Q
and\\*U
are removed to remove the opening and closing double quotation marks, respectively, around the title field. - In both the
.ds ref*spec!T:0
and.ds ref*spec!T:2
rows,\fI
inarg 3
and\fP
inarg 5
are removed to not italicise the text and because of redundancy (\fP
resets font style back to the previous style), respectively. - In the
.ds ref*spec!V
row, itsarg 1
is changed from empty (""
) to a comma (,
) to add a comma after the journal/periodical field; itsarg 3
is changed from bold-ing (\fI
) to italicising (\fB
) the text. - All
\fP
inarg 5
are moved toarg 4
to make sure the punctuations after each field are not in bold or italics.
Period Suppression
By default, refer appends a period at the end of each entry. This means that a period is added after the last field that contains a DOI or URL, which APA has explicitly stated to not do.
To fix this, first go into refer.tmac
, where you will find this on lines 210–213:
. \" now add a final period
. ie d ref*string \{\
. if !\\n[ref*suppress-period] \
. as ref*string .
Now just remove the period (.
) on the last line (213):
. \" now add a final period
. ie d ref*string \{\
. if !\\n[ref*suppress-period] \
. as ref*string
Exporting as PDF
The plaintext document can be compiled with either groff
,
groff -ms -Tpdf -R -dpaper=a4 -P-pa4 sample.ms > sample.pdf
or pdfroff
(which is just a wrapper around groff
):
pdfroff -ms -R -dpaper=a4 -P-pa4 sample.ms > sample.pdf
I found that pdfroff
produces better-looking text output, but it may need to be installed separately for macOS, which uses an older version of groff
that does not come packaged with pdfroff
.
Below is a list explaining what each of the optional arguments mean:
-ms
selects ms macros.-Tpdf
compiles it to PDF; it is not needed forpdfroff
.-R
selects refer macros.- (Optional)
-dpaper=a4
and-P-pa4
exports the paper to the international-standard A4 size instead of the default US letter.
Conclusion
If you found this helpful in any way or have any questions, feel free to leave a comment below. Also read my previous guide on how I justify and hyphenate the text on this website.