summaryrefslogtreecommitdiff
path: root/macros/latex-dev/base/ltcmd.dtx
diff options
context:
space:
mode:
Diffstat (limited to 'macros/latex-dev/base/ltcmd.dtx')
-rw-r--r--macros/latex-dev/base/ltcmd.dtx217
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 }