diff --git a/base/changes.txt b/base/changes.txt index 86137063e..cbe16a702 100644 --- a/base/changes.txt +++ b/base/changes.txt @@ -6,6 +6,10 @@ to completeness or accuracy and it contains some references to files that are not part of the distribution. ================================================================================ +2024-12-12 Joseph Wright + * ltcmd.dtx, usrguide.tex + New "f"-type argument + 2024-12-10 Yukai Chou * ltxref.dtx (subsection{Cross Referencing}) Replace \@tempa with \reserved@a in \Ref (gh/1579) diff --git a/base/doc/ltnews41.tex b/base/doc/ltnews41.tex index ee1914c56..820be51d2 100644 --- a/base/doc/ltnews41.tex +++ b/base/doc/ltnews41.tex @@ -227,6 +227,39 @@ \subsection{Fixing the spacing after display math} \section{New or improved commands} +\subsection{Collecting environment bodies verbatim} + +The mechanisms in \pkg{ltcmd} (\enquote{\pkg{xparse}}) offer a powerful way to +specify a range of types of document command and environment syntax. This +includes the ability to collect the entire body of an environment, for cases +where treating it as a standard argument is useful. It is also possible in +\pkg{ltcmd} to define arguments which grab their content verbatim, another +specialist argument form. To date, however, it was not possible to combine +these two ideas. + +In this release, a new specifier~\texttt{f} is introduced, which collects the +body of an environment in a verbatim-like way. Like the existing +\texttt{v}~specification, each separate line is marked by the special +\cs{obeyedline} marker, which as standard issues a normal paragraph. Thus, this +new specifier is usable both for typesetting and collecting file contents (the +\texttt{f} indicates \enquote{\texttt{filecontents}-like}). Thus, we may use +\begin{verbatim} +\NewDocumentEnvironment + {MyVerbatim}{!O{\ttfamily} +f} + {\begin{center} #1 #2\end{center}} {} +\begin{MyVerbatim}[\ttfamily\itshape] + % Some code is show here + $y = mx + c$ +\end{MyVerbatim} +\end{verbatim} +to obtain +\NewDocumentEnvironment{MyVerbatim}{!O{\ttfamily} +f} + {\begin{center} #1 #2\end{center}} {} +\begin{MyVerbatim}[\ttfamily\itshape] + % Some code is show here + $y = mx + c$ +\end{MyVerbatim} + \section{Code improvements} \subsection{Refinement of \cs{MakeTitlecase}} diff --git a/base/doc/usrguide.tex b/base/doc/usrguide.tex index de37d6d41..c37f7c462 100644 --- a/base/doc/usrguide.tex +++ b/base/doc/usrguide.tex @@ -43,7 +43,7 @@ \texttt{usrguide.tex} for full details.}% } -\date{2024-11-17} +\date{2024-12-12} \NewDocumentCommand\cs{m}{\texttt{\textbackslash\detokenize{#1}}} \NewDocumentCommand\marg{m}{\arg{#1}} @@ -858,6 +858,41 @@ \subsection{Typesetting verbatim-like material} Similarly, the \texttt{verbatim} environment sets up the meaning of \cs{par} suitable for breaking lines. +\subsection{Verbatim environments} +\label{sec:cmd:verbenv} + +In some cases, as well as grabbing an environment body you will want the +contents to be treated verbatim. This is available using the argument +specification~\texttt{f}. Like the \texttt{b} specification, this has to be the +last one. Thus for example +\begin{verbatim} +\NewDocumentEnvironment{MyVerbatim}{!O{\ttfamily} f} + {\begin{center} #1 #2\end{center}} {} +\begin{MyVerbatim}[\ttfamily\itshape] + % Some code is show here + $y = mx + c$ +\end{MyVerbatim} +\end{verbatim} +will typeset +\NewDocumentEnvironment{MyVerbatim}{!O{\ttfamily} f} + {\begin{center} #1 #2\end{center}} {} +\begin{MyVerbatim}[\ttfamily\itshape] + % Some code is show here + $y = mx + c$ +\end{MyVerbatim} + +As grabbing the entire contents verbatim, newlines are always permitted: there +is no need for a |+| here. As for the \texttt{v} specification, new lines are +stored as \cs{obeyedline}. In a similar fashion to the +\texttt{b}~specification, by default \emph{newlines} are trimmed at both ends +of the body. Putting the prefix |!| before \texttt{f} suppresses +space-trimming. + +Notice that for technical reasons, we recommend that an optional argument +coming immediately before an \texttt{f} specification should not allow any +spaces, achieved by adding the \texttt{!} as showing in the example. However, +this is left as a choice for the user. + \subsection{Performance} For document commands where the argument specification is entirely diff --git a/base/ltcmd.dtx b/base/ltcmd.dtx index ffbb6c5af..aea83d7a1 100644 --- a/base/ltcmd.dtx +++ b/base/ltcmd.dtx @@ -326,6 +326,13 @@ % \end{macrocode} % \end{variable} % +% \begin{variable}{\l_@@_verb_safe_bool} +% To track if optional arguments should be collected \enquote{verbatim safe}. +% \begin{macrocode} +\bool_new:N \l_@@_verb_safe_bool +% \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} @@ -1045,6 +1052,7 @@ \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 + \bool_set_false:N \l_@@_verb_safe_bool \@@_normalize_arg_spec_loop:n #1 \q_recursion_tail \q_recursion_tail \q_recursion_tail \q_recursion_stop \int_compare:nNnT \l_@@_current_arg_int > 9 @@ -1202,6 +1210,12 @@ { = { \tl_trim_spaces:n {#1} } } } } +\cs_new_protected:cpn { @@_normalize_type_*:w } #1 + { + \@@_normalize_type_aux:NnNn * {#1} + \l_@@_verb_safe_bool + { \bool_set_true:N \l_@@_verb_safe_bool } + } \cs_new_protected:Npn \@@_normalize_type_aux:NnNn #1#2#3#4 { \quark_if_recursion_tail_stop_do:nn {#2} { \@@_bad_arg_spec:wn } @@ -1331,28 +1345,40 @@ % \end{macro} % % \begin{macro}{\@@_normalize_type_b:w} -% This argument type is not allowed for commands. This is only +% \changes{v1.3a}{2024-12-12}{Extend to cover \texttt{f}-type grabbing} +% \begin{macro}{\@@_normalize_type_f:w} +% \changes{v1.3a}{2024-12-12}{New function} +% \begin{macro}{\@@_normalize_type_b_or_f:nn} +% \changes{v1.3a}{2024-12-12}{New function} +% These argument type is not allowed for commands. They are only % allowed at the end of the argument specification, hence we check % that |#1| is the end. % \begin{macrocode} \cs_new_protected:Npn \@@_normalize_type_b:w #1 + { \@@_normalize_type_b_or_f:nn {#1} { b } } +\cs_new_protected:Npn \@@_normalize_type_f:w #1 + { \@@_normalize_type_b_or_f:nn {#1} { f } } +\cs_new_protected:Npn \@@_normalize_type_b_or_f:nn #1#2 { \bool_if:NF \l_@@_environment_bool { \msg_error:nnxx { cmd } { invalid-command-arg } - { \@@_environment_or_command: } { b } + { \@@_environment_or_command: } {#2} \@@_bad_def:wn } \tl_clear:N \l_@@_last_delimiters_tl - \@@_add_arg_spec:n { b } + \@@_add_arg_spec:n {#2} \quark_if_recursion_tail_stop:n {#1} - \msg_error:nnxx { cmd } { arg-after-body } + \msg_error:nnxxx { cmd } { arg-after-body } + {#2} { \@@_environment_or_command: } { \tl_to_str:n {#1} } \@@_bad_def:wn } % \end{macrocode} % \end{macro} +% \end{macro} +% \end{macro} % % \begin{macro}{\@@_single_token_check:n} % Checks that the argument is a single (non-space) token (possibly @@ -1472,6 +1498,7 @@ % \changes{v1.2c}{2023/12/22} % {Clarify error message when \texttt{!} prefix is applied to % non-trailing opt-arg (gh/1198)} +% \changes{v1.3a}{2024-12-12}{Extend to support \texttt{f}-type grabbing} % 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. @@ -1501,8 +1528,19 @@ { \bool_set_true:N \l_@@_some_short_bool } \tl_put_right:Nx \l_@@_arg_spec_tl { - \bool_if:NT \l_@@_long_bool { + } + \bool_lazy_and:nnT + { \l_@@_long_bool } + { + ! \bool_lazy_or_p:nn + { \str_if_eq_p:nn {#1} { f } } + { \str_if_eq_p:nn {#1} { t } } + } + { + } \bool_if:NT \l_@@_obey_spaces_bool { ! } + \bool_lazy_or:nnT + { \l_@@_verb_safe_bool } + { \str_if_eq_p:nn {#1} { f } } + { * } \exp_not:n {#1} } \bool_set_false:N \l_@@_long_bool @@ -1543,6 +1581,7 @@ \bool_set_false:N \l_@@_long_bool \bool_set_false:N \l_@@_obey_spaces_bool \bool_set_false:N \l_@@_suppress_strip_bool + \bool_set_false:N \l_@@_verb_safe_bool \int_zero:N \l_@@_m_args_int \bool_set_false:N \l_@@_defaults_bool \tl_clear:N \l_@@_defaults_tl @@ -1657,17 +1696,41 @@ % \end{macrocode} % \end{macro} % +% \begin{macro}{\@@_add_type_*:w} +% \changes{v1.3a}{2024-12-12}{New macro} +% \begin{macrocode} +\cs_new_protected:cpn { @@_add_type_*:w } + { + \@@_flush_m_args: + \bool_set_true:N \l_@@_verb_safe_bool + \bool_set_true:N \l_@@_prefixed_bool + \@@_prepare_signature_bypass:N + } +% \end{macrocode} +% \end{macro} +% % \begin{macro}{\@@_add_type_b:w} +% \changes{v1.3a}{2024-12-12}{Extend to cover \texttt{f}-type grabbing} +% \begin{macro}{\@@_add_type_f:w} +% \changes{v1.3a}{2024-12-12}{New function} +% \begin{macro}{\@@_add_type_b_or_f:N} +% \changes{v1.3a}{2024-12-12}{New function} % \begin{macrocode} \cs_new_protected:Npn \@@_add_type_b:w + { \@@_add_type_b_or_f:N b } +\cs_new_protected:Npn \@@_add_type_f:w + { \@@_add_type_b_or_f:N f } +\cs_new_protected:Npn \@@_add_type_b_or_f:N #1 { \@@_flush_m_args: \@@_add_default: - \@@_add_grabber:N b + \@@_add_grabber:N #1 \@@_prepare_signature:N } % \end{macrocode} % \end{macro} +% \end{macro} +% \end{macro} % % \begin{macro}{\@@_add_type_D:w} % \begin{macrocode} @@ -1842,6 +1905,7 @@ % ignored when looking for that optional argument. % \changes{v1.0g}{2021/08/07} % {Replicate argument processors for all embellishments (gh/639)} +% \changes{v1.3a}{2024-12-12}{Extend to support \texttt{f}-type grabbing} % \begin{macrocode} \cs_new_protected:Npn \@@_add_grabber:N #1 { @@ -1856,12 +1920,17 @@ { \l_@@_suppress_strip_bool } { \str_if_eq_p:nn {#1} { D } } { _no_strip } + \bool_lazy_and:nnT + { \l_@@_verb_safe_bool } + { \str_if_eq_p:nn {#1} { D } } + { _verb_safe } :w } } \bool_set_false:N \l_@@_long_bool \bool_set_false:N \l_@@_obey_spaces_bool \bool_set_false:N \l_@@_suppress_strip_bool + \bool_set_false:N \l_@@_verb_safe_bool \tl_put_right:Nx \l_@@_process_all_tl { { @@ -3002,6 +3071,173 @@ % \end{macrocode} % \end{macro} % +% \begin{macro}{\@@_grab_f:w} +% \changes{v1.3a}{2024-12-12}{New \texttt{f}-type grabbing function} +% \begin{macro}{\@@_grab_f_obey_spaces:w} +% \begin{macro}{\@@_grab_f_aux:n} +% \begin{macro}{\@@_grab_f_aux:w} +% \begin{macro}{\@@_grab_f_check:w} +% \begin{macro}{\@@_grab_f_loop:w} +% \begin{macro}{\@@_grab_f_space_check:w} +% \begin{macro}{\@@_grab_f_space_aux:w} +% \begin{macro}{\@@_grab_f_end:nn} +% \begin{macro}{\@@_grab_f_end:n} +% \begin{macro}{\@@_grab_f_end_auxi:w} +% \begin{macro}{\@@_grab_f_end_auxii:w} +% Collecting an environment body verbatim shares some ideas with the +% \texttt{v}-type grabber, and others with the standard \texttt{filecontents} +% environment. The start is to set the end-of-line to a predictable value +% and to deactivate the specials. We then define the end marker: this +% has to have the correct category codes, so is a token list not a string +% (\texttt{end} and the end-of-env name are catcode-11). We use this to set +% up the end-of-env test, then hand over to an auxiliary. +% \begin{macrocode} +\cs_new_protected:Npn \@@_grab_f:w #1 \@@_run_code: + { + \bool_set_false:N \l_@@_obey_spaces_bool + \@@_grab_f_aux:n {#1} + } +\cs_new_protected:Npn \@@_grab_f_obey_spaces:w #1 \@@_run_code: + { + \bool_set_true:N \l_@@_obey_spaces_bool + \@@_grab_f_aux:n {#1} + } +\cs_new_protected:Npn \@@_grab_f_aux:n #1 + { + \tl_set:Nn \l_@@_signature_tl {#1} + \group_begin: + \tl_clear:N \l_@@_v_arg_tl + \tex_escapechar:D = 92 \scan_stop: + \tex_endlinechar:D = `\^^M \scan_stop: + \cs_set_eq:NN \do \char_set_catcode_other:N + \dospecials + \tl_set:Ne \l_@@_tmpa_tl + { + \c_backslash_str end + \c_left_brace_str \@currenvir \c_right_brace_str + } + \use:e + { + \cs_set_protected:Npn \@@_grab_f_check:w + ##1 \l_@@_tmpa_tl ##2 \l_@@_tmpa_tl ##3 + \scan_stop: + } + { + \tl_if_empty:nTF {##3} + { + \tl_put_right:Nn \l_@@_v_arg_tl + { + ##1 + \obeyedline + } + \@@_grab_f_loop:w + } + { \@@_grab_f_end:nn {##1} {##2} } + } + \@@_grab_f_aux:w + } +% \end{macrocode} +% To allow for the need to change the category code of end-of-lines, we +% put this in a small auxiliary. At the end of this, we deal with the +% a special case for the first line before looping. +% \begin{macrocode} +\group_begin: + \char_set_catcode_other:N \^^M % + \cs_new_protected:Npn \@@_grab_f_aux:w % + { % + \cs_set_protected:Npe \@@_grab_f_loop:w ##1 ^^M % + { % + \@@_grab_f_check:w ##1 % + \l_@@_tmpa_tl % + \l_@@_tmpa_tl % + \scan_stop: % + } % + \char_set_catcode_other:N \^^M % + \group_align_safe_begin: % + \peek_after:Nw \@@_grab_f_space_check:w + } % +\group_end: % +\cs_new_protected:Npn \@@_grab_f_check:w { } +\cs_new_protected:Npn \@@_grab_f_loop:w { } +% \end{macrocode} +% If there was a potential optional argument before the \texttt{f}-type +% one, but it was missed out, the next character will already have been +% tokenized. The most common case will be a newline, which will have +% been converted to a space: that is picked up here. (It is impossible +% to filter out all possible cases, as the underlying behavior of +% \tn{futurelet} means that for example a \verb=%= would be a comment +% and be lost.) Alternative approaches require that a category code +% change for \verb=^^M= takes place before searching for any optional +% arguments (see for example \pkg{fancyvrb}). +% \begin{macrocode} +\cs_new_protected:Npn \@@_grab_f_space_check:w + { + \if_meaning:w \l_peek_token \c_space_token + \exp_after:wN \@@_grab_f_space_aux:w + \else: + \group_align_safe_end: + \exp_after:wN \@@_grab_f_loop:w + \fi: + } +\cs_new_protected:Npn \@@_grab_f_space_aux:w + { + \group_align_safe_end: + \tl_set:Nn \l_@@_v_arg_tl { \obeyedline } + \peek_remove_spaces:n + { \@@_grab_f_loop:w } + } +\cs_new_protected:Npn \@@_grab_f_end:nn #1#2 + { + \tl_if_blank:nF {#1#2} + \ERROR + \exp_args:NNNo \group_end: + \tl_set:Nn \l_@@_v_arg_tl { \l_@@_v_arg_tl } + \@@_add_arg:x + { + \bool_if:NTF \l_@@_obey_spaces_bool + { \exp_not:V } + { \exp_args:NV \@@_grab_f_end:n } + \l_@@_v_arg_tl + } + \exp_args:NV \end \@currenvir + } +% \end{macrocode} +% Look for line markers at each end and tidy up if required. +% \begin{macrocode} +\cs_new:Npn \@@_grab_f_end:n #1 + { + \@@_grab_f_end_auxi:w {#1} #1 + \q_nil \obeyedline \q_nil \obeyedline \q_nil \q_stop + } +\cs_new:Npn \@@_grab_f_end_auxi:w + #1#2 \obeyedline \q_nil \obeyedline \q_nil #3 \q_stop + { + \tl_if_empty:nTF {#3} + { \@@_grab_f_end_auxii:w {#1} #1 } + { \@@_grab_f_end_auxii:w {#2} #2 } + \obeyedline \q_stop + } +\cs_new:Npn \@@_grab_f_end_auxii:w + #1#2 \obeyedline #3 \q_stop + { + \tl_if_blank:nTF {#2} + { \tl_tail:n {#1} } + { \exp_not:n {#1} } + } +% \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} +% % \begin{macro} % { % \@@_grab_D:w , @@ -3025,26 +3261,36 @@ { \tl_map_inline:nn { { } { _no_strip } } { - \cs_new_protected:cpe { @@_grab_D #1 ##1 ####1 :w } - ########1########2########3 \@@_run_code: + \tl_map_inline:nn { { } { _verb_safe } } { - \exp_not:N \@@_grab_D_aux:NNnNNN - ########1 ########2 {########3} - \str_if_eq:nnTF {#1} { _long } - \cs_set_protected:Npn - \cs_set_protected_nopar:Npn - \str_if_eq:nnTF {##1} { _obey_spaces } - { \exp_not:N \@@_peek_meaning_remove:NTF } - { \exp_not:N \@@_peek_nonspace_remove:NTF } - \str_if_eq:nnTF {####1} { _no_strip } - { \exp_not:N \use_none:n } - { \exp_not:N \use_ii:nn } + \cs_new_protected:cpe { @@_grab_D #1 ##1 ####1 ########1 :w } + ################1################2################3 + \@@_run_code: + { + \exp_not:N \@@_grab_D_aux:NNnNNNN + ################1 ################2 {################3} + \str_if_eq:nnTF {#1} { _long } + \cs_set_protected:Npn + \cs_set_protected_nopar:Npn + \str_if_eq:nnTF {##1} { _obey_spaces } + { \exp_not:N \@@_peek_meaning_remove:NTF } + { \exp_not:N \@@_peek_nonspace_remove:NTF } + \str_if_eq:nnTF {####1} { _no_strip } + { \exp_not:N \use_none:n } + { \exp_not:N \use_ii:nn } + \str_if_eq:nnTF {########1} { _verb_safe } + { \exp_not:N \use:n } + { \exp_not:N \use_none:n } + } } } } } % \end{macrocode} -% \begin{macro}{\@@_grab_D_aux:NNnNNN} +% \begin{macro}{\@@_grab_D_aux:NNnNNNN} +% \changes{v1.3a}{2024-12-12}{Extend to support \texttt{f}-type grabbing} +% \begin{macro}{\@@_grab_D_verb_safe:N} +% \changes{v1.3a}{2024-12-12}{New macro} % \begin{macro}{\@@_grab_D_aux:NNnNN} % This is a bit complicated. The idea is that, in order to check for % nested optional argument tokens (\texttt{[[...]]} and so on) the @@ -3054,12 +3300,48 @@ % 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:NNnNNN #1#2#3#4#5#6 +\group_begin: + \char_set_catcode_other:N \^^M + \cs_new_protected:Npn \@@_grab_D_aux:NNnNNNN #1#2#3#4#5#6#7 + { + \@@_grab_D_aux:NNnNN #1#2 {#3} #4 #6 + #7 + { + \group_begin: + \@@_grab_D_verb_safe:N #1 + } + #5 #1 + { + #7 { \group_end: } + \@@_grab_D_call:Nw #1 + } + { + #7 { \group_end: } + \@@_add_arg:o \c_novalue_tl + } + } +\group_end: +% \end{macrocode} +% The only awkwardness here is the need to preserve the catcode of the search +% token: this is done low-level for performance reasons. Only values that +% are realistic are included. +% \begin{macrocode} +\cs_new_protected:Npn \@@_grab_D_verb_safe:N #1 { - \@@_grab_D_aux:NNnNN #1#2 {#3} #4 #6 - #5 #1 - { \@@_grab_D_call:Nw #1 } - { \@@_add_arg:o \c_novalue_tl } + \cs_set_eq:NN \do \char_set_catcode_other:N + \dospecials + \char_set_catcode_other:N \^^M + \use:c + { + char_set_catcode_ + \if_catcode:w \c_math_toggle_token #1 math_toggle \else: + \if_catcode:w ^ #1 math_subscript \else: + \if_catcode:w \c_math_subscript_token #1 math_superscript \else: + \if_catcode:w A #1 letter \else: + other \fi: \fi: \fi: \fi: + :N + } + #1 } % \end{macrocode} % Inside the \enquote{standard} grabber, there is a test to see if the @@ -3094,6 +3376,7 @@ % \end{macro} % \end{macro} % \end{macro} +% \end{macro} % % \begin{macro}{\@@_grab_D_nested:NNnN} % \begin{macro}{\@@_grab_D_nested:w} @@ -4697,12 +4980,13 @@ % \changes{v1.0f}{2021/06/04}{Normalize various error messages} % \changes{v1.2c}{2023/12/22} % {Generalize message \texttt{invalid-bang} (gh/1198)} +% \changes{v1.3a}{2024-12-12}{Generalize message \texttt{arg-after-body}} % \begin{macrocode} \msg_new:nnnn { cmd } { arg-after-body } - { Argument~type~'b'~must~be~last~in~#1. } + { Argument~type~'#1'~must~be~last~in~#2. } { - The~'b'~argument~type~must~come~last~but~it~is~followed~ - by~'#2'~in~the~argument~specification.~This~is~not~allowed. + The~'#1'~argument~type~must~come~last~but~it~is~followed~ + by~'#3'~in~the~argument~specification.~This~is~not~allowed. \c_@@_ignore_def_tl } \msg_new:nnnn { cmd } { bad-arg-spec } diff --git a/base/testfiles-ltcmd/ltcmd005.luatex.tlg b/base/testfiles-ltcmd/ltcmd005.luatex.tlg deleted file mode 100644 index ad67a80c8..000000000 --- a/base/testfiles-ltcmd/ltcmd005.luatex.tlg +++ /dev/null @@ -1,358 +0,0 @@ -This is a generated file for the LaTeX2e validation system. -Don't change this file in any respect. -Author: Bruno Le Floch -============================================================ -TEST 1: Invalid '!' -============================================================ -! LaTeX cmd Error: Invalid argument prefix '!' in command '\testA'. -For immediate help type H . - ... -l. ... } -The prefix '!' is only allowed for trailing optional arguments. You tried to apply it to an optional argument before mandatory 'R(){-NoValue-}'. -LaTeX will ignore this entire definition. -! LaTeX cmd Error: Invalid argument prefix '!' in command '\testA'. -For immediate help type H . - ... -l. ... } -The prefix '!' is only allowed for trailing optional arguments. You tried to apply it to an optional argument before mandatory 'm'. -LaTeX will ignore this entire definition. -! LaTeX cmd Error: Invalid argument prefix '!' in command '\testA'. -For immediate help type H . - ... -l. ... } -The argument specification provided for command '\testA' has two '!' markers applied to the same argument; one is redundant. -! LaTeX cmd Error: Bad argument specification '!+!' for command '\testA'. -For immediate help type H . - ... -l. ... } -The argument specification provided is not valid: one or more mandatory parts are missing. -LaTeX will ignore this entire definition. -! LaTeX cmd Error: Bad argument specification '+!' for command '\testA'. -For immediate help type H . - ... -l. ... } -The argument specification provided is not valid: one or more mandatory parts are missing. -LaTeX will ignore this entire definition. -! LaTeX cmd Error: Bad argument specification '!' for command '\testA'. -For immediate help type H . - ... -l. ... } -The argument specification provided is not valid: one or more mandatory parts are missing. -LaTeX will ignore this entire definition. -! LaTeX cmd Error: Invalid argument prefix '+' in command '\testA'. -For immediate help type H . - ... -l. ... } -The argument specification provided for command '\testA' has two '+' markers applied to the same argument; one is redundant. -! LaTeX cmd Error: Bad argument specification '!o' for \testA. -For immediate help type H . - ... -l. ... } -Expandable commands must have a final mandatory argument (or no arguments at all). You cannot have a terminal optional argument with expandable commands. -! LaTeX cmd Error: Invalid argument prefix '!' in command '\testA'. -For immediate help type H . - ... -l. ... } -The prefix '!' is only allowed for trailing optional arguments. You tried to apply it to 'm'. -LaTeX will ignore this entire definition. -============================================================ -============================================================ -TEST 2: Valid '!' and avoid dropping spaces -============================================================ -Runaway argument? -! Paragraph ended before \testA was complete. - -\par -l. ... } -I suspect you've forgotten a `}', causing me to apply this -control sequence to too much text. How can we recover? -My plan is to forget the whole thing and hope for the best. -|a|-NoValue-|b|| -|a|b|-NoValue-| | -|a|b|d|| -|a|b|c[d]| \c_space_token | -Runaway argument? -! Paragraph ended before \testB was complete. - -\par -l. ... } -I suspect you've forgotten a `}', causing me to apply this -control sequence to too much text. How can we recover? -My plan is to forget the whole thing and hope for the best. -|a|\BooleanFalse |\BooleanTrue || -|a|\BooleanTrue |\BooleanFalse | | -|a|\BooleanTrue |\BooleanTrue || -|a|\BooleanTrue |\BooleanTrue | \c_space_token | -============================================================ -============================================================ -TEST 3: Environment body valid -============================================================ -============================================================ -|...|{\begin {any} \begin {unbalanced} \end {environments} \begin {provided}}{\end {nesting} \end {works} \begin {out} \end {!}}| -|...| -|-NoValue-| [...] \begin {any} \begin {unbalanced} \end {environments} \begin {provided} \end {nesting} \end {works} \begin {out} \end {!} | -|-NoValue-| -============================================================ -TEST 4: Body invalid -============================================================ -|-NoValue-|{}| -! LaTeX Error: \begin{env1} on input line ... ended by \end{env2}. -See the LaTeX manual or LaTeX Companion for explanation. -Type H for immediate help. - ... -l. ... } -Your command was ignored. -Type I to replace it with another command, -or to continue without it. -Runaway argument? -\begin -! Paragraph ended before \environment env2 was complete. - -\par -l. ... } -I suspect you've forgotten a `}', causing me to apply this -control sequence to too much text. How can we recover? -My plan is to forget the whole thing and hope for the best. -! LaTeX cmd Error: Invalid argument type 'b' in command '\testE'. -For immediate help type H . - ... -l. ... } -The letter 'b' can only be used in environment argument specifications, but not for commands. -LaTeX will ignore the entire definition. -! LaTeX cmd Error: Argument type 'b' must be last in environment 'env3'. -For immediate help type H . - ... -l. ... } -The 'b' argument type must come last but it is followed by 'm' in the argument specification. This is not allowed. -LaTeX will ignore this entire definition. -============================================================ -============================================================ -TEST 5: Invalid signatures -============================================================ -! LaTeX cmd Error: Bad argument specification 'O' for command '\testA'. -For immediate help type H . - ... -l. ... } -The argument specification provided is not valid: one or more mandatory parts are missing. -LaTeX will ignore this entire definition. -! LaTeX cmd Error: Bad argument specification 'D[]' for environment 'testA'. -For immediate help type H . - ... -l. ... } -The argument specification provided is not valid: one or more mandatory parts are missing. -LaTeX will ignore this entire definition. -! LaTeX cmd Error: Bad argument specification '!+>{\TrimSpaces }' for environment 'testA'. -For immediate help type H . - ... -l. ... } -The argument specification provided is not valid: one or more mandatory parts are missing. -LaTeX will ignore this entire definition. -! LaTeX cmd Error: Invalid argument prefix '!' in command '\testA'. -For immediate help type H . - ... -l. ... } -The prefix '!' is only allowed for trailing optional arguments. You tried to apply it to an optional argument before mandatory 'm'. -LaTeX will ignore this entire definition. -! LaTeX cmd Error: Invalid argument prefix '!' in environment 'testA'. -For immediate help type H . - ... -l. ... } -The prefix '!' is only allowed for trailing optional arguments. You tried to apply it to an optional argument before mandatory 'm'. -LaTeX will ignore this entire definition. -! LaTeX cmd Error: Too many arguments for command '\testA'. -For immediate help type H . - ... -l. ... } -The argument specification 'mmmmmmmmmmmm' asks for more than 9 arguments. This cannot be implemented. -LaTeX will ignore this entire definition. -! LaTeX cmd Error: Too many arguments for environment 'testA'. -For immediate help type H . - ... -l. ... } -The argument specification 'mmmmmmmmmmmm' asks for more than 9 arguments. This cannot be implemented. -LaTeX will ignore this entire definition. -! LaTeX cmd Error: Invalid argument prefix '!' in command '\testA'. -For immediate help type H . - ... -l. ... } -The argument specification provided for command '\testA' has two '!' markers applied to the same argument; one is redundant. -! LaTeX cmd Error: Invalid argument prefix '!' in environment 'testA'. -For immediate help type H . - ... -l. ... } -The argument specification provided for environment 'testA' has two '!' markers applied to the same argument; one is redundant. -! LaTeX cmd Error: Invalid argument type 'X' in command '\testA'. -For immediate help type H . - ... -l. ... } -The letter 'X' does not specify a known argument type. -LaTeX will ignore this entire definition. -! LaTeX cmd Error: Invalid argument type 'X' in environment 'testA'. -For immediate help type H . - ... -l. ... } -The letter 'X' does not specify a known argument type. -LaTeX will ignore this entire definition. -============================================================ -============================================================ -TEST 6: Already or not yet defined -============================================================ -! LaTeX cmd Error: Command '\space' already defined. -For immediate help type H . - ... -l. ... } -You have used \NewDocumentCommand with a command that already has a definition. -The existing definition of '\space' will not be altered. -|macro:-> | -! LaTeX cmd Error: Environment 'foo' already defined. -For immediate help type H . - ... -l. ... } -You have used \NewDocumentEnvironment with an environment that already has a definition. -The existing definition of 'foo' will not be altered. -foo -! LaTeX cmd Error: Command '\testA' undefined. -For immediate help type H . - ... -l. ... } -You have used \RenewDocumentCommand with a command that was never defined. -LaTeX will ignore this entire definition. -! LaTeX cmd Error: Environment 'testA' undefined. -For immediate help type H . - ... -l. ... } -You have used \RenewDocumentEnvironment with an environment that was never defined. -LaTeX will ignore this entire definition. -============================================================ -============================================================ -TEST 7: Not definable/multi-char -============================================================ -! LaTeX cmd Error: First argument of '\NewDocumentCommand' must be a command. -For immediate help type H . - ... -l. ... } -The first argument of '\NewDocumentCommand' should be the document command that will be defined. The provided argument '+' is a character. Perhaps a backslash is missing? -LaTeX will ignore this entire definition. -! LaTeX cmd Error: First argument of '\NewDocumentCommand' must be a command. -For immediate help type H . - ... -l. ... } -The first argument of '\NewDocumentCommand' should be the document command that will be defined. The provided argument 'space' contains more than one token. Perhaps a backslash is missing? -LaTeX will ignore this entire definition. -! LaTeX cmd Error: Argument delimiter 'ab' invalid in command '\testB'. -For immediate help type H . - ... -l. ... } -The argument specification contains 'ab' in a place where a single token is required. -LaTeX will ignore this entire definition. -! Use of \??? doesn't match its definition. - \??? - ! LaTeX cmd Error: Invalid argument {foo} to \IfBoolean... -l. ... } -If you say, e.g., `\def\a1{...}', then you must always -put `1' after `\a', since control sequence names are -made up of letters only. The macro here has not been -followed by the required stuff, so I'm ignoring it. -FALSE -! Use of \??? doesn't match its definition. - \??? - ! LaTeX cmd Error: Invalid argument {\foo } to \IfBoolean... -l. ... } -If you say, e.g., `\def\a1{...}', then you must always -put `1' after `\a', since control sequence names are -made up of letters only. The macro here has not been -followed by the required stuff, so I'm ignoring it. -! Use of \??? doesn't match its definition. - \??? - ! LaTeX cmd Error: Invalid argument {?} to \IfBoolean... -l. ... } -If you say, e.g., `\def\a1{...}', then you must always -put `1' after `\a', since control sequence names are -made up of letters only. The macro here has not been -followed by the required stuff, so I'm ignoring it. -FALSE -============================================================ -============================================================ -TEST 8: Invalid signatures for expandable commands -============================================================ -! LaTeX cmd Error: Bad argument specification 'mo' for \testA. -For immediate help type H . - ... -l. ... } -Expandable commands must have a final mandatory argument (or no arguments at all). You cannot have a terminal optional argument with expandable commands. -! LaTeX cmd Error: Invalid argument prefix '+' in command '\testA'. -For immediate help type H . - ... -l. ... } -The arguments for an expandable command must not involve short arguments after long arguments. You have tried to mix the two types when defining '\testA'. -! LaTeX cmd Error: Invalid argument type 'v' in \testA. -For immediate help type H . - ... -l. ... } -The letter 'v' specifies an argument type which cannot be used in an expandable command. -LaTeX will ignore this entire definition. -! LaTeX cmd Error: Invalid argument prefix '>' in command '\testA'. -For immediate help type H . - ... -l. ... } -The argument specification for '\testA' contains the processor function '>{\TrimSpaces }'. This is only supported for robust commands, but not for expandable ones. -LaTeX will ignore this entire definition. -============================================================ -============================================================ -TEST 9: Run-time errors -============================================================ -! LaTeX cmd Error: Circular dependency in defaults of command '\testA'. -For immediate help type H . - ... -l. ... } -The default values of two or more arguments of the command '\testA' depend on each other in a way that cannot be resolved. -\C \E \C \E \C \E \C \E -NoValue-|\C \E \C \E \C \E \C \E -NoValue--NoValue-|\C |\C \E |\E -! LaTeX cmd Error: Circular dependency in defaults of environment 'testB'. -For immediate help type H . - ... -l. ... } -The default values of two or more arguments of the environment 'testB' depend on each other in a way that cannot be resolved. -\C \E \C \E \C \E \C \E -NoValue-|\C \E \C \E \C \E \C \E -NoValue--NoValue-|\C |\C \E |\E -! LaTeX cmd Error: Too many ',' separators in argument. -For immediate help type H . - ... -l. ... } -LaTeX was asked to split the input 'a,b,c,d' at each occurrence of the separator ',' into 3 parts. Too many separators were found. -! LaTeX cmd Error: Too many ',' separators in argument. -For immediate help type H . - ... -l. ... } -LaTeX was asked to split the input 'a,b,c,d' at each occurrence of the separator ',' into 3 parts. Too many separators were found. -! LaTeX cmd Error: Verbatim-like command '\testE' illegal in argument. -For immediate help type H . - ... -l. ... } -The command '\testE' takes a verbatim argument and should therefore normally not be used in arguments of other commands or environments. LaTeX found an illegal token (\TYPE ) after '+' and will drop everything up to this point. -Expect further (low-level) errors. --NoValue- -+ -! LaTeX cmd Error: Verbatim-like environment 'testF' illegal in argument. -For immediate help type H . - ... -l. ... } -The environment 'testF' takes a verbatim argument and should therefore normally not be used in arguments of other commands or environments. LaTeX found an illegal token (\TYPE ) after '+' and will drop everything up to this point. -Expect further (low-level) errors. --NoValue- -+ -============================================================ -! LaTeX cmd Error: Verbatim-like command '\testG' ended by end of line. -For immediate help type H . - ... -l. ...\testG+ -The verbatim argument of the command '\testG' 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 '+' and you may get some additional (low-level) errors. --NoValue- -+ -! LaTeX cmd Error: Verbatim-like environment 'testH' ended by end of line. -For immediate help type H . - ... -l. ...\begin{testH}+ -The verbatim argument of the environment 'testH' 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 '+' and you may get some additional (low-level) errors. --NoValue- -+ diff --git a/base/testfiles-ltcmd/ltcmd005.lvt b/base/testfiles-ltcmd/ltcmd005.lvt index 08d4570f0..94c79952b 100644 --- a/base/testfiles-ltcmd/ltcmd005.lvt +++ b/base/testfiles-ltcmd/ltcmd005.lvt @@ -56,54 +56,6 @@ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% The following tests are outside to allow \ExplSyntaxOff and \obeylines -\TEST { Environment~body~valid } { } - -\NewDocumentEnvironment { env1 } { o >{\SplitList{\par}} + b } - { \TYPE { \tl_to_str:n {|#1|#2|} } } - { \TYPE { \tl_to_str:n {|#1|} } } -\NewDocumentEnvironment { env2 } { ! o ! b } - { \TYPE { \tl_to_str:n {|#1|#2|} } } - { \TYPE { \tl_to_str:n {|#1|} } } -\ExplSyntaxOff -\begin{env1} [...] - \begin{any} - \begin{unbalanced} - \end{environments} - \begin{provided} - - \end{nesting} - \end{works} - \begin{out} - \end{!} -\end{env1} -\begin{env2} [...] - \begin{any} - \begin{unbalanced} - \end{environments} - \begin{provided} - \end{nesting} - \end{works} - \begin{out} - \end{!} -\end{env2} -\ExplSyntaxOn - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -\TEST { Body~invalid } - { - \begin{env1}\end{env2} - \begin{env2} - \par - \end{env2} - \NewDocumentCommand{\testE} { b } { } - \NewDocumentEnvironment{env3} { b m } { } { } - } - -% The rest of this test tests all of xparse's messages. - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - \TEST { Invalid~signatures } { % Disabled: test requires deprecated xparse.sty diff --git a/base/testfiles-ltcmd/ltcmd005.tlg b/base/testfiles-ltcmd/ltcmd005.tlg index 1a20f4d3b..c085f0b5e 100644 --- a/base/testfiles-ltcmd/ltcmd005.tlg +++ b/base/testfiles-ltcmd/ltcmd005.tlg @@ -85,49 +85,7 @@ My plan is to forget the whole thing and hope for the best. |a|\BooleanTrue |\BooleanTrue | \c_space_token | ============================================================ ============================================================ -TEST 3: Environment body valid -============================================================ -============================================================ -|...|{\begin {any} \begin {unbalanced} \end {environments} \begin {provided}}{\end {nesting} \end {works} \begin {out} \end {!}}| -|...| -|-NoValue-| [...] \begin {any} \begin {unbalanced} \end {environments} \begin {provided} \end {nesting} \end {works} \begin {out} \end {!} | -|-NoValue-| -============================================================ -TEST 4: Body invalid -============================================================ -|-NoValue-|{}| -! LaTeX Error: \begin{env1} on input line ... ended by \end{env2}. -See the LaTeX manual or LaTeX Companion for explanation. -Type H for immediate help. - ... -l. ... } -Your command was ignored. -Type I to replace it with another command, -or to continue without it. -Runaway argument? -\begin -! Paragraph ended before \environment env2 was complete. - - \par -l. ... } -I suspect you've forgotten a `}', causing me to apply this -control sequence to too much text. How can we recover? -My plan is to forget the whole thing and hope for the best. -! LaTeX cmd Error: Invalid argument type 'b' in command '\testE'. -For immediate help type H . - ... -l. ... } -The letter 'b' can only be used in environment argument specifications, but not for commands. -LaTeX will ignore the entire definition. -! LaTeX cmd Error: Argument type 'b' must be last in environment 'env3'. -For immediate help type H . - ... -l. ... } -The 'b' argument type must come last but it is followed by 'm' in the argument specification. This is not allowed. -LaTeX will ignore this entire definition. -============================================================ -============================================================ -TEST 5: Invalid signatures +TEST 3: Invalid signatures ============================================================ ! LaTeX cmd Error: Bad argument specification 'O' for command '\testA'. For immediate help type H . @@ -195,7 +153,7 @@ The letter 'X' does not specify a known argument type. LaTeX will ignore this entire definition. ============================================================ ============================================================ -TEST 6: Already or not yet defined +TEST 4: Already or not yet defined ============================================================ ! LaTeX cmd Error: Command '\space' already defined. For immediate help type H . @@ -225,7 +183,7 @@ You have used \RenewDocumentEnvironment with an environment that was never defin LaTeX will ignore this entire definition. ============================================================ ============================================================ -TEST 7: Not definable/multi-char +TEST 5: Not definable/multi-char ============================================================ ! LaTeX cmd Error: First argument of '\NewDocumentCommand' must be a command. For immediate help type H . @@ -273,7 +231,7 @@ followed by the required stuff, so I'm ignoring it. FALSE ============================================================ ============================================================ -TEST 8: Invalid signatures for expandable commands +TEST 6: Invalid signatures for expandable commands ============================================================ ! LaTeX cmd Error: Bad argument specification 'mo' for \testA. For immediate help type H . @@ -299,7 +257,7 @@ The argument specification for '\testA' contains the processor function '>{\Trim LaTeX will ignore this entire definition. ============================================================ ============================================================ -TEST 9: Run-time errors +TEST 7: Run-time errors ============================================================ ! LaTeX cmd Error: Circular dependency in defaults of command '\testA'. For immediate help type H . diff --git a/base/testfiles-ltcmd/ltcmd009.lvt b/base/testfiles-ltcmd/ltcmd009.lvt new file mode 100644 index 000000000..fa8892b9d --- /dev/null +++ b/base/testfiles-ltcmd/ltcmd009.lvt @@ -0,0 +1,106 @@ + +\documentclass{minimal} +\input{regression-test} + +\ExplSyntaxOn +\debug_on:n { check-declarations , deprecation , log-functions } +\ExplSyntaxOff +% \RequirePackage{xparse} + +\begin{document} + +\START +\AUTHOR{Bruno Le Floch, Joseph Wright} + +\ExplSyntaxOn + +% The following tests are outside to allow \ExplSyntaxOff and \obeylines +\TEST { Environment~body~valid } { } + +\NewDocumentEnvironment { env1 } { o >{\SplitList{\par}} +b } + { \TYPE { \tl_to_str:n {|#1|#2|} } } + { \TYPE { \tl_to_str:n {|#1|} } } +\NewDocumentEnvironment { env2 } { !o !b } + { \TYPE { \tl_to_str:n {|#1|#2|} } } + { \TYPE { \tl_to_str:n {|#1|} } } +\ExplSyntaxOff +\begin{env1} [...] + \begin{any} + \begin{unbalanced} + \end{environments} + \begin{provided} + + \end{nesting} + \end{works} + \begin{out} + \end{!} +\end{env1} +\begin{env2} [...] + \begin{any} + \begin{unbalanced} + \end{environments} + \begin{provided} + \end{nesting} + \end{works} + \begin{out} + \end{!} +\end{env2} +\ExplSyntaxOn + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\TEST { Body~invalid } + { + \begin{env1}\end{env2} + \begin{env2} + \par + \end{env2} + \NewDocumentCommand{\testE} { b } { } + \NewDocumentEnvironment{env3} { b m } { } { } + } + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\TEST { Verbatim~body~collection } { } +\NewDocumentEnvironment { env3 } { *o f } + { \TYPE { \tl_to_str:n {|#1|#2|} } } + { } +\NewDocumentEnvironment { env4 } { *!o !f } + { \TYPE { \tl_to_str:n {|#1|#2|} } } + { } +\NewDocumentEnvironment { env5 } { *d$$ f } + { \TYPE { \tl_to_str:n {|#1|#2|} } } + { } + +\ExplSyntaxOff +\begin{env3}% + + Content + &\^ +\end{env3} +\begin{env3}[...] + + Content + &\^ +\end{env3} +\begin{env4}% + + Content + &\^ +\end{env4} +\begin{env4}[...] + + Content + &\^ +\end{env4} +\begin{env5}% + + Content + &\^ +\end{env5} +\begin{env5}$...$ + + Content + &\^ +\end{env5} + +\END diff --git a/base/testfiles-ltcmd/ltcmd009.tlg b/base/testfiles-ltcmd/ltcmd009.tlg new file mode 100644 index 000000000..d360369cb --- /dev/null +++ b/base/testfiles-ltcmd/ltcmd009.tlg @@ -0,0 +1,55 @@ +This is a generated file for the LaTeX2e validation system. +Don't change this file in any respect. +Author: Bruno Le Floch, Joseph Wright +============================================================ +TEST 1: Environment body valid +============================================================ +============================================================ +|...|{\begin {any} \begin {unbalanced} \end {environments} \begin {provided}}{\end {nesting} \end {works} \begin {out} \end {!}}| +|...| +|-NoValue-| [...] \begin {any} \begin {unbalanced} \end {environments} \begin {provided} \end {nesting} \end {works} \begin {out} \end {!} | +|-NoValue-| +============================================================ +TEST 2: Body invalid +============================================================ +|-NoValue-|{}| +! LaTeX Error: \begin{env1} on input line ... ended by \end{env2}. +See the LaTeX manual or LaTeX Companion for explanation. +Type H for immediate help. + ... +l. ... } +Your command was ignored. +Type I to replace it with another command, +or to continue without it. +Runaway argument? +\begin +! Paragraph ended before \environment env2 was complete. + + \par +l. ... } +I suspect you've forgotten a `}', causing me to apply this +control sequence to too much text. How can we recover? +My plan is to forget the whole thing and hope for the best. +! LaTeX cmd Error: Invalid argument type 'b' in command '\testE'. +For immediate help type H . + ... +l. ... } +The letter 'b' can only be used in environment argument specifications, but not for commands. +LaTeX will ignore the entire definition. +! LaTeX cmd Error: Argument type 'b' must be last in environment 'env3'. +For immediate help type H . + ... +l. ... } +The 'b' argument type must come last but it is followed by 'm' in the argument specification. This is not allowed. +LaTeX will ignore this entire definition. +============================================================ +============================================================ +TEST 3: Verbatim body collection +============================================================ +============================================================ +|-NoValue-|%\obeyedline \obeyedline Content\obeyedline &\^| +|...|\obeyedline Content\obeyedline &\^| +|-NoValue-|%\obeyedline \obeyedline Content\obeyedline &\^\obeyedline | +|...|\obeyedline \obeyedline Content\obeyedline &\^\obeyedline | +|-NoValue-|%\obeyedline \obeyedline Content\obeyedline &\^| +|...|\obeyedline Content\obeyedline &\^|