0% found this document useful (0 votes)
15 views

Dashundergaps Code

The document describes the dashundergaps LaTeX package, which allows text to be replaced with gaps that can later be filled in. The package provides the \gap command to create gaps of a specified width and style (underlined, dashed, etc.). Gaps can be numbered and formatting of the numbers and gaps is customizable. The package loads the ulem package to perform the underlining and adds additional functionality like artificially widening gaps and a "teacher mode" to show hidden text.
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
15 views

Dashundergaps Code

The document describes the dashundergaps LaTeX package, which allows text to be replaced with gaps that can later be filled in. The package provides the \gap command to create gaps of a specified width and style (underlined, dashed, etc.). Gaps can be numbered and formatting of the numbers and gaps is customizable. The package loads the ulem package to perform the underlining and adds additional functionality like artificially widening gaps and a "teacher mode" to show hidden text.
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 14

TUGboat, Volume 0 (9999), No.

0 draft: March 5, 2021 17:59 1

The dashundergaps package∗


Frank Mittelbach

Abstract
The dashundergaps package offers the possibility to replace material in running text
with white space in order to build up forms that can be filled in at a later time.
By default the gaps are underlined and followed by a gap number in parentheses, but
many other designs are possible, e.g., dashes or dots instead of the underline, no gap
numbers or a different format for them, gap widening for easier fill-in, etc.
There is also a teacher’s mode which shows the normally hidden text in a special
(customizable) format.
This is another article in a series of TUGboat articles describing small packages to
introduce coding practices using the expl3 programming language. See [1] for the first
article in the series. For more details on expl3 refer to [2].

Contents
1 Introduction 1
2 The user interface 2
2.1 Options to customize the gap display . . . . . . . . . . . . . . . . . 3
2.1.1 Gap modes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
2.1.2 Gap formatting . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
2.1.3 Gap numbers . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
2.1.4 Gap widening . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
3 Differences from the original package 4
4 Solution to the puzzle 5
5 The implementation 6
5.1 Loading and fixing/changing ulem . . . . . . . . . . . . . . . . . . . 6
5.2 The main implementation part . . . . . . . . . . . . . . . . . . . . . 7
5.2.1 User interface commands . . . . . . . . . . . . . . . . . . . . . 7
5.2.2 Counters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
5.2.3 Messages . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
5.2.4 Option handling . . . . . . . . . . . . . . . . . . . . . . . . . . 9
5.2.5 Closing shop . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
Index 13

1 Introduction
The dashundergaps package provides a single command \gap which takes one argument
and produces a gap of the width of that argument. To better mark this gap it is
underlined in some form (could be a solid line, a dashed or dotted line or even a
wriggling line). Furthermore, gaps can be numbered to be able to easily refer to them.
::::::::::::
Figure 1 shows an example in the form of a fill-in puzzle.
As you see there, some gaps are numbered with a superscript number (not the default
setting) while others aren’t. How this is done and how to change the result is explained
in the next section.
There also exists a “teacher mode” in which the gaps are filled with the text given in
the argument. This can be used to show the correct answers of a test (as we do in
∗ This is a reimplementation (using expl3, the L ATEX3 programming language) of a package
originally written by Luca Merciadri in 2010. The current package version is v2.0h dated 2021-03-05.

The dashundergaps package


2 draft: March 5, 2021 17:59 TUGboat, Volume 0 (9999), No. 0

The initial ‘E.’ in Donald E. Knuth’s name stands for (1)


. The well-known answer to
the Ultimate Question is 42 according to
(2)
. The first edition of (3)
celebrates its silver anniversary
in 2019. Historically speaking, expl3 stands for
(4)
even though it is a production language these days.

And here are some hints for the puzzle if you want to fill it out:

1. If only everything would be that easy 3. Back then known as the doggie book.
to answer.
2. The author of the book “Last Chance 4. Old names die hard.
To See” and of a famous radio show.

The answers are given in Section 4, showing the gaps filled in using the so-called teacher mode,
which can be activated or deactivated at any point in the document.

Figure 1: A fill-in puzzle using dashundergaps

Section 4) or to give a sample fill-in for a form, to help people fill it out correctly. The
“teacher mode” produces the same line breaks because it ensures that the fill-ins take
the same amount of space as the gaps.
Another important feature is the possibility to artificially widen the gaps, compared to
the textual material in the argument. After all, when a form is filled by hand people
typically need more space to write some text compared to the same text being typeset.
So making the gaps simply as wide as the material likely results in too little space.

2 The user interface


The dashundergaps package is built as a small application on top of the ulem package,
a package that defines several commands for underlining hsimple-texti in various ways.

\uline \uline{hsimple-text i} \uwave{hsimple-text i} ...


\uuline
This means that by loading dashundergaps the ulem commands such as \uline, \uwave
\uwave
\dashuline
and so forth are automatically made available. These commands are used to do most
\dotuline of the work and the current package only makes sure that, instead of the words, empty
boxes of the same width are used by ulem. This way we get underlined gaps of the
right size.
By default, ulem changes \emph to underline text, so for this application, it is loaded
with the option normalem to prevent that from happening.

\gap \gap*[hstyle i]{htext i}


The main command provided by the package is \gap which expects a mandatory htexti
Possible hstyleis: argument containing the material that is used to produce the gap (and is normally
u = \uline invisible). By default the gap is underlined, though that can be changed.
d = \uuline The optional hstylei argument explicitly defines a certain type of underlining: u stands
w = \uwave for normal underlining (via \uline), d for double underlining (via \uuline), w for a
b = hblanki
wavy line (via \uwave), b for blank (i.e., no underlining whatsoever), “-” for a dash-line
- = \dashuline
(via \dashuline) and finally “.” for underlining with dots (via \dotuline).
. = \dotuline
In the default configuration gaps are numbered using the counter gapnumber and this
number is shown in parentheses after the gap. With the star form the generation of the

Frank Mittelbach
TUGboat, Volume 0 (9999), No. 0 draft: March 5, 2021 17:59 3

number is toggled, i.e., if it would be produced because of the current option settings
it will be suppressed; if it is suppressed through an option it will be typeset. This way
one can select the most convenient setting via an option for the whole document and
use * to toggle it as needed.
Since \gap uses ulem’s commands it inherits the limitations of these commands; notably,
only simple text can be used in the htexti argument. For example, a \footnote couldn’t
be used in the argument (but then that wouldn’t make much sense in a gap, would it?).
Another important (and sometimes annoying) restriction is that any brace group
or command with arguments inside the ulem commands is set as if is is inside an
\mbox, in particular it will not break across lines. For example \gap{\emph{...}} will
show this behavior. The dashundergaps package tries mediate as best as possible, e.g.,
\gap{\mytext} works, but in other cases you have to live with this limitation.

\TeacherModeOn \TeacherModeOn % show gap material


\TeacherModeOff \TeacherModeOff % do not show gap material
Also supported is a teacher mode in which the material for the gaps is visible. This can
be used to show the expected answers in case \gap is used for preparing tests, or to
show a sample fill-in of a form. The teacher mode can be turned on or off anywhere in
the document using \TeacherModeOn or \TeacherModeOff, respectively. Alternatively,
it can also be set via an option, as we will see below.

\dashundergapssetup \dashundergapssetup{hcomma-separated key-value list i}


The package can be loaded with a number of options (discussed in Section 2.1). A
likely better approach is to set any options with the declaration \dashundergapssetup
which is normally used in the preamble, but can be used throughout the document to
change settings on the fly. It only changes explicitly given options so it can be used to
overwrite some defaults but leave everything else unchanged.
2.1 Options to customize the gap display
All of the package options are implemented as key/value options. For boolean options
one can give just the option name as a short form for setting the option to true.
Most options can be specified during package loading in the optional argument of
\usepackage. However if the value requires some LATEX code (e.g., gap-font, which
expects a font declaration command) then this will not work due to some limitations in
the current LATEX package loader. For such options use \dashundergapssetup instead,
which will always work.

2.1.1 Gap modes


The general processing mode is defined through the following options:
teacher-mode Boolean that turns on teacher mode (i.e., the gap material will be
visible if set to true). Its default is false.
gap-mode Boolean that is the inverse of teacher-mode and just provided for conve-
nience, i.e., an abbreviation for teacher-mode=false.
teachermode Alternative name for teacher-mode because that is what it was called
in the first package release.

2.1.2 Gap formatting


Formatting of the gaps is handled by the following six options:
gap-format A choice option defining how the gap is marked. It accepts the following
values: underline (default), double-underline, dash, dot, wave, blank.

The dashundergaps package


4 draft: March 5, 2021 17:59 TUGboat, Volume 0 (9999), No. 0

gap-format-adjust A boolean (default true). If set, the “line” below the gap is
raised to be roughly at the baseline, which normally looks better when there is no
text above the line.
teacher-gap-format Another choice option, with the same values as gap-format,
used when we are in “teacher mode”, but this time the default is blank as normally
the gap text is typeset in the bold font and is therefore already identifiable, with
no need for additional underlining. However, depending on the circumstances it
might be helpful to keep the underlining (or use a different kind of underlining)
while in “teacher mode”.
gap-font This option expects a font directive as its value, e.g., \bfseries (which
is also the default). Using this option without supplying a value is equivalent
to supplying an empty value. It will be used to determine the font for the gap
material regardless of the mode. This is important to ensure that the gaps always
have the same width regardless of whether or not the material is shown.
For the example puzzle above it was set to \itshape, which you can see in the
puzzle answer.
dash Short name for gap-format=dash.
dot Short name for gap-format=dot.

2.1.3 Gap numbers


Producing the gap numbers is handled by the following options:
gap-numbers Boolean that determines whether or not gap numbers are displayed.
Default is true.
gap-number-format Code that is executed when a gap number is produced. Default
is \textnormal{␣(\thegapnumber)}.
numbers Short name for gap-numbers.
There is also a way to control displaying the total number of gaps:
display-total-gaps Boolean to determine if the total number of gaps should be
shown at the very end of the document. Default is false.
displaynbgaps This is just another name for the same boolean; it was used in the
first version of the package.

2.1.4 Gap widening


Finally, for extending the gap width we have these options:
gap-widen Boolean that decides if the gaps should be made wider or not (default is
false but mainly for historical reasons).
gap-extend-minimum Minimum of extra space that should be added to each gap if
gap widening is active. Default is 20pt, i.e., 10pt on either side.
gap-extend-percent Percentage (as a number) by which the gap should be made
wider if widening is active. The result is compared to gap-extend-minimum and
the larger of the two is used. Default is 20.
widen Short name for gap-widen.

3 Differences from the original package


The main user interface of the two versions is identical, so it is possible to use the
new version as a drop-in replacement for the old. However, the feature set in form
of key/value options has been greatly extended, offering functionality previously
unavailable. Furthermore, a number of bugs have been corrected (and possibly new
ones introduced).

Frank Mittelbach
TUGboat, Volume 0 (9999), No. 0 draft: March 5, 2021 17:59 5

• Stray spaces in the definition of \gap (that showed up in the output) have been
eliminated.
• Various combinations of options that didn’t work are now possible.
• Explicit hyphenations \- showed up in gap mode, now they can be used.
• Nesting isn’t possible for obvious reasons, but the fact is now detected and catered
to by ignoring the inner gap requests after generating an error.
• Option names have been normalized (though the original names are still available).
• The option phantomtext is no longer necessary, though still supported (with a
warning) as a no-op.
• The names of the LATEX counters used have changed, so if you directly addressed
them that would need changing.
• The font used in teacher mode (by default boldface) is now also used if gap mode
is chosen, to ensure that the output in all modes produces identical line breaks;
for the same reason, the ulem machinery is always used, even if not underlining
(or dashing, etc.).
• The gaps can be extended by a percentage or by a minimum amount to ensure that
there is enough space to fill in the text (given that hand-written text is typically
wider than typeset material); the values are adjustable.
• \gap now has an optional argument through which you can explicitly request the
type of underlining you want to use.
• \gap also supports a star form which toggles the setting of gap numbers.
• The use of \label within the \gap command argument allows for later reference
to that gap by its number (provided a gap number is typeset).
• The implementation is done with expl3, the programming language for LATEX3.
Although invisible to the user, in some sense that was the main purpose of the
exercise: to see how easy it is to convert a package and use the extended features
of expl3.

4 Solution to the puzzle


Here we repeat the puzzle from above with \TeacherModeOn.

The initial ‘E.’ in Donald E. Knuth’s name stands for Ervin (5)
. The well-known answer to
the Ultimate Question of Life, the Universe, and Everything is 42 according to Douglas
Adams (6)
. The first edition of
The LATEX Companion (7) celebrates its silver anniversary
in 2019. Historically speaking, expl3 stands for EXperimental Programming Language 3
(8)
even though it is a production language these days.

This was produced using the following changes to the defaults:


\dashundergapssetup{
,gap-number-format = \,\textsuperscript{\normalfont
(\thegapnumber)}
,gap-font = \itshape
,teacher-gap-format = underline
,gap-widen
}
As you can see we use \itshape for the font (to be able to show the bold face in
one of the answers) and also force underlining in teacher mode to better show the
gap widening. The gap number is raised and we separate it a tiny bit from the gap
material. We also use \normalfont in the formatting to ensure that the gap number
is set upright and not in italic shape.

The dashundergaps package


6 draft: March 5, 2021 17:59 TUGboat, Volume 0 (9999), No. 0

5 The implementation
5.1 Loading and fixing/changing ulem
The first thing to do is to load ulem without changing \emph or \em:
1 h*packagei
2 \RequirePackage[normalem]{ulem}
The code in this section follows LATEX 2ε conventions, i.e., models the commands as
they look in the ulem package.

\dotuline The dots produced by \dotuline depend on the current font, which is a somewhat
questionable design — if you underline a text with a single bold word somewhere inside
it will change the shape of the dot line. So we always use the \normalfont dot (this
is not done in the original definition).
3 \protected\def\dotuline{\leavevmode\bgroup
4 \UL@setULdepth
5 \ifx\UL@on\UL@onin \advance\ULdepth2\p@\fi
6 \markoverwith{\begingroup
7 % \advance\ULdepth0.08ex
8 \lower\ULdepth\hbox{\normalfont \kern.1em .\kern.04em}%
9 \endgroup}%
10 \ULon}

(End definition for \dotuline. This function is documented on page 2.)

\uwave The original \uwave used a hard-wired value of 3.5pt for the lowering. We change
that to be based on the current value of \ULdepth so that the user (or this package
here) can change the placement.
11 \protected\def\uwave{\leavevmode\bgroup
12 \UL@setULdepth
13 \advance\ULdepth 0.6\p@
14 \markoverwith{\lower\ULdepth\hbox{\sixly \char58}}\ULon}

(End definition for \uwave. This function is documented on page 2.)

\fmdug@ublank \fmdug@ublank underlines with blanks. Normally not especially useful (which is why
we make it internal), but if we want to have ulem acting, but without actually visibly
underlining, this is the command to use.
15 \def\fmdug@ublank{\bgroup\let\UL@leadtype\@empty\ULon}

(End definition for \fmdug@ublank.)

\UL@dischyp We need to do a little patching to ensure that nothing is output by the ulem commands
\UL@putbox if we don’t want it to. So the next two commands are from ulem with \box replaced
by \fmdug@box so that we can change the behavior.
16 \def\UL@dischyp{\global\setbox\UL@hyphenbox\hbox
17 {\ifnum \hyphenchar\font<\z@ \string-\else \char\hyphenchar\font \fi}%
18 \kern\wd\UL@hyphenbox \LA@penalty\@M
19 \UL@stop \kern-\wd\UL@hyphenbox
20 \discretionary{\fmdug@box\UL@hyphenbox}{}{}\UL@start}
21 \def\UL@putbox{\ifx\UL@start\@empty \else % not inner
22 \vrule\@width\z@ \LA@penalty\@M
23 {\UL@skip\wd\UL@box \UL@leaders \kern-\UL@skip}%
24 \fmdug@box\UL@box \fi}

(End definition for \UL@dischyp and \UL@putbox.)

Frank Mittelbach
TUGboat, Volume 0 (9999), No. 0 draft: March 5, 2021 17:59 7

\fmdug@box By default we output the box in the commands above, but when we don’t want to
output anything visible we change the definition to generate a box with empty content
but the right size.
25 \let\fmdug@box\box

(End definition for \fmdug@box.)

5.2 The main implementation part


The rest of the package is written in expl3. We use fmdug as our internal prefix.
26 h@@=fmdugi
We need the package xparse for specifying the document-level interface commands
and l3keys2e to use the expl3 key value methods within LATEX 2ε . These packages
automatically require expl3 so there is no need to load that explicitly and nowadays
the core of xparse is part of the LATEX kernel.
27 \RequirePackage{l3keys2e}
As the code uses some functions from expl3 that got introduced sometime in 2018 we
need to require a fairly recent version (the date is somewhat arbitrarily picked).
28 \@ifpackagelater{expl3}{2018-06-24}
29 {}
30 {%
31 \PackageError{dashundergaps}{Support package l3kernel too old}
32 {%
33 Please install an up to date version of l3kernel\MessageBreak
34 using your TeX package manager or from CTAN.\MessageBreak
35 \MessageBreak
36 Loading dashundergaps will abort!%
37 }%
38 \endinput
39 }
Here we introduce the package and specify its version number:
40 \ProvidesExplPackage{dashundergaps}
41 {\dashundergapsdate}
42 {\dashundergapsversion}
43 {Dashing and underlining phantom text}

5.2.1 User interface commands


\gap The \gap command parses for a star, optional and mandatory argument and then calls
\__fmdug_gap:nnn to do the work.
44 \DeclareDocumentCommand \gap { som }
45 {
We try to expand as much as possible up front to avoid the ulem limitations:
46 \protected@edef\next{#3}
Use the “content” of \next in the processing:
47 \__fmdug_gap:nno {#1}{#2}{ \next } }

(End definition for \gap. This function is documented on page 2.)

\dashundergapssetup Change options anywhere.


48 \NewDocumentCommand \dashundergapssetup { m }
49 { \keys_set:nn {fmdug} {#1} \ignorespaces }

(End definition for \dashundergapssetup. This function is documented on page 3.)

The dashundergaps package


8 draft: March 5, 2021 17:59 TUGboat, Volume 0 (9999), No. 0

\TeacherModeOn We provide shortcuts for turning teacher mode on or off.


\TeacherModeOff 50 \DeclareDocumentCommand \TeacherModeOn {}
51 { \bool_set_true:N \l__fmdug_teacher_bool }
52 \DeclareDocumentCommand \TeacherModeOff {}

53 { \bool_set_false:N \l__fmdug_teacher_bool }

(End definition for \TeacherModeOn and \TeacherModeOff. These functions are documented on page
3.)

5.2.2 Counters
\c@gapnumber We have one user-level counter which is referenceable and holds the gap number of the
current gap. It can be reset to 0 to restart counting.
54 \newcounter{gapnumber}

(End definition for \c@gapnumber.)

\c@totalgapnumber We also keep track of all gaps ever made using another user-level counter. Since this
one is supposed to keep track of the total number of gaps, it makes little sense to
modify it at the document level. However, there may be use cases even for that and
more importantly, by making it a user-level counter it is possible to refer to the total
number of gaps easily, e.g., via \thetotalgapnumber.
55 \newcounter{totalgapnumber}

(End definition for \c@totalgapnumber.)

\l__fmdug_extend_dim A help register to calculate the gap width later on.


56 \dim_new:N \l__fmdug_extend_dim

(End definition for \l__fmdug_extend_dim.)

\l__fmdug_extra_left_gap_tl Two scratch token lists to enlarge the gap on the left or right side.
\l__fmdug_extra_right_gap_tl 57 \tl_new:N \l__fmdug_extra_left_gap_tl
58 \tl_new:N \l__fmdug_extra_right_gap_tl

(End definition for \l__fmdug_extra_left_gap_tl and \l__fmdug_extra_right_gap_tl.)

\l__fmdug_gap_format_tl The gap formatting is normally handled by a ulem command; which one depends on
\l__fmdug_teacher_gap_format_tl the options used. To record the choice we store it in a token list (one for normal and
one for teacher mode).
59 \tl_new:N \l__fmdug_gap_format_tl
60 \tl_new:N \l__fmdug_teacher_gap_format_tl

(End definition for \l__fmdug_gap_format_tl and \l__fmdug_teacher_gap_format_tl.)

5.2.3 Messages
61 \msg_new:nnn {dashundergaps} {deprecated}
62 { The~ #1~ ‘#2’~ you~ used~ \msg_line_context: \ is~ deprecated~ and~
63 there~ is~ no~ replacement.~ Since~ I~ will~ not~ guarantee~ that~
64 #1~ ‘#2’~ will~ be~ kept~ forever~ I~ strongly~ encourage~ you~
65 to~ remove~ it~ from~ your~ document. }
66 \msg_new:nnnn {dashundergaps} {nested}
67 { The~ \gap command~ can’t~ be~ nested! }
68 { Nesting~ doesn’t~ make~ much~ sense~ as~ the~ inner~ one~
69 wouldn’t~ be~ visible.~ ~ To~ allow~ further~ processing~ it~ is~
70 handled~ as~ if~ it~ hasn’t~ been~ asked~ for. }
71 \msg_new:nnnn {dashundergaps} {gap-format-value}
72 { Unknown~ value~ for~ key~ ’#1 gap-format’! }

Frank Mittelbach
TUGboat, Volume 0 (9999), No. 0 draft: March 5, 2021 17:59 9

73 { Supported~ values~ are~ ’underline’,~ ’double-underline’,\\


74 ’dash’,~ ’dot’,~ ’wave’~ or~ ’blank’. }
5.2.4 Option handling
Here we define all the possible option keys for use either as package options or inside
\dashundergapssetup. These are all straightforward assignments to variables. These
internal variables are declared by the key declarations if unknown, so they are not
separately declared beforehand.
75 \keys_define:nn {fmdug}
76 {
77 % ====================================
78 ,teacher-mode .bool_set:N = \l__fmdug_teacher_bool
79 ,teacher-mode .default:n = true
80 ,teacher-mode .initial:n = false
81 % ------------------
82 ,gap-mode .bool_set_inverse:N = \l__fmdug_teacher_bool
83 % ====================================
84 ,gap-format
85 .choice:
In the case of dashes and even more so in the case of dots, it looks fairly ugly if they
are below the baseline as if there were text above. We therefore raise them up a bit if
the option gap-format-adjust is given (which is the default).
In the case of dots we undo exactly the amount by which they are lowered in ulem so
that they end up precisely at the baseline, in case they are followed by a real dot. In
other cases we stay a bit below the baseline.
The same is done below when the optional argument is evaluated. But we don’t do
this in teacher mode since there we will have text above and we don’t want to bump
into that.
86 ,gap-format / underline
87 .code:n = \tl_set:Nn \l__fmdug_gap_format_tl
88 { \__fmdug_gap_format_adjust:n{.4pt} \uline }
89 ,gap-format / double-underline
90 .code:n = \tl_set:Nn \l__fmdug_gap_format_tl
91 { \__fmdug_gap_format_adjust:n{2pt} \uuline }
92 ,gap-format / dash
93 .code:n = \tl_set:Nn \l__fmdug_gap_format_tl
94 { \__fmdug_gap_format_adjust:n{0pt} \dashuline }
95 ,gap-format / dot
96 .code:n = \tl_set:Nn \l__fmdug_gap_format_tl
97 { \__fmdug_gap_format_adjust:n{-.08ex} \dotuline }
98 ,gap-format / wave
99 .code:n = \tl_set:Nn \l__fmdug_gap_format_tl
100 { \__fmdug_gap_format_adjust:n{1pt} \uwave }
101 ,gap-format / blank
102 .code:n = \tl_set:Nn \l__fmdug_gap_format_tl { \fmdug@ublank }
103 ,gap-format / unknown
104 .code:n = \msg_error:nnn{dashundergaps}{gap-format-value}{}
105 ,gap-format
106 .initial:n = underline
107 % ====================================
This controls the raising of the gap underline by some amount. We implement it as a
.choice even though it looks like a boolean.
108 ,gap-format-adjust
109 .choice:
110 ,gap-format-adjust / true

The dashundergaps package


10 draft: March 5, 2021 17:59 TUGboat, Volume 0 (9999), No. 0

111 .code:n = \cs_set:Npn \__fmdug_gap_format_adjust:n ##1


112 { \setlength\ULdepth {##1} }
113 ,gap-format-adjust / false
114 .code:n = \cs_set_eq:NN \__fmdug_gap_format_adjust:n \use_none:n
115 ,gap-format-adjust
116 .default:n = true
117 ,gap-format-adjust
118 .initial:n = true
119 ,adjust .meta:n = { gap-format-adjust }
120 % ====================================
121 ,teacher-gap-format
122 .choice:
123 ,teacher-gap-format / underline
124 .code:n = \tl_set:Nn \l__fmdug_teacher_gap_format_tl { \uline }
125 ,teacher-gap-format / double-underline
126 .code:n = \tl_set:Nn \l__fmdug_teacher_gap_format_tl { \uuline }
127 ,teacher-gap-format / dash
128 .code:n = \tl_set:Nn \l__fmdug_teacher_gap_format_tl { \dashuline }
129 ,teacher-gap-format / dot
130 .code:n = \tl_set:Nn \l__fmdug_teacher_gap_format_tl { \dotuline }
131 ,teacher-gap-format / wave
132 .code:n = \tl_set:Nn \l__fmdug_teacher_gap_format_tl { \uwave }
133 ,teacher-gap-format / blank
134 .code:n = \tl_set:Nn \l__fmdug_teacher_gap_format_tl { \fmdug@ublank }
135 ,teacher-gap-format / unknown
136 .code:n = \msg_error:nnn{dashundergaps}{gap-format-value}{teacher-}
137 ,teacher-gap-format
138 .initial:n = blank
139 % ====================================
140 ,gap-widen .bool_set:N = \l__fmdug_gap_widen_bool
141 ,gap-widen .default:n = true
142 ,gap-widen .initial:n = false
143 % ------------------
144 ,widen .meta:n = { gap-widen }
145 % ------------------
146 ,gap-extend-minimum .dim_set:N = \l__fmdug_gap_min_dim
147 ,gap-extend-minimum .initial:n = 20pt
148 % ------------------
149 ,gap-extend-percent .tl_set:N = \l__fmdug_gap_percent_tl
150 ,gap-extend-percent .initial:n = 20
151 % ====================================
152 ,gap-numbers .bool_set:N = \l__fmdug_number_bool
153 ,gap-numbers .default:n = true
154 ,gap-numbers .initial:n = true
155 % ------------------
156 ,numbers .meta:n = { gap-numbers }
157 % ------------------
158 ,gap-number-format .tl_set:N = \l__fmdug_gapnum_format_tl
159 ,gap-number-format .initial:n = \textnormal{\space (\thegapnumber)}
160 % ====================================
161 ,display-total-gaps .bool_gset:N = \g__fmdug_display_total_gaps_bool
162 ,display-total-gaps .default:n = true
163 ,display-total-gaps .initial:n = false
164 % ====================================
165 ,gap-font .tl_set:N = \l__fmdug_font_tl
166 ,gap-font .default:n =
167 ,gap-font .initial:n = \bfseries
And finally the original options, now as aliases:

Frank Mittelbach
TUGboat, Volume 0 (9999), No. 0 draft: March 5, 2021 17:59 11

168 % ====================================
169 ,teachermode .meta:n = { teacher-mode }
170 ,dash .meta:n = { gap-format = dash }
171 ,dot .meta:n = { gap-format = dot }
172 ,displaynbgaps .meta:n = { display-total-gaps }
173 % ------------------
174 ,phantomtext
175 .code:n = \msg_warning:nnnn{dashundergaps}{deprecated}
176 {option}{phantomtext}
177 % ====================================
178 }

\__fmdug_gap:nnn At last, here comes the action. \__fmdug_gap:nn expects three arguments: #1 identifies
if a star was present, #2 indicates what kind of “underlining” is wanted (anything not
recognized is ignored, in particular “–NoValue–” if \gap was used without an optional
argument) and #3 is the material to produce a gap for.
179 \cs_new:Npn\__fmdug_gap:nnn #1#2#3 {
180 \group_begin:
Define the font used inside the gap. We need to do this up front since we want to
measure the text (and that needs the correct font already).
181 \l__fmdug_font_tl
Nesting is not supported so inside the gap we redefine \__fmdug_gap:nnn to raise an
error and just return the third argument if it is encountered again.
182 \cs_set:Npn \__fmdug_gap:nnn ##1##2##3
183 {
184 \msg_error:nn{dashundergaps}{nested}
185 ##3
186 }
We always increment the counter for the total number of gaps, but increment the
gapnumber only if we are displaying it. For the latter one we use \refstepcounter to
make it referenceable.
187 \stepcounter{totalgapnumber}
188 \bool_xor:nnT { #1 } { \l__fmdug_number_bool }
189 { \refstepcounter{gapnumber} }
Next we prepare for widening if that is being asked for: Measure the width of the text
and then set \l__fmdug_extend_dim to be the requested percentage divided by two
of that width (since we add it later on both sides).
190 \bool_if:NTF \l__fmdug_gap_widen_bool
191 {
192 \settowidth \l__fmdug_extend_dim {#3}
193 \dim_set:Nn \l__fmdug_extend_dim
194 { \l__fmdug_gap_percent_tl \l__fmdug_extend_dim / 200 }
Then compare it to the minimum / 2 and choose whatever is larger.
195 \dim_compare:nNnT \l__fmdug_extend_dim < { .5\l__fmdug_gap_min_dim }
196 { \dim_set:Nn \l__fmdug_extend_dim { .5\l__fmdug_gap_min_dim } }
Now we prepare what needs to go to the left and the right of the gap.
197 \tl_set:Nn \l__fmdug_extra_left_gap_tl
198 { \hbox_to_wd:nn\l__fmdug_extend_dim{} \allowbreak }
199 \tl_set:Nn \l__fmdug_extra_right_gap_tl
200 { \allowbreak \hbox_to_wd:nn\l__fmdug_extend_dim{} }
201 }

The dashundergaps package


12 draft: March 5, 2021 17:59 TUGboat, Volume 0 (9999), No. 0

And if no widening is asked for we clear these two token lists so they don’t do anything.
202 {
203 \tl_clear:N \l__fmdug_extra_left_gap_tl
204 \tl_clear:N \l__fmdug_extra_right_gap_tl
205 }
Next comes deciding the gap format. If in teacher mode it will be whatever is in \l__
fmdug_teacher_gap_tl. Otherwise, either it is based on the content of the optional
argument or, if that is not given or unknown, it will be \l__fmdug_gap_format_tl.
206 \bool_if:NTF \l__fmdug_teacher_bool
207 { \l__fmdug_teacher_gap_format_tl }
208 {
But before we execute any of the ulem commands we make sure that they do not
output text.
209 \cs_set:Npn \fmdug@box ##1 {\hbox_to_wd:nn{\box_wd:N ##1}{}}
210 \str_case:nnF {#2}
211 {
212 {u} { \__fmdug_gap_format_adjust:n{.4pt} \uline }
213 {d} { \__fmdug_gap_format_adjust:n{2pt} \uuline }
214 {w} { \__fmdug_gap_format_adjust:n{1pt} \uwave }
215 {b} { \fmdug@ublank }
216 {.} { \__fmdug_gap_format_adjust:n{-.08ex} \dotuline }
217 {-} { \__fmdug_gap_format_adjust:n{0pt} \dashuline }
218 }
219 { \l__fmdug_gap_format_tl }
220 }
Whatever was decided as the gap format, it needs one argument, i.e., the material
(with possible gap extension on both sides).
221 {\l__fmdug_extra_left_gap_tl #3 \l__fmdug_extra_right_gap_tl }
Finally we typeset the gap number if that was requested.
222 \bool_xor:nnT { #1 } { \l__fmdug_number_bool }
223 { \l__fmdug_gapnum_format_tl }
Close the group from above to keep any of the redefinitions confined.
224 \group_end:
225 }
226 \cs_generate_variant:Nn \__fmdug_gap:nnn {nno}
(End definition for \__fmdug_gap:nnn.)

\__fmdug_display_total_gaps: This command will display the total number of gaps if requested. The hard-wired
formatting comes from the first version of the package.
227 \cs_new:Npn \__fmdug_display_total_gaps: {
228 \vfill \centering
229 \bfseries Total~ Gaps:~ \thetotalgapnumber
230 }
(End definition for \__fmdug_display_total_gaps:.)

5.2.5 Closing shop


At the end of the document we typeset the total number of gaps if requested.
231 \AtEndDocument{
232 \bool_if:NT \g__fmdug_display_total_gaps_bool
233 \__fmdug_display_total_gaps:
234 }

Frank Mittelbach
TUGboat, Volume 0 (9999), No. 0 draft: March 5, 2021 17:59 13

So what remains to be done is executing all options passed to the package via
\usepackage.
235 \ProcessKeysPackageOptions{fmdug}
236 h/packagei

References
[1] Frank Mittelbach. The widows-and-orphans package. TUGboat 39:3, 20018.
https://ctan.org/pkg/widows-and-orphans
[2] LATEX3 Project Team. A collection of articles on expl3.
https://latex-project.org/publications/indexbytopic/l3-expl3/

Index
The italic numbers denote the pages where the corresponding entry is described,
numbers underlined point to the definition, all others indicate the places where it is
used.

Symbols \g__fmdug_display_total_gaps_bool
\\ . . . . . . . . . . . . . . . . . . . . . . . . . . 73 . . . . . . . . . . . . . . . . . . . 161, 232
\l__fmdug_extend_dim . . . . . 11,
A 56, 192, 193, 194, 195, 196, 198, 200
\allowbreak . . . . . . . . . . . . . . . 198, 200 \l__fmdug_extra_left_gap_tl . . . .
\AtEndDocument . . . . . . . . . . . . . . . . 231 . . . . . . . . . . . . . 57, 197, 203, 221
\l__fmdug_extra_right_gap_tl . . .
B . . . . . . . . . . . . . 57, 199, 204, 221
\bfseries . . . . . . . . . . . . . . . . 167, 229 \l__fmdug_font_tl . . . . . . . 165, 181
bool commands: \__fmdug_gap:nn . . . . . . . . . . . . 11
\bool_if:NTF . . . . . . . 190, 206, 232 \__fmdug_gap:nnn . . . . 7, 11, 47, 179
\bool_set_false:N . . ......... 53 \__fmdug_gap_format_adjust:n . . .
\bool_set_true:N . . . ......... 51 . . . . . . . . . . . . . 88, 91, 94, 97,
\bool_xor:nnTF . . . . . . . . . 188, 222 100, 111, 114, 212, 213, 214, 216, 217
box commands: \l__fmdug_gap_format_tl . . . 12,
\box_wd:N . . . . . . . .......... 209 59, 87, 90, 93, 96, 99, 102, 219
\l__fmdug_gap_min_dim 146, 195, 196
C
\l__fmdug_gap_percent_tl . 149, 194
\centering . . . . . . . . . . . . . . . . . . . 228
\l__fmdug_gap_widen_bool . 140, 190
cs commands:
\l__fmdug_gapnum_format_tl 158, 223
\cs_generate_variant:Nn . . . . . 226
\l__fmdug_number_bool 152, 188, 222
D \l__fmdug_teacher_bool . . . . . . . . .
\dashuline . . . . . . . . . 2, 2, 94, 128, 217 . . . . . . . . . . . . 51, 53, 78, 82, 206
\dashundergapsdate . . . . . . . . . . . . . 41 \l__fmdug_teacher_gap_format_tl .
\dashundergapssetup . . . . . . . . 3, 9, 48 59, 124, 126, 128, 130, 132, 134, 207
\dashundergapsversion . . . . . . . . . . 42 \l__fmdug_teacher_gap_tl . . . . . 12
\DeclareDocumentCommand . . . 44, 50, 52 \footnote . . . . . . . . . . . . . . . . . . . . . 3
dim commands: G
\dim_compare:nNnTF . . . . . . . . . 195 \gap . . . . . . . . . 1, 2, 3, 3, 5, 7, 11, 44, 67
\dotuline . . . . . . 2, 2, 3, 6, 97, 130, 216 group commands:
\group_begin: . . . . . . . . . . . . . 180
E
\group_end: . . . . . . . . . . . . . . . 224
\em . . . . . . . . . . . . . . . . . . . . . . . . . . 6
\emph . . . . . . . . . . . . . . . . . . . . . . . 2, 6 H
\endinput . . . . . . . . . . . . . . . . . . . . 38 hbox commands:
\hbox_to_wd:nn ..... 198, 200, 209
F
fmdug internal commands: K
\__fmdug_display_total_gaps: . . . keys commands:
. . . . . . . . . . . . . . . . . . . 227, 233 \keys_define:nn . . . . . . . . . . . . 75

The dashundergaps package


14 draft: March 5, 2021 17:59 TUGboat, Volume 0 (9999), No. 0

\keys_set:nn . . . . . . . . . . . . . . . 49 \space . . . . . . . . . . . . . . . . . . . . . . 159


\stepcounter . . . . . . . . . . . . . . . . . 187
L str commands:
\label . . . . . . . . . . . . . . . . . . . . . . . . 5 \str_case:nnTF . . . . . . . . . . . . 210
\leavevmode . . . . . . . . . . . . . . . . . 3, 11
T
M \TeacherModeOff . . . . . . . . . . . . . 3, 50
\mbox . . . . . . . . . . . . . . . .......... 3 \TeacherModeOn . . . . . . . . . . . . 3, 5, 50
\MessageBreak . . . . . . . . . . . . 33, 34, 35 TEX and LATEX 2ε commands:
msg commands: \@ifpackagelater . . . . . . . . . . . . 28
\msg_error:nn . . . . . . . . . . . . . 184 \c@gapnumber . . . . . . . . . . . . . . . 54
\msg_error:nnn . . . . . . . . . 104, 136 \c@totalgapnumber . . . . . . . . . . . 55
\msg_line_context: . . . . . . . . . . 62 \fmdug@box . . . . . . . . 20, 24, 25, 209
\msg_new:nnn . . . . . . . . . . . . . . . 61 \fmdug@ublank . . 6, 15, 102, 134, 215
\msg_new:nnnn . . . . . . . . . . . . 66, 71 \protected@edef . . . . . . . . . . . . 46
\msg_warning:nnnn . . . . . . . . . . 175 \UL@dischyp . . . . . . . . . . . . . . . . 16
\UL@on . . . . . . . . . . . . . . . . . . . . . 5
N \UL@onin . . . . . . . . . . . . . . . . . . . 5
\newcounter . . . . . . . . . . . . . . . . . 54, 55 \UL@putbox . . . . . . . . . . . . . . . . . 16
\NewDocumentCommand . . . . . . . . . . . . 48 \textnormal . . . . . . . . . . . . . . . . . . 159
\next . . . . . . . . . . . . . . . . . . . . 7, 46, 47 \thegapnumber . . . . . . . . . . . . . . . . 159
\normalfont . . . . . . . . . . . . . . . . 5, 6, 8 \thetotalgapnumber . . . . . . . . . . . 8, 229
tl commands:
P \tl_clear:N . . . . . . . . . . . . 203, 204
\PackageError . . . . . . . . . . . . . . . . . 31
\ProcessKeysPackageOptions . . . . . 235 U
\protected . . . . . . . . . . . . . . . . . . 3, 11 \ULdepth . . . . . ................. 6
\ProvidesExplPackage . . . . . . . . . . . 40 \uline . . . . . . . . . . . . 2, 2, 88, 124, 212
use commands:
R \use_none:n . . . . . . . . . . . . . . . 114
\refstepcounter . . . . . . . . . . . . 11, 189 \usepackage . . . . . . . . . . . . . . . . . 3, 13
\RequirePackage . . . . . . . . . . . . . 2, 27 \uuline . . . . . . . . . . . 2, 2, 91, 126, 213
\uwave . . . . . . . 2, 2, 6, 11, 100, 132, 214
S
\setlength . . . . . . . . . . . . . . . . . . . 112 V
\settowidth . . . . . . . . . . . . . . . . . . 192 \vfill . . . . . . . . . . . . . . . . . . . . . . 228

 Frank Mittelbach
Mainz, Germany
https://www.latex-project.org
https://ctan.org/pkg/dashundergaps

Frank Mittelbach

You might also like