diff options
Diffstat (limited to 'Master/texmf-dist/source/latex/base/ltcmd.dtx')
-rw-r--r-- | Master/texmf-dist/source/latex/base/ltcmd.dtx | 1015 |
1 files changed, 883 insertions, 132 deletions
diff --git a/Master/texmf-dist/source/latex/base/ltcmd.dtx b/Master/texmf-dist/source/latex/base/ltcmd.dtx index 806161d5386..04be2abfbfd 100644 --- a/Master/texmf-dist/source/latex/base/ltcmd.dtx +++ b/Master/texmf-dist/source/latex/base/ltcmd.dtx @@ -34,8 +34,8 @@ %%% From File: ltcmd.dtx % % \begin{macrocode} -\def\ltcmdversion{v1.0e} -\def\ltcmddate{2021-05-24} +\def\ltcmdversion{v1.0h} +\def\ltcmddate{2021-08-30} % \end{macrocode} % %<*driver> @@ -343,8 +343,7 @@ % % \begin{macro}{\@@_declare_cmd:Nnn, \@@_declare_expandable_cmd:Nnn} % \begin{macro}{\@@_declare_cmd_aux:Nnn} -% \begin{macro} -% {\@@_declare_cmd_internal:Nnnn, \@@_declare_cmd_internal:cnxn} +% \begin{macro}{\@@_declare_cmd_internal:Nnnn} % The main functions for creating commands set the appropriate flag then % use the same internal code to do the definition. % \begin{macrocode} @@ -366,7 +365,7 @@ { \cs_if_exist:NTF #1 { - \msg_info:nnxx { cmd } { redefine-command } + \msg_info:nnxx { cmd } { redefine } { \token_to_str:N #1 } { \tl_to_str:n {#2} } } { @@ -400,7 +399,6 @@ #4 \@@_break_point:n {#2} } -\cs_generate_variant:Nn \@@_declare_cmd_internal:Nnnn { cnx } % \end{macrocode} % \end{macro} % \end{macro} @@ -536,11 +534,11 @@ { \tl_trim_spaces:o { \l_@@_environment_str } } \cs_if_exist:cTF { \l_@@_environment_str } { - \msg_info:nnxx { cmd } { redefine-environment } + \msg_info:nnxx { cmd } { redefine-env } { \l_@@_environment_str } { \tl_to_str:n {#2} } } { - \msg_info:nnxx { cmd } { define-environment } + \msg_info:nnxx { cmd } { define-env } { \l_@@_environment_str } { \tl_to_str:n {#2} } } \bool_set_false:N \l_@@_expandable_bool @@ -565,15 +563,8 @@ % \begin{macrocode} \cs_new_protected:Npn \@@_declare_env_internal:nnnn #1#2#3#4 { - \@@_declare_cmd_internal:cnxn { environment~ #1 } {#2} - { - \cs_set_nopar:Npx \exp_not:c { environment~ #1 ~end~aux } - { - \exp_not:N \exp_not:N \exp_not:c { environment~ #1~end~aux~ } - \exp_not:n { \exp_not:o \l_@@_args_tl } - } - \exp_not:n {#3} - } + \exp_args:Nc \@@_declare_cmd_internal:Nnnn { environment~ #1 } {#2} + {#3} { \cs_set_nopar:cpx { environment~ #1 ~end } { \exp_not:c { environment~ #1 ~end~aux } } @@ -584,6 +575,14 @@ \cs_set_eq:cc { end #1 } { environment~ #1 ~end } } } +\cs_new_protected:Npn \@@_set_environment_end:n #1 + { + \cs_set_nopar:cpx { environment~ #1 ~end~aux } + { + \exp_not:c { environment~ #1 ~end~aux~ } + \exp_not:o \l_@@_args_tl + } + } % \end{macrocode} % \end{macro} % \end{macro} @@ -639,7 +638,10 @@ \tl_set:Nn \l_@@_fn_code_tl {#2} \tl_set:Nn \l_@@_defaults_tl {#5} \tl_set:Nn \l_@@_process_all_tl {#6} - #4 \@@_run_code: + #4 + \bool_if:NT \l_@@_environment_bool + { \exp_args:No \@@_set_environment_end:n \l_@@_environment_str } + \@@_run_code: } \cs_generate_variant:Nn \@@_start_aux:NNnnnn { cc } % \end{macrocode} @@ -693,7 +695,7 @@ } \cs_new_protected:Npn \@@_defaults_error:w \q_recursion_stop { - \msg_error:nnx { cmd } { loop-in-defaults } + \msg_error:nnx { cmd } { default-loop } { \@@_environment_or_command: } } % \end{macrocode} @@ -821,7 +823,7 @@ \@@_end_expandable_defaults:nnnNNn {#1} { } {#1} #2#3 { } { } { } { } { } { } { } { } { } { } { - \msg_expandable_error:nnf { cmd } { loop-in-defaults } + \msg_expandable_error:nnf { cmd } { default-loop } { \exp_args:Nf \tl_trim_spaces:n { \token_to_str:N #4 } } \use_iv:nnnn } @@ -919,7 +921,7 @@ \q_recursion_tail \q_recursion_tail \q_recursion_tail \q_recursion_stop \int_compare:nNnT \l_@@_current_arg_int > 9 { - \msg_error:nnxx { cmd } { too-many-arguments } + \msg_error:nnxx { cmd } { too-many-args } { \@@_environment_or_command: } { \tl_to_str:n {#1} } \@@_bad_def:wn } @@ -951,7 +953,7 @@ { \str_if_eq_p:nn {#1} { u } } } { - \msg_error:nnxx { cmd } { xparse-argument-type } + \msg_error:nnxx { cmd } { xparse-arg-type } { \@@_environment_or_command: } { \tl_to_str:n {#1} } } { @@ -1241,7 +1243,7 @@ { \use_none:n } } { - \msg_error:nnxxx { cmd } { forbidden-implicit-group-token } + \msg_error:nnxxx { cmd } { forbidden-group-token } { \@@_environment_or_command: } { \tl_to_str:n {#1} } { \token_if_eq_meaning:NNTF #1 \c_group_begin_token @@ -1261,7 +1263,7 @@ { \bool_if:NT \l_@@_expandable_bool { - \msg_error:nnxx { cmd } { invalid-expandable-argument-type } + \msg_error:nnxx { cmd } { invalid-expandable-arg } { \iow_char:N \\ \l_@@_function_tl } { \tl_to_str:n {#1} } \@@_bad_def:wn } @@ -1334,7 +1336,7 @@ { \bool_if:NT \l_@@_expandable_bool { - \msg_error:nnx { cmd } { inconsistent-long } + \msg_error:nnx { cmd } { long-short-mix } { \iow_char:N \\ \l_@@_function_tl } \@@_bad_def:wn } @@ -1356,7 +1358,7 @@ { \bool_if:NT \l_@@_some_obey_spaces_bool { - \msg_error:nnxx { cmd } { non-trailing-obey-spaces } + \msg_error:nnxx { cmd } { invalid-bang } { \@@_environment_or_command: } { \tl_to_str:n {#1} } \@@_bad_def:wn } @@ -1505,12 +1507,21 @@ % % \begin{macro}{\@@_add_type_E:w} % The \texttt{E}-type argument needs a special handling of default -% values. +% values. Since each embellishment is a separate argument, it +% also needs to replicate the argument processors for each embellishment +% argument so that the numbers of arguments and processors remain in sync. +% \changes{v1.0g}{2021/08/07} +% {Replicate argument processors for all embellishments (gh/639)} % \begin{macrocode} \cs_new_protected:Npn \@@_add_type_E:w #1#2 { \@@_flush_m_args: \@@_add_default_E:nn {#1} {#2} + \use:x + { + \@@_replicate_processor:nn { \tl_count:n {#1} } + { \exp_not:o \l_@@_process_one_tl } + } \@@_add_grabber:N E \tl_put_right:Nn \l_@@_signature_tl { {#1} } \@@_prepare_signature:N @@ -1518,6 +1529,48 @@ % \end{macrocode} % \end{macro} % +% \begin{macro}{\@@_replicate_processor:nn} +% In the command's argument processor signature (the final argument of +% \cs{@@_start:nNNnnn}) there is one braced item for each formal +% argument (up to nine), and in each of these items there is one +% braced item for each processor (as many as there were processors +% declared for a given argument). Something like this: +% \begin{quote} +% \ttfamily \obeylines +% \{ \% argument processors +% \ \ \{ \% argument 1 +% \ \ \ \ \{ processor 1 \} \{ processor 2 \} \ldots\ \{ processor n \} +% \ \ \} \% end argument 1 +% \ \ \{ \ldots\ \} \% argument 2 +% \ \ \ \ \ \vdots +% \ \ \{ \ldots\ \} \% argument n +% \} \% end argument processors +% \end{quote} +% +% The function \cs{@@_add_grabber:N} adds one single grabber for an +% argument, and adds the braced item for that one argument. However, +% in an |E|-type argument each embellishment requires its own formal +% argument, so we need to break out of one layer of braces in +% \cs{l_@@_process_one_tl}, add copies of the processor as necessary, +% and then return the removed brace. The function below does just +% that: it defines \cs{l_@@_process_one_tl} starting with a |}|$_2$ +% and ending with a |{|$_1$, so that it adds as many processors as +% needed when |x|-expanded. +% \begin{macrocode} +\cs_new_protected:Npn \@@_replicate_processor:nn #1 #2 + { + \int_compare:nNnF {#1} > { 1 } { \use_none:nnn } + \tl_set:Nx \l_@@_process_one_tl + { + \exp_not:n { \exp_not:n {#2} \if_false: { \fi: } } + \prg_replicate:nn { #1 - 2 } + { \exp_not:n { \exp_not:n { {#2} } } } + \exp_not:n { { \if_false: } \fi: \exp_not:n {#2} } + } + } +% \end{macrocode} +% \end{macro} +% % \begin{macro}{\@@_add_type_m:w} % The \texttt{m} type is special as short arguments which are not % post-processed are simply counted at this stage. Thus there is a check @@ -1608,6 +1661,8 @@ % \cs{l_@@_obey_spaces_bool} boolean can only be \texttt{true} for % trailing optional arguments. In that case spaces will not be % ignored when looking for that optional argument. +% \changes{v1.0g}{2021/08/07} +% {Replicate argument processors for all embellishments (gh/639)} % \begin{macrocode} \cs_new_protected:Npn \@@_add_grabber:N #1 { @@ -1624,7 +1679,12 @@ \bool_set_false:N \l_@@_long_bool \bool_set_false:N \l_@@_obey_spaces_bool \tl_put_right:Nx \l_@@_process_all_tl - { { \exp_not:o \l_@@_process_one_tl } } + { + { + \if_charcode:w E #1 \use_i:nn \fi: + \exp_not:o \l_@@_process_one_tl + } + } \tl_clear:N \l_@@_process_one_tl } % \end{macrocode} @@ -1676,8 +1736,7 @@ % We have already checked that short arguments are before long % arguments, so \cs{l_@@_long_bool} only changes from \texttt{false} % to \texttt{true} once (and there is no need to reset it after each -% argument). Also knock back the argument count because |+| is not an -% argument. Continue the loop. +% argument). Continue the loop. % \begin{macrocode} \cs_new_protected:cpn { @@_add_expandable_type_+:w } { @@ -1875,6 +1934,657 @@ % \end{macro} % \end{macro} % +% \subsubsection{Copying a command and its internal structure} +% +% \begin{macrocode} +%<latexrelease>\IncludeInRelease{2021/11/15}{\@@_copy:NN}% +%<latexrelease> {Support~\NewCommandCopy~in~ltcmd} +% \end{macrocode} +% +% \changes{v1.0h}{2021/08/30}{Added support for \cs{NewCommandCopy}} +% Since the 2020-10-01 \LaTeXe{} release, support for copying, and +% showing the definition of, robust commands has been available, but the +% specifics of each command are implemented separately. Here we'll add +% support for copying and showing \pkg{ltcmd} definitions. +% +% To fully support copying, we need two commands: a conditional to test +% if a command is in fact a \pkg{ltcmd} command, and another command to +% actually copy the command. The conditional is defined later as +% \cs{__kernel_cmd_if_xparse:NTF}, so now to the copying: +% +% \begin{macro}{\@@_copy:NN} +% \begin{macro}{\@@_set_eq_if_exist:NN,\@@_set_eq_if_exist:cc} +% This macro just branches to the proper copying command by using +% \cs{@@_cmd_type_cases:NnnnnF}. The copying command takes the names +% of the commands to be copied to and from, and the actual commands +% as its four arguments. +% \begin{macrocode} +\cs_new_protected:Npn \@@_copy:NN #1 #2 + { + \use:x + { + \int_set:Nn \tex_escapechar:D { 92 } + \exp_not:N \@@_cmd_type_cases:NnnnnF \exp_not:N #2 + { \@@_copy_command:nnNN } + { \@@_copy_expandable:nnNN } + { \@@_copy_environment:nnNN } + { \@@_copy_environment_end:nnNN } + { \@@_cant_copy:nwn { non-ltcmd } } + { \cs_to_str:N #1 } { \cs_to_str:N #2 } + \exp_not:N #1 \exp_not:N #2 + \exp_not:N \@@_break_point:n { \cs_to_str:N #2 } + \int_set:Nn \tex_escapechar:D { \int_use:N \tex_escapechar:D } + } + } +\cs_new_protected:Npn \@@_set_eq_if_exist:NN #1 #2 + { \cs_if_exist:NTF #2 { \cs_set_eq:NN } { \use_none:nn } #1 #2 } +\cs_generate_variant:Nn \@@_set_eq_if_exist:NN { cc } +% \end{macrocode} +% +% \begin{macro}{\@@_cant_copy:nwn} +% An utility macro similar to \cs{@@_bad_def:wn} to abort a command +% copy. Contrary to \cs{@@_bad_def:wn} though, when this happens the +% issue is most likely internal, because the command was already +% (supposedly) correcly defined so it should be copyable. Hopefully +% this macro will never be used ever, but if it does, apologise and +% give the reason for the failure so the user can report. +% \begin{macrocode} +\cs_new_protected:Npn \@@_cant_copy:nwn #1 #2 \@@_break_point:n #3 + { \msg_error:nnnn { cmd } { copy-bug } {#1} {#3} } +\msg_new:nnn { cmd } { copy-bug } + { + Error~while~copying~command~\iow_char:N\\#2:\\ + \str_case:nn {#1} + { + { non-ltcmd } { Command~is~not~a~valid~ltcmd~command. } + { unknown-type } { Found~an~unknown~argument~type. } + { invalid-end } + { Target~command~is~not~named~\iow_char:N \\end<name>. } + } + } +% \end{macrocode} +% \end{macro} +% +% And, of course, add \cs{__kernel_cmd_if_xparse:NTF} and +% \cs{@@_copy:NN} to \cs{@declarecommandcopylisthook}: +% \begin{macrocode} +\tl_gput_right:Nn \@declarecommandcopylisthook + { { \__kernel_cmd_if_xparse:NTF \@@_copy:NN } } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\@@_copy_command:nnNN,\@@_copy_command:NnNNnnnn} +% A normal (non-expandable) command has a pretty straightforward +% structure. Its definition is stored in +% \cs{\meta{cmd}\textvisiblespace code}, its defaults (if any) are +% stored in \cs{\meta{cmd}\textvisiblespace defaults}, and its +% top-level definition contains its signature, which can just be +% copied over. \cs{@@_copy_command:nnNN} copies the command code and +% defaults, and then defines the top-level command using the auxiliary +% \cs{@@_copy_command:NnNNnnnn}. This macro takes the signature of +% the command being copied from its top-level definition, and replaces +% the named bits with the new name. +% \begin{macrocode} +\cs_new_protected:Npn \@@_copy_command:nnNN #1 #2 #3 #4 + { + \cs_set_eq:cc { #1 ~ code } { #2 ~ code } + \@@_set_eq_if_exist:cc { #1 ~ defaults } { #2 ~ defaults } + \cs_set_protected_nopar:Npx #3 + { \exp_after:wN \@@_copy_command:NnNNnnnn #4 {#1} } + } +\cs_new:Npn \@@_copy_command:NnNNnnnn #1 #2 #3 #4 #5 #6 #7 #8 + { + #1 \exp_not:n { {#2} } + \exp_not:c { #8 ~ } \exp_not:c { #8 ~ code } + \exp_not:n { {#5} {#6} {#7} } + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\@@_copy_expandable:nnNN,\@@_copy_expandable:NnNNNNnnn} +% An expandable command is slightly more complicated. Besides the +% \cs{\meta{cmd}\textvisiblespace code}, and +% \cs{\meta{cmd}\textvisiblespace defaults}, it also has an auxiliary +% \cs{\meta{cmd}\textvisiblespace} for grabbing delimited arguments, +% and possibly another auxiliary +% \cs{\meta{cmd}\textvisiblespace\textvisiblespace}, if the command +% has both long and short arguments. Then, its signature also has +% several specific bits that are unique to that command; this is in contrast to +% non-expandable commands, which use a common set of parsing functions. +% +% We start by copying the basics, then call +% \cs{@@_copy_expandable_signature:NnNNNNnnn} to parse the signature +% of the command and build up the modified copy in a temporary token list, +% then we call \cs{@@_copy_expandable:NnNNNNnnn} that will copy the +% top-level definition of the command, with the proper internal +% renames. +% \begin{macrocode} +\cs_new_protected:Npn \@@_copy_expandable:nnNN #1 #2 #3 #4 + { + \cs_set_eq:cc { #1 ~ code } { #2 ~ code } + \@@_set_eq_if_exist:cc { #1 ~ } { #2 ~ } + \@@_set_eq_if_exist:cc { #1 ~ \c_space_tl } { #2 ~ \c_space_tl } + \@@_set_eq_if_exist:cc { #1 ~ defaults } { #2 ~ defaults } + \exp_after:wN \@@_copy_expandable_signature:NnNNNNnnn #4 {#1} {#2} + \cs_set_nopar:Npx #3 + { \exp_after:wN \@@_copy_expandable:NnNNNNnnn #4 {#1} {#2} } + } +\cs_new:Npn \@@_copy_expandable:NnNNNNnnn #1 #2 #3 #4 #5 #6 #7 #8 #9 + { + \exp_not:N #1 \exp_not:n { {#2} } + \exp_not:c { #8 ~ } + \exp_not:c + { + #8 ~ + \str_if_eq:eeT + { \exp_not:c { #9 ~ \c_space_tl } } { \exp_not:N #4 } + { \c_space_tl } + } + \exp_not:c { #8 ~ code } + \str_if_eq:eeTF { \exp_not:N #6 } { ? } + { ? } + { \exp_not:c { #8 ~ defaults } } + { \exp_not:V \l_@@_tmpa_tl } + } +% \end{macrocode} +% +% \begin{macro}{ +% \@@_copy_expandable_signature:NnNNNNnnn, +% \@@_copy_expandable:nnN, +% \@@_copy_parse_grabber:w, +% } +% A signature for an expandable command contains as many +% \cs{expandable_grab_\meta{type}:w} as there are arguments, and what +% follows this macro depends on the \meta{type}. We'll start a loop +% through the signature, and at each argument grabber, we'll step the +% argument count, and look for the \meta{type} with +% \cs{@@_copy_parse_grabber:w} so that we know which +% \cs{@@_copy_grabber_\meta{type}:w} to call next. +% \begin{macrocode} +\cs_new_protected:Npn \@@_copy_expandable_signature:NnNNNNnnn + #1 #2 #3 #4 #5 #6 #7 #8 #9 + { + \int_zero:N \l_@@_current_arg_int + \tl_clear:N \l_@@_tmpa_tl + \@@_copy_expandable:nnN {#8} {#9} #7 + \q_recursion_tail \q_recursion_stop + } +\cs_new_protected:Npn \@@_copy_expandable:nnN #1 #2 #3 + { + \quark_if_recursion_tail_stop:n {#3} + \int_incr:N \l_@@_current_arg_int + \exp_after:wN \@@_copy_parse_grabber:w \token_to_str:N #3 {#1} {#2} + } +\use:x + { + \cs_new_protected:Npn \exp_not:N \@@_copy_parse_grabber:w ##1 + \tl_to_str:n { expandable_grab_ } ##2 \tl_to_str:n { :w } + { + \tl_put_right:Nx \exp_not:N \l_@@_tmpa_tl + { \exp_not:N \exp_not:c { @@_expandable_grab_##2:w } } + \exp_not:N \cs_if_exist_use:cF { @@_copy_grabber_##2:w } + { \@@_cant_copy:nwn { unknown-type } } + } + } +% \end{macrocode} +% +% \begin{macro}{ +% \@@_copy_grabber_D:w,\@@_copy_grabber_D_alt:w, +% \@@_copy_grabber_R:w,\@@_copy_grabber_R_alt:w, +% \@@_copy_grabber_E:w,\@@_copy_grabber_E_long:w, +% \@@_copy_grabber_t:w, +% \@@_copy_grabber_m:w,\@@_copy_grabber_m_long:w, +% } +% The most complicated is the |D|elimited argument: each argument has +% a dedicated grabbing function named after the command that has to be +% copied over (of the form +% \cs{\meta{cmd}\textvisiblespace(arg\textvisiblespace\meta{num})}). +% \begin{macrocode} +\cs_new_protected:Npn \@@_copy_grabber_D:w #1 #2 #3 #4 #5 + { + \tl_put_right:Nx \l_@@_tmpa_tl + { + \exp_not:c { #1 ~ (arg ~ \int_use:N \l_@@_current_arg_int ) } + \exp_not:n { #4 #5 } + } + \cs_set_eq:cc + { #1 ~ (arg ~ \int_use:N \l_@@_current_arg_int ) } + { #2 ~ (arg ~ \int_use:N \l_@@_current_arg_int ) } + \@@_copy_expandable:nnN {#1} {#2} + } +% \end{macrocode} +% +% |D_alt| is just a special case of |D| that uses a single delimiter +% (used when both delimiters of the argument are identical): +% \begin{macrocode} +\cs_new_protected:Npn \@@_copy_grabber_D_alt:w #1 #2 #3 #4 + { \@@_copy_grabber_D:w {#1} {#2} {#3} {#4} { } } +% \end{macrocode} +% +% As far as copying is concerned, |R| is identical to |D|: +% \begin{macrocode} +\cs_new_eq:NN \@@_copy_grabber_R:w \@@_copy_grabber_D:w +\cs_new_eq:NN \@@_copy_grabber_R_alt:w \@@_copy_grabber_D_alt:w +% \end{macrocode} +% +% |E| is straightforward: we just copy the embellishments over, and +% increase the current argument number \cs{l_@@_current_arg_int} by +% the number of embellishments (minus one because there is a +% \cs{int_incr:N} down the line). +% \begin{macrocode} +\cs_new_protected:Npn \@@_copy_grabber_E:w #1 #2 #3 #4 + { + \tl_put_right:Nn \l_@@_tmpa_tl { {#3} {#4} } + \int_add:Nn \l_@@_current_arg_int { \tl_count:n {#4} - 1 } + \@@_copy_expandable:nnN {#1} {#2} + } +\cs_new_eq:NN \@@_copy_grabber_E_long:w \@@_copy_grabber_E:w +% \end{macrocode} +% +% |t| just needs copying the token to be tested for: +% \begin{macrocode} +\cs_new_protected:Npn \@@_copy_grabber_t:w #1 #2 #3 #4 + { + \tl_put_right:Nn \l_@@_tmpa_tl { #3 #4 } + \@@_copy_expandable:nnN {#1} {#2} + } +% \end{macrocode} +% +% And last but not least, |m| is the simplest; the grabber is just +% \cs{@@_expandable_grab_m:w}, which is already added to the new +% command so here we just resume the loop: +% \begin{macrocode} +\cs_new_protected:Npn \@@_copy_grabber_m:w { \@@_copy_expandable:nnN } +\cs_new_eq:NN \@@_copy_grabber_m_long:w \@@_copy_grabber_m:w +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\@@_copy_environment:nnNN} +% \begin{macro}{\@@_copy_environment:Nnnnnnn} +% Copying an environment's \cs{begin} part is pretty much like copying +% a command, except it has a longer name, and at the end we have to +% copy \cs[no-index]{environment~\meta{name}} into +% \cs[no-index]{\meta{name}}. +% \begin{macrocode} +\cs_new_protected:Npn \@@_copy_environment:nnNN #1 #2 #3 #4 + { + \cs_set_eq:cc { environment~ #1 ~ code } { environment~ #2 ~ code } + \@@_set_eq_if_exist:cc + { environment~ #1 ~ defaults } { environment~ #2 ~ defaults } + \cs_set_protected_nopar:cpx { environment~ #1 } + { \exp_after:wN \@@_copy_environment:Nnnnnnn #4 {#1} } + \cs_set_eq:cc {#1} { environment~ #1 } + } +\cs_new:Npn \@@_copy_environment:Nnnnnnn #1 #2 #3 #4 #5 #6 #7 + { #1 \exp_not:n { {#2} } {#7} \exp_not:n { {#4} {#5} {#6} } } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\@@_copy_environment_end:nnNN} +% \begin{macro}{\@@_copy_environment_end_aux:nnNN} +% Copying an environment's \cs{end} part is a bit trickier. We first +% have to make sure that both parts are named +% \cs[no-index]{end\meta{name}} (that's actually not a hard +% requirement, but an environment \cs{end} command makes no sense +% without the |end| in its name), and strip the leading |end| from the +% strings. After that, copying is straightforward. +% \begin{macrocode} +\cs_new_protected:Npn \@@_copy_environment_end:nnNN #1 #2 + { + \@@_check_end:Nn \l_@@_tmpa_tl {#1} + \@@_check_end:Nn \l_@@_tmpb_tl {#2} + \exp_args:Noo \@@_copy_environment_end_aux:nnNN + { \l_@@_tmpa_tl } { \l_@@_tmpb_tl } + } +\cs_new_protected:Npn \@@_copy_environment_end_aux:nnNN #1 #2 #3 #4 + { + \cs_set_nopar:cpx { environment~ #1 ~end } + { \exp_not:c { environment~ #1 ~end~aux } } + \cs_set_eq:cc + { environment~ #1 ~end~aux~ } { environment~ #2 ~end~aux~ } + \cs_set_eq:cc { end #1 } { environment~ #1 ~end } + } +% \end{macrocode} +% +% \begin{macro}{\@@_check_end:Nn,\@@_check_end:n,\@@_check_end:w} +% To check whether an \cs{end} command is valid, we look for the +% string |end| at the beginning of the command name, and if not found, +% raise an error: +% \begin{macrocode} +\cs_new_protected:Npn \@@_check_end:Nn #1 #2 + { + \tl_set:Nx #1 { \@@_check_end:n {#2} } + \token_if_eq_meaning:NNT #1 \q_nil + { \@@_cant_copy:nwn { invalid-end } } + } +\cs_set_protected:Npn \@@_tmp:w #1 + { + \cs_new:Npn \@@_check_end:n ##1 + { + \exp_after:wN \@@_check_end:w \tl_to_str:n {##1} + #1 \q_mark #1 \q_stop + } + \cs_new:Npn \@@_check_end:w ##1 #1 ##2 #1 ##3 \q_stop + { \if_meaning:w ##2 \q_mark \exp_not:N \q_nil \else: ##2 \fi: } + } +\exp_args:No \@@_tmp:w { \tl_to_str:n { end } } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% Not much to do regarding \pkg{latexrelease}: we could remove the +% entries from \cs{@declarecommandcopylisthook}, but it doesn't seem +% worth it. +% \begin{macrocode} +%<latexrelease>\EndIncludeInRelease +%<latexrelease>\IncludeInRelease{2020/10/01}{\@@_copy:NN}% +%<latexrelease> {Support~\NewCommandCopy~in~ltcmd} +%<latexrelease>\EndIncludeInRelease +% \end{macrocode} +% +% \subsubsection{Showing the definition of a command} +% +% \begin{macrocode} +%<latexrelease>\IncludeInRelease{2021/11/15}{\@@_show:N}% +%<latexrelease> {Support~\ShowCommand~in~ltcmd} +% \end{macrocode} +% +% \changes{v1.0h}{2021/08/30}{Added support for \cs{ShowCommand}} +% To show the definition of a command we need more or less the same +% building blocks as for copying, except that instead of making a copy, +% we'll just print stuff to the terminal. +% +% \begin{macro}{\@@_show:N} +% This macro just branches to the proper showing command by using +% \cs{@@_cmd_type_cases:NnnnnF}. The showing command takes the command +% to be shown as argument. +% \begin{macrocode} +\cs_new_protected:Npn \@@_show:N #1 + { + \use:x + { + \int_set:Nn \tex_escapechar:D { 92 } + \exp_not:N \@@_cmd_type_cases:NnnnnF \exp_not:N #1 + { \@@_show_command:N } + { \@@_show_expandable:N } + { \@@_show_environment:N } + { \@@_show_environment_end:N } + { \@@_cant_copy:nwn { non-ltcmd } } + \exp_not:N #1 + \exp_not:N \@@_break_point:n { \cs_to_str:N #1 } + \int_set:Nn \tex_escapechar:D { \int_use:N \tex_escapechar:D } + } + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{ +% \@@_show_command:N, +% \@@_show_command:NnNNwN, +% \@@_show_expandable:N, +% \@@_show_expandable:NnNNNNnN, +% \@@_show_command_aux:nNNn, +% \@@_show_environment:N, +% } +% These commands just expand the command once to reveal its innards, +% then pass the type of command, the control sequence, the signature, +% and the code macro to \cs{@@_show_command_aux:nNNn}. +% \begin{macrocode} +\cs_new_protected:Npn \@@_show_command:N #1 + { \exp_after:wN \@@_show_command:NnNNwN #1 \q_@@ #1 } +\cs_new_protected:Npn \@@_show_command:NnNNwN #1 #2 #3 #4 #5 \q_@@ #6 + { \@@_show_command_aux:nNNn { document~command } #6 #4 {#2} } +\cs_new_protected:Npn \@@_show_expandable:N #1 + { \exp_after:wN \@@_show_expandable:NnNNNNnN #1 #1 } +\cs_new_protected:Npn \@@_show_expandable:NnNNNNnN #1 #2 #3 #4 #5 #6 #7 #8 + { \@@_show_command_aux:nNNn { expandable~document~command } #8 #5 {#2} } +% \end{macrocode} +% +% Now just print everything in the required format. The auxiliary +% \cs{@@_split_signature:n} stores a ready-to-print token list in +% \cs{l_@@_tmpa_tl}, so we ust use that here: +% \begin{macrocode} +\cs_new_protected:Npn \@@_show_command_aux:nNNn #1 #2 #3 #4 + { + \@@_split_signature:n {#4} + \iow_term:x + { + > ~ \token_to_str:N #2 = #1: \iow_newline: + \tl_use:N \l_@@_tmpa_tl + -> \cs_replacement_spec:N #3 . + } + } +% \end{macrocode} +% +% We can reuse most of the above to show an environment, except that +% we need to ensure that the proper \cs[no-index]{environment~\ldots} +% are passed to \cs{@@_show_command_aux:nNNn}. Additionally, when +% |\ShowCommand\foo| is used (if |foo| is an environment), we show +% |\endfoo| as well, and when |\ShowCommand\endfoo| is used, change +% that to |\ShowCommand\foo| and do the same. +% \begin{macrocode} +\cs_new_protected:Npn \@@_show_environment:N #1 + { + \exp_after:wN \@@_show_environment:Nnnw #1 \q_@@ + \iow_term:x + { + > ~ \token_to_str:N \end { \cs_to_str:N #1 } : \iow_newline: + -> \exp_args:Nc \cs_replacement_spec:N + { environment~ \cs_to_str:N #1 ~end~aux~ } . + } + } +\cs_new_protected:Npn \@@_show_environment:Nnnw #1 #2 #3 #4 \q_@@ + { + \use:x + { + \@@_show_command_aux:nNNn { document~environment } + { \exp_not:N \begin {#3} } + \exp_not:c { environment~ #3 ~ code } + {#2} + } + } +\cs_new_protected:Npn \@@_show_environment_end:N #1 + { + \exp_args:NNx \@@_check_end:Nn \l_@@_tmpa_tl { \cs_to_str:N #1 } + \exp_args:Nc \@@_show_environment:N { \l_@@_tmpa_tl } + } +% \end{macrocode} +% +% And, of course, add \cs{__kernel_cmd_if_xparse:NTF} and +% \cs{@@_show:N} to \cs{@showcommandlisthook}: +% \begin{macrocode} +\tl_gput_right:Nn \@showcommandlisthook + { { \__kernel_cmd_if_xparse:NTF \@@_show:N } } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\@@_split_signature:n} +% Now we'll try a least-effort adventure into splitting the symbolic +% user-provided signature for a command into individual parameters for +% pretty-printing. A counter is used to keep track of the current +% argument number, and two token lists are used: \cs{l_@@_tmpa_tl} +% holds the final token list to be printed, and \cs{l_@@_tmpb_tl} +% holds just the current item, so that we can make changes to an +% individual item without having to dissect the whole thing (this is +% used for |e|- and |E|-types). +% \begin{macrocode} +\cs_new_protected:Npn \@@_split_signature:n #1 + { + \int_set:Nn \l_@@_current_arg_int { 1 } + \tl_clear:N \l_@@_tmpa_tl + \tl_clear:N \l_@@_tmpb_tl + \@@_split_signature_loop:Nw #1 \q_recursion_tail \q_recursion_stop + } +% \end{macrocode} +% +% \begin{macro}{\@@_split_signature_loop:Nw} +% This is the main chunk of the loop: it starts an item with +% \cs{@@_split_start_item:} +% (this adds indentation and the argument number to +% \cs{l_@@_tmpb_tl}), then checks if a special token list +% \cs[no-index]{c_@@_show_type_\meta{type}_tl} exists. If it doesn't, +% the current argument is a ``simple'' type which needs no extra +% processing. Otherwise, call a specific function depending on the +% value of said token list. +% \begin{macrocode} +\cs_new_protected:Npn \@@_split_signature_loop:Nw #1 + { + \quark_if_recursion_tail_stop:N #1 + \tl_if_empty:NT \l_@@_tmpb_tl { \@@_split_start_item: } + \tl_if_exist:cTF { c_@@_show_type_#1_tl } + { + \use:c + { + @@_show_ + \if_case:w \tl_use:c { c_@@_show_type_#1_tl } \exp_stop_f: + delim \or: delims \or: delims_opt \or: opt \or: + e \or: E \or: prefix \or: processor \fi: :Nw + } #1 + } + { \@@_split_end_item:n {#1} \@@_split_signature_loop:Nw } + } +% \end{macrocode} +% +% \begin{macro}{ +% \c_@@_show_type_t_tl, +% \c_@@_show_type_r_tl,\c_@@_show_type_d_tl, +% \c_@@_show_type_R_tl,\c_@@_show_type_D_tl, +% \c_@@_show_type_O_tl, +% \c_@@_show_type_e_tl, +% \c_@@_show_type_E_tl, +% \c_@@_show_type_+_tl,\c_@@_show_type_!_tl, +% \c_@@_show_type_>_tl, +% } +% The token lists \cs[no-index]{c_@@_show_type_\meta{type}_tl} exist +% for nontrivial (for printing) \meta{types} that require special +% parsing (like delimiters or optional arguments). Values from~0 to~7 +% are assigned to each type: +% \begin{enumerate} +% \item a single delimiter token; +% \item two delimiter tokens; +% \item two delimiter tokens plus a default value; +% \item a default value; +% \item a list of embellishments (exclusive for |e|-type); +% \item embellishments plus defaults (exclusive for |E|-type); +% \item simple prefixes; +% \item prefixes with arguments (argument processors); +% \end{enumerate} +% \begin{macrocode} +\cs_set_protected:Npn \@@_tmp:w #1 #2 + { + \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 +% \end{macrocode} +% +% \begin{macro}{ +% \@@_show_delim:Nw,\@@_show_delims:Nw, +% \@@_show_delims_opt:Nw,\@@_show_opt:Nw, +% \@@_show_e:Nw,\@@_show_E:Nw, +% \@@_show_prefix:Nw,\@@_show_processor:Nw, +% } +% Now, based on each type we know how to act. In most cases it is +% just a matter of feeding in the grabbed arguments and resuming the +% loop. The embellishments require a bit more attention: the +% |e|-type loops through the list of embellishments and adds each to +% the token list as a separate argument. The |E|-type does more or +% less the same, but uses \cs{@@_tl_mapthread_function:nnN} to map +% over two lists simultaneously, adding each token and default to the +% token list for printing. +% \begin{macrocode} +\cs_new_protected:Npn \@@_show_delim:Nw #1 #2 + { \@@_split_end_item:n { #1 #2 } \@@_split_signature_loop:Nw } +\cs_new_protected:Npn \@@_show_delims:Nw #1 #2 #3 + { \@@_split_end_item:n { #1 #2 #3 } \@@_split_signature_loop:Nw } +\cs_new_protected:Npn \@@_show_delims_opt:Nw #1 #2 #3 #4 + { \@@_split_end_item:n { #1 #2 #3 {#4} } \@@_split_signature_loop:Nw } +\cs_new_protected:Npn \@@_show_opt:Nw #1 #2 + { \@@_split_end_item:n { #1 {#2} } \@@_split_signature_loop:Nw } +\cs_new_protected:Npn \@@_show_e:Nw #1 #2 + { + \tl_map_inline:nn {#2} + { + \@@_split_start_item: + \@@_split_end_item:n { #1 ##1 } + } + \@@_split_signature_loop:Nw + } +\cs_set_protected:Npn \@@_tmp:w #1 + { + \cs_new_protected:Npn \@@_show_E:Nw ##1 ##2 ##3 + { + \cs_set_protected:Npn \@@_tmp:w ####1 ####2 + { + \@@_split_start_item: + \@@_split_end_item:n { ##1 ####1 {####2} } + } + \@@_tl_mapthread_function:nnN {##2} + { ##3 {#1} {#1} {#1} {#1} {#1} {#1} {#1} {#1} {#1} } \@@_tmp:w + \@@_split_signature_loop:Nw + } + } +\exp_args:NV \@@_tmp:w \c_novalue_tl +% \end{macrocode} +% +% Minor wrinkle with the prefixes: they use \cs{@@_split_add_item:n} +% instead of \cs{@@_split_end_item:n} (|add| \emph{vs.} |end|) because +% they are followed by an argument, so they can't end the item. +% \begin{macrocode} +\cs_new_protected:Npn \@@_show_prefix:Nw #1 + { \@@_split_add_item:n {#1} \@@_split_signature_loop:Nw } +\cs_new_protected:Npn \@@_show_processor:Nw #1 #2 + { \@@_split_add_item:n { #1 {#2} } \@@_split_signature_loop:Nw } +% \end{macrocode} +% +% \begin{macro}{ +% \@@_split_start_item:, +% \@@_split_add_item:n, +% \@@_split_end_item:n, +% } +% And now the auxiliaries that store the strings to be printed. +% \cs{@@_split_start_item:} starts an item from scratch, +% \cs{@@_split_add_item:n} adds tokens to an item without adding a +% newline, and \cs{@@_split_end_item:n} adds tokens, terminates the +% item with a newline, and steps the argument count. +% \begin{macrocode} +\cs_new_protected:Npn \@@_split_start_item: + { + \tl_set:Nx \l_@@_tmpb_tl + { ~ \c_space_tl \c_hash_str \int_use:N \l_@@_current_arg_int : } + } +\cs_new_protected:Npn \@@_split_add_item:n #1 + { \tl_put_right:Nx \l_@@_tmpb_tl { \tl_to_str:n {#1} } } +\cs_new_protected:Npn \@@_split_end_item:n #1 + { + \tl_put_right:Nx \l_@@_tmpa_tl + { \l_@@_tmpb_tl \tl_to_str:n {#1} \iow_newline: } + \tl_clear:N \l_@@_tmpb_tl + \int_incr:N \l_@@_current_arg_int + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% Not much to do regarding \pkg{latexrelease}: we could remove the +% entries from \cs{@showcommandlisthook}, but it doesn't seem +% worth it. +% \begin{macrocode} +%<latexrelease>\EndIncludeInRelease +% +%<latexrelease>\IncludeInRelease{2020/10/01}{\@@_show:N}% +%<latexrelease> {Support~\ShowCommand~in~ltcmd} +%<latexrelease>\EndIncludeInRelease +% \end{macrocode} +% % \subsection{Grabbing arguments} % % All of the grabbers follow the same basic pattern. The initial @@ -2023,6 +2733,7 @@ % \end{macro} % \end{macro} % \end{macro} +% % \begin{macro}{\@@_grab_D_nested:NNnN} % \begin{macro}{\@@_grab_D_nested:w} % \begin{macro}{\l_@@_nesting_a_tl} @@ -2587,7 +3298,7 @@ \exp_after:wN \exp_after:wN \exp_after:wN \peek_meaning_remove:NTF \char_generate:nn { \tex_endlinechar:D } { 6 } { - \msg_error:nnxxx { cmd } { verbatim-newline } + \msg_error:nnxxx { cmd } { verbatim-nl } { \@@_environment_or_command: } { \tl_to_str:N \l_@@_v_arg_tl } { \tl_to_str:n {#1} } @@ -3115,7 +3826,7 @@ \ProcessedArgument \q_stop } - \msg_error:nnxxx { cmd } { split-excess-tokens } + \msg_error:nnxxx { cmd } { arg-split } { \tl_to_str:n {#3} } { \int_eval:n { #2 + 1 } } { \tl_to_str:n {#4} } } @@ -3375,8 +4086,11 @@ % \end{macro} % % \begin{macro}{\__kernel_cmd_if_xparse:NTF} +% \begin{macro}{\@@_cmd_type_cases:Nnnnn} % \changes{v1.0d}{2021/04/19}{Renamed \cs{__cmd_cmd_if_xparse:NTF} to % \cs{__kernel_cmd_if_xparse:NTF} for cross-module usage} +% \changes{v1.0d}{2021/07/30}{Added \cs{@@_cmd_type_cases:Nnnnn} for +% \cs{NewCommandCopy} and \cs{ShowCommand} support} % \begin{macro}{\@@_cmd_if_xparse_aux:N} % % To determine whether the command is an \pkg{xparse} command check @@ -3384,31 +4098,50 @@ % that its |replacement_spec| starts with either % \cs{@@_start:nNNnnn} (non-expandable command) or % \cs{@@_start_expandable:nNNNNn} (expandable command) or -% \cs{@@_start_env:nnnnn} (environment). +% \cs{@@_start_env:nnnnn} (environment) or +% \cs[no-index]{environment~\#1~end~aux} (environment end). % % This conditional is needed in several kernel modules and is % therefore has a kernel-internal name. % \begin{macrocode} -\cs_new_protected:Npn \__kernel_cmd_if_xparse:NTF #1 +\cs_new_protected:Npn \@@_cmd_type_cases:NnnnnF #1 #2 #3 #4 #5 #6 { - \exp_args:Nf \str_case_e:nnTF + \exp_args:Ne \str_case_e:nnF { \exp_args:Nf \tl_if_empty:nT { \cs_argument_spec:N #1 } { - \exp_last_unbraced:Nf \@@_cmd_if_xparse_aux:w - { \cs_replacement_spec:N #1 } ~ \q_stop + \token_if_macro:NT #1 + { + \exp_after:wN \exp_after:wN + \exp_after:wN \token_to_str:N + \exp_after:wN \use_i_delimit_by_q_stop:nw + #1 \scan_stop: \q_stop + } } } { - { \token_to_str:N \@@_start:nNNnnn } { } - { \token_to_str:N \@@_start_expandable:nNNNNn } { } - { \token_to_str:N \@@_start_env:nnnnn } { } + { \token_to_str:N \@@_start:nNNnnn } {#2} + { \token_to_str:N \@@_start_expandable:nNNNNn } {#3} + { \token_to_str:N \@@_start_env:nnnnn } {#4} + { + \exp_after:wN \token_to_str:N + \cs:w environment~ + \exp_last_unbraced:Ne \use_none:nnn + { \cs_to_str:N #1 } ~end~aux \cs_end: + } {#5} } + {#6} + } +\cs_new_protected:Npn \__kernel_cmd_if_xparse:NTF #1 + { + \@@_cmd_type_cases:NnnnnF #1 + { } { } { } { } { \use_iii:nnn } + \use_i:nn } -\cs_new:Npn \@@_cmd_if_xparse_aux:w #1 ~ #2 \q_stop {#1} % \end{macrocode} % \end{macro} % \end{macro} +% \end{macro} % % \begin{macro}{\@@_peek_nonspace:NTF, \@@_peek_nonspace_remove:NTF, \@@_peek_nonspace_aux:nNNTF} % Collect spaces in a loop, and put the collected spaces back in the @@ -3434,7 +4167,7 @@ % token is a control sequence, also check that the \meta{csname} is % the same as the control sequence peeked at. This extra verification % is necessary when the command is delimited by control sequence tokens -% (as opposed to character tokens), and we want the the exact same +% (as opposed to character tokens), and we want the exact same % control sequence to match. % \begin{macrocode} \cs_new_protected:Npn \@@_peek_meaning:NTF @@ -3504,94 +4237,98 @@ % \end{macro} % % Some messages intended as errors when defining commands/environments. +% \changes{v1.0f}{2021/06/04}{Normalize various error messages} % \begin{macrocode} \msg_new:nnnn { cmd } { arg-after-body } - { In~the~definition~of~#1,~b~(body)~argument~must~be~last. } + { Argument~type~'b'~must~be~last~in~#1. } { - The~'body'~argument~type~is~followed~by~'#2'~in~the~argument~ - specification~of~the~#1.~This~is~not~allowed. + The~'b'~argument~type~must~come~last~but~it~is~followed~ + by~'#2'~in~the~argument~specification.~This~is~not~allowed. \c_@@_ignore_def_tl } \msg_new:nnnn { cmd } { bad-arg-spec } { Bad~argument~specification~'#2'~for~#1. } { - The~argument~specification~provided~was~not~valid:~ - one~or~more~mandatory~pieces~of~information~were~missing. + The~argument~specification~provided~is~not~valid:~ + one~or~more~mandatory~parts~are~missing. \c_@@_ignore_def_tl } -\msg_new:nnnn { cmd } { command-already-defined } - { Command~'#1'~already~defined! } +\msg_new:nnnn { cmd } { already-defined } + { Command~'#1'~already~defined. } { You~have~used~#2~ with~a~command~that~already~has~a~definition. \\ \\ The~existing~definition~of~'#1'~will~not~be~altered. } -\msg_new:nnnn { cmd } { command-not-yet-defined } - { Command ~'#1'~not~yet~defined! } +\msg_new:nnnn { cmd } { undefined } + { Command ~'#1'~undefined. } { You~have~used~#2~ with~a~command~that~was~never~defined. \c_@@_ignore_def_tl } -\msg_new:nnnn { cmd } { environment-already-defined } - { Environment~'#1'~already~defined! } +\msg_new:nnnn { cmd } { env-already-defined } + { Environment~'#1'~already~defined. } { You~have~used~\NewDocumentEnvironment with~an~environment~that~already~has~a~definition. \\ \\ The~existing~definition~of~'#1'~will~not~be~altered. } -\msg_new:nnnn { cmd } { environment-not-yet-defined } - { Environment~'#1'~not~yet~defined! } +\msg_new:nnnn { cmd } { env-end-already-defined } + { End~of~environment~'#1'~already~defined. } + { + You~have~used~\NewDocumentEnvironment + with~an~environment~that~already~has~a~definition~for~'end#1'. \\ \\ + The~existing~definition~of~'#1'~will~not~be~altered. + } +\msg_new:nnnn { cmd } { env-undefined } + { Environment~'#1'~undefined. } { You~have~used~\RenewDocumentEnvironment with~an~environment~that~was~never~defined. \c_@@_ignore_def_tl } \msg_new:nnnn { cmd } { expandable-ending-optional } - { - Argument~specification~'#2'~for~expandable~command~'#1'~ - ends~with~optional~argument. - } + { Bad~argument~specification~'#2'~for~#1. } { Expandable~commands~must~have~a~final~mandatory~argument~ (or~no~arguments~at~all).~You~cannot~have~a~terminal~optional~ argument~with~expandable~commands. } -\msg_new:nnnn { cmd } { inconsistent-long } - { Inconsistent~long~arguments~for~expandable~command~'#1'. } +\msg_new:nnnn { cmd } { long-short-mix } + { Invalid~argument~prefix~'+'~in~command~'#1'. } { The~arguments~for~an~expandable~command~must~not~involve~short~ - arguments~after~long~arguments.~You~have~tried~to~mix~the~two~types. + arguments~after~long~arguments.~You~have~tried~to~mix~the~two~types~ + when~defining~'#1'. } \msg_new:nnnn { cmd } { invalid-command-arg } - { Argument~type~'#2'~not~available~for~#1. } + { Invalid~argument~type~'#2'~in~#1. } { The~letter~'#2'~can~only~be~used~in~environment~argument~ - specifications,~not~for~commands. + specifications,~but~not~for~commands. \\ \\ - LaTeX~will~ignore~this~entire~definition. + LaTeX~will~ignore~the~entire~definition. } -\msg_new:nnnn { cmd } { invalid-expandable-argument-type } - { Argument~type~'#2'~not~available~for~expandable~command~'#1'. } +\msg_new:nnnn { cmd } { invalid-expandable-arg } + { Invalid~argument~type~'#2'~in~#1. } { The~letter~'#2'~specifies~an~argument~type~which~cannot~be~used~ in~an~expandable~command. \c_@@_ignore_def_tl } \msg_new:nnnn { cmd } { invalid-after-optional-expandably } - { - Argument~type~'#2'~not~available~after~optional~argument~ - for~expandable~command~'#1'. - } + { Argument~'#2'~invalid~after~optional~arg~in~#1. } { The~letter~'#2'~specifies~an~argument~type~which~cannot~be~used~ in~an~expandable~command~after~an~optional~argument. \c_@@_ignore_def_tl } -\msg_new:nnnn { cmd } { non-trailing-obey-spaces } - { Prefix~'!'~used~before~mandatory~argument~'#2'~of~#1. } +\msg_new:nnnn { cmd } { invalid-bang } + { Invalid~argument~prefix~'!'~in~#1. } { - The~prefix~'!'~can~only~apply~to~trailing~optional~arguments. + The~prefix~'!'~is~only~allowed~for~trailing~optional~arguments.~ + You~tried~to~apply~it~to~'#2'. \c_@@_ignore_def_tl } \msg_new:nnnn { cmd } { not-definable } @@ -3611,75 +4348,75 @@ \c_@@_ignore_def_tl } \msg_new:nnnn { cmd } { not-single-token } + { Argument~delimiter~'#2'~invalid~in~#1. } { - Argument~delimiter~'#2'~for~the~#1~should~be~ - a~single~non-space~token. - } - { - The~argument~specification~provided~was~not~valid:~in~a~place~ - where~a~single~token~is~required,~LaTeX~found~'#2'. + The~argument~specification~contains~ + \tl_if_empty:nTF{#2}{nothing}{'#2'}~ + in~a~place~ + where~a~single~token~is~required. \c_@@_ignore_def_tl } -\msg_new:nnnn { cmd } { forbidden-implicit-group-token } - { Argument~delimiter~'#2'~for~the~#1~is~not~allowed. } +\msg_new:nnnn { cmd } { forbidden-group-token } + { Argument~delimiter~'#2'~invalid~in~#1. } { - The~argument~specification~provided~was~not~valid:~the~implicit~ - #3-group~token~'#2'~is~not~allowed~as~an~argument~delimiter. + The~argument~specification~contains~the~implicit~ + #3-group~token~'#2'~which~is~not~allowed~as~an~argument~delimiter. \c_@@_ignore_def_tl } \msg_new:nnnn { cmd } { processor-in-expandable } - { Argument~processor~'>{#2}'~cannot~be~used~for~the~expandable~command~'#1'. } + { Invalid~argument~prefix~'>'~in~command~'#1'. } { - The~argument~specification~for~#1~contains~a~processor~function:~ - this~is~only~supported~for~standard~robust~commands. + The~argument~specification~for~'#1'~contains~the~processor~function~'>{#2}'.~ + This~is~only~supported~for~robust~commands,~but~not~for~expandable~ones. \c_@@_ignore_def_tl } -\msg_new:nnnn { cmd } { too-many-arguments } - { Too~many~arguments~in~argument~specification~'#2'~of~#1. } +\msg_new:nnnn { cmd } { too-many-args } + { Too~many~arguments~for~#1. } { - The~argument~specification~provided~has~more~than~9~arguments.~ + The~argument~specification~'#2'~asks~for~more~than~9~arguments.~ This~cannot~be~implemented. \c_@@_ignore_def_tl } \msg_new:nnnn { cmd } { two-markers } - { Two~'#2'~apply~to~the~same~argument~in~argument~specification~of~#1. } + { Invalid~argument~prefix~'#2'~in~#1. } { - The~argument~specification~provided~has~two~markers~'#2'~applying~ - to~the~same~argument;~these~are~redundant. + The~argument~specification~provided~for~#1~has~two~'#2'~markers~applied~ + to~the~same~argument;~one~is~redundant. } -\msg_new:nnnn { cmd } { unknown-argument-type } - { Unknown~argument~type~'#2'~for~the~#1. } +\msg_new:nnnn { cmd } { unknown-argument-type } % should be unkown-arg-type but dep in xparse + { Invalid~argument~type~'#2'~in~#1. } { The~letter~'#2'~does~not~specify~a~known~argument~type. \c_@@_ignore_def_tl } -\msg_new:nnnn { cmd } { xparse-argument-type } - { Deprecated~argument~type~'#2'~for~the~#1~requires~xparse. } +\msg_new:nnnn { cmd } { xparse-arg-type } + { Invalid~argument~type~'#2'~in~#1~(requires~xparse). } { - The~letter~'#2'~specifies~a~known~argument~type~that~requires~ - the~xparse~package. + The~letter~'#2'~specifies~a~known~but~deprecated~argument~type.~ + If~you~really~need~it~you~have~to~load~the~xparse~package. \c_@@_ignore_def_tl } % \end{macrocode} % % Errors when using commands/environments. The \texttt{if-boolean} % message is always used in expandable errors. The -% \texttt{loop-in-defaults} and \texttt{missing-required} messages can +% \texttt{default-loop} and \texttt{missing-required} messages can % be expandable or not expandable. % \begin{macrocode} \msg_new:nnn { cmd } { if-boolean } - { Invalid~use~\iow_char:N\\IfBooleanTF~{#1} } -\msg_new:nnnn { cmd } { loop-in-defaults } - { Defaults~of~#1~have~circular~dependency. } + { Invalid~argument~{#1}~to~\iow_char:N\\IfBoolean... } +\msg_new:nnnn { cmd } { default-loop } + { Circular~dependency~in~defaults~of~#1. } { The~default~values~of~two~or~more~arguments~of~the~#1~ depend~on~each~other~in~a~way~that~cannot~be~resolved. } \msg_new:nnnn { cmd } { missing-required } - { Missing~required~argument~for~#1. } + { Required~argument~missing~for~#1. } { - The~current~#1~expects~an~argument~starting~with~'#2'.~ - LaTeX~did~not~find~it,~and~will~insert~a~default~value~to~be~processed. + The~#1~expects~one~of~its~arguments~to~start~with~'#2'.~ + LaTeX~did~not~find~this~argument~and~will~insert~a~default~value~ + for~further~processing. } \msg_new:nnnn { cmd } { non-xparse } { \str_uppercase:n #1~not~defined~using~xparse. } @@ -3687,12 +4424,12 @@ You~have~asked~for~the~argument~specification~for~the~#1,~ but~this~was~not~defined~using~xparse. } -\msg_new:nnnn { cmd } { split-excess-tokens } - { Too~many~'#1'~tokens~when~trying~to~split~argument. } +\msg_new:nnnn { cmd } { arg-split } + { Too~many~'#1'~separators~in~argument. } { LaTeX~was~asked~to~split~the~input~'#3'~ - at~each~occurrence~of~the~token~'#1',~up~to~a~maximum~of~#2~parts.~ - There~were~too~many~'#1'~tokens. + at~each~occurrence~of~the~separator~'#1'~into~#2~parts.~ + Too~many~separators~were~found. } \msg_new:nnnn { cmd } { unknown } { Unknown~document~#1. } @@ -3700,54 +4437,62 @@ You~have~asked~for~the~argument~specification~for~the~#1,~ but~it~is~not~defined. } -\msg_new:nnnn { cmd } { verbatim-newline } - { Verbatim~argument~of~#1~ended~by~end~of~line. } +\msg_new:nnnn { cmd } { verbatim-nl } + { Verbatim-like~#1~ended~by~end~of~line. } { The~verbatim~argument~of~the~#1~cannot~contain~more~than~one~line,~ but~the~end~ of~the~current~line~has~been~reached.~You~may~have~forgotten~the~ closing~delimiter. \\ \\ - LaTeX~will~ignore~'#2'. + LaTeX~will~ignore~'#2'~and~you~may~get~some~additional~ + (low-level)~errors. } \msg_new:nnnn { cmd } { verbatim-tokenized } - { The~verbatim~#1~cannot~be~used~inside~an~argument. } + { Verbatim-like~#1~illegal~in~argument. } { - The~#1~takes~a~verbatim~argument.~ - It~may~not~appear~within~the~argument~of~another~function.~ - It~received~an~illegal~token \tl_if_empty:nF {#3} { ~'#3' } . + The~#1~takes~a~verbatim~argument~and~should~therefore~normally~ + not~be~used~in~arguments~of~other~commands~or~environments.~ + LaTeX~found~an~illegal~token~ \tl_if_empty:nF {#3} { (#3)~ } + after~'#2'~and~will~drop~everything~up~to~this~point. \\ \\ - LaTeX~will~ignore~'#2'. + Expect~further~(low-level)~errors. } % \end{macrocode} % % Intended more for information. % \begin{macrocode} -\msg_new:nnn { cmd } { define-command } +\msg_new:nnn { cmd } { define-command } % should be just ``define'' but dep in xparse { Defining~command~#1~ with~sig.~'#2'~\msg_line_context:. } -\msg_new:nnn { cmd } { define-environment } +\msg_new:nnn { cmd } { define-env } { Defining~environment~'#1'~ with~sig.~'#2'~\msg_line_context:. } -\msg_new:nnn { cmd } { redefine-command } +\msg_new:nnn { cmd } { redefine } { Redefining~command~#1~ with~sig.~'#2'~\msg_line_context:. } -\msg_new:nnn { cmd } { redefine-environment } +\msg_new:nnn { cmd } { redefine-env } { Redefining~environment~'#1'~ with~sig.~'#2'~\msg_line_context:. } \msg_new:nnn { cmd } { optional-mandatory } { - Since~the~mandatory~argument~'#1'~has~the~same~delimiter~'#2'~ - as~a~previous~optional~argument,~it~will~not~be~possible~to~ - omit~all~optional~arguments~when~calling~this~command. + Optional~and~mandatory~argument~with~same~delimiter~'#2'. + \\ \\ + The~mandatory~argument~specified~with~ + '\str_case:nnF{#1}{ {R/r}{r'~or~'R} }{#1}'~has~the~ + same~delimiter~'#2'~as~an~earlier~optional~argument.~ + It~will~therefore~not~be~possible~to~omit~all~the~earlier~ + optional~arguments~when~calling~this~command. + \\ \\ + This~may~be~intentional,~but~then~it~might~be~a~mistake. } \msg_new:nnn { cmd } { unsupported-let } { @@ -3787,7 +4532,7 @@ { \cs_if_exist:NTF #1 { - \msg_error:nnxx { cmd } { command-already-defined } + \msg_error:nnxx { cmd } { already-defined } { \use:nnn \token_to_str:N #1 { } } { \token_to_str:N \NewDocumentCommand } } @@ -3801,7 +4546,7 @@ \cs_if_exist:NTF #1 { \@@_declare_cmd:Nnn #1 {#2} {#3} } { - \msg_error:nnxx { cmd } { command-not-yet-defined } + \msg_error:nnxx { cmd } { undefined } { \use:nnn \token_to_str:N #1 { } } { \token_to_str:N \RenewDocumentCommand } } @@ -3824,6 +4569,7 @@ % \end{macro} % % \begin{macro}{\NewDocumentEnvironment} +% \changes{v1.0h}{2021/08/27}{Check for end-of-environment command} % \begin{macro}{\RenewDocumentEnvironment} % \begin{macro}{\ProvideDocumentEnvironment} % \begin{macro}{\DeclareDocumentEnvironment} @@ -3832,14 +4578,18 @@ \cs_new_protected:Npn \NewDocumentEnvironment #1#2#3#4 { \cs_if_exist:cTF {#1} - { \msg_error:nnx { cmd } { environment-already-defined } {#1} } - { \@@_declare_env:nnnn {#1} {#2} {#3} {#4} } + { \msg_error:nnx { cmd } { env-already-defined } {#1} } + { + \cs_if_exist:cTF { end #1 } + { \msg_error:nnx { cmd } { env-end-already-defined } {#1} } + { \@@_declare_env:nnnn {#1} {#2} {#3} {#4} } + } } \cs_new_protected:Npn \RenewDocumentEnvironment #1#2#3#4 { \cs_if_exist:cTF {#1} { \@@_declare_env:nnnn {#1} {#2} {#3} {#4} } - { \msg_error:nnx { cmd } { environment-not-yet-defined } {#1} } + { \msg_error:nnx { cmd } { env-undefined } {#1} } } \cs_new_protected:Npn \ProvideDocumentEnvironment #1#2#3#4 { \cs_if_exist:cF {#1} { \@@_declare_env:nnnn {#1} {#2} {#3} {#4} } } @@ -3866,7 +4616,7 @@ { \cs_if_exist:NTF #1 { - \msg_error:nnxx { cmd } { command-already-defined } + \msg_error:nnxx { cmd } { already-defined } { \use:nnn \token_to_str:N #1 { } } { \token_to_str:N \NewExpandableDocumentCommand } } @@ -3880,7 +4630,7 @@ \cs_if_exist:NTF #1 { \@@_declare_expandable_cmd:Nnn #1 {#2} {#3} } { - \msg_error:nnxx { cmd } { command-not-yet-defined } + \msg_error:nnxx { cmd } { undefined } { \use:nnn \token_to_str:N #1 { } } { \token_to_str:N \RenewExpandableDocumentCommand } } @@ -4032,3 +4782,4 @@ % \end{macrocode} % % \Finale + |