1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
|
.so k.tmac
.so kx.tmac
.so toc/toc.tmac
.mediasize letter
.fp 0 M DejaVuSansMono ttf
.hw Eng-lish
.
.\" configure table of contents
.eo
.de he
. bp
. nr a +1
. h
\X'PDFMark: Bookmark 0 \\$*'\A'\na'
. br
. sp -1
\$*
. te .the \\\T'\na'\$*\t\n%\\T
..
.
.de se
. nr a +1
. s
\X'PDFMark: Bookmark 1 \\$*'\A'\na'
. br
. sp -1
\$*
. if '\$1 \$2 \$3'How do I' \{\
. nr hdi +1
. if \n[hdi]>1 \{\
. shift 3
. te .the \\\T'\na'\\h'36p'"\\h'20.4p'\$*\t\n%\\T
. return
. \}
. \}
. te .the \\\T'\na'\\h'18p'\$*\t\n%\\T
..
.
.ec
.
.\" configure header and footer
.eo
.de @h
. sp |36p
. if \n%>1 .tl ''-%-''
. sp |1i
..
.
.de @f
. sp |\n(.pu-48p
. tl ''\*(#e''
..
.ec
.
.\" configure environments
.@e l
. ft M
. vs +1p
.@e
.
.\" start document
.t
.x Mk ,
a simple macro package for troff
.d
John Ankarström
.d e
.
.s
.ce
.i "TABLE OF CONTENTS"
.sp 4p
.@e
\X'SetLinkBorder: 0 0 0'\c
.to
.sp 0.5i
.ns
.
.he Introduction
.p
.i Mk
is a simple macro package for troff with the following features:
.n 1
It is designed to be easy to understand and to customize
by editing the source code.
.n
It makes use of the extended support for environments
offered by modern troff implementations.
.n
It is designed to be practically easy to use.
Macros consist of a single lowercase letter.
.p
While
.i mk
does provide macros for many common tasks,
including footnotes,
it is at the end of the day an idiosyncratic macro package,
written to serve the author's personal needs.
Users of
.i mk
are encouraged to
.n 1 a )
modify the source code
according to their own needs, as well as
.n
use built-in troff requests for some things
that other packages might provide custom macros for.
.p
All in all,
.i mk
aspires to abstract as little as possible
from the underlying troff requests and registers.
In its author's humble opinion,
it is the ideal macro package for learning troff.
.p
In this document, the fundamental concepts of
.i mk
are explained.
The document itself also serves as a demonstration of
.i mk .
With a couple of exceptions, it uses
.i mk 's
default settings.
The reader is encouraged to inspect the document's source code
in order to see how the macro package is used in practice.
.p
And yes, that table of contents is automatically generated!
See p. \n[&toc] for more information.
.
.
.he Environments
.te .nr &env \n%
.p
.i Mk
makes heavy use of named environments,
supported by implementations such as GNU troff, Heirloom troff and Neatroff.
Environments obliviate the need for many special registers
that a macro package (and its user) would otherwise need to keep track of.
For example,
.i ms
keeps track of the document's font size in the
.c PS
register.
For the font size of headings,
it has yet another register.
.i mk
has no such registers.
If the user wishes to modify the default font size,
he or she can simply switch to the relevant environment
and set the font size as desired
using regular troff requests:
.l(
.\" set heading font
.h
.fam H
.ps +1p
.l)
.p
Troff saves the font settings in the environment,
so that the next time the environment is invoked,
the desired font family and point size are automatically restored.
.p
The environments are initialized
as soon as the first
." block-level
macro is called.
At the initialization of each environment,
the default environment (0) is copied,
meaning that all environment-relevant settings
defined before the first macro call
are applied to all
.i mk
environments.
It is thus remarkably simple and intuitive to set,
for example, the default font of a document:
.l(
.fam N
.t
Document title
.p
First paragraph.
.l)
.p
In addition to the normal environment-relevant settings,
.i mk
manually associates a few special registers with the current environment:
.n 1
.c sp ,
the amount of vertical space to add before an environment
.n
.c sq ,
the amount of vertical space to add before a different type of environment
.n
.c ti ,
the indentation of the first line in some environments
(currently only
.c p )
.p
These can be set inside a given environment
to control its behavior when invoked.
The only exception are the margin and footnote environments
.c @m , (
.c @f ),
which are treated specially
and do not support these registers.
.
.
.he External macros
.p
.i Mk
defines a number of macros.
Some of them are used internally by
.i mk
itself;
these carry an at
.c @ ) (
prefix
and are going to be explored later.
For now, we will focus on the external macros provided by
.i mk .
.
.se Inline macros
.p
There is a group of macros that provide
convenient inline formatting.
All take three arguments:
the text to be formatted,
the text to be placed immediately after
and the text to be placed immediately before.
The inline macros are the following:
.n 1
.c \(dq ,
quotation (like
." this )
.n
.c b ,
bold font
.n
.c c ,
constant-width font
.n
.c i ,
italic font
.n
.c i ,
bold italic font
.p
For example, the following request outputs
.i mk .\(rq: \(lq
.l(
.i mk .
.l)
.
.p
Note that
.c c
uses the font family and point size
set in the
.c l
environment (see below).
.se Block-level macros
.p
There is a large group of macros that provide
block-level formatting:
.n 1
.c d ,
centered date or text
.n
.c h ,
heading
.n
.c l ,
literal display (for source code)
.n
.c p ,
paragraph
.n
.c q ,
indented quotation
.n
.c s ,
subheading
.n
.c t ,
centered title
.p
The
.c t
and
.c d
macros can be used at the beginning of a document
to create a centered header:
.l(
.t
Document title
.d
First author
.br
Second author
.d i \" current date formatted as YYYY-MM-DD
.l)
.p
In the example above, you can see that the
.c d
macro may be used for other things than just dates.
This works because
.c d
displays the date only if given
an argument describing the desired date format:
.n 1 a )
.c i :
international date, like
." 2021-06-21
.n
.c e :
English date, like
." "21 June 2021"
.p
The formatted dates are defined in strings prefixed with a hash symbol
.c # ): (
.c #i
and
.c #e
are provided by default,
but more may be added by the user.
.
.se Other macros
.p
Finally, there are a few macros
that belong to neither category:
.n 1
.ne 2
.c ( ,
begin footnote
.n
.c ) ,
end footnote
.n
.c w ,
want space
.p
The macros
.c (
and
.c )
create footnotes,
placing a numerical reference at the place of their invocation.
Both
.c (
and
.c )
take an optional argument,
which is output either immediately before or immediately after
the inline reference.
For example, the code
.l(
.q
This is a quotation\c
.(
\!.ne 1
This is a footnote.
.)
.l)
.p
generates the following output:
.q
This is a quotation\c
.(
This is a footnote.
.) .
.p
If
.c (
and
.c )
are called at such a position that the collected footnotes
cannot fit on the current page,
.i mk
will print the footnotes on the next page instead.
.p
The
.c w
macro is an alternative to troff's
.c ne
request,
which ensures that a given amount of space is available on the page
\(en otherwise, a line break is issued \(en
but unlike
.c ne ,
which takes an exact amount of space as its argument,
.c w
takes a declarative specification
describing the amount of desired space
in terms of
.i mk
environments.
For example:
.l(
.\" want space for...
.w s p \" a subheading of one line + a paragraph of one line
.w s pp \" a subheading of one line + a paragraph of two lines
.w ss p \" a subheading of two lines + a paragraph of one line
.l)
.
.
.he Internal macros
.p
.i Mk
internal macros are generally not meant to be used outside of
.i k.tmac .
Documented in this section are the exceptions to this rule.
For examples of how these macros are used in practice,
see the FAQ section on page \n[&faq].
.
.se Page header and footer
.p
The
.c @h ,
.c @f ,
.c @th
and
.c @tf
macros control the page header and footer.
.p
At document initialization,
.i mk
automatically creates traps for
.c @th
and
.c @tf .
When sprung,
.c @th
and
.c @tf
call
.c @h
and
.c @t ,
which control the text and spacing of the header and footer.
.p
.i Mk
will avoid creating a trap for
.c @tf
if any trap has already been set before document initialization.
This means that users can override the position of the
.c @tf
trap by setting it themselves.
Likewise, users can redefine
.c @h
and
.c @f
to change the content of the header and footer.
.
.se Environments
.p
The environment-related macros
.c (e ,
.c @e
and
.c @c
may be used in advanced documents to define custom environments.
.p
At the present,
.c (e
is nothing more than a wrapper around troff's built-in
.c ev ,
but it may eventually be redefined in order to offer
compatibility with troff implementations
without support for named environments.
.p
.c @e
and
.c @c
are equivalent to troff's
.c ev
and
.c evc ,
but perform some extra work to keep track of
.i mk 's
special environment variables
(see
.i Environments ,
p. \n[&env]).
.
.
.he Frequently anticipated questions
.te .nr &faq \n%
.
.se How do I customize the default appearance of a document?
.p
All environment settings,
like point size, font family and indentation\c
.(
For a complete list of settings that are associated with the environment,
see 5.26\~\c
.i Environments
in the full GNU troff manual
.nh
.c "info 'groff\:.info)Environments'" ). (
.hy
.) ,
are configured with the standard troff requests.
If you set the point size at the beginning of the document,
before any
.i mk
macros have been called,
it will be correctly set for the entire document.
This works because
.i mk 's
environments initially copy all their settings from 0,
the default environment.
.p
For example, if you wanted to write a document
with the New Century Schoolbook font
at 9 points
and a vertical spacing of 12 points,
you would start the document like this
(before you call any
.i mk
macros):
.l(
.fam N
.ps 9p
.vs 12p
.l)
.
.se How do I customize the default appearance of a given environment?
.p
To configure the layout and font settings of a specific environment,
you can switch to that environment and use the relevant troff requests:
.l(
\!.ne 1
.q
.ps +1p
.l)
.p
If you are merely configuring the environment
without printing anything in it,
you can also use
.c @e :
.l(
.@e q
.ps +1p
.l)
.
.w s ll
.se How do I customize the default appearance of the margin text?
.l(
.(e @m \" margin environment
.ps +1p
.l)
.p
You can also set such settings in your redefinition of
.c @h
or
.c @f .
.
.w s ll
.se How do I customize the default appearance of footnotes?
.l(
.(e @f \" footnote environment
.ps +1p
.l)
.
.w s ll
.se How do I redefine the page header?
.l(
.de @h
. \" set position of header text
. sp |36p
. \" set header text
. tl 'left'center'right'
. \" set position of page text
\!.ne 1
. sp |1i
..
.l)
.
.w s ll
.se How do I redefine the page footer?
.p
To change the position of the footer:
.l(
.\" set position of footer trap
.\" (must be done before any macros have been called)
.wh -1i @tf
.
.l)
.p
To change the contents of the footer:
.l(
.de @f
. \" set position of footer text
. \" (must be below the footer trap)
. sp |\\n(.pu-48p
. \" set footer text
. tl 'left'center'right'
..
.l)
.
.se How do I define my own environments?
.p
Environments are a feature built into troff,
accessed via the
.c ev
request, but because
.i mk
extends environments with additional functionality,
it provides special macros to be used instead of
.c ev :
.n 1
.c (e ,
set environment (same as
.c ev )
.n
.c @e ,
set extended environment
.n
.c @c ,
copy environment (same as
.c evc )
.p
The
.c @e
macro
can be used to activate any environment that supports
.i mk 's
extensions (see
.i Environments ,
p. \n[&env]).
The following code configures an environment called
.c n
and defines a corresponding macro:
.l(
.@e n
. @c 0 \" copy default environment
. ps -1p
.@e
.
.de n
. br \" finish current environment
\!.ne 1
. @e n \" activate new environment
..
.l)
.
.se How do I prevent a section from being broken up by a page break?
.p
Some macro packages have a concept of
." keeps ,
sections that are kept together across page breaks.
.i Mk
does not (at least yet) define any such macros by default.
The simplest solution is to use troff's
.c ne
request:
.l(
.ne 7 \" break page if seven lines won't fit on this page
.\" ... some text ...
.l)
.p
If you want to keep text of various styles together,
you can use
.i mk 's
own
.c w
macro:
.l(
.w s qq \" break page if a subheading and two lines of a quotation won't fit
.\" ... some text ...
.l)
.ig
.p
For a more general solution, you can use a diversion:
.l(
.di keep
.\" ... some text ...
.br
.di
.ne \n(dnu
.keep
.l)
..
.
.se How do I use alternative quotation marks?
.p
Redefine
.c \(dq .
The following code defines a Swedish quotation style:
.l(
.de "
\\&\\$3”\\$1”\\$2
..
.l)
.p
Another option is to create new macros for alternative quotation styles:
.l(
.\" alternative swedish quotation styles
.de ><
\\&\\$3»\\$1«\\$2
..
.de >>
\\&\\$3»\\$1»\\$2
..
.l)
.
.se How do I create nested inline quotations?
.p
Just use the backtick
.c \(ga ) (
and apostrophe
.c \(aq ) (
directly in the argument to
.c \(dq .
.p
If you need to change the quotation style,
for example when converting a document from US to British English,
you can redefine
.c "
to translate backticks and apostrophes accordingly:
.l(
.eo
.de "
. char ` \(lq
. char ' \(rq
\&\$3\(oq\$1\(cq\$2
. char ` \\(oq
. char ' \\(cq
..
.ec
.l)
.
.se How do I include a table of contents in my document?
.te .nr &toc \n%
.p
Included with the
.i mk
distribution is a package called
.i toc ,
which includes the following files:
.n 1
.i toc.tmac ,
which provides the
.c te
and
.c to
macros
.n
.i toc ,
a script that invokes troff in three passes
in order to allow a table of contents to be generated
.p
Use
.c te
to register a line to be inserted into the table of contents.
Use
.c to
to insert the lines registered by
.c te
into the document.
Note that the argument given to
.c te
will be interpreted as a troff input line.
.p
The following definitions provide a good starting point:
.l(
.eo
.de he
. h
\$*
. tm .the \$*\t\n%
..
.de the
. ta 0 \n(.luR
. tc .
\$*
. tc
. br
..
.ec
.l)
.p
Now, instead of
.c h ,
you may use
.c he
to create a heading to be included in the table of contents:
.l(
.he A heading
.l)
.p
Wherever you want the table of contents to be inserted,
you may simply invoke
.c to .
.p
Just remember to use
.c toc
to run your processing pipeline:
.l(
<example.t toc refer \| troff -Tps >example.ps
.l)
.p
Thanks to the multiple passes performed by
.i toc ,
.c to
can be invoked at any place in the document,
including the beginning.
.p
The macro definition listed above is included in
.i ux.tmac .
.
.se How do I create a reference to a later page?
.p
Use the macros provided by
.i toc.tmac
in combination with the
.i toc
program.
Near the beginning of your document, invoke
.c to .
Then, at each position you want to reference,
invoke
.c .te
like this:
.l(
.te .nr &refname \n%
.l)
.p
To refer to that position, interpolate the register:
.l(
See page \n[&refname].
.l)
.p
(I prefer prefixing my references with an ampersand.)
.
.se How do I include source code without needing to escape it?
.p
The
.i mk
distribution includes a troff preprocessor called
.i list ,
which filters text delimited by
.c .l(
and
.c .l) ,
escaping standard troff syntax.
.p
To automatically add a
.c .l
request before each listing, set the
.i -p
(prefix) flag accordingly:
.l(
list -p.l
.l)
.p
To transparently pass an input line to troff,
prefix it with
.c \\\\! .
(To disable this behavior, use the
.i -E
flag.)
|