summaryrefslogtreecommitdiff
path: root/macros/latex/required/graphics/mathcolor.dtx
blob: 5dc482e38e3c1214af9fb4fa4271749386648163 (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
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
% \iffalse meta-comment
%
%% File: mathcolor.dtx (C) Copyright 2021-2022
%       Frank Mittelbach, LaTeX Team
%
% 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
%
%
%%% From File: mathcolor.dtx
%
%    \begin{macrocode}
\def\mathcolorversion{v1.0c}
\def\mathcolordate{2022/07/25}
%    \end{macrocode}
%<*driver>
\documentclass{l3doc}

%\makeatletter \input{mathcolor.ltx} \makeatother

\usepackage{color}

% Fixing footnotes in  functions and variables: this should be in l3doc!

\newcommand\fixfootnote[2]{\footnotemark
  \AddToHookNext{env/#1/after}{\footnotetext{#2}}}
\AddToHook{env/function/begin}{\def\footnote{\fixfootnote{function}}}
\AddToHook{env/variable/begin}{\def\footnote{\fixfootnote{variable}}}

\EnableCrossrefs
\CodelineIndex
\begin{document}
  \DocInput{mathcolor.dtx}
\end{document}
%</driver>
%
% \fi
%
% \title{Providing color in math\thanks{This file has version
%    \mathcolorversion\ dated \mathcolordate, \copyright\ \LaTeX\
%    Project.}}
% \author{Frank Mittelbach}
%
% \maketitle
%
%
% \section{Introduction}
%
%    It is possible to use the \cs{color} command in math formulas but
%    doing that has a number of restrictions and often leads to rather
%    unreadable input. For example, to color the summation sign in red
%    in the following formula
% \[
%     X = \color{red} \sum_{{\color{black} i=1}}^{{\color{black} n}} \color{black} x_i
% \]
%    A total of four color commands and a number of seemingly
%    unnecessary extra braces in the sub and superscript are needed:
%\begin{verbatim}
%  \[ X = \color{red} \sum
%         _{{\color{black} i=1}}  % without {{ the superscript is misplaced
%         ^{{\color{black} n}}    % without {{ the \sum is black
%        \color{black}            % without the x_i is red
%        x_i                  \]
%\end{verbatim}
%    While this is ugly but at least works, other things are simply
%    impossible, e.g.,
% \[  \left\{ \frac{1}{2} \mathcolor{red}{\right\}} \]
%    are not achievable at all because of the fact that \cs{left} and
%    \cs{right} form a group. Thus, a \cs{color} command immediately
%    before the \cs{right} has no effect and \verb=\}= remains black.
%    Putting the color change before the \cs{left} and then resetting
%    the color inside would work if you want to color both braces, but
%    the above combination or the attempt to color only the left brace
%    fails always.
%
%    Using \cs{textcolor} in formulas appears to work on first glance,
%    but it produces spacing problems that are not easy to overcome
%    either, because it generates a single \cs{mathord} and no
%    longer reflects its input, thus
%    \verb/\[ a = b \textcolor{red}{\neq} c \]/
%    produces
%  \[ a = b \textcolor{red}{\neq} c \]
%    This is a case one could mend by wrapping the
%    \cs{textcolor} and its arguments in a \cs{mathrel}, but even when
%    that is possible, the resulting formula source is difficult to
%    maintain and in other situations the solutions are even more
%    complicated or there is no solution at all.
%
%    We therefore offer now a dedicated math coloring command named
%    \cs{mathcolor}.
%
% \begin{function}{\mathcolor}
% \begin{syntax}
%   \cs{mathcolor} \oarg{model} \Arg{color-spec} \Arg{math material}
% \end{syntax}
%    It has the same arguments as \cs{textcolor} but is intended for
%    use in formulas. The command does not generate a group and the
%    \meta{math material} retains its math atom states and it correctly
%    handles sub and superscripts that follow.
% \end{function}
%
%    The command can also be used to color a single opening or closing
%    symbol, e.g., the correct input to our earlier example is
%\begin{verbatim}
%    \[  \left\{ \frac{1}{2} \mathcolor{red}{\right\}} \]
%\end{verbatim}
%    which is how it was produced.
%
%    If you attempt to color large operators that use explicit
%    \cs{limits}, \cs{nolimits}, or \cs{displaylimits}, then these
%    limit controls need to immediately follow the operator. However,
%    \cs{mathcolor} is written in a way that it is possible write
%\begin{verbatim}
%     \[  \mathcolor{red}{\int}\limits_0^1 \textrm{ or }
%         \mathcolor{red}{\int\limits}_0^1                \]
%\end{verbatim}
%    and achieve the same effect:
%     \[  \mathcolor{red}{\int}\limits_0^1 \textrm{ or }
%         \mathcolor{red}{\int\limits}_0^1                \]
%
%
% \MaybeStop{\setlength\IndexMin{200pt}  \PrintIndex  }
%
%
% \section{The Implementation}
%
%    The code is called inside of the \pkg{color} or \pkg{xcolor}
%    packages, so \texttt{@} is already a letter, but the
%    coding here is done in the L3 programming layer, so we need to
%    activate that. But first we check if this file was loaded before,
%    e.g., when both \pkg{color} and \pkg{xcolor} are in the preamble
%    and in that case we stop immediately.
%    \begin{macrocode}
%<*code>
\ifcsname mathcolor\endcsname \endinput \fi
%    \end{macrocode}
%
%    \begin{macrocode}
\ExplSyntaxOn
%<@@=mathcolor>
%    \end{macrocode}
%
%  \begin{macro}{\g_@@_seq}
%    We need to keep our own stack of color commands, so we allocate a
%    sequence for that.
%    \begin{macrocode}
\seq_new:N \g_@@_seq
%    \end{macrocode}
%  \end{macro}
%
%
%  \begin{macro}{\mathcolor}
%    The document-level command which expects a color (if unnamed then
%    the optional argument is the model) and colors the content of the
%    second argument (like \cs{textcolor}, but without spacing
%    problems in math).
%    \begin{macrocode}
\DeclareDocumentCommand \mathcolor { o m m }
  {
%    \end{macrocode}
%    The \cs{mathcolor} is only supported in math mode because in text
%    mode it has problems scanning away a space after it, for example.
%    We therefore raise an error if it executes
%    anywhere else. The \LaTeXe{} error command is a
%    bit strangely named, because in the kernel it is only used for
%    math alphabets, but the message it gives is fine.
% \changes{v1.0b}{2022/01/28}{Restrict command to math mode}
%    \begin{macrocode}
    \mode_if_math:F { \non@alpherr {\mathcolor\space} }
%    \end{macrocode}
%    First real action is to save the current color value on a stack
%    (needed if the command is nested or contains some further color
%    changes with \cs{color} inside).
%    \begin{macrocode}
    \seq_gpush:No \g_@@_seq \current@color
%    \end{macrocode}
%    Then we switch to the new color, but we do not want to reset the
%    color after the group (which is done by \cs{color} using
%    \cs{aftergroup}\cs{reset@color}). The best solution here would be
%    if the color packages  would provide a command doing just the
%    color switching, but for now we simply undo that part by pushing
%    \cs{use_none:n} which gobbles the \cs{reset@color} added by
%    \cs{color} with \cs{aftergroup}.
%    \begin{macrocode}
    \group_insert_after:N \use_none:n
%    \end{macrocode}
%    Switching the color is also slightly suboptimal, because
%    depending on whether or not we have a \meta{model} argument, we
%    have to call \cs{color} with or without the optional argument. But
%    going low-level here is not an option as we need to support
%    different color packages and their internals are not identical.
%    \begin{macrocode}
    \IfValueTF {#1} { \color[#1]{#2} } { \color{#2} }
%    \end{macrocode}
%    Then comes the math material we want to see colored:
%    \begin{macrocode}
    #3
%    \end{macrocode}
%    After that we need to reset the color ourselves (without a group
%    that does it for us), i.e., popping the saved  color from our
%    stack, but there are some twists to that so we do this in a
%    separate command (which in fact needs to be called several times,
%    so inlining the code wouldn't be possible.
%    \begin{macrocode}
    \@@_scan_for_scripts:w
  }
%    \end{macrocode}
%  \end{macro}
%
%
%
%  \begin{macro}{\@@_scan_for_scripts:w}
%    The complication when changing the color back is due to the fact
%    that the \cs{mathcolor} may be followed by \verb=^= or \verb=_=
%    or the hidden superscript \texttt{'} and its argument may end in a
%    \cs{mathop} in which case the sub and superscripts may be
%    attached as \cs{limits} instead of after the material. All cases
%    need separate treatment.
%    And we need to watch out for an upcoming \verb=&= and avoid
%    prematurely triggering the end of an alignment cell.
% \changes{v1.0c}{2022/07/25}{Avoid ending an alignment cell
%    prematurely when hitting an \texttt{\&} during
%                             scanning (gh/901)}
%    \begin{macrocode}
\cs_new_protected:Npn \@@_scan_for_scripts:w
  {
%    \end{macrocode}
%    We need to look at what follows \cs{mathcolor}, and we need to do
%    that ignoring (and dropping) any spaces and \cs{relax} as \TeX{}
%    would do in normal math processing (for example before a subscript
%    token). We do this with expansion so that hidden sub or superscripts
%    in macros are still found as long as the macros are expandable.
%    \begin{macrocode}
    \peek_remove_filler:n
      {
%    \end{macrocode}
%    To avoid problems hitting on \verb=&= we start with a
%    \cs{group_align_safe_begin:}. That has to be ended with
%    \cs{group_align_safe_end:} when the
%    danger (aka scanning) is over, which, due to the branching below, happens at
%    four different points, i.e., when the \cs{mathcolor} is
% \begin{enumerate}
% \item
%    followed by a \enquote{normal} token;
% \item
%    followed by a braced sub/superscript;
% \item
%    followed by an unbraced sub/superscript;
% \item
%    followed by one of the \cs{limits} primitives.
% \end{enumerate}
%    In each case we have to end the align safe group and we mark the
%    points below in the code for easy reference.
%    \begin{macrocode}
        \group_align_safe_begin:
%    \end{macrocode}
%    We first parse for \cs{c_math_subscript_token} or
%    \cs{c_math_superscript_token}.
%    After \cs{peek_remove_filler:n} is done, it sets \cs{l_peek_token}
%    equal to the next non-filler token, so we can avoid unnecessary
%    work and just compare that.  If either of the tokens is found, call
%    \cs{@@_handle_scripts:Nw}:
%    \begin{macrocode}
        \token_case_catcode:NnTF \l_peek_token
          {
            \c_math_subscript_token { }
            \c_math_superscript_token { }
          }
          { \@@_handle_scripts:Nw }
%    \end{macrocode}
%    Otherwise we check if it was any of the limit operation
%    primitives. If that is the case, e.g., if we have a situation
%    such as
%\begin{verbatim}
%    \mathcolor{red}{\int}\limits_1
%\end{verbatim}
%    we have to move it directly after the \cs{int} to ensure there
%    is no color reset between the operator and the \cs{limits} command.
%    \begin{macrocode}
          {
            \token_case_meaning:NnTF \l_peek_token
              {
                \limits   { \limits }
                \nolimits { \nolimits }
                \displaylimits { \displaylimits }
              }
%    \end{macrocode}
%    Once that is done, we have to get rid of the token we peeked at
%    and then restart scanning for sub or superscripts. Given that
%    \cs{@@_scan_for_scripts:w} expands while scanning the simplest
%    solution is to add \cs{use_none:n} in front of the peeked at
%    token.
%
%    Here we end the align safe group and
%    \cs{@@_scan_for_scripts:w} will start a new one.
%    \begin{macrocode}
              {
                \group_align_safe_end:                          % case 4
                \@@_scan_for_scripts:w \use_none:n
              }
%    \end{macrocode}
%    If it was not one of these we look for a \texttt{'} and if found remove it and
%    replace it by its expansion. The reason we have to do this (and
%    not rely on the earlier peeking to expand for us is the fact
%    that \texttt{'} is only ``math active'' and that doesn't expand
%    under \cs{expanded} or \cs{expandafter}.
%    \begin{macrocode}
              {
                \token_if_eq_meaning:NNTF \l_peek_token '
                  {
                    \@@_handle_scripts:Nw ^
                    \c_group_begin_token
                      \exp_after:wN \prim@s \use_none:n
                  }
%    \end{macrocode}
%    If it is anything else we finish off which means we reset the
%    color (because we prevented that before to happen automatically
%    after the next group) and pop the color stack setting \cs{current@color}.
%    \begin{macrocode}
                  {
                    \group_align_safe_end:                      % case 1
                    \reset@color
                    \seq_gpop:NN \g_@@_seq \current@color
                  }
              }
          }
      }
  }
%    \end{macrocode}
%  \end{macro}
%
%
%  \begin{macro}{\@@_handle_scripts:Nw}
%    The tricky part of handling sub and superscripts is that we have
%    to reset color to the one that is on the stack but reset it back
%    to what it was before to allow for cases like
%\begin{verbatim}
%    \[  \mathcolor{red}{a+\sum}_{i=1}^n  \]
%\end{verbatim}
%    Here, \TeX{} constructs a \cs{vbox} stacking subscript, summation
%    sign, and superscript. So technically the superscript comes first
%    and the \cs{sum} that should get colored red is the middle.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_handle_scripts:Nw #1
  {
%    \end{macrocode}
%    The argument is either \verb=^= or \verb=_=, so we execute it and
%    explicitly open two \verb={= groups. We need two because color
%    resets are always done after a group, so the first group is for
%    script material (in case it was just something like \verb=_i=)
%    and the second is needed for the color reset to keep it within
%    the super or subscript. If that reset would happen after it then
%    the color \cs{special} would interfere with \TeX{} math spacing.
%    \begin{macrocode}
    #1 \c_group_begin_token \c_group_begin_token
%    \end{macrocode}
%    Now it is time to change the color back to the one on the stack.
%    \begin{macrocode}
    \seq_get:NN \g_@@_seq \current@color
    \set@color
%    \end{macrocode}
%    \cs{set@color} adds \cs{aftergroup}\cs{reset@color}. We now a add
%    bit more so that the code executed after the current (inner) group
%    looks like this:
%\begin{verbatim}
%      \reset@color } \@@_scan_for_scripts:w
%\end{verbatim}
%    The \cs{@@_scan_for_scripts:w} then retakes control and initiates
%    parsing for another sub or superscript.
%    \begin{macrocode}
    \group_insert_after:N \c_group_end_token
    \group_insert_after:N \@@_scan_for_scripts:w
%    \end{macrocode}
%    Before we give control to \TeX{} to process the sub or
%    superscript some final adjustment is necessary: if the input was
%    \verb=^{...}= then we have one \verb={= too many, because we
%    already supplied the outer one already. In that case we drop
%    it. Otherwise we have an unbraced single token sub or superscript
%    which means we are missing a closing \verb=}= at the end and need
%    to account for that: this is done in false branch by 
%    \cs{use_ii_i:nn}.
%
%    After scanning for a brace all scanning is done, so here are the
%    other two points where we have to end the align safe group (in
%    the true and false case).
%    \begin{macrocode}
    \peek_remove_filler:n
      {
        \token_if_eq_meaning:NNTF \l_peek_token \c_group_begin_token
          {
            \group_align_safe_end:                              % case 2
            \peek_catcode_remove:NT \c_group_begin_token { }
          }
          {
            \exp_after:wN \group_align_safe_end:                % case 3
              \use_ii_i:nn \c_group_end_token
          }
      }
  }
%    \end{macrocode}
%  \end{macro}
%
%    \begin{macrocode}
%<@@=>
%    \end{macrocode}
%
%    \begin{macrocode}
\ExplSyntaxOff
%</code>
%    \end{macrocode}
%
% \Finale
%
%
%%%%%%%%%%%%%%%%
\endinput
%%%%%%%%%%%%%%%%