diff options
Diffstat (limited to 'macros/latex/contrib/l3kernel/l3color.dtx')
-rw-r--r-- | macros/latex/contrib/l3kernel/l3color.dtx | 224 |
1 files changed, 219 insertions, 5 deletions
diff --git a/macros/latex/contrib/l3kernel/l3color.dtx b/macros/latex/contrib/l3kernel/l3color.dtx index cdd2f31ac6..afef4571cd 100644 --- a/macros/latex/contrib/l3kernel/l3color.dtx +++ b/macros/latex/contrib/l3kernel/l3color.dtx @@ -43,7 +43,7 @@ % }^^A % } % -% \date{Released 2022-01-21} +% \date{Released 2022-02-05} % % \maketitle % @@ -304,6 +304,31 @@ % When using \texttt{dvips}, this PostScript variables hold the stroke color. % \end{variable} % +% \subsection{Coloring math mode material} +% +% Coloring math mode material using \cs{color_select:nn(n)} has some restrictions +% and often leads to spacing issues and/or poor input syntax. Avoiding generating +% \tn{mathord} atoms whilst coloring only those parts of the input which are +% required needs careful handling. The functionality here covers this important +% use case. +% +% \begin{function}[added = 2022-01-26]{\color_math:nn, \color_math:nnn} +% \begin{syntax} +% \cs{color_math:nn} \Arg{color expression}\Arg{content} +% \cs{color_math:nnn} \Arg{model(s)} \Arg{value(s)} \Arg{content} +% \end{syntax} +% Works as for \cs{color_select:n(n)} but applies color only to the math mode +% \meta{content}. The function does not generate a group and the \meta{content} +% therefore retains its math atom states. Sub/superscripts are also properly +% handled. +% \end{function} +% +% \begin{variable}[added = 2022-01-26]{\l_color_math_active_tl} +% This list controls which tokens are considered as math active and +% should therefore be replaced by their definition during searching for +% sub/superscripts. +% \end{variable} +% % \section{Multiple color models} % % When selecting or setting a color with an explicit model, it is possible @@ -534,19 +559,21 @@ % \end{macrocode} % \end{variable} % -% \begin{macro}{\@@_select:N} +% \begin{macro}{\@@_select:N, \@@_select_math:N} % \begin{macro}{\@@_select:nn} % Take an internal color specification and pass it to the driver. This code % is needed to ensure the current color but will also be used by the % higher-level material. % \begin{macrocode} \cs_new_protected:Npn \@@_select:N #1 - { \exp_after:wN \@@_select:nn #1 } -\cs_new_protected:Npn \@@_select:nn #1#2 { - \use:c { @@_backend_select_ #1 :n } {#2} + \exp_after:wN \@@_select:nn #1 \group_insert_after:N \@@_backend_reset: } +\cs_new_protected:Npn \@@_select_math:N #1 + { \exp_after:wN \@@_select:nn #1 } +\cs_new_protected:Npn \@@_select:nn #1#2 + { \use:c { @@_backend_select_ #1 :n } {#2} } % \end{macrocode} % \end{macro} % \end{macro} @@ -1357,6 +1384,193 @@ % \end{macro} % \end{macro} % +% \subsection{Math color} +% +% The approach here is the same as for the \LaTeXe{} \cs{mathcolor} command, +% but as we are working at the \pkg{expl3} level we can make some minor +% changes. +% +% \begin{macro}{\l_color_math_active_tl} +% Tokens representing active sub/superscripts. +% \begin{macrocode} +\tl_new:N \l_color_math_active_tl +\tl_set:Nn \l_color_math_active_tl { ' } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\g_@@_math_seq} +% Not all engines have multiple color stacks, and at the same time we are +% not expecting breaking within a colored math fragment. So we track the +% color stack ourselves. +% \begin{macrocode} +\seq_new:N \g_@@_math_seq +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\color_math:nn} +% \begin{macro}{\color_math:nnn} +% \begin{macro}{\@@_math:nn} +% The basic set up here is relatively simple: store the current color, +% parse the new color as-normal, then switch color before inserting the +% tokens we are asked to change. The tricky part is right at the end, +% handling the reset. +% \begin{macrocode} +\cs_new_protected:Npn \color_math:nn #1#2 + { + \@@_math:nn {#2} + { \@@_parse:nN {#1} \l_@@_current_tl } + } +\cs_new_protected:Npn \color_math:nnn #1#2#3 + { + \@@_math:nn {#3} + { + \@@_select_main:Nw \l_@@_current_tl + #1 / / \s_@@_mark #2 / / \s_@@_stop + } + } +\cs_new_protected:Npn \@@_math:nn #1#2 + { + \seq_gpush:NV \g_@@_math_seq \l_@@_current_tl + #2 + \@@_select_math:N \l_@@_current_tl + #1 + \@@_math_scan:w + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro} +% { +% \@@_math_scan:w , +% \@@_math_scan_auxi: , +% \@@_math_scan_auxii: , +% \@@_math_scan_end: +% } +% The complication when changing the color back is due to the fact +% that the \cs{color_math:nn(n)} may be followed by \verb=^= or \verb=_= +% or the hidden superscript (for example \texttt{'}) and its argument may +% end in a \tn{mathop} in which case the sub- and superscripts may be +% attached as \cs{limits} instead of after the material. All cases +% need separate treatment. To avoid repeatedly collecting the same +% token, we first check for an alignment tab: assuming we don't have +% one of those, we can \enquote{recycle} \cs{l_peek_token} safely. +% \begin{macrocode} +\cs_new_protected:Npn \@@_math_scan:w + { + \peek_remove_filler:n + { + \peek_catcode:NTF \c_alignment_token + { \@@_math_scan_end: } + { \@@_math_scan_auxi: } + } + } +% \end{macrocode} +% Dealing with literal |_| and |^| is easy, and as we have exactly two cases, +% we can hard-code this. We use a hard-coded list for limits: these are all +% primitives. The \cs{use_none:n} herealso removes the test token so it is +% left just in the right place. +% \begin{macrocode} +\cs_new_protected:Npn \@@_math_scan_auxi: + { + \token_case_meaning:NnTF \l_peek_token + { + \c_math_subscript_token { } + \c_math_superscript_token { } + } + { \@@_math_scripts:Nw } + { + \token_case_meaning:NnTF \l_peek_token + { + \tex_limits:D { \tex_limits:D } + \tex_nolimits:D { \tex_nolimits:D } + \tex_displaylimits:D { \tex_displaylimits:D } + } + { \@@_math_scan:w \use_none:n } + { \@@_math_scan_auxii: } + } + } +% \end{macrocode} +% The one final case to handle is math-active tokens, most obviously +% \texttt{'}, as these won't be covered earlier. +% \begin{macrocode} +\cs_new_protected:Npn \@@_math_scan_auxii: + { + \tl_map_inline:Nn \l_color_math_active_tl + { + \token_if_eq_meaning:NNT \l_peek_token ##1 + { + \tl_map_break:n + { + \use_i:nn + { \@@_math_scan_auxiii:N ##1 } + } + } + \@@_math_scan_end: + } + } +\cs_new_protected:Npn \@@_math_scan_auxiii:N #1 + { + \exp_after:wN \exp_after:wN \exp_after:wN \@@_math_scan:w + \char_generate:nn { `#1 } { 13 } + } +\cs_new_protected:Npn \@@_math_scan_end: + { + \@@_backend_reset: + \seq_gpop:NN \g_@@_math_seq \l_@@_current_tl + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\@@_math_scripts:Nw} +% \begin{macro}{\@@_math_script_aux:N} +% 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} +% \[ \color_math:n { 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. +% +% The approach here is to set up a brace group immediately after the +% script token, then to set the color appropriately in that argument. +% We need an extra group to keep the color contained, and as we +% need to allow for an explicit closing brace in the source, the +% inner group also is a brace one rather than \cs{group_begin:}-based. +% At the end of the outer group we need to insert \cs{@@_math_scan:w} +% to continue the search for a second script token. +% +% Notice that here we \emph{don't} need to use the math-specific +% color selector as we can allow the +% |\group_insert_after:N \@@_backend_reset:| to operate normally. +% \begin{macrocode} +\cs_new_protected:Npn \@@_math_scripts:Nw #1 + { + #1 + \c_group_begin_token + \c_group_begin_token + \seq_get:NN \g_@@_math_seq \l_@@_current_tl + \@@_select:N \l_@@_current_tl + \group_insert_after:N \c_group_end_token + \group_insert_after:N \@@_math_scan:w + \peek_remove_filler:n + { + \peek_catcode_remove:NF \c_group_begin_token + { \@@_math_script_aux:N } + } + } +% \end{macrocode} +% Deal with the case where we do not have an explicit brace pair in the +% source. +% \begin{macrocode} +\cs_new_protected:Npn \@@_math_script_aux:N #1 { #1 \c_group_end_token } +% \end{macrocode} +% \end{macro} +% \end{macro} +% % \subsection{Fill and stroke color} % % \begin{macro}{\color_fill:n, \color_stroke:n} |