diff options
Diffstat (limited to 'macros/latex-dev/base/ltcmd.dtx')
-rw-r--r-- | macros/latex-dev/base/ltcmd.dtx | 217 |
1 files changed, 184 insertions, 33 deletions
diff --git a/macros/latex-dev/base/ltcmd.dtx b/macros/latex-dev/base/ltcmd.dtx index dcb85a1ae8..1733af5416 100644 --- a/macros/latex-dev/base/ltcmd.dtx +++ b/macros/latex-dev/base/ltcmd.dtx @@ -2,7 +2,7 @@ % % Copyright (C) 1999 Frank Mittelbach, Chris Rowley, David Carlisle % Copyright (C) 2004-2008 Frank Mittelbach, The LaTeX Project -% Copyright (C) 2009-2023 +% Copyright (C) 2009-2024 % The LaTeX Project and any individual authors listed elsewhere % in this file. % @@ -34,8 +34,8 @@ %%% From File: ltcmd.dtx % % \begin{macrocode} -\def\ltcmdversion{v1.2a} -\def\ltcmddate{2023-08-19} +\def\ltcmdversion{v1.2c} +\def\ltcmddate{2024-02-08} % \end{macrocode} % %<*driver> @@ -415,8 +415,6 @@ \cs_new_protected:Npn \@@_declare_cmd_internal:Nnnn #1#2#3#4 { \tl_set:Nx \l_@@_function_tl { \cs_to_str:N #1 } - \tl_set:Nx \l_@@_fn_tl - { \exp_not:c { \l_@@_function_tl \c_space_tl } } \@@_normalize_arg_spec:n {#2} \exp_args:No \@@_prepare_signature:n \l_@@_arg_spec_tl \@@_declare_cmd_code:Nnn #1 {#2} {#3} @@ -435,17 +433,93 @@ % \end{macrocode} % \end{macro} % +% \begin{macro}[EXP]{\@@_all_m_check:n, \@@_all_m_check_aux:n} +% A quick loop to check for all |(+)m|-type arguments. +% \begin{macrocode} +\cs_new:Npn \@@_all_m_check:n #1 + { \tl_map_function:nN {#1} \@@_all_m_check_aux:n } +\cs_new:Npn \@@_all_m_check_aux:n #1 + { + \str_if_eq:nnF {#1} { m } + { + \str_if_eq:nnF {#1} { + } + { X } + } + } +% \end{macrocode} +% \end{macro} +% % \begin{macro}{\@@_declare_cmd_code:Nnn} % \begin{macro} -% {\@@_declare_cmd_code_aux:Nnn, \@@_declare_cmd_code_expandable:Nnn} -% The appropriate auxiliary is called. +% { +% \@@_declare_cmd_optimized:Nnn, +% \@@_declare_cmd_code_aux:Nnn, +% \@@_declare_cmd_code_expandable:Nnn +% } +% \begin{macro}{\@@_start_optimized:} +% \changes{v1.2b}{2023/12/01} +% {Optimize cmd creation for all-\texttt{m} arguments} +% At this stage we can check for a short-cut possibility: if the argument +% specification is made up of just |(+)m| tokens, and if all arguments are +% either short or long, then we can produce an optimized document command. +% This only applies to document commands, not creation of environments (which +% are more complex). +% \begin{macrocode} +\cs_new_protected:Npn \@@_declare_cmd_code:Nnn #1#2 + { + \bool_lazy_any:nTF + { + { \l_@@_environment_bool } + { + \bool_lazy_and_p:nn + { \l_@@_some_short_bool } + { \l_@@_some_long_bool } + } + { ! \tl_if_blank_p:e { \@@_all_m_check:n {#2} } } + } + { + \tl_set:Nx \l_@@_fn_tl + { \exp_not:c { \l_@@_function_tl \c_space_tl } } + \bool_if:NTF \l_@@_grab_expandably_bool + { \@@_declare_cmd_code_expandable:Nnn } + { \@@_declare_cmd_code_aux:Nnn } + } + { \@@_declare_cmd_optimized:Nnn } + #1 {#2} + } +% \end{macrocode} +% The optimized version of commands just has to worry about whether to make +% them protected or long. The commands start with an expandable marker so +% that other parts of the kernel know these are set up by \pkg{ltcmd}. +% We need the two layers of redirection so that the \texttt{code} internal +% function has the same form as it would for any other document command. +% Optimization means that there is no \cs{group_align_safe_begin:} before +% grabbing the arguments, so anything involving |&| tokens will not work. +% However, this is really only intended for making optional argument +% processing safe anyway, so in practice should not be an issue. % \begin{macrocode} -\cs_new_protected:Npn \@@_declare_cmd_code:Nnn +\cs_new_protected:Npn \@@_declare_cmd_optimized:Nnn #1#2#3 { - \bool_if:NTF \l_@@_grab_expandably_bool - { \@@_declare_cmd_code_expandable:Nnn } - { \@@_declare_cmd_code_aux:Nnn } - } + \bool_if:NTF \l_@@_expandable_bool + { \cs_set_nopar:Npe } + { \cs_set_protected_nopar:Npe } + #1 + { + \exp_not:N \@@_start_optimized: + \exp_not:c { \l_@@_function_tl \c_space_tl code } + } + \exp_args:Ncc \cs_generate_from_arg_count:NNnn + { \l_@@_function_tl \c_space_tl code } + { + cs_set + \bool_if:NF \l_@@_expandable_bool { _protected } + \bool_if:NF \l_@@_some_long_bool { _nopar } + :Npn + } + \l_@@_current_arg_int + {#3} + } +\cs_new:Npn \@@_start_optimized: { } % \end{macrocode} % Standard functions call \cs{@@_start:nNNnnn}, which receives the % argument specification, an auxiliary used for @@ -544,6 +618,7 @@ % \end{macrocode} % \end{macro} % \end{macro} +% \end{macro} % % \begin{macro}{\@@_declare_env:nnnn} % \begin{macro}{\@@_declare_env_internal:nnnn} @@ -1286,7 +1361,7 @@ % that is not possible without the risk of mistakenly grabbing the % entire brace group (potentially leading to a~\texttt{!~Runaway argument} % error) or trying to grab a |}|$_2$, leading to -% an~\verb|! Argument of \dots has an extra }| error. +% \iffalse{\fi an~\verb|! Argument of \dots has an extra }| error. % \begin{macrocode} \cs_new_protected:Npn \@@_allowed_token_check:N #1 { @@ -1373,6 +1448,9 @@ % \end{macro} % % \begin{macro}{\@@_add_arg_spec:n, \@@_add_arg_spec_mandatory:n} +% \changes{v1.2c}{2023/12/22} +% {Clarify error message when \texttt{!} prefix is applied to +% non-trailing opt-arg (gh/1198)} % 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. @@ -1414,7 +1492,12 @@ \bool_if:NT \l_@@_some_obey_spaces_bool { \msg_error:nnxx { cmd } { invalid-bang } - { \@@_environment_or_command: } { \tl_to_str:n {#1} } + { \@@_environment_or_command: } + { + \bool_if:NTF \l_@@_obey_spaces_bool + { \tl_to_str:n {'#1'} } + { an~optional~argument~before~mandatory~ \tl_to_str:n {'#1'} } + } \@@_bad_def:wn } \tl_clear:N \l_@@_last_delimiters_tl @@ -1626,8 +1709,10 @@ % 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 +% that: it defines \cs{l_@@_process_one_tl} starting with a +% \iffalse{\fi |}|$_2$ +% and ending with a |{|$_1$, \iffalse}\fi +% so that it adds as many processors as % needed when |x|-expanded. % \begin{macrocode} \cs_new_protected:Npn \@@_replicate_processor:nn #1 #2 @@ -2033,7 +2118,7 @@ % \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 +% \cs{@@_cmd_type_cases:NnnnnnF}. 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} @@ -2042,9 +2127,10 @@ \use:x { \int_set:Nn \tex_escapechar:D { 92 } - \exp_not:N \@@_cmd_type_cases:NnnnnF \exp_not:N #2 + \exp_not:N \@@_cmd_type_cases:NnnnnnF \exp_not:N #2 { \@@_copy_command:nnNN } { \@@_copy_expandable:nnNN } + { \@@_copy_optimized:nnNN } { \@@_copy_environment:nnNN } { \@@_copy_environment_end:nnNN } { \@@_cant_copy:nwn { non-ltcmd } } @@ -2186,6 +2272,24 @@ %<latexrelease>\EndIncludeInRelease % \end{macrocode} % +% \begin{macro}{\@@_copy_optimized:nnNN} +% Copy the code, simply define the wrapper. +% \begin{macrocode} +\cs_new_protected:Npn \@@_copy_optimized:nnNN #1#2#3#4 + { + \cs_set_eq:cc { #1 ~ code } { #2 ~ code } + \token_if_protected_macro:NTF #4 + { \cs_set_protected_nopar:Npe } + { \cs_set_nopar:Npe } + #3 + { + \exp_not:N \@@_start_optimized: + \exp_not:c { #1 ~ code } + } + } +% \end{macrocode} +% \end{macro} +% % \begin{macrocode} %<latexrelease>\IncludeInRelease{2021/11/15}{\@@_copy:NN (part 2)}% %<latexrelease> {Support~\NewCommandCopy~in~ltcmd} @@ -2423,7 +2527,7 @@ % % \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 +% \cs{@@_cmd_type_cases:NnnnnnF}. The showing command takes the command % to be shown as argument. % \begin{macrocode} \cs_new_protected:Npn \@@_show:N #1 @@ -2431,9 +2535,10 @@ \use:x { \int_set:Nn \tex_escapechar:D { 92 } - \exp_not:N \@@_cmd_type_cases:NnnnnF \exp_not:N #1 + \exp_not:N \@@_cmd_type_cases:NnnnnnF \exp_not:N #1 { \@@_show_command:N } { \@@_show_expandable:N } + { \@@_show_optimized:N } { \@@_show_environment:N } { \@@_show_environment_end:N } { \@@_cant_copy:nwn { non-ltcmd } } @@ -2450,6 +2555,7 @@ % \@@_show_command:NnNNwN, % \@@_show_expandable:N, % \@@_show_expandable:NnNNNNnN, +% \@@_show_optimized:N, % \@@_show_command_aux:NnNNn, % \@@_show_environment:N, % \@@_show:x, @@ -2530,6 +2636,48 @@ } % \end{macrocode} % +% Optimized functions need things done a bit differently as we need to +% reconstruct the argument spec. +% \begin{macrocode} +\cs_new_protected:Npn \@@_show_optimized:N #1 + { + \exp_args:Nc \@@_show_optimized:NN + { \cs_to_str:N #1 \c_space_tl code } + #1 + } +\cs_new_protected:Npn \@@_show_optimized:NN #1#2 + { + \cs_set:Npe \@@_show_optimized_aux:N ##1 + { + \c_space_tl \c_space_tl \c_hash_str ##1 : + \bool_lazy_or:nnT + { \token_if_long_macro_p:N #1 } + { \token_if_protected_long_macro_p:N #1 } + { + } m + \iow_newline: + } + \tl_show:e + { + \token_to_str:N #2 = + \bool_lazy_or:nnF + { \token_if_protected_macro_p:N #1 } + { \token_if_protected_long_macro_p:N #1 } + { expandable ~ } document~command: + \iow_newline: + \int_step_function:nN + { + \int_div_truncate:nn + { \tl_count:e { \cs_parameter_spec:N #1 } } + { 2 } + } + \@@_show_optimized_aux:N + -> + \cs_replacement_spec:N #1 + } + } +\cs_generate_variant:Nn \tl_count:n { e } +% \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:NnNNn}. Additionally, when @@ -4376,13 +4524,14 @@ % \end{macro} % % \begin{macro}{\__kernel_cmd_if_xparse:NTF} -% \begin{macro}{\@@_cmd_type_cases:Nnnnn} +% \begin{macro}{\@@_cmd_type_cases:NnnnnnF} % \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:NnnnnF} for % \cs{NewCommandCopy} and \cs{ShowCommand} support} % \changes{v1.0l}{2022/03/18}{Fix \cs{@@_cmd_type_cases:NnnnnF} -%" prematurely expanding macros (gh/795)} +% prematurely expanding macros (gh/795)} +% \changes{v1.2b}{2023/12/01}{Extend for optimized commands} % \begin{macro}{\@@_cmd_if_xparse_aux:N} % % To determine whether the command is an \pkg{xparse} command check @@ -4390,13 +4539,14 @@ % that its |replacement_spec| starts with either % \cs{@@_start:nNNnnn} (non-expandable command) or % \cs{@@_start_expandable:nNNNNn} (expandable command) or +% \cs{@@_start_optimized:} (optimized command) or % \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 \@@_cmd_type_cases:NnnnnF #1 #2 #3 #4 #5 #6 +\cs_new_protected:Npn \@@_cmd_type_cases:NnnnnnF #1 #2 #3 #4 #5 #6 #7 { \exp_args:Ne \str_case_e:nnF { @@ -4406,20 +4556,21 @@ { { \exp_not:N \@@_start:nNNnnn } {#2} { \exp_not:N \@@_start_expandable:nNNNNn } {#3} - { \exp_not:N \@@_start_env:nnnnn } {#4} + { \exp_not:N \@@_start_optimized: } {#4} + { \exp_not:N \@@_start_env:nnnnn } {#5} { \exp_after:wN \exp_not:N \cs:w environment~ \exp_last_unbraced:Ne \use_none:nnn { \cs_to_str:N #1 } ~end~aux \cs_end: - } {#5} + } {#6} } - {#6} + {#7} } \cs_new_protected:Npn \__kernel_cmd_if_xparse:NTF #1 { - \@@_cmd_type_cases:NnnnnF #1 - { } { } { } { } { \use_iii:nnn } + \@@_cmd_type_cases:NnnnnnF #1 + { } { } { } { } { } { \use_iii:nnn } \use_i:nn } % \end{macrocode} @@ -4511,10 +4662,8 @@ \bool_if:NTF \l_@@_environment_bool { environment ~ ' \l_@@_environment_str ' } { - command ~ ' - \exp_args:Nf \tl_trim_spaces:n - { \exp_after:wN \token_to_str:N \l_@@_fn_tl } - ' + command ~ + ' \c_backslash_str \tl_to_str:N \l_@@_function_tl ' } } % \end{macrocode} @@ -4522,6 +4671,8 @@ % % Some messages intended as errors when defining commands/environments. % \changes{v1.0f}{2021/06/04}{Normalize various error messages} +% \changes{v1.2c}{2023/12/22} +% {Generalize message \texttt{invalid-bang} (gh/1198)} % \begin{macrocode} \msg_new:nnnn { cmd } { arg-after-body } { Argument~type~'b'~must~be~last~in~#1. } @@ -4612,7 +4763,7 @@ { Invalid~argument~prefix~'!'~in~#1. } { The~prefix~'!'~is~only~allowed~for~trailing~optional~arguments.~ - You~tried~to~apply~it~to~'#2'. + You~tried~to~apply~it~to~#2. \c_@@_ignore_def_tl } \msg_new:nnnn { cmd } { not-definable } |