The venerable typesetter groff is ubiquitous. With the standard
package ms, it lets you create a wide variety of documents in
plain text with your favorite text editor. It lacks some basic
features, however, viz., cross references, table of contents, and
index.
The mpca macro package is an unobtrusive extension of the
standard ms package that provides workable defaults for these
basic needs which can be extended or overridden as needed.
mpca may stand for “Macros for the Prevention of Cruelty to
Authors”.
Get the mpca package from GitHub:
git clone https://github.com/ds26gte/mpca
Inside the directory mpca, the subdirectory tmac contains the
macro file pca.tmac and several subfiles pca-*.tmac.
Either include this directory in your GROFF_TMAC_PATH, or add
the *.tmac files here to some directory in your
GROFF_TMAC_PATH.
|
Tip
|
If you’re just experimenting, you could simply copy the
The |
To use mpca, you can simply source pca.tmac at the head of
your document:
.mso pca.tmac
Alternatively, you can use the groff command-line option -m,
e.g.,
% groff -mpca doc.ms > doc.ps
Other groff options can be added as usual.
Let’s now go into the mpca features that you can use in your document.
mpca will source a macro file .groffrc.tmac if it can find it in
your GROFF_TMAC_PATH or home directory.
~/.groffrc.tmac is a good place to put minor customizations that are
relevant only to your system. (E.g., I find I sometimes need to
slightly tweak the page-offset register (PO) to suit a
particular printer — this tweak needn’t or shouldn’t be enshrined
in my document.)
Use .EX to start and .EE to end a verbatim display, typically
used for program listings, e.g.,
.EX function fact(n) if n == 0 then return 1 else return n*fact(n - 1) end end .EE
In this style of call, a display is allowed to cross page
boundaries. You can’t use the backslash (\) without triggering
a troff escape. You also can’t use a period (.) in the first
column of any line in the display. This is typically not a
problem if you consistently indent the body of your displays
anyway. (Periods in the middle of lines are ok.)
You can use a leading period to effect styling changes. For example
.EX function fact(n) .ft CI -- returns the factorial of n .ft C if n == 0 then return 1 else return n*fact(n - 1) end end .EE
Adding an argument to .EX (doesn’t matter what, say 1) lets
you use backslash verbatim in the display, however this requires
the display to fit in one page. (The reason is that groff’s page boundary
traps require the troff escape enabled.)
In the general .EX (without argument), you can briefly
turn off the troff escape with .eo, as long as you quickly
(before danger of a page boundary) turn
it back on with .ec. These lines of course use . in the
first column and will not be themselves displayed.
The .IMG macro can be used to insert image files. The syntax
follows that of the .IMG macro in the www.tmac, but (a) isn’t
restricted to HTML output. E.g.,
.IMG t2p.png
sources the image t2p.png.
You can specify the image alignment with an optional first argument: -L
for left, -R for right, -C for centered. If no alignment is
specified, -C is assumed.
.IMG -L t2p.png
.IMG takes an optional final argument to specify the width of
the image. The default is 1 inch.
.IMG t2p.png 3i .IMG -L t2p.png 4i
.IMG relies on the external programs convert (from
ImageMagick); mkbitmap and potrace (both from the Potrace
package); and Inkscape. (mkbitmap and potrace are needed
for PNG images. Inkscape is needed for SVG
images.)
The .TAG macro manages cross-references. E.g.,
.TAG sec_grofflua
associates the label TAG:sec_grofflua with the number of the
current page. The string \*[TAG:sec_grofflua] is defined to
typeset as that page number. Thus, in a hand-crafted table of
contents, you could use
Extending groff using Lua, \*[TAG:sec_grofflua]
.TAG takes an optional second argument. The label is then
associated with the text of the second argument instead of the
current page number.
|
Note
|
mpca’s .TAG overrides a similarly named macro in
the file www.tmac in the groff distribution, which only
allows backward references.
|
|
Important
|
.TAG requires two runs of groff. Please see the
section on aux files.
|
The .ToC macro inserts a table of contents (ToC). Add your own
header, e.g., “Contents”, or “Table of Contents” (which is also
the default value of the ms string \*[TOC]).
.ToC does not require you to modify how you use your sectioning
macros — it automatically draws its information from the
distribution of the .NH and .SH macros within your document.
It is thus a solution to the following statement from the groff
manual:
Altering the ‘NH’ macro to automatically build the table of contents is perhaps initially more difficult, but would save a great deal of time in the long run if you use ‘ms’ regularly.
ToC entries are generated for the usual ms section headers (.SH,
.NH). The depth of the ToC is governed by the number register
GROWPS: Only those .SH/.NH headers at a level less than or
equal to GROWPS will go into the ToC.
The number register \n[pca:DI] (default: .5 inch) determines
how much subsections are indented in the ToC.
The .IX macro is used to generate index entries:
.IX item to be indexed
marks the text “item to be indexed” as an indexable item. The sorted index made from these entries can be sourced into the input document via
.so \*[AUXF].ind
Adding a section header on top is up to you.
The sorted index is constructed using the external program
makeindex. makeindex is included in TeX distributions, but
you can also obtain it as
a
standalone package.
The metacharacters @, !, ", and | can be used
to respectively specify
-
alternate alphabetization,
-
subitems,
-
literal metacharacters, and
-
encapsulation of the page number.
E.g.,
.IX m@-m, groff option
identifies an index entry for “-m, groff option” but alphabetizes it as though it were “m” rather than something that starts with a hyphen.
.IX groff!macro packages
makes “macro packages” an indented index subentry under “groff”.
Up to two !s may be used.
.IX groff!macro packages!ms
produces “ms” as a subsubentry under “macro packages” under “groff”.
.IX troff|see groff
has the index entry for “troff” point to “groff” rather than have a page number of its own.
If any of the metacharacters need to
appear in the index entry as themselves, precede them with ".
.IX set"!car
creates an index entry for “set!car” rather than creating a subentry “car” under “set"”.
|
Tip
|
The syntax for .IX item where in LaTeX one would use \index{item}
|
|
Note
|
For full details on index-entry syntax, consult the makeindex documentation. |
The .BIB macro is used to introduce a paragraph that is a simple bibliographic
reference, e.g.,
.BIB utp David S. Landes, \fIRevolutions in Time: Clocks and the Making of the Modern World\fP, Belknap Press, 1983.
If it is the nth such reference in the document, it is prefixed
with “[n]” in the output. Furthermore, the label TAG:utp is
associated with n, using the cross-reference mechanism
described earlier, and can be used to cite the reference. E.g.,
For a history of the first portable device that, for better or worse, completely changed how we live, see Landes [\*[TAG:landes_clock]].
The macro .eval allows you to insert Lua, Common Lisp or JavaScript
code in your document to guide its transformation via
groff. In other words, it lets you you use Lua, CL, or JS to
extend groff instead of relying purely on groff macros.
The code inside .eval is evaluated using the language specified
by the string pca-eval-lang, which by default is lua.
We will first describe the Lua version of .eval.
.eval does only one thing: It allows you to place arbitrary
Lua code until the following .endeval, and the text written to
the stream troff this Lua code is substituted for the .eval …
.endeval. The usefulness of this tactic will be apparent from an
example. Consider the following document, tau.ms:
The ratio of the circumference of a circle to its radius is \(*t \(~= .eval -- the following prints tau, because cos(tau/2) = -1 troff:write(2*math.acos(-1), '.\n') .endeval
Run it through mpca:
groff -z -U -mpca tau.ms
The -z avoids generating ouput, because we’re not ready for it
yet. The -U runs groff in “unsafe” mode, i.e., it allows the
writing of aux files.
You will find that the groff call produces the following
message:
Rerun groff with -U
Call groff again as folows:
groff -U -mpca tau.ms > tau.ps
tau.ps will now look like:
The ratio of the circumference of a circle to its radius is τ ≈ 6.2831853071796.
Here’s how it works. The first groff call produces a Lua file
\*[AUXF].lua that collects all the .eval code in the
document. The second groff call invokes Lua to create an aux
file for each .eval and sources it back into the document.
It should be clear that Lua code via .eval can serve as a very
powerful second extension language for groff. For a more
substantial example of .eval’s use see
the troff2page manual.
To use Common Lisp inside .eval, set
.ds pca-eval-lang lisp
in your document before the first use of .eval. Thus, the
tau.ms file, translated to Common Lisp, will now read:
.ds pca-eval-lang lisp The ratio of the circumference of a circle to its radius is \(*t \(~= .eval ;the following prints tau, because cos(tau/2) = -1 (princ (* 2 (acos -1)) *troff*) (princ "." *troff*) (terpri *troff*) .endeval
|
Note
|
For the Common Lisp .eval, we write to the stream
*troff* rather than troff.
|
To use JavaScript inside .eval, set
.ds pca-eval-lang js
in your document before the first use of .eval. Thus, the
tau.ms file, translated to JavaScript, will now read:
.ds pca-eval-lang js
The ratio of the circumference of a circle to
its radius is \(*t \(~=
.eval
// the following prints tau, because cos(tau/2) = -1
troff.write('' + 2*Math.acos(-1));
troff.write('.\n');
.endeval
mpca uses auxiliary (aux) files to implement its
cross-referencing, ToC, indexing, and eval features.
The troff string \*[AUXF] is used to construct the names of
these auxiliary files. By default this is quietly set to .trofftemp.
You can change it to something else (provided it satisfies
your OS’s file-naming conventions) in your document before the first use of
any macros that use or write aux files.
Aux files are created in one run of groff and slurped back in
during a second run. Thus groff needs to be run twice for the
defined feature to take effect. Furthermore, the first run of
groff must be run in “unsafe” mode (groff option -U) as
groff won’t create external files in “safe” mode.
|
Tip
|
You may ignore this section if you don’t mind loading all of
the mpca features.
|
You may pick and choose individual features of mpca
without committing to the rest of it.
To do this source one or more of the following
macro files:
pca-eval.tmac (eval),
pca-img.tmac (images),
pca-ix.tmac (index),
pca-sc.tmac (thought break),
pca-tag.tmac (cross-references),
and
pca-toc.tmac (ToC).
E.g.,
.mso pca-eval.tmac
If the feature uses aux files, you will need to run groff
twice, once in unsafe mode,
as described in the section on aux files.