% \iffalse meta-comment
%
%% File: dashundergaps.dtx (C) Copyright 2018-2021 Frank Mittelbach
%
% It may be distributed and/or modified under the conditions of the
% LaTeX Project Public License (LPPL), either version 1.3c of this
% license or (at your option) any later version.  The latest version
% of this license is in the file
%
%    https://www.latex-project.org/lppl.txt
%
%
% The development version of the bundle can be found below
%
%    https://github.com/FrankMittelbach/fmitex/
%
% for those people who are interested or want to report an issue.
%

\def\dashundergapsdate   {2021-03-05}    % don't forget to also adjust build.lua!
\def\dashundergapsversion{v2.0h}

%<*driver>
\let\fmipagebreak\pagebreak

\RequirePackage[nohyphen]{underscore}    % no hyphen after undercore
                                         %   in csname
\documentclass
    [final]
    {l3doc-TUB}

\setcounter{page}{1}       

% fix for _TF undefined,
% https://github.com/latex3/latex3/issues/477#issuecomment-419458783
\ExplSyntaxOn
\cs_set_protected:Npn \__codedoc_typeset_TF:
  {
    \group_begin:
      \exp_args:No \__codedoc_if_macro_internal:nT \l__codedoc_tmpa_tl
        { \color[gray]{0.5} }
      \itshape TF
    \group_end:
  }
\ExplSyntaxOff

% fix for doc/ltugboat issue
\def\pfill{~%
           \leaders\hbox to.6em{\hss .\hss}\hskip 0em plus 1fill
           \kern-1.5em
           \penalty500
           \kern 1.5em
           \strut\nobreak
           \leaders\hbox to.6em{\hss .\hss}\hskip 0em plus 1fil
           \null~\ignorespaces}%

\usepackage{dashundergaps,multicol}
\EnableCrossrefs
\CodelineIndex
\begin{document}
  \DocInput{dashundergaps.dtx}
\addtolength\signaturewidth{42pt}
\makesignature
\end{document}
%</driver>
%
% \fi
%
%
% \newcommand\option[1]{\texttt{#1}}
%
% \DoNotIndex{}
%
% \title{The \texttt{dashundergaps} package\thanks{This is a
%    reimplementation (using \texttt{expl3}, the \LaTeX3 programming
%    language) of a package originally written by Luca Merciadri in
%    2010. The current package version is \dashundergapsversion\
%    dated \dashundergapsdate.}}
% \author{Frank Mittelbach}
% \address{Mainz, Germany}
% \netaddress{https://www.latex-project.org}
% \personalURL{https://ctan.org/pkg/dashundergaps}
%
% \maketitle
%
% \begin{abstract}
%   The \pkg{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.
%
%   \medskip
%
%    This is another article in a series of \TUB{} articles
%    describing small packages to introduce coding practices using the
%    \pkg{expl3} programming language. See~\cite{tub-wao-code} for the
%    first article in the series.
%   For more details on \pkg{expl3} refer to~\cite{expl3}.
%
% \end{abstract}
%
% \tableofcontents
%
%
% \section{Introduction}
%
% The \pkg{dashundergaps} package provides a single command \cs{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 \uwave{wriggling
%   line}). Furthermore, gaps can be numbered to be able to easily
% refer to them. Figure~\ref{fig:puzzle} shows an example in the form of a
%    fill-in puzzle.
%
%
% \newcommand\puzzletext{%
% \begin{quote}
%   \addtolength\baselineskip{3pt}
%   The initial `E.' in Donald E. Knuth's name stands for \gap{Ervin}.
%   The well-known  answer to the Ultimate Question \gap*{of Life, the
%   Universe, and Everything} is 42 according to \gap{Douglas Adams}.
%   The first edition of \gap{The \LaTeX{} Companion} celebrates its silver
%   anniversary in 2019.  Historically speaking, \texttt{expl3} stands for
%   \gap{\textbf{EX}perimental \textbf{P}rogramming \textbf{L}anguage
%   \textbf{3}} even though it is a production language these days.
% \end{quote}}
%
%
% \dashundergapssetup{
%   ,gap-number-format  = \,\textsuperscript{\normalfont
%                                            (\thegapnumber)}
%   ,gap-font           = \itshape
%   ,teacher-gap-format = underline
%   ,gap-widen
% }
%
% \begin{figure}
%  \centering
%   \setlength\fboxsep{10pt}
%   \noindent\hspace{-\marginparwidth}\fbox{\begin{minipage}{1.20\textwidth}
% \puzzletext
%
% \bigskip
%
% And here are some hints for the puzzle if you want to fill it out:
% \begin{quote}
% \begin{multicols}{2}
%   \begin{enumerate}
%   \item If only everything would be that easy\newline to answer.
%   \item The author of the book ``Last Chance To~See'' and of a famous
%     radio~show.
%   \item Back then known as the doggie book.
%   \item Old names die hard.\\
%     \mbox{}                      ^^A manual to get same height
%   \end{enumerate}
% \end{multicols}
% \end{quote}
% The answers are given in Section~\ref{sec:answer}, showing the gaps
% filled in using the so-called teacher mode, which~can be
%    activated or deactivated at any point in the document.\raggedright
% \end{minipage}}
% \caption{A fill-in puzzle using \pkg{dashundergaps}}\label{fig:puzzle}
% \end{figure}
%
% 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 Section~\ref{sec:answer}) 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.
%
%
% \section{The user interface}
%
%
% The \pkg{dashundergaps} package is built as a small application on top
% of the \pkg{ulem} package, a package that defines several commands for
% underlining \meta{simple-text} in various ways.
% \begin{function}{\uline,\uuline,\uwave,\dashuline,\dotuline}
%   \begin{syntax}
% \cs{uline}\Arg{simple-text}  \cs{uwave}\Arg{simple-text}  ...
%   \end{syntax}
%   This means that by loading
%   \pkg{dashundergaps} the \pkg{ulem} commands such as \cs{uline},
%   \cs{uwave} and so forth are automatically made available.
%   These commands are used to do most of
%   the work and the current package only makes sure that, instead of the
%   words, empty boxes of the same width are used by \pkg{ulem}. This
%   way we get underlined gaps of the right size.
%
% By default, \pkg{ulem} changes \cs{emph} to underline text, so
% for this application, it is loaded with the option \texttt{normalem} to
% prevent that from happening.
%
% \end{function}
%
%
%
% \begin{function}{\gap}
%   \begin{syntax}
%      \cs{gap}*\oarg{style}\Arg{text}
%   \end{syntax}
%   \noindent\llap{\small\smash{\begin{tabular}[t]{r@{ = }l} ^^A really low-level hacked
%     \multicolumn{2}{c}{}\\
%     \multicolumn{2}{c}{\hspace*{-1.2pc}Possible \meta{style}s:}\\[3pt]
%     \texttt{u} & \cs{uline} \\
%     \texttt{d} & \cs{uuline} \\
%     \texttt{w} & \cs{uwave} \\
%     \texttt{b} & \meta{blank} \\
%     \texttt{-} & \cs{dashuline} \\
%     \texttt{.} & \cs{dotuline}
%   \end{tabular}}\ }^^A
%   The main command provided by the package is \cs{gap} which expects a
%   mandatory \meta{text} argument containing the material that is used
%   to produce the gap (and is normally invisible). By default the gap is
%   underlined, though that can be changed.
% \end{function}    ^^A not really meant for no parindent and positive
%                   ^^A parskip ...
% \vspace{\parskip} ^^A ... thus manual fix for now
%
%
%   The optional \meta{style} argument explicitly defines a certain type
%   of underlining: |u| stands for normal underlining (via \cs{uline}),
%   |d| for double underlining (via \cs{uuline}),
%   |w| for a wavy line (via \cs{uwave}), |b| for blank (i.e., no
%   underlining whatsoever), ``|-|'' for a dash-line (via \cs{dashuline})
%   and finally ``|.|''\ for underlining with dots (via \cs{dotuline}).
%
%   In the default configuration gaps are numbered using the counter
%   \texttt{gapnumber} and this number is shown in parentheses after
%   the gap. With the star form the generation of the 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 \cs{gap} uses \pkg{ulem}'s commands it inherits the limitations
%   of these commands; notably, only simple text can be used in the
%   \meta{text} argument. For example, a \cs{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 \pkg{ulem}
%    commands is set as if is is inside an \cs{mbox}, in particular it will
%    not break across lines. For example \verb=\gap{\emph{...}}= will
%    show this behavior.  The \pkg{dashundergaps} package tries
%    mediate as best as possible, e.g., \verb=\gap{\mytext}= works,
%    but in other cases you have to live with this limitation.
%
% \begin{function}{\TeacherModeOn,\TeacherModeOff}
%   \begin{syntax}
%     \cs{TeacherModeOn}   \texttt{\,\% show gap material}
%     \cs{TeacherModeOff}  \texttt{\% do not show gap material}
%   \end{syntax}
% 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 \cs{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 \cs{TeacherModeOn} or \cs{TeacherModeOff},
% respectively. Alternatively, it can also be set via an option, as we
% will see below.
% \end{function}
%
% \begin{function}{\dashundergapssetup}
%   \begin{syntax}
% \cs{dashundergapssetup}\Arg{comma-separated key-value list}
%   \end{syntax}
%   The package can be loaded with a number of options (discussed in
% Section~\ref{sec:options}). A likely better approach is to set any
% options with the declaration \cs{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.
% \end{function}
%
%
%
%
%
%
%
%
% \subsection{Options to customize the gap display}\label{sec:options}
%
% 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
% \cs{usepackage}. However if the value requires some \LaTeX{} code
% (e.g., \option{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
% \cs{dashundergapssetup} instead, which will always work.
%
% \subsubsection{Gap modes}
%
% The general processing mode is defined through the following options:
% \begin{description}
% \item[\option{teacher-mode}] Boolean that turns on teacher mode (i.e., the gap
%   material will be visible if set to |true|). Its default is
%   |false|.
% \item[\option{gap-mode}] Boolean that is the inverse of \option{teacher-mode}
%   and just provided for convenience, i.e., an abbreviation
%   for \option{teacher-mode}|=false|.
% \item[\option{teachermode}] Alternative name for \option{teacher-mode} because
%   that is what it was called in the first package release.
% \end{description}
%
% \subsubsection{Gap formatting}
%
% Formatting of the gaps is handled by the following six options:
% \begin{description}
% \item[\option{gap-format}] A choice option defining how the gap is
%   marked. It accepts the following values: |underline| (default),
%   |double-underline|,
%   |dash|, |dot|, |wave|, |blank|.
% \item[\option{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.
% \item[\option{teacher-gap-format}] Another choice option, with the
%   same values as \option{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''.
% \item[\option{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.
% \item[\option{dash}] Short name for \option{gap-format}|=dash|.
% \item[\option{dot}] Short name for \option{gap-format}|=dot|.
% \end{description}
%
% \subsubsection{Gap numbers}
%
% Producing the gap numbers is handled by the following options:
% \begin{description}
% \item[\option{gap-numbers}] Boolean that determines whether or not gap numbers
%   are displayed. Default is |true|.
%
% \item[\option{gap-number-format}] Code that is executed when a gap number is
%   produced. Default is \verb*|\textnormal{ (\thegapnumber)}|.
% \item[\option{numbers}] Short name for \option{gap-numbers}.
% \end{description}
%
% There is also a way to control displaying the total number of gaps:
% \begin{description}
% \item[\option{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|.
% \item[\option{displaynbgaps}] This is just another name for the same boolean;
%   it was used in the first version of the package.
% \end{description}
%
%
%
% \subsubsection{Gap widening}
%
% Finally, for extending the gap width we have these options:
% \begin{description}
% \item[\option{gap-widen}] Boolean that decides if the gaps should be made wider
%   or not (default is |false| but mainly for historical reasons).
% \item[\option{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.
% \item[\option{gap-extend-percent}] Percentage (as a number) by which the gap should be made
%   wider if widening is active. The result is compared to
%   \option{gap-extend-minimum} and the larger of the two is
%   used. Default is |20|.
% \item[\option{widen}] Short name for \option{gap-widen}.
% \end{description}
%
%
%
%
% \section{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).
%
% \begin{itemize}
% \item
%   Stray spaces in the definition of \cs{gap} (that showed up in
%   the output) have been eliminated.
% \item
%   Various combinations of options that didn't work are now possible.
% \item
%   Explicit hyphenations |\-| showed up in gap mode, now they can be used.
% \item
%   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.
% \item
%   Option names have been normalized (though the original names are
%   still available).
% \item
%   The option \option{phantomtext} is no longer necessary, though still
%   supported (with a warning) as a no-op.
% \item
%   The names of the \LaTeX{} counters used have changed, so if you
%   directly addressed them that would need changing.
% \item
%   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
%   \pkg{ulem} machinery is always used, even if not underlining (or
%   dashing, etc.).
% \item 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.
% \item
%   \cs{gap} now has an optional argument through which you can
%   explicitly request the type of underlining you want to use.
% \item
%   \cs{gap} also supports a star form which toggles the setting of gap numbers.
% \item
%   The use of \cs{label} within the \cs{gap} command argument allows for
%   later reference to that gap by its number (provided a gap number is typeset).
% \item The implementation is done with \texttt{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 \texttt{expl3}.
% \end{itemize}
%
%
% \section{Solution to the puzzle} \label{sec:answer}
%
% \TeacherModeOn
%
% Here we repeat the puzzle from above with \cs{TeacherModeOn}.
% \par\smallskip
% \noindent\hfill\llap{\setlength\fboxsep{10pt}
%                      \fbox{\begin{minipage}{1.2\textwidth}
%                      \puzzletext
% \end{minipage}\hskip\marginparsep}}
% \par\smallskip
% This was produced using the following changes to the defaults:
% \begin{verbatim}
%   \dashundergapssetup{
%     ,gap-number-format  = \,\textsuperscript{\normalfont
%                                              (\thegapnumber)}
%     ,gap-font           = \itshape
%     ,teacher-gap-format = underline
%     ,gap-widen
%   }
% \end{verbatim}
% 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 \cs{normalfont} in the formatting to ensure that the gap number
% is set upright and not in italic shape.
%
%
% \StopEventually{
% \begin{thebibliography}{1}
%\bibitem{tub-wao-code}
% Frank Mittelbach.
% \newblock The \pkg{widows-and-orphans} package.
% \newblock \textsl{TUG}boat 39:3,
%   \ifx\thisissuepageref\undefined ^^A undefined if non-TUGboat
%     20018.\\
%   \else \thisissuepageref{mitt-widows-code}, 2018.\fi
% \newblock  \url{https://ctan.org/pkg/widows-and-orphans}
% \bibitem{expl3}
% \LaTeX3 Project Team.
% \newblock A collection of articles on \pkg{expl3}.\\
%    \url{https://latex-project.org/publications/indexbytopic/l3-expl3/}
%\end{thebibliography}
% \ifx\thisissuepageref\undefined    ^^A is this TUB production ??? if not gen index
%    \setlength\IndexMin{200pt}  \PrintIndex
% \fi}
%
%
% \newpage
%
%
% \DoNotIndex{\ ,\advance,\begingroup,\bgroup,\def,\else,\endgroup,\fi}
% \DoNotIndex{\hbox,\ifx,\kern,\let,\lower,\@M,\@empty,\c@gapnumber}
% \DoNotIndex{\c@totalgapnumber,\hb@xt@,\LA@penalty,\UL@box,\UL@leaders}
% \DoNotIndex{\UL@leadtype,\UL@setULdepth,\UL@skip,\UL@start,\z@,\ULdepth}
% \DoNotIndex{\ULon,\vrule,\wd,\@width,\UL@putbox,\markoverwith}
% \DoNotIndex{\char,\cs_new:Npn,\cs_set:Npn,\dim_new:N,\font,\global,\hyphenchar}
% \DoNotIndex{\setbox,\string,\UL@hyphenbox,\UL@start}
% \DoNotIndex{\tl_new:N,\tl_set:Nn,\ifnum,\UL@stop,\dim_set:Nn,\box}
% \DoNotIndex{\discretionary,\sixly,\p@,\usepackage,\ignorespaces}
% \DoNotIndex{\cs_set_eq:NN}
%
%
%
% \section{The implementation}
%
% \subsection{Loading and fixing/changing \pkg{ulem}}
%
% The first thing to do is to load \pkg{ulem} without changing \cs{emph}
% or \cs{em}:
%    \begin{macrocode}
%<*package>
\RequirePackage[normalem]{ulem}
%    \end{macrocode}
%
% The code in this section follows \LaTeXe{} conventions, i.e., models
% the commands as they look in the \pkg{ulem} package.
%
%  \begin{macro}{\dotuline}
%     The dots produced by \cs{dotuline} depend on the current font,
%     which is a somewhat questionable design\Dash 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 \cs{normalfont}
%     dot (this is not done in the original definition).
% \changes{v2.0f}{2020/01/22}{Adjusted definition to new ulem release}
%    \begin{macrocode}
\protected\def\dotuline{\leavevmode\bgroup
  \UL@setULdepth
  \ifx\UL@on\UL@onin \advance\ULdepth2\p@\fi
  \markoverwith{\begingroup
%     \advance\ULdepth0.08ex
     \lower\ULdepth\hbox{\normalfont \kern.1em .\kern.04em}%
     \endgroup}%
  \ULon}
%    \end{macrocode}
%  \end{macro}
%
%
%
%  \begin{macro}{\uwave}
%    The original \cs{uwave} used a hard-wired value of |3.5pt| for
%     the lowering. We change that to be based on the current
%     value of \cs{ULdepth} so that the user (or this package here)
%     can change the placement.
% \changes{v2.0f}{2020/01/22}{Adjusted definition to new ulem release}
%    \begin{macrocode}
\protected\def\uwave{\leavevmode\bgroup
  \UL@setULdepth
  \advance\ULdepth 0.6\p@
  \markoverwith{\lower\ULdepth\hbox{\sixly \char58}}\ULon}
%    \end{macrocode}
%  \end{macro}
%
%
%  \begin{macro}[int]{\fmdug@ublank}
%    \cs{fmdug@ublank} underlines with blanks. Normally not especially useful
%    (which is why we make it internal),
%    but if we want to have \pkg{ulem} acting, but without actually
%    visibly underlining, this is the command to use.
%    \begin{macrocode}
\def\fmdug@ublank{\bgroup\let\UL@leadtype\@empty\ULon}
%    \end{macrocode}
%  \end{macro}
%
%
%
%  \begin{macro}[int]{\UL@dischyp}
%  \begin{macro}[int]{\UL@putbox}
%   We need to do a little patching to ensure that nothing is output
%   by the \pkg{ulem} commands if we don't want it to. So the next two
%   commands are from \pkg{ulem} with |\box| replaced by
%   |\fmdug@box| so that we can change the behavior.
%    \begin{macrocode}
\def\UL@dischyp{\global\setbox\UL@hyphenbox\hbox
   {\ifnum \hyphenchar\font<\z@ \string-\else \char\hyphenchar\font \fi}%
   \kern\wd\UL@hyphenbox \LA@penalty\@M 
   \UL@stop \kern-\wd\UL@hyphenbox
   \discretionary{\fmdug@box\UL@hyphenbox}{}{}\UL@start}
%    \end{macrocode}
%    
%    \begin{macrocode}
\def\UL@putbox{\ifx\UL@start\@empty \else % not inner
  \vrule\@width\z@ \LA@penalty\@M
  {\UL@skip\wd\UL@box \UL@leaders \kern-\UL@skip}%
  \fmdug@box\UL@box  \fi}
%    \end{macrocode}
%  \end{macro}
%  \end{macro}
%
%
%
%  \begin{macro}[int]{\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.
%    \begin{macrocode}
\let\fmdug@box\box
%    \end{macrocode}
%  \end{macro}
%
%
%
%
%
%
%
%  \subsection{The main implementation part}
%
%  The rest of the package is written in \texttt{expl3}. We use
%  \texttt{fmdug} as our internal prefix.

%    \begin{macrocode}
%<@@=fmdug>
%    \end{macrocode}
%
% We need the package \pkg{xparse} for specifying the document-level
%    interface commands and \pkg{l3keys2e} to use the \pkg{expl3} key
%    value  methods within \LaTeXe{}. These packages automatically
%    require \pkg{expl3} so there is no need to load that explicitly
%    and nowadays the core of \pkg{xparse} is part of the \LaTeX{} kernel.
%    \begin{macrocode}
\RequirePackage{l3keys2e}
%    \end{macrocode}
%
%    As the code uses some functions from \pkg{expl3} that got
%    introduced sometime in 2018 we need to require a fairly recent
%    version (the date is somewhat arbitrarily picked).
%    \begin{macrocode}
\@ifpackagelater{expl3}{2018-06-24}
  {}
  {%
    \PackageError{dashundergaps}{Support package l3kernel too old}
      {%
        Please install an up to date version of l3kernel\MessageBreak
        using your TeX package manager or from CTAN.\MessageBreak
        \MessageBreak
        Loading dashundergaps will abort!%
      }%
    \endinput
  }
%    \end{macrocode}
%    
% Here we introduce the package and specify its version number:
%    \begin{macrocode}
\ProvidesExplPackage{dashundergaps}
                    {\dashundergapsdate}
                    {\dashundergapsversion}
                    {Dashing and underlining phantom text}
%    \end{macrocode}
%
%
% \subsubsection{User interface commands}
%

%  \begin{macro}{\gap}
%    The \cs{gap} command parses for a star, optional and mandatory
%    argument and then calls \cs{@@_gap:nnn} to do the work.
% \changes{v2.0g}{2020/02/11}{Expand argument up front to work around
%    ulem restrictions if possible (gh/10)}
%    \begin{macrocode}
\DeclareDocumentCommand \gap { som }
   {
%    \end{macrocode}
%    We try to expand as much as possible up front to avoid the
%    \pkg{ulem} limitations:
%    \begin{macrocode}
     \protected@edef\next{#3}
%    \end{macrocode}
%    Use the \enquote{content} of \cs{next} in the processing:
%    \begin{macrocode}
     \@@_gap:nno {#1}{#2}{ \next } }
%    \end{macrocode}
%  \end{macro}
%
%
%  \begin{macro}{\dashundergapssetup}
%    Change options anywhere.
%    \begin{macrocode}
\NewDocumentCommand \dashundergapssetup { m }
  { \keys_set:nn {fmdug} {#1} \ignorespaces }
%    \end{macrocode}
%  \end{macro}
%
%
%  \begin{macro}{\TeacherModeOn}
%  \begin{macro}{\TeacherModeOff}
%    We provide shortcuts for turning teacher mode on or off.
%    \begin{macrocode}
\DeclareDocumentCommand \TeacherModeOn  {}
                        { \bool_set_true:N \l_@@_teacher_bool }
\DeclareDocumentCommand \TeacherModeOff {}
                        { \bool_set_false:N \l_@@_teacher_bool }
%    \end{macrocode}
%  \end{macro}
%  \end{macro}
%
%
%
%
% \subsubsection{Counters}
%
%  \begin{macro}[int]{\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.
%    \begin{macrocode}
\newcounter{gapnumber}
%    \end{macrocode}
%  \end{macro}
%
%
%  \begin{macro}[int]{\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
%    \cs{thetotalgapnumber}.
% ^^A\makeatletter\@endparpenalty=10000\makeatother
%    \begin{macrocode}
\newcounter{totalgapnumber}
%    \end{macrocode}
%  \end{macro}

%  \begin{macro}{\l_@@_extend_dim}
%    A help register to calculate the gap width later on.
%    \begin{macrocode}
\dim_new:N \l_@@_extend_dim
%    \end{macrocode}
%  \end{macro}
%
%
%
%  \begin{macro}{\l_@@_extra_left_gap_tl}
%  \begin{macro}{\l_@@_extra_right_gap_tl}
%    Two scratch token lists to enlarge the gap on the left or right side.
%    \begin{macrocode}
\tl_new:N \l_@@_extra_left_gap_tl
\tl_new:N \l_@@_extra_right_gap_tl
%    \end{macrocode}
%  \end{macro}
%  \end{macro}
%
%
%  \begin{macro}{\l_@@_gap_format_tl}
%  \begin{macro}{\l_@@_teacher_gap_format_tl}
%    The gap formatting is normally handled by a \pkg{ulem}
%    command; which one depends on the options used. To record the
%    choice we store it in a token list (one for normal and one for
%    teacher mode).
%    \begin{macrocode}
\tl_new:N \l_@@_gap_format_tl
\tl_new:N \l_@@_teacher_gap_format_tl
%    \end{macrocode}
%  \end{macro}
%  \end{macro}
%
% \subsubsection{Messages}
%
%    \begin{macrocode}
\msg_new:nnn {dashundergaps} {deprecated}
  { The~ #1~ `#2'~ you~ used~ \msg_line_context: \ is~ deprecated~ and~
    there~ is~ no~ replacement.~ Since~ I~ will~ not~ guarantee~ that~
    #1~ `#2'~ will~ be~ kept~ forever~ I~ strongly~ encourage~ you~
    to~ remove~ it~ from~ your~ document. }
%    \end{macrocode}
%
%    \begin{macrocode}
\msg_new:nnnn {dashundergaps} {nested}
  { The~ \gap command~ can't~ be~ nested! }
  { Nesting~ doesn't~ make~ much~ sense~ as~ the~ inner~ one~
    wouldn't~ be~ visible.~ ~ To~ allow~ further~ processing~ it~ is~
    handled~ as~ if~ it~ hasn't~ been~ asked~ for. }
%    \end{macrocode}
%
%
%    \begin{macrocode}
\msg_new:nnnn {dashundergaps} {gap-format-value}
  { Unknown~ value~ for~ key~ '#1 gap-format'! }
  { Supported~ values~ are~ 'underline',~ 'double-underline',\\
    'dash',~ 'dot',~ 'wave'~ or~ 'blank'. }
%    \end{macrocode}
%
%
%
% \subsubsection{Option handling}
%
% Here we define all the possible option keys for use either as package
% options or inside
% \cs{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.
%    \begin{macrocode}
\keys_define:nn {fmdug}
     {
       % ====================================
      ,teacher-mode      .bool_set:N = \l_@@_teacher_bool
      ,teacher-mode      .default:n  = true
      ,teacher-mode      .initial:n  = false
       % ------------------
      ,gap-mode  .bool_set_inverse:N = \l_@@_teacher_bool
       % ====================================
      ,gap-format
         .choice:
%    \end{macrocode}
%
%    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
%    \texttt{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 \pkg{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
%     \emph{will} have text above and we don't want to bump into that.
%
%    \begin{macrocode}
      ,gap-format / underline
         .code:n = \tl_set:Nn \l_@@_gap_format_tl
                              { \@@_gap_format_adjust:n{.4pt} \uline }
      ,gap-format / double-underline
         .code:n = \tl_set:Nn \l_@@_gap_format_tl
                              { \@@_gap_format_adjust:n{2pt} \uuline }
      ,gap-format / dash
         .code:n = \tl_set:Nn \l_@@_gap_format_tl
                           { \@@_gap_format_adjust:n{0pt} \dashuline }
      ,gap-format / dot
         .code:n = \tl_set:Nn \l_@@_gap_format_tl
                         { \@@_gap_format_adjust:n{-.08ex} \dotuline }
      ,gap-format / wave
         .code:n = \tl_set:Nn \l_@@_gap_format_tl
                              { \@@_gap_format_adjust:n{1pt} \uwave }
      ,gap-format / blank
         .code:n = \tl_set:Nn \l_@@_gap_format_tl { \fmdug@ublank  }
      ,gap-format / unknown
         .code:n = \msg_error:nnn{dashundergaps}{gap-format-value}{}
      ,gap-format
         .initial:n = underline
       % ====================================
%    \end{macrocode}
%     This controls the raising of the gap underline by some
%     amount. We implement it as a |.choice| even though it looks like
%     a boolean.
%\begingroup\hfuzz=15pt
%    \begin{macrocode}
       ,gap-format-adjust
         .choice:
       ,gap-format-adjust / true
         .code:n = \cs_set:Npn \@@_gap_format_adjust:n ##1
                               { \setlength\ULdepth {##1} }
       ,gap-format-adjust / false
         .code:n = \cs_set_eq:NN \@@_gap_format_adjust:n \use_none:n
      ,gap-format-adjust
         .default:n = true
      ,gap-format-adjust
         .initial:n = true
      ,adjust .meta:n = { gap-format-adjust }
       % ====================================
      ,teacher-gap-format
         .choice:
     ,teacher-gap-format / underline
         .code:n = \tl_set:Nn \l_@@_teacher_gap_format_tl { \uline }
      ,teacher-gap-format / double-underline
         .code:n = \tl_set:Nn \l_@@_teacher_gap_format_tl { \uuline }
      ,teacher-gap-format / dash
         .code:n = \tl_set:Nn \l_@@_teacher_gap_format_tl { \dashuline }
      ,teacher-gap-format / dot
         .code:n = \tl_set:Nn \l_@@_teacher_gap_format_tl { \dotuline }
      ,teacher-gap-format / wave
         .code:n = \tl_set:Nn \l_@@_teacher_gap_format_tl { \uwave }
      ,teacher-gap-format / blank
         .code:n = \tl_set:Nn \l_@@_teacher_gap_format_tl { \fmdug@ublank }
      ,teacher-gap-format / unknown
         .code:n = \msg_error:nnn{dashundergaps}{gap-format-value}{teacher-}
      ,teacher-gap-format
         .initial:n = blank
       % ====================================
      ,gap-widen         .bool_set:N = \l_@@_gap_widen_bool
      ,gap-widen         .default:n  = true
      ,gap-widen         .initial:n  = false
       % ------------------
      ,widen                 .meta:n = { gap-widen }
       % ------------------
      ,gap-extend-minimum .dim_set:N = \l_@@_gap_min_dim
      ,gap-extend-minimum .initial:n = 20pt
       % ------------------
      ,gap-extend-percent .tl_set:N  = \l_@@_gap_percent_tl
      ,gap-extend-percent .initial:n = 20
       % ====================================
      ,gap-numbers        .bool_set:N = \l_@@_number_bool
      ,gap-numbers        .default:n  = true
      ,gap-numbers        .initial:n  = true
       % ------------------
      ,numbers                .meta:n = { gap-numbers }
       % ------------------
      ,gap-number-format .tl_set:N    = \l_@@_gapnum_format_tl
      ,gap-number-format .initial:n   = \textnormal{\space (\thegapnumber)}
       % ====================================
      ,display-total-gaps .bool_gset:N = \g_@@_display_total_gaps_bool
      ,display-total-gaps   .default:n = true
      ,display-total-gaps   .initial:n = false
       % ====================================
      ,gap-font    .tl_set:N = \l_@@_font_tl
      ,gap-font   .default:n =
      ,gap-font   .initial:n = \bfseries
%    \end{macrocode}
%    And finally the original options, now as aliases:
%    \begin{macrocode}
       % ====================================
      ,teachermode   .meta:n =  { teacher-mode }
      ,dash          .meta:n =  { gap-format = dash }
      ,dot           .meta:n =  { gap-format = dot }
      ,displaynbgaps .meta:n =  { display-total-gaps }
       % ------------------
      ,phantomtext
         .code:n = \msg_warning:nnnn{dashundergaps}{deprecated}
                                    {option}{phantomtext}
       % ====================================
     }
%    \end{macrocode}
%\endgroup
%
%
%  \begin{macro}{\@@_gap:nnn}
%    At last, here comes the action. \cs{@@_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 \cs{gap} was used
%    without an optional argument) and |#3| is the material to produce
%    a gap for.
%    \begin{macrocode}
\cs_new:Npn\@@_gap:nnn #1#2#3 {
%    \end{macrocode}
%
%    \begin{macrocode}
  \group_begin:
%    \end{macrocode}
%    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).
%    \begin{macrocode}
    \l_@@_font_tl
%    \end{macrocode}
%    Nesting is not supported so inside the gap we redefine
%    \cs{@@_gap:nnn} to raise an error and just return the third argument if it is
%    encountered again. 
%    \begin{macrocode}
    \cs_set:Npn \@@_gap:nnn ##1##2##3
      {
        \msg_error:nn{dashundergaps}{nested}
        ##3
      }
%    \end{macrocode}
%    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 \cs{refstepcounter} to make it referenceable.
%    \begin{macrocode}
    \stepcounter{totalgapnumber}
    \bool_xor:nnT { #1 } { \l_@@_number_bool }
      { \refstepcounter{gapnumber} }
%    \end{macrocode}
%    Next we prepare for widening if that is being asked for: Measure
%    the width of the text and then set \cs{l_@@_extend_dim} to be the
%    requested percentage divided by two of that width (since we add
%    it later on both sides).
%    \begin{macrocode}
    \bool_if:NTF \l_@@_gap_widen_bool
      {
        \settowidth \l_@@_extend_dim {#3}
        \dim_set:Nn \l_@@_extend_dim
                  { \l_@@_gap_percent_tl \l_@@_extend_dim / 200 }
%    \end{macrocode}
%    Then compare it to the minimum / 2 and choose whatever is larger.
%    \begin{macrocode}
       \dim_compare:nNnT \l_@@_extend_dim < { .5\l_@@_gap_min_dim }
          { \dim_set:Nn \l_@@_extend_dim { .5\l_@@_gap_min_dim } }
%    \end{macrocode}
%    Now we prepare what needs to go to the left and the right of the gap.
%    \begin{macrocode}
       \tl_set:Nn \l_@@_extra_left_gap_tl
          { \hbox_to_wd:nn\l_@@_extend_dim{} \allowbreak }
       \tl_set:Nn \l_@@_extra_right_gap_tl
          { \allowbreak \hbox_to_wd:nn\l_@@_extend_dim{} }
      }
%    \end{macrocode}
%    And if no widening is asked for we clear these two token lists so
%    they don't do anything.
%    \begin{macrocode}
      {
        \tl_clear:N \l_@@_extra_left_gap_tl
        \tl_clear:N \l_@@_extra_right_gap_tl
      }
%    \end{macrocode}
%    Next comes deciding the gap format. If in teacher mode it will be
%    whatever is in \cs{l_@@_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 \cs{l_@@_gap_format_tl}.
%    \begin{macrocode}
    \bool_if:NTF \l_@@_teacher_bool
      { \l_@@_teacher_gap_format_tl }
      {
%    \end{macrocode}
%    But before we execute any of the \pkg{ulem} commands we make sure
%    that they do not output text.
%    \begin{macrocode}
        \cs_set:Npn   \fmdug@box ##1 {\hbox_to_wd:nn{\box_wd:N ##1}{}}
        \str_case:nnF {#2}
            {
              {u} { \@@_gap_format_adjust:n{.4pt}   \uline  }
              {d} { \@@_gap_format_adjust:n{2pt}    \uuline }
              {w} { \@@_gap_format_adjust:n{1pt}    \uwave  }
              {b} { \fmdug@ublank }
              {.} { \@@_gap_format_adjust:n{-.08ex} \dotuline }
              {-} { \@@_gap_format_adjust:n{0pt}   \dashuline }
            }
            { \l_@@_gap_format_tl }
      }
%    \end{macrocode}
%    Whatever was decided as the gap format, it needs one argument,
%    i.e., the material (with possible gap extension on both sides).
%    \begin{macrocode}
    {\l_@@_extra_left_gap_tl #3 \l_@@_extra_right_gap_tl }
%    \end{macrocode}
%    Finally we typeset the gap number if that was requested.
%    \begin{macrocode}
    \bool_xor:nnT { #1 } { \l_@@_number_bool }
                  { \l_@@_gapnum_format_tl }
%    \end{macrocode}
%    Close the group from above to keep any of the redefinitions confined.
%    \begin{macrocode}
  \group_end:
}
%    \end{macrocode}
%    
%    \begin{macrocode}
\cs_generate_variant:Nn \@@_gap:nnn {nno}
%    \end{macrocode}
%  \end{macro}
%
%
%
%  \begin{macro}{\@@_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.
%    \begin{macrocode}
\cs_new:Npn \@@_display_total_gaps: {
  \vfill \centering
  \bfseries Total~ Gaps:~ \thetotalgapnumber
}
%    \end{macrocode}
%  \end{macro}
%
%
%
% \subsubsection{Closing shop}
%
% At the end of the document we typeset the total number of gaps if requested.
%    \begin{macrocode}
\AtEndDocument{
  \bool_if:NT \g_@@_display_total_gaps_bool
              \@@_display_total_gaps:
}
%    \end{macrocode}
%  So what remains to be done is executing all options passed to the
%    package via \cs{usepackage}.
%    \begin{macrocode}
\ProcessKeysPackageOptions{fmdug}
%</package>
%    \end{macrocode}
%
% \Finale
%
%
\endinput
