diff options
author | Norbert Preining <norbert@preining.info> | 2022-11-02 03:09:43 +0000 |
---|---|---|
committer | Norbert Preining <norbert@preining.info> | 2022-11-02 03:09:43 +0000 |
commit | 2281af8ba8fd52341e706f3979712f3280fcfdad (patch) | |
tree | 5e83a2779b732f03b430cf208b732ce611ee2cff /macros/latex/base/ltcmd.dtx | |
parent | 7ad25021e74ea26e33d705fbb402d29aabaf6314 (diff) |
CTAN sync 202211020309
Diffstat (limited to 'macros/latex/base/ltcmd.dtx')
-rw-r--r-- | macros/latex/base/ltcmd.dtx | 386 |
1 files changed, 339 insertions, 47 deletions
diff --git a/macros/latex/base/ltcmd.dtx b/macros/latex/base/ltcmd.dtx index 59aa5bf475..14d6756f5c 100644 --- a/macros/latex/base/ltcmd.dtx +++ b/macros/latex/base/ltcmd.dtx @@ -34,8 +34,8 @@ %%% From File: ltcmd.dtx % % \begin{macrocode} -\def\ltcmdversion{v1.0l} -\def\ltcmddate{2022-03-18} +\def\ltcmdversion{v1.1a} +\def\ltcmddate{2022-08-16} % \end{macrocode} % %<*driver> @@ -247,6 +247,15 @@ % \end{macrocode} % \end{variable} % +% \begin{variable}{\l_@@_suppress_strip_bool} +% \changes{v1.1a}{2022/08/10}{New switch} +% Used to indicate that an a pair of braces should not be stripped from +% an optional argument. +% \begin{macrocode} +\bool_new:N \l_@@_suppress_strip_bool +% \end{macrocode} +% \end{variable} +% % \begin{variable}{\l_@@_m_args_int} % The number of \texttt{m} arguments: if this is the same as the total % number of arguments, then a short-cut can be taken in the creation of @@ -315,6 +324,19 @@ % \end{macrocode} % \end{variable} % +% \begin{variable}{\q_@@_recursion_tail,\q_@@_recursion_stop} +% \begin{macro}{\@@_if_recursion_tail_stop_do:Nn} +% \begin{macro}{\@@_use_i_delimit_by_q_recursion_stop:nw} +% Quarks and functions for internal processing. +% \begin{macrocode} +\quark_new:N \q_@@_recursion_tail +\quark_new:N \q_@@_recursion_stop +\__kernel_quark_new_test:N \@@_if_recursion_tail_stop_do:Nn +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{variable} +% % \begin{variable}{\l_@@_tmp_prop, \l_@@_tmpa_tl, \l_@@_tmpb_tl} % \begin{macro}{\@@_tmp:w} % Scratch space. @@ -874,7 +896,7 @@ % \item Check that each argument has the correct number of data items % associated with it, and that where a single character is required, % one has actually been supplied. -% \item Check that processors and the markers~|+| and~|!| are followed +% \item Check that processors and the markers~|+|, |!| and~|=| are followed % by an argument for which they make sense, and are not redundant. % \item Check the absence of forbidden types for expandable commands, % namely \texttt{G}/\texttt{v} always, and \texttt{l}/\texttt{u} @@ -918,6 +940,7 @@ \bool_set_true:N \l_@@_grab_expandably_bool \bool_set_false:N \l_@@_obey_spaces_bool \bool_set_false:N \l_@@_long_bool + \bool_set_false:N \l_@@_suppress_strip_bool \bool_set_false:N \l_@@_some_obey_spaces_bool \bool_set_false:N \l_@@_some_long_bool \bool_set_false:N \l_@@_some_short_bool @@ -1020,7 +1043,11 @@ % \@@_normalize_type_>:w, % \@@_normalize_type_+:w, % \@@_normalize_type_!:w, +% \@@_normalize_type_=:w % } +% \changes{v1.1a}{2022/08/10}{Refactor to use common auxiliary} +% \changes{v1.1a}{2022/08/10}{Add support for \texttt{=} modifier} +% \begin{macro}{\@@_normalize_type_aux:NnNn} % Check that these prefixes have arguments, namely that the next token % is not \cs{q_recursion_tail}, and remember to leave it after the % looping macro. Processors are forbidden in expandable commands. @@ -1044,33 +1071,52 @@ } \cs_new_protected:cpn { @@_normalize_type_+:w } #1 { - \quark_if_recursion_tail_stop_do:nn {#1} { \@@_bad_arg_spec:wn } - \bool_if:NT \l_@@_long_bool + \@@_normalize_type_aux:NnNn + {#1} + \l_@@_long_bool + { \bool_set_true:N \l_@@_long_bool } + } +\cs_new_protected:cpn { @@_normalize_type_!:w } #1 + { + \@@_normalize_type_aux:NnNn ! {#1} + \l_@@_obey_spaces_bool { - \msg_error:nnxx { cmd } { two-markers } - { \@@_environment_or_command: } { + } - \@@_bad_def:wn + \bool_set_true:N \l_@@_obey_spaces_bool + \bool_set_true:N \l_@@_some_obey_spaces_bool } - \bool_set_true:N \l_@@_long_bool - \int_decr:N \l_@@_current_arg_int - \@@_normalize_arg_spec_loop:n {#1} } -\cs_new_protected:cpn { @@_normalize_type_!:w } #1 +\cs_new_protected:cpn { @@_normalize_type_=:w } #1#2 + { + \@@_normalize_type_aux:NnNn = {#2} + \l_@@_suppress_strip_bool + { + \bool_if:NT \l_@@_expandable_bool + { + \msg_error:nnxx { cmd } { keyval-in-expandable } + { \iow_char:N \\ \l_@@_function_tl } { \tl_to_str:n {#1} } + \@@_bad_def:wn + } + \bool_set_true:N \l_@@_suppress_strip_bool + \bool_set_false:N \l_@@_grab_expandably_bool + \tl_put_right:Nx \l_@@_arg_spec_tl + { = { \tl_trim_spaces:n {#1} } } + } + } +\cs_new_protected:Npn \@@_normalize_type_aux:NnNn #1#2#3#4 { - \quark_if_recursion_tail_stop_do:nn {#1} { \@@_bad_arg_spec:wn } - \bool_if:NT \l_@@_obey_spaces_bool + \quark_if_recursion_tail_stop_do:nn {#2} { \@@_bad_arg_spec:wn } + \bool_if:NT #3 { \msg_error:nnxx { cmd } { two-markers } - { \@@_environment_or_command: } { ! } + { \@@_environment_or_command: } { #1 } \@@_bad_def:wn } - \bool_set_true:N \l_@@_obey_spaces_bool - \bool_set_true:N \l_@@_some_obey_spaces_bool + #4 \int_decr:N \l_@@_current_arg_int - \@@_normalize_arg_spec_loop:n {#1} + \@@_normalize_arg_spec_loop:n {#2} } % \end{macrocode} % \end{macro} +% \end{macro} % % \begin{macro} % { @@ -1224,12 +1270,12 @@ % \end{macro} % % \begin{macro}{\@@_allowed_token_check:N} -% Some tokens are now allowed as delimiters for some argument types, +% Some tokens are not allowed as delimiters for some argument types, % notably implicit begin/end-group tokens (|\bgroup|/|\egroup|). % The major problem with these tokens is that for |\peek_...| functions, -% a literal~|{|$_1$. is virtually indistinguishable from a |\bgroup| or +% a literal~|{|$_1$ is virtually indistinguishable from a |\bgroup| or % other token which was |\let| to a~|{|$_1$, and the same goes -% for~|}|$_2$. All other tokens can be easily distingushed from their +% for~|}|$_2$. All other tokens can be easily distinguished from their % implicit counterparts by grabbing them and looking at the string % length (see \cs{@@_token_if_cs:NTF}), but for begin/end group tokens % that is not possible without the risk of mistakenly grabbing the @@ -1324,13 +1370,13 @@ % \begin{macro}{\@@_add_arg_spec:n, \@@_add_arg_spec_mandatory:n} % When adding an argument to the argument specification, set the % \texttt{some_long} or \texttt{some_short} booleans as appropriate -% and clear the booleans keeping track of |+| and |!| markers. +% and clear the booleans keeping track of |+|, |!| and |=| markers. % Before that, test for a short argument following some long % arguments: this is forbidden for expandable commands and prevents % grabbing arguments expandably. % % For mandatory arguments do some more work, in particular complain if -% they were preceeded by~|!|. +% they were preceded by~|!|. % \begin{macrocode} \cs_new_protected:Npn \@@_add_arg_spec:n #1 { @@ -1387,6 +1433,7 @@ \int_zero:N \l_@@_current_arg_int \bool_set_false:N \l_@@_long_bool \bool_set_false:N \l_@@_obey_spaces_bool + \bool_set_false:N \l_@@_suppress_strip_bool \int_zero:N \l_@@_m_args_int \bool_set_false:N \l_@@_defaults_bool \tl_clear:N \l_@@_defaults_tl @@ -1484,6 +1531,23 @@ % \end{macrocode} % \end{macro} % +% \begin{macro}{\@@_add_type_=:} +% \changes{v1.1a}{2022/08/10}{Add support for \texttt{=} modifier} +% A mix of the ideas from above: set a flag and add a processor. +% \begin{macrocode} +\cs_new_protected:cpn { @@_add_type_=:w } #1 + { + \@@_flush_m_args: + \bool_set_true:N \l_@@_prefixed_bool + \bool_set_true:N \l_@@_suppress_strip_bool + \bool_set_true:N \l_@@_process_some_bool + \tl_put_left:Nn \l_@@_process_one_tl + { { \@@_arg_to_keyvalue:nn {#1} } } + \@@_prepare_signature_bypass:N + } +% \end{macrocode} +% \end{macro} +% % \begin{macro}{\@@_add_type_b:w} % \begin{macrocode} \cs_new_protected:Npn \@@_add_type_b:w @@ -1677,11 +1741,16 @@ @@_grab_ #1 \bool_if:NT \l_@@_long_bool { _long } \bool_if:NT \l_@@_obey_spaces_bool { _obey_spaces } + \bool_lazy_and:nnT + { \l_@@_suppress_strip_bool } + { \str_if_eq_p:nn {#1} { D } } + { _no_strip } :w } } \bool_set_false:N \l_@@_long_bool \bool_set_false:N \l_@@_obey_spaces_bool + \bool_set_false:N \l_@@_suppress_strip_bool \tl_put_right:Nx \l_@@_process_all_tl { { @@ -2488,7 +2557,7 @@ \quark_if_nil:nF {#1} { \tl_const:cn { c_@@_show_type_#1_tl } {#2} \@@_tmp:w } } -\@@_tmp:w t0 r1 d1 R2 D2 O3 e4 E5 +6 !6 >7 \q_nil \q_nil +\@@_tmp:w t0 r1 d1 R2 D2 O3 e4 E5 +6 !6 >7 =7 \q_nil \q_nil % \end{macrocode} % % \begin{macro}{ @@ -2615,6 +2684,7 @@ % \@@_grab_b_aux:NNw, % \@@_grab_b_end:Nw % } +% \changes{v1.1a}{2022/08/10}{Track changes in \texttt{D}-type implementation} % This uses the well-tested code of \texttt{D}-type arguments, % skipping the peeking step because the \texttt{b}-type argument is % always present, and adding a cleanup stage at the end by hijacking @@ -2640,7 +2710,7 @@ { \@@_grab_b_aux:NNw \cs_set_protected:Npn \exp_not:n } \cs_new_protected:Npn \@@_grab_b_aux:NNw #1#2#3 \@@_run_code: { - \@@_grab_D_aux:NNnN \begin \end {#3} #1 + \@@_grab_D_aux:NNnNN \begin \end {#3} #1 \use_ii:nn \tl_put_left:Nn \l_@@_signature_tl { \@@_grab_b_end:Nw #2 } \tl_set_eq:NN \l_@@_saved_args_tl \l_@@_args_tl \tl_clear:N \l_@@_args_tl @@ -2660,37 +2730,69 @@ % \end{macrocode} % \end{macro} % -% \begin{macro}{\@@_grab_D:w} -% \begin{macro}{\@@_grab_D_long:w} -% \begin{macro}{\@@_grab_D_obey_spaces:w} -% \begin{macro}{\@@_grab_D_long_obey_spaces:w} +% \begin{macro} +% { +% \@@_grab_D:w , +% \@@_grab_D_long:w , +% \@@_grab_D_obey_spaces:w , +% \@@_grab_D_long_obey_spaces:w , +% \@@_grab_D_no_strip:w , +% \@@_grab_D_long_no_strip:w , +% \@@_grab_D_obey_spaces_no_strip:w , +% \@@_grab_D_long_obey_spaces_no_strip:w +% } +% \changes{v1.1a}{2022/08/10}{Add support for skipping brace stripping} % The generic delimited argument grabber. The auxiliary function does % a peek test before calling \cs{@@_grab_D_call:Nw}, so that the % optional nature of the argument works as expected. % \begin{macrocode} \cs_new_protected:Npn \@@_grab_D:w #1#2#3 \@@_run_code: { - \@@_grab_D_aux:NNnNN #1 #2 {#3} \cs_set_protected_nopar:Npn - \@@_peek_nonspace_remove:NTF + \@@_grab_D_aux:NNnNNN #1 #2 {#3} \cs_set_protected_nopar:Npn + \@@_peek_nonspace_remove:NTF \use_ii:nn } \cs_new_protected:Npn \@@_grab_D_long:w #1#2#3 \@@_run_code: { - \@@_grab_D_aux:NNnNN #1 #2 {#3} \cs_set_protected:Npn - \@@_peek_nonspace_remove:NTF + \@@_grab_D_aux:NNnNNN #1 #2 {#3} \cs_set_protected:Npn + \@@_peek_nonspace_remove:NTF \use_ii:nn } \cs_new_protected:Npn \@@_grab_D_obey_spaces:w #1#2#3 \@@_run_code: { - \@@_grab_D_aux:NNnNN #1 #2 {#3} \cs_set_protected_nopar:Npn - \@@_peek_meaning_remove:NTF + \@@_grab_D_aux:NNnNNN #1 #2 {#3} \cs_set_protected_nopar:Npn + \@@_peek_meaning_remove:NTF \use_ii:nn } \cs_new_protected:Npn \@@_grab_D_long_obey_spaces:w #1#2#3 \@@_run_code: { - \@@_grab_D_aux:NNnNN #1 #2 {#3} \cs_set_protected:Npn - \@@_peek_meaning_remove:NTF + \@@_grab_D_aux:NNnNNN #1 #2 {#3} \cs_set_protected:Npn + \@@_peek_meaning_remove:NTF \use_ii:nn + } +\cs_new_protected:Npn \@@_grab_D_no_strip:w + #1#2#3 \@@_run_code: + { + \@@_grab_D_aux:NNnNNN #1 #2 {#3} \cs_set_protected_nopar:Npn + \@@_peek_nonspace_remove:NTF \use_none:n + } +\cs_new_protected:Npn \@@_grab_D_long_no_strip:w + #1#2#3 \@@_run_code: + { + \@@_grab_D_aux:NNnNNN #1 #2 {#3} \cs_set_protected:Npn + \@@_peek_nonspace_remove:NTF \use_none:n + } +\cs_new_protected:Npn \@@_grab_D_obey_spaces_no_strip:w + #1#2#3 \@@_run_code: + { + \@@_grab_D_aux:NNnNNN #1 #2 {#3} \cs_set_protected_nopar:Npn + \@@_peek_meaning_remove:NTF \use_none:n + } +\cs_new_protected:Npn \@@_grab_D_long_obey_spaces_no_strip:w + #1#2#3 \@@_run_code: + { + \@@_grab_D_aux:NNnNNN #1 #2 {#3} \cs_set_protected:Npn + \@@_peek_meaning_remove:NTF \use_none:n } % \end{macrocode} +% \begin{macro}{\@@_grab_D_aux:NNnNNN} % \begin{macro}{\@@_grab_D_aux:NNnNN} -% \begin{macro}{\@@_grab_D_aux:NNnN} % This is a bit complicated. The idea is that, in order to check for % nested optional argument tokens (\texttt{[[...]]} and so on) the % argument needs to be grabbed without removing any braces at all. If @@ -2699,9 +2801,9 @@ % prevents loss of braces, and there is then a test to see if there are % nested delimiters to handle. % \begin{macrocode} -\cs_new_protected:Npn \@@_grab_D_aux:NNnNN #1#2#3#4#5 +\cs_new_protected:Npn \@@_grab_D_aux:NNnNNN #1#2#3#4#5#6 { - \@@_grab_D_aux:NNnN #1#2 {#3} #4 + \@@_grab_D_aux:NNnNN #1#2 {#3} #4 #6 #5 #1 { \@@_grab_D_call:Nw #1 } { \@@_add_arg:o \c_novalue_tl } @@ -2712,9 +2814,10 @@ % extra factors to allow for: the argument might be entirely empty, and % spaces at the start and end of the input must be retained around a brace % group. Also notice that a \emph{blank} argument might still contain -% spaces. +% spaces. To allow for suppression of brace stripping, the business end +% is passed here as |#5|. % \begin{macrocode} -\cs_new_protected:Npn \@@_grab_D_aux:NNnN #1#2#3#4 +\cs_new_protected:Npn \@@_grab_D_aux:NNnNN #1#2#3#4#5 { \tl_set:Nn \l_@@_signature_tl {#3} \exp_after:wN #4 \l_@@_fn_tl ##1 #2 @@ -2728,7 +2831,7 @@ \str_if_eq:eeTF { \exp_not:o { \use_none:n ##1 } } { { \exp_not:o { \use_ii:nnn ##1 \q_nil } } } - { \@@_add_arg:o { \use_ii:nn ##1 } } + { \@@_add_arg:o { #5 ##1 } } { \@@_add_arg:o { \use_none:n ##1 } } } } @@ -2738,9 +2841,6 @@ % \end{macro} % \end{macro} % \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} % % \begin{macro}{\@@_grab_D_nested:NNnN} % \begin{macro}{\@@_grab_D_nested:w} @@ -3039,6 +3139,7 @@ % % \begin{macro}{\@@_grab_R:w, \@@_grab_R_long:w} % \begin{macro}{\@@_grab_R_aux:NNnN} +% \changes{v1.1a}{2022/08/10}{Track changes in \texttt{D}-type implementation} % The grabber for \texttt{R}-type arguments is basically the same as % that for \texttt{D}-type ones, but always skips spaces (as it is mandatory) % and has a hard-coded error message. @@ -3049,7 +3150,7 @@ { \@@_grab_R_aux:NNnN #1 #2 {#3} \cs_set_protected:Npn } \cs_new_protected:Npn \@@_grab_R_aux:NNnN #1#2#3#4 { - \@@_grab_D_aux:NNnN #1 #2 {#3} #4 + \@@_grab_D_aux:NNnNN #1 #2 {#3} #4 \use_ii:nn \@@_peek_nonspace_remove:NTF #1 { \@@_grab_D_call:Nw #1 } { @@ -3873,6 +3974,190 @@ % \end{macrocode} % \end{macro} % +% \subsection{Conversion to key--value form} +% +% This is implemented as a process but with no public interfaces, +% hence is treated separately from the others: it's a feature of +% \pkg{ltcmd} which just happens to use the same mechanism as a processor. +% +% \begin{macro}{\@@_arg_to_keyvalue:nn} +% \changes{v1.1a}{2022/08/10}{New internal arg-to-keyval processor} +% \begin{macro}{\@@_arg_to_keyvalue_braces:nnn} +% \begin{macro}{\@@_arg_to_keyvalue_auxi:nnn} +% \begin{macro}{\@@_arg_to_keyvalue_auxii:Nnnn} +% \begin{macro}{\@@_arg_to_keyvalue_auxiii:nnn} +% \begin{macro}{\@@_arg_to_keyvalue_auxiv:Nnnn} +% \begin{macro}{\@@_arg_to_keyvalue_auxv:nn} +% \begin{macro}{\@@_arg_to_keyvalue_loop:w} +% \begin{macro}{\@@_arg_to_keyvalue_loop_group:n} +% \begin{macro}{\@@_arg_to_keyvalue_loop_space:w} +% \begin{macro}{\@@_arg_to_keyvalue_loop_N_type:N} +% \begin{macro}{\@@_arg_to_keyvalue_math:w} +% \begin{macro}{\@@_arg_to_keyvalue_math_N_type:N} +% \begin{macro}{\@@_arg_to_keyvalue_math_group:n} +% \begin{macro}{\@@_arg_to_keyvalue_math_space:w} +% \begin{macro}{\@@_arg_to_keyvalue_set_default:nn} +% \begin{macro}{\@@_arg_to_keyvalue_set_keyvalue:nn} +% \begin{macro}[EXP]{\@@_split_N_head_apply:Nn} +% \begin{macro}[EXP]{\@@_split_N_head_apply_aux:NNw} +% If the entire argument is braced, we treat as free text and return as +% the value for the text key. Alternatively, if the start of the input is +% |=,| then it is forced to be key--value. To avoid needing to worry about +% catcodes for this, and to allow spaces around the |=|, we use a +% series of steps rather than a delimited argument. +% \begin{macrocode} +\cs_new_protected:Npn \@@_arg_to_keyvalue:nn #1#2 + { + \tl_trim_spaces_apply:nN {#2} \@@_arg_to_keyvalue_braces:nnn + {#1} {#2} + } +\cs_new_protected:Npn \@@_arg_to_keyvalue_braces:nnn #1#2#3 + { + \tl_if_head_is_group:nT {#1} + { + \tl_if_blank:oT { \use_none:n #1 } + { + \tl_set:Nx \ProcessedArgument { #2 = { \exp_not:n #1 } } + \use_none:nnnn + } + } + \@@_arg_to_keyvalue_auxi:nnn {#1} {#2} {#3} + } +\cs_new:Npn \@@_arg_to_keyvalue_auxi:nnn #1 + { + \tl_if_head_is_N_type:nTF {#1} + { \@@_split_N_head_apply:Nn \@@_arg_to_keyvalue_auxii:Nnnn {#1} } + { \@@_arg_to_keyvalue_auxv:nn } + } +\cs_new:Npn \@@_arg_to_keyvalue_auxii:Nnnn #1#2 + { + \str_if_eq:eeTF { \exp_not:n {#1} } { = } + { \tl_trim_spaces_apply:nN {#2} \@@_arg_to_keyvalue_auxiii:nnn } + { \@@_arg_to_keyvalue_auxv:nn } + } +\cs_new:Npn \@@_arg_to_keyvalue_auxiii:nnn #1 + { + \tl_if_head_is_N_type:nTF {#1} + { \@@_split_N_head_apply:Nn \@@_arg_to_keyvalue_auxiv:Nnnn {#1} } + { \@@_arg_to_keyvalue_auxv:nn } + } +\cs_new:Npn \@@_arg_to_keyvalue_auxiv:Nnnn #1#2 + { + \str_if_eq:eeTF { \exp_not:n {#1} } { , } + { \tl_set:Nn \ProcessedArgument {#2} \use_none:nn } + { \@@_arg_to_keyvalue_auxv:nn } + } +% \end{macrocode} +% The two clear-cut cases have been eliminated, and we therefore have to deal +% with a search for |=| signs. We need an \enquote{action} loop here +% so we do not get mislead by for example |{=}|. As the code here is for +% very much predictable types of input, we hard-code what constitutes +% math mode opening and closing. At the very beginning, the default +% key (|#1|) and the argument as given by the user (|#2|) are placed +% right after the \cs{q_@@_recursion_stop}, so that when the recursion +% ends, the macros \cs{@@_arg_to_keyvalue_set_default:nn} or +% \cs{@@_arg_to_keyvalue_set_keyvalue:nn} can be used to grab these +% two items and set the \cs{ProcessedArgument} accordingly. +% \begin{macrocode} +\cs_new_protected:Npn \@@_arg_to_keyvalue_auxv:nn #1#2 + { + \@@_arg_to_keyvalue_loop:w #2 + \q_@@_recursion_tail \q_@@_recursion_stop {#1} {#2} + } +\cs_new_protected:Npn \@@_arg_to_keyvalue_loop:w #1 \q_@@_recursion_stop + { + \tl_if_head_is_N_type:nTF {#1} + { \@@_arg_to_keyvalue_loop_N_type:N } + { + \tl_if_head_is_group:nTF {#1} + { \@@_arg_to_keyvalue_loop_group:n } + { \@@_arg_to_keyvalue_loop_space:w } + } + #1 \q_@@_recursion_stop + } +\cs_new_protected:Npn \@@_arg_to_keyvalue_loop_group:n #1 + { \@@_arg_to_keyvalue_loop:w } +\use:n { \cs_new_protected:Npn \@@_arg_to_keyvalue_loop_space:w } ~ + { \@@_arg_to_keyvalue_loop:w } +\cs_new_protected:Npn \@@_arg_to_keyvalue_loop_N_type:N #1 + { + \@@_if_recursion_tail_stop_do:Nn #1 + { \@@_arg_to_keyvalue_set_default:nn } + \str_if_eq:nnTF {#1} { = } + { + \@@_use_i_delimit_by_q_recursion_stop:nw + { \@@_arg_to_keyvalue_set_keyvalue:nn } + } + { + \bool_lazy_or:nnTF + { \token_if_math_toggle_p:N #1 } + { \str_if_eq_p:nn {#1} { \( } } + { \@@_arg_to_keyvalue_math:w } + { \@@_arg_to_keyvalue_loop:w } + } + } +\cs_new_protected:Npn \@@_arg_to_keyvalue_math:w #1 \q_@@_recursion_stop + { + \tl_if_head_is_N_type:nTF {#1} + { \@@_arg_to_keyvalue_math_N_type:N } + { + \tl_if_head_is_group:nTF {#1} + { \@@_arg_to_keyvalue_math_group:n } + { \@@_arg_to_keyvalue_math_space:w } + } + #1 \q_@@_recursion_stop + } +\cs_new_protected:Npn \@@_arg_to_keyvalue_math_N_type:N #1 + { + \@@_if_recursion_tail_stop_do:Nn #1 + { \@@_arg_to_keyvalue_set_default:nn } + \bool_lazy_or:nnTF + { \token_if_math_toggle_p:N #1 } + { \str_if_eq_p:nn {#1} { \) } } + { \@@_arg_to_keyvalue_loop:w } + { \@@_arg_to_keyvalue_math:w } + } +\cs_new_protected:Npn \@@_arg_to_keyvalue_math_group:n #1 + { \@@_arg_to_keyvalue_math:w } +\use:n { \cs_new_protected:Npn \@@_arg_to_keyvalue_math_space:w } ~ + { \@@_arg_to_keyvalue_math:w } +\cs_new_protected:Npn \@@_arg_to_keyvalue_set_default:nn #1#2 + { \tl_set:Nn \ProcessedArgument { #1 = {#2} } } +\cs_new_protected:Npn \@@_arg_to_keyvalue_set_keyvalue:nn #1#2 + { \tl_set:Nn \ProcessedArgument {#2} } +% \end{macrocode} +% A utility to allow us to grab the first \texttt{N}-type token without +% risking brace stripping the rest of the input. +% \begin{macrocode} +\cs_new:Npn \@@_split_N_head_apply:Nn #1#2 + { \exp:w \if_false: { \fi: \@@_split_N_head_apply_aux:NNw #1#2 } } +\cs_new:Npn \@@_split_N_head_apply_aux:NNw #1#2 + { + \exp_after:wN \exp_end: + \exp_after:wN #1 \exp_after:wN #2 \exp_after:wN { \if_false: } \fi: + } + +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% % \subsection{Access to the argument specification} % % \begin{macro}{\@@_get_arg_spec_error:N, \@@_get_arg_spec_error:n} @@ -4372,6 +4657,13 @@ This~is~only~supported~for~robust~commands,~but~not~for~expandable~ones. \c_@@_ignore_def_tl } +\msg_new:nnnn { cmd } { keyval-in-expandable } + { Invalid~argument~prefix~'='~in~command~'#1'. } + { + The~argument~specification~for~'#1'~contains~a~key--value~marker~'={#2}'.~ + This~is~only~supported~for~robust~commands,~but~not~for~expandable~ones. + \c_@@_ignore_def_tl + } \msg_new:nnnn { cmd } { too-many-args } { Too~many~arguments~for~#1. } { |