summaryrefslogtreecommitdiff
path: root/macros/latex/contrib/gatherenum/gatherenum.dtx
blob: 8024754151564049a6308800321162984364b11e (plain)
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
% \iffalse meta-comment
% vim: tw=80 spl=en
%
%% File: gatherenum.dtx (C) Copyright 2016-2019 RIVAUD Julien
%%
%% It may be distributed and/or modified under the conditions of the
%% General Public License (GPL), either version 3 of this
%% license or (at your option) any later version.
%
%<*driver|package>
% The version of expl3 required is tested as early as possible, as
% some really old versions do not define \ProvidesExplPackage.
\NeedsTeXFormat{LaTeX2e}[1995/12/01]
\RequirePackage{expl3}[2018/06/19]
\def\ExplFileName{gatherenum}
\def\ExplFileDescription{Crossover between align* and enumerate}
\def\ExplFileDate{2019/09/29}
\def\ExplFileVersion{1.8}
%</driver|package>
%<*driver>
\documentclass[full]{l3doc}
\usepackage{gatherenum}
\begin{document}
  \DocInput{\jobname.dtx}
\end{document}
%</driver>
% \fi
%
% \title{^^A
%   The \textsf{\ExplFileName} package\\
%   Gathered, display-like \env{enumerate}^^A
%   \thanks{This file describes v\ExplFileVersion,
%     last revised \ExplFileDate.}^^A
% }
%
% \author{^^A
%  Julien ``\_FrnchFrgg\_'' \textsc{Rivaud}\thanks
%    {^^A
%      E-mail:
%        \href{mailto:frnchfrgg@free.fr}
%             {frnchfrgg@free.fr}^^A
%    }^^A
% }
%
% \date{Released \ExplFileDate}
%
% \maketitle
%
% \begin{documentation}
%
% \section{Documentation}
%
% \subsection{Package description}
%
% This package (ab)uses the inline enumeration capabilities of \pkg{enumitem} to
% add a ``displayed'' enumeration mode, triggered by adding |gathered| to the
% key-val option list of the \env{enumerate} environment.
%
% The end result is similar to The end result is similar to a regular enumerate
% environment wrapped in a multicols environment, with the following advantages:
% \begin{itemize}
%   \item \emph{gathered} enumerate can pack items depending on their actual
%       width rather than a fixed, constant number per line;
%   \item it fills items in a line-major order (instead of column-major order),
%       which my students found less confusing.Your mileage may vary.
% \end{itemize}
%
% All settings of the standard enumeration that are relevant still apply to the
% gathered mode --- which would not have been the case with a separate
% inline enumeration like the \env{enumerate*} provided by \pkg{enumitem}.
%
% Individual items are separately boxed, to mimic the behavior of \env{align}.
% This package is not for you if you want free-flow enumeration in a paragraph,
% since \pkg{enumitem} already provides a reasonable one, and you probably do
% not want to share that many settings with regular \env{enumerate} due to the
% very different nature and look of inline enumerations.
%
% Say:
%\begin{verbatim}
% \setlist{enumerate}{label=\arabic*.}
% \begin{enumerate}
%   \item Test
%   \item $\int_a^b$ with math
%   \item And another
%   \item $f(x) = 6$
%   \item $D(t) = 0$
%   \item $d$~and~$d'$ are parallel
% \end{enumerate}
%\end{verbatim}
% produces:
% \setlist[enumerate]{label=\arabic*.}
% \begin{enumerate}
%   \item Test
%   \item $\int_a^b$ with math
%   \item And another
%   \item $f(x) = 6$
%   \item $D(t) = 0$
%   \item $d$~and~$d'$ are parallel
% \end{enumerate}
%
% Then:
%\begin{verbatim}
% \begin{enumerate}[gathered]
%   \item Test
%   \item $\int_a^b$ with math
%   \item And another
%   \item $f(x) = 6$
%   \item $D(t) = 0$
%   \item $d$~and~$d'$ are parallel
% \end{enumerate}
%\end{verbatim}
% will produce:
% \begin{enumerate}[gathered]
%   \item Test
%   \item $\int_a^b$ with math
%   \item And another
%   \item $f(x) = 6$
%   \item $D(t) = 0$
%   \item $d$~and~$d'$ are parallel
% \end{enumerate}
%
% \subsection{Customizing}
%
% Most of the changes are in fact done through the usual \pkg{enumitem}
% interface. |itemjoin| can be a useful setting to tweak. \pkg{gatherenum}
% provides several additional options:
%
% \begin{itemize}[noitemsep]
%   \item |gatherformat| this is put just before every item content; the last
%       token in that option can take an argument, which will be the unboxed
%       item content.  Note that since the item has already been typeset in an
%       horizontal box, you cannot change the font family, shape or size at that
%       point, but can add a frame around for instance.
%   \item |center| display the items in a centered paragraph. This is the most
%       display-like and is the default. Equivalent to |before*=\centering|.
%   \item |alignleft| display the items in a left-aligned paragraph.\\
%       Equivalent
%       to |before*=\raggedright|.
% \end{itemize}
%
% Lastly, an example of something I use a lot:
%
% \bigskip
% \hrule\medskip
% Compute the following:
% \begin{enumerate}[gathered, label={$\alph* = {}$}, labelsep=0pt]
%   \item $1+1$
%   \item $\sin\left( 2\pi + \frac{\pi}{3} \right)$
%   \item $\displaystyle \int_0^{+\infty} \mathrm{e}^{-t^2} \mathrm{d}t$
%   \item $\varphi(52330)$
% \end{enumerate}
% \medskip\hrule
% \begin{verbatim}
% Compute the following:
% \begin{enumerate}[gathered, label={$\alph* = {}$}, labelsep=0pt]
%   \item $1+1$
%   \item $\sin\left( 2\pi + \frac{\pi}{3} \right)$
%   \item $\displaystyle \int_0^{+\infty} \mathrm{e}^{-t^2} \mathrm{d}t$
%   \item $\varphi(52330)$
% \end{enumerate}
% \end{verbatim}
% \hrule
%
% \end{documentation}
%
% \begin{implementation}
%
% \section{\pkg{\ExplFileName} implementation}
%
%    \begin{macrocode}
%<*package>
%<@@=gatherenum>
%    \end{macrocode}
%
%    \begin{macrocode}
\ProvidesExplPackage
  {\ExplFileName}{\ExplFileDate}{\ExplFileVersion}{\ExplFileDescription}
%    \end{macrocode}
%
%   We use \pkg{enumitem} as a base, and \pkg{xparse} to define our environment.
%    \begin{macrocode}
\RequirePackage{enumitem}
\RequirePackage{xparse}
%    \end{macrocode}
%
%   \pkg{enumitem} has a mechanism to make the \env{enumerate} environment use
%   settings and counters prefixed by \cs{enum} instead of \cs{enumerate}
%   (because that's what \LaTeX\ does). We take advantage of that to define our
%   internal enumeration, because we want to share settings and counter with
%   \env{enumerate} since we will act as an option of that environment.
%    \begin{macrocode}
\tl_set:Nn \enit@shortgatherenum {enum}
\newlist{gatherenum}{enumerate*}{3}
%    \end{macrocode}
%
%   Since \pkg{enumitem} inline enumerations are intended for pararaph-like
%   enumerations, the item content is unpacked with \cs{unhbox} even in
%   \emph{boxed} mode. That's not what we want, so we have to add another layer
%   of boxing. While we're at it, we add a formatting command for the user
%   to customize.
%    \begin{macrocode}
\tl_new:N \l@@_itemformat
\cs_new_protected_nopar:Nn \@@_boxitem: {
    \nobreak\skip_horizontal:n {\labelsep}
    \hbox_set:Nn \enit@inbox {
        \hbox:n {
            \l@@_itemformat{\hbox_unpack:N \enit@inbox}
        }
    }
}
\enitkv@key{enumitem}{gatherformat}{\tl_set:Nn\l@@_itemformat{#1}}
%    \end{macrocode}
%
%   Now is the time to change the enumerate environment. We save the start and
%   end of existing environment from \pkg{enumitem} to be able to fall back to
%   it.
%    \begin{macrocode}
\let\@@_save_enumerate:w\enumerate
\let\@@_save_endenumerate:w\endenumerate
\RenewDocumentEnvironment{enumerate}{ O{} }{
%    \end{macrocode}
%
%   The trigger for gathered enumeration is the \texttt{gathered} option given
%   by the user in the list of local options. If there is no such option, we
%   directly use the original \cs{endenumerate}.
%
%    \begin{macrocode}
    \clist_if_in:nnTF { #1 } { gathered } {
%    \end{macrocode}
%
%   To act more display-like, we ensure that running heads that are not already
%   typeset are flushed now. This is especially important in the default
%   centered typesetting: we don't want to center the theorem or enumerate heads
%   along with our content.
%    \begin{macrocode}
        \if@inlabel
            \leavevmode
        \fi
        \par
        \centering
%    \end{macrocode}
%
%   Synchronise the current depth of gatherenum with that of enumerate
%   (oddly \cs{enit@shortgatherenum} doesn't imply that). That enables us to get
%   the right settings depending on depth (labels, mostly, since indention is
%   irrelevant here).
%    \begin{macrocode}
        \int_set_eq:NN \enitdp@gatherenum \enitdp@enumerate
%    \end{macrocode}
%
%   Insert a display-like penalty, and start our inline enumeration. Since
%   setting defaults for gatherenum would clobber (or a least mess with)
%   the settings of normal enumerate, we give them here using the optional
%   argument (recall that they share most counters and settings).
%
%   We use a trivial align mode to ensure \pkg{enumitem} doesn't try to apply
%   indention, alignment or spacing effects to the label. \meta{afterlabel} is
%   a hook that enumitem calls after closing the \cs{hbox} with item content,
%   after typesetting the label, but before unboxing the content. We use
%   \cs{@@_boxitem:} defined before to ensure the content stays
%   boxed.
%    \begin{macrocode}
        \penalty \predisplaypenalty
        \gatherenum[
            itemjoin=\skip_horizontal:n{1em plus 1fil},
            #1,
            mode=boxed,
            align=none,
            afterlabel=\@@_boxitem:,
        ]
    }{
        \@@_save_enumerate:w[#1]
    }
}{
%    \end{macrocode}
%
%   Finish the environment, either by closing the standard \env{enumerate}, or
%   by ending our horizontal enumeration, and closing the paragraph. We are
%   less strict on widows and clubs than normal.
%    \begin{macrocode}
    \clist_if_in:nnTF { #1 } { gathered } {
        \endgatherenum
        \unskip
        \int_set_eq:NN \clubpenalty \interlinepenalty
        \int_set_eq:NN \widowpenalty \interlinepenalty
        \use:c{@ @ par}% avoid l3docstrip replacement of @
    }{
        \@@_save_endenumerate:w
    }
}
%    \end{macrocode}
%
%   Last touches: a \texttt{gathered} key for \pkg{enumitem} so that it doesn't
%   complain when it sees it (this enables us to keep the key in the list
%   instead of filtering it with \cs{clist_remove_all:Nn}). Next is the trivial
%   align mode we talked about earlier, and at last some shorthands for common
%   layouts.
%
%    \begin{macrocode}
\SetEnumitemKey{gathered}{}
\SetLabelAlign{none}{#1}
\SetEnumitemKey{centered}{before*=\centering}
\SetEnumitemKey{alignleft}{before*=\raggedright}
%</package>
%    \end{macrocode}
%
% \end{implementation}