summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/source/latex-dev/base
diff options
context:
space:
mode:
Diffstat (limited to 'Master/texmf-dist/source/latex-dev/base')
-rw-r--r--Master/texmf-dist/source/latex-dev/base/classes.dtx9
-rw-r--r--Master/texmf-dist/source/latex-dev/base/cmfonts.fdd6
-rw-r--r--Master/texmf-dist/source/latex-dev/base/doc.dtx4
-rw-r--r--Master/texmf-dist/source/latex-dev/base/ltclass.dtx23
-rw-r--r--Master/texmf-dist/source/latex-dev/base/ltcmd.dtx110
-rw-r--r--Master/texmf-dist/source/latex-dev/base/ltcmdhooks.dtx424
-rw-r--r--Master/texmf-dist/source/latex-dev/base/ltfilehook.dtx10
-rw-r--r--Master/texmf-dist/source/latex-dev/base/ltfiles.dtx66
-rw-r--r--Master/texmf-dist/source/latex-dev/base/ltfinal.dtx94
-rw-r--r--Master/texmf-dist/source/latex-dev/base/ltfssbas.dtx13
-rw-r--r--Master/texmf-dist/source/latex-dev/base/lthooks.dtx2769
-rw-r--r--Master/texmf-dist/source/latex-dev/base/ltlists.dtx7
-rw-r--r--Master/texmf-dist/source/latex-dev/base/ltmarks.dtx5
-rw-r--r--Master/texmf-dist/source/latex-dev/base/ltmath.dtx23
-rw-r--r--Master/texmf-dist/source/latex-dev/base/ltmeta.dtx5
-rw-r--r--Master/texmf-dist/source/latex-dev/base/ltpara.dtx5
-rw-r--r--Master/texmf-dist/source/latex-dev/base/ltplain.dtx54
-rw-r--r--Master/texmf-dist/source/latex-dev/base/ltshipout.dtx2
-rw-r--r--Master/texmf-dist/source/latex-dev/base/ltspace.dtx4
-rw-r--r--Master/texmf-dist/source/latex-dev/base/ltvers.dtx2
-rw-r--r--Master/texmf-dist/source/latex-dev/base/ltxdoc.dtx14
-rw-r--r--Master/texmf-dist/source/latex-dev/base/ltxref.dtx93
-rw-r--r--Master/texmf-dist/source/latex-dev/base/slifonts.fdd2
-rw-r--r--Master/texmf-dist/source/latex-dev/base/tulm.fdd2
24 files changed, 3269 insertions, 477 deletions
diff --git a/Master/texmf-dist/source/latex-dev/base/classes.dtx b/Master/texmf-dist/source/latex-dev/base/classes.dtx
index e16dc657a1d..58690e83759 100644
--- a/Master/texmf-dist/source/latex-dev/base/classes.dtx
+++ b/Master/texmf-dist/source/latex-dev/base/classes.dtx
@@ -53,7 +53,7 @@
%<*driver>
\ProvidesFile{classes.drv}
%</driver>
- [2022/07/02 v1.4n
+ [2023/05/17 v1.4n
%<article|report|book> Standard LaTeX document class]
%<10pt|11pt|12pt> Standard LaTeX file (size option)]
% \end{macrocode}
@@ -3688,9 +3688,8 @@
%
% A |\caption| command in a `figure' environment writes
%
-% |\contentsline{figure}{\numberline{|\meta{num}|}{|%
+% |\contentsline{figure}{\numberline{|\meta{num}|}{|^^A
% \meta{caption}|}}{|\meta{page}|}|
-%
% on the .\file{lof} file, where \meta{num} is the number produced
% by |\thefigure| and \meta{caption} is the figure caption. It
% works similarly for a `table' environment.
@@ -3707,8 +3706,8 @@
% \meta{title}|}{|\meta{page}|}|
%
% \begin{description}
-% \item[\meta{level}] An entry is produced only if\meta{ level}
-% $<=$ value of the \Lcount{tocdepth} counter. Note,
+% \item[\meta{level}] An entry is produced only if \meta{level}
+% $\leq$ value of the \Lcount{tocdepth} counter. Note,
% |\chapter| is level 0, |\section| is level 1, etc.
% \item[\meta{indent}] The indentation from the outer left margin
% of the start of the contents line.
diff --git a/Master/texmf-dist/source/latex-dev/base/cmfonts.fdd b/Master/texmf-dist/source/latex-dev/base/cmfonts.fdd
index 477085eaeff..af898e47b24 100644
--- a/Master/texmf-dist/source/latex-dev/base/cmfonts.fdd
+++ b/Master/texmf-dist/source/latex-dev/base/cmfonts.fdd
@@ -1,6 +1,6 @@
% \iffalse meta-comment
%
-% Copyright 1993-2022
+% Copyright (C) 1993-2023
% The LaTeX Project and any individual authors listed elsewhere
% in this file.
%
@@ -67,7 +67,7 @@
%<*driver, >
\ProvidesFile{cmfonts.drv}
%</driver, >
- [2022/07/10 v2.5l Standard LaTeX font definitions]
+ [2023/04/13 v2.5m Standard LaTeX font definitions]
%
%<*driver>
\documentclass{ltxdoc}
@@ -1048,8 +1048,10 @@
% \end{macrocode}
%
% \changes{v2.5j}{2019/12/16}{Provide substitutions for cmtt/bx/sl}
+% \changes{v2.5m}{2023/04/13}{Add missing substitution for U/cmtt/bx/sl}
% \begin{macrocode}
%<+OT1cmtt>\DeclareFontShape{OT1}{cmtt}{bx}{sl}
+%<+Ucmtt>\DeclareFontShape{U}{cmtt}{bx}{sl}
%<-nowarn> {<->sub*cmtt/m/n}{}
%<+nowarn> {<->ssub*cmtt/m/n}{}
%<+OT1cmtt>\DeclareFontShape{OT1}{cmtt}{bx}{ui}
diff --git a/Master/texmf-dist/source/latex-dev/base/doc.dtx b/Master/texmf-dist/source/latex-dev/base/doc.dtx
index a2c95694aee..75e04cc299c 100644
--- a/Master/texmf-dist/source/latex-dev/base/doc.dtx
+++ b/Master/texmf-dist/source/latex-dev/base/doc.dtx
@@ -1,7 +1,7 @@
% \iffalse meta-comment
%
-% Copyright 1993-2022
-% The LaTeX3 Project and any individual authors listed elsewhere
+% Copyright (C) 1993-2023
+% The LaTeX Project and any individual authors listed elsewhere
% in this file.
%
% This file is part of the LaTeX base system.
diff --git a/Master/texmf-dist/source/latex-dev/base/ltclass.dtx b/Master/texmf-dist/source/latex-dev/base/ltclass.dtx
index f6d5994d3fc..bb521485085 100644
--- a/Master/texmf-dist/source/latex-dev/base/ltclass.dtx
+++ b/Master/texmf-dist/source/latex-dev/base/ltclass.dtx
@@ -33,7 +33,7 @@
%<*driver>
% \fi
\ProvidesFile{ltclass.dtx}
- [2022/11/16 v1.5f LaTeX Kernel (Class & Package Interface)]
+ [2023/04/14 v1.5h LaTeX Kernel (Class & Package Interface)]
% \iffalse
\documentclass{ltxdoc}
\GetFileInfo{ltclass.dtx}
@@ -324,6 +324,7 @@
%
% \DescribeMacro\IfPackageAtLeastTF
% \DescribeMacro\IfClassAtLeastTF
+% \DescribeMacro\IfFileAtLeastTF
% \DescribeMacro\@ifpackagelater
% \DescribeMacro\@ifclasslater
% \changes{v1.1i}{2013/07/07}{Correctly describe how the date in
@@ -890,12 +891,14 @@
%
% \begin{macro}{\IfPackageAtLeastTF}
% \begin{macro}{\IfClassAtLeastTF}
+% \begin{macro}{\IfFileAtLeastTF}
% \begin{macro}{\IfFormatAtLeastTF}
% |\IfFormatAtLeastTF{YYYY/MM/DD}{|\meta{true
% code}|}{|\meta{false code}|}|
% Test if the format is later or equal to the given date.
% \changes{v1.3k}{2020/04/07}{Macro added; also in rollback (gh/168)}
% \changes{v1.4e}{2021/07/19}{Drop \cs{@onlypreamble}}
+% \changes{v1.5g}{2023/03/28}{Added \cs{IfFileAtLeastTF} (gh/1015)}
% \begin{macrocode}
%</2ekernel>
%<*2ekernel|latexrelease>
@@ -904,6 +907,7 @@
\def\IfFormatAtLeastTF{\@ifl@t@r\fmtversion}
\let\IfPackageAtLeastTF\@ifpackagelater
\let\IfClassAtLeastTF\@ifclasslater
+\def\IfFileAtLeastTF#1{\expandafter\@ifl@t@r\csname ver@#1\endcsname}
% \end{macrocode}
% For rollback pretend it was available since the beginning of dawn.
% \begin{macrocode}
@@ -914,12 +918,14 @@
%<latexrelease>\def\IfFormatAtLeastTF{\@ifl@t@r\fmtversion}
%<latexrelease>\let\IfPackageAtLeastTF\@ifpackagelater
%<latexrelease>\let\IfClassAtLeastTF\@ifclasslater
+%<latexrelease>\def\IfFileAtLeastTF#1{\expandafter\@ifl@t@r\csname ver@#1\endcsname}
%<latexrelease>\EndIncludeInRelease
%<*2ekernel>
% \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
+% \end{macro}
%
% \begin{macro}{\@ifl@ter}
% \changes{v1.4e}{2021/07/19}{Drop \cs{@onlypreamble}}
@@ -2133,13 +2139,28 @@
% {Reset \cs{CurrentOption}}
% \changes{v1.3d}{2019/10/18}{Initialize \cs{...-h@@k} only when loading
% the package or class (gh/198)}
+% \changes{v1.5h}{2023/04/14}{Define \cs{load@onefilewithoptions} when
+% in \pkg{latexrelease} (gh/992)}
% \begin{macrocode}
%</2ekernel>
%<*2ekernel|latexrelease>
%<latexrelease>\IncludeInRelease{2020/10/01}%
%<latexrelease> {\@onefilewithoptions}{Hooks and unused options issue}%
+% \end{macrocode}
+%
+% Here this macro is called \cs{@onefilewithoptions}, but further
+% ahead in this file it is renamed to \cs{load@onefilewithoptions},
+% and \cs{@onefilewithoptions} becomes a wrapper around this, used for
+% bookkeeping when rolling back. Therefore, when in
+% \pkg{latexrelease}, we need to define \cs{load@onefilewithoptions}
+% instead, thus the extra guarded \cs{def} line below:
+% \begin{macrocode}
+%<*2ekernel>
\def\@onefilewithoptions#1[#2][#3]#4{%
+%</2ekernel>
+%<latexrelease>\def\load@onefilewithoptions#1[#2][#3]#4{%
% \end{macrocode}
+%
% We have to sanitise file names, so that something like
% \begin{verbatim}
% \usepackage{some/local/path/array}
diff --git a/Master/texmf-dist/source/latex-dev/base/ltcmd.dtx b/Master/texmf-dist/source/latex-dev/base/ltcmd.dtx
index 78a5a389aec..5f019cdc2a0 100644
--- a/Master/texmf-dist/source/latex-dev/base/ltcmd.dtx
+++ b/Master/texmf-dist/source/latex-dev/base/ltcmd.dtx
@@ -1,7 +1,7 @@
% \iffalse meta-comment
%
% Copyright (C) 1999 Frank Mittelbach, Chris Rowley, David Carlisle
-% Copyright (C) 2004-2008 Frank Mittelbach, The LaTeX3 Project
+% Copyright (C) 2004-2008 Frank Mittelbach, The LaTeX Project
% Copyright (C) 2009-2023
% 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.1b}
-\def\ltcmddate{2022-11-29}
+\def\ltcmdversion{v1.1d}
+\def\ltcmddate{2023-04-13}
% \end{macrocode}
%
%<*driver>
@@ -2123,8 +2123,8 @@
% 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.
+% 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
@@ -2132,7 +2132,24 @@
% then we call \cs{@@_copy_expandable:NnNNNNnnn} that will copy the
% top-level definition of the command, with the proper internal
% renames.
+%
% \begin{macrocode}
+%<latexrelease>\EndIncludeInRelease
+%<latexrelease>\IncludeInRelease{2020/10/01}{\@@_copy:NN}%
+%<latexrelease> {Support~\NewCommandCopy~in~ltcmd}
+%<latexrelease>\EndIncludeInRelease
+% \end{macrocode}
+%
+% \changes{v1.1c}{2023/03/12}
+% {Distinguish (non-expandable) document commands starting with
+% \cs{@@_start_expandable:nNNNNn}}
+% There's one variant: a command begins with \cs{@@_start_expandable:nNNNNn}
+% may still be un-expandable/protected if it's defined by
+% \cs{NewDocumentCommand} and friends, with empty or only m-type arguments.
+%
+% \begin{macrocode}
+%<latexrelease>\IncludeInRelease{2023/06/01}{\@@_copy_expandable:nnNN}%
+%<latexrelease> {Distinguish~non-expandable~document~commands}
\cs_new_protected:Npn \@@_copy_expandable:nnNN #1 #2 #3 #4
{
\cs_set_eq:cc { #1 ~ code } { #2 ~ code }
@@ -2140,9 +2157,36 @@
\@@_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
+ \token_if_protected_macro:NTF #4
+ { \cs_set_protected_nopar:Npx }{ \cs_set_nopar:Npx }
+ #3
{ \exp_after:wN \@@_copy_expandable:NnNNNNnnn #4 {#1} {#2} }
}
+%<latexrelease>\EndIncludeInRelease
+%<latexrelease>\IncludeInRelease{2021/11/15}{\@@_copy_expandable:nnNN}%
+%<latexrelease> {Support~\NewCommandCopy~in~ltcmd}
+%<latexrelease>\cs_new_protected:Npn \@@_copy_expandable:nnNN #1 #2 #3 #4
+%<latexrelease> {
+%<latexrelease> \cs_set_eq:cc { #1 ~ code } { #2 ~ code }
+%<latexrelease> \@@_set_eq_if_exist:cc { #1 ~ } { #2 ~ }
+%<latexrelease> \@@_set_eq_if_exist:cc { #1 ~ \c_space_tl } { #2 ~ \c_space_tl }
+%<latexrelease> \@@_set_eq_if_exist:cc { #1 ~ defaults } { #2 ~ defaults }
+%<latexrelease> \exp_after:wN \@@_copy_expandable_signature:NnNNNNnnn #4 {#1} {#2}
+%<latexrelease> \cs_set_nopar:Npx #3
+%<latexrelease> { \exp_after:wN \@@_copy_expandable:NnNNNNnnn #4 {#1} {#2} }
+%<latexrelease> }
+%<latexrelease>\EndIncludeInRelease
+%<latexrelease>\IncludeInRelease{2020/10/01}{\@@_copy_expandable:nnNN}%
+%<latexrelease> {Support~\NewCommandCopy~in~ltcmd}
+%<latexrelease>\EndIncludeInRelease
+% \end{macrocode}
+%
+% \begin{macrocode}
+%<latexrelease>\IncludeInRelease{2021/11/15}{\@@_copy:NN (part 2)}%
+%<latexrelease> {Support~\NewCommandCopy~in~ltcmd}
+% \end{macrocode}
+%
+% \begin{macrocode}
\cs_new:Npn \@@_copy_expandable:NnNNNNnnn #1 #2 #3 #4 #5 #6 #7 #8 #9
{
\exp_not:N #1 \exp_not:n { {#2} }
@@ -2355,7 +2399,7 @@
% worth it.
% \begin{macrocode}
%<latexrelease>\EndIncludeInRelease
-%<latexrelease>\IncludeInRelease{2020/10/01}{\@@_copy:NN}%
+%<latexrelease>\IncludeInRelease{2020/10/01}{\@@_copy:NN (part 2)}%
%<latexrelease> {Support~\NewCommandCopy~in~ltcmd}
%<latexrelease>\EndIncludeInRelease
% \end{macrocode}
@@ -2418,11 +2462,47 @@
}
\cs_new_protected:Npn \@@_show_expandable:N #1
{ \exp_after:wN \@@_show_expandable:NnNNNNnN #1 #1 }
+% \end{macrocode}
+%
+% \begin{macrocode}
+%<latexrelease>\EndIncludeInRelease
+%<latexrelease>\IncludeInRelease{2020/10/01}{\@@_show:N}%
+%<latexrelease> {Support~\ShowCommand~in~ltcmd}
+%<latexrelease>\EndIncludeInRelease
+% \end{macrocode}
+%
+% \changes{v1.1c}{2023/03/12}
+% {Distinguish (non-expandable) document commands starting with
+% \cs{@@_start_expandable:nNNNNn}}
+% There's one variant: a command begins with \cs{@@_start_expandable:nNNNNn}
+% may still be un-expandable/protected if it's defined by
+% \cs{NewDocumentCommand} and friends, with empty or only m-type arguments.
+% \begin{macrocode}
+%<latexrelease>\IncludeInRelease{2023/06/01}{\@@_show_expandable:NnNNNNnN}%
+%<latexrelease> {Distinguish~non-expandable~document~commands}
\cs_new_protected:Npn \@@_show_expandable:NnNNNNnN #1 #2 #3 #4 #5 #6 #7 #8
{
- \@@_show_command_aux:NnNNn \tl_show:x
- { expandable~document~command } #8 #5 {#2}
+ \exp_args:NNe \@@_show_command_aux:NnNNn \tl_show:x
+ { \token_if_protected_macro:NF #8 { expandable~ } document~command }
+ #8 #5 {#2}
}
+%<latexrelease>\EndIncludeInRelease
+%<latexrelease>\IncludeInRelease{2021/11/15}{\@@_show_expandable:NnNNNNnN}%
+%<latexrelease> {Support~\ShowCommand~in~ltcmd}
+%<latexrelease>\cs_new_protected:Npn \@@_show_expandable:NnNNNNnN #1 #2 #3 #4 #5 #6 #7 #8
+%<latexrelease> {
+%<latexrelease> \@@_show_command_aux:NnNNn \tl_show:x
+%<latexrelease> { expandable~document~command } #8 #5 {#2}
+%<latexrelease> }
+%<latexrelease>\EndIncludeInRelease
+%<latexrelease>\IncludeInRelease{2020/10/01}{\@@_show_expandable:NnNNNNnN}%
+%<latexrelease> {Support~\ShowCommand~in~ltcmd}
+%<latexrelease>\EndIncludeInRelease
+% \end{macrocode}
+%
+% \begin{macrocode}
+%<latexrelease>\IncludeInRelease{2021/11/15}{\@@_show:N (part 2)}%
+%<latexrelease> {Support~\ShowCommand~in~ltcmd}
% \end{macrocode}
%
% Now just print everything in the required format. The auxiliary
@@ -2675,7 +2755,7 @@
% \begin{macrocode}
%<latexrelease>\EndIncludeInRelease
%
-%<latexrelease>\IncludeInRelease{2020/10/01}{\@@_show:N}%
+%<latexrelease>\IncludeInRelease{2020/10/01}{\@@_show:N (part 2)}%
%<latexrelease> {Support~\ShowCommand~in~ltcmd}
%<latexrelease>\EndIncludeInRelease
% \end{macrocode}
@@ -3218,6 +3298,10 @@
% \begin{macro}{\@@_grab_v_long:w}
% \begin{macro}{\@@_grab_v_aux:w}
% \begin{macro}{\@@_grab_v_group_end:}
+% Firstly, it is necessary to change \cs{tex_endlinechar:D} so that
+% newlines in different catcode regimes (e.g., \cs{ExplSyntaxOn}) are
+% not misinterpreted as spaces.
+% \changes{v1.1d}{2023/04/13}{Set \cs{tex_endlinechar:D} earlier (gh/876).}
% The opening delimiter is the first non-space token, and is never
% read verbatim. This is required by consistency with the case where
% the preceding argument was optional and absent: then \TeX{} has
@@ -3251,6 +3335,7 @@
\tl_set:Nn \l_@@_signature_tl {#1}
\group_begin:
\tex_escapechar:D = 92 \scan_stop:
+ \tex_endlinechar:D = `\^^M \scan_stop:
\tl_clear:N \l_@@_v_arg_tl
\peek_remove_spaces:n
{
@@ -3268,8 +3353,8 @@
}
\cs_new_protected:Npn \@@_grab_v_group_end:
{
- \exp_args:NNNo
- \group_end:
+ \exp_args:NNNo
+ \group_end:
\tl_set:Nn \l_@@_v_arg_tl { \l_@@_v_arg_tl }
}
% \end{macrocode}
@@ -3414,7 +3499,6 @@
{
\cs_set_eq:NN \do \char_set_catcode_other:N
\dospecials
- \tex_endlinechar:D = `\^^M \scan_stop:
\bool_if:NTF \l_@@_long_bool
{ \char_set_catcode_other:n { \tex_endlinechar:D } }
{ \char_set_catcode_parameter:n { \tex_endlinechar:D } }
diff --git a/Master/texmf-dist/source/latex-dev/base/ltcmdhooks.dtx b/Master/texmf-dist/source/latex-dev/base/ltcmdhooks.dtx
index ccb5a35a712..27907af6798 100644
--- a/Master/texmf-dist/source/latex-dev/base/ltcmdhooks.dtx
+++ b/Master/texmf-dist/source/latex-dev/base/ltcmdhooks.dtx
@@ -1,7 +1,8 @@
% \iffalse meta-comment
%
-%% File: ltcmdhooks.dtx (C) Copyright 2020-2021
-%% Frank Mittelbach, Phelype Oleinik, LaTeX Team
+%% File: ltcmdhooks.dtx
+%% Copyright (C) 2020-2023
+%% Frank Mittelbach, Phelype Oleinik, The LaTeX Project
%
% It may be distributed and/or modified under the conditions of the
% LaTeX Project Public License (LPPL), either version 1.3c of this
@@ -13,8 +14,8 @@
%
%%% From File: ltcmdhooks.dtx
%
-\def\ltcmdhooksversion{v1.0f}
-\def\ltcmdhooksdate{2021/10/20}
+\def\ltcmdhooksversion{v1.0h}
+\def\ltcmdhooksdate{2023/05/21}
%
%
%
@@ -51,20 +52,32 @@
%
% This file implements generic hooks for (arbitrary) commands.
% In theory every command \tn[no-index]{\meta{name}} offers now two
-% associated hooks to which code can be added using \tn{AddToHook}
-% or \tn{AddToHookNext}.\footnote{In practice this is not supported
+% associated hooks to which code can be added using
+% \tn{AddToHook},\!\footnote{In this documentation, when something is
+% being said about \tn{AddToHook}, the same will be valid for
+% \tn{AddToHookWithArguments}, unless that particular paragraph is
+% highlighting the differences between both. The same is true for
+% the other hook-related functions and their
+% \texttt{\ldots WithArguments} counterparts.}
+% \tn{AddToHookNext}, \tn{AddToHookWithArguments}, and
+% \tn{AddToHookNextWithArguments}.\footnote{In practice this is not
+% supported
% for all types of commands, see section~\ref{sec:look-ahead} for
% the restrictions that apply and what happens if one tries to use
-% this with commands for which this is not supported.} These are
+% this with commands for which this is not supported.} These are:
% \begin{description}
% \item[\hook{cmd/\meta{name}/before}]
%
-% This hook is executed at the very start of the command
-% execution after its arguments (if any) are parsed. The hook
-% \meta{code} is wrapped in the command inside a call to
-% \cs{UseHook}|{cmd/|\meta{name}|/before}|, so the arguments
-% passed to the command are \emph{not} available in the hook
-% \meta{code}.
+% This hook is executed at the very start of the command, right
+% after its arguments (if any) are parsed. The hook \meta{code}
+% runs in the command inside a call to \cs{UseHookWithArguments}.
+% Any code added to this hook using \tn{AddToHookWithArguments}
+% or \tn{AddToHookNextWithArguments} can access the command's
+% arguments using |#1|, |#2|, etc., up to the number of arguments
+% of the command. If \tn{AddToHook} or \tn{AddToHookNext} are
+% used, the arguments cannot be accessed (see the \pkg{lthooks}
+% documentation\footnote{\texttt{texdoc lthooks-doc}} on hooks
+% with arguments).
%
% \item[\hook{cmd/\meta{name}/after}]
%
@@ -74,9 +87,12 @@
% \end{description}
%
% The hooks are not physically present before
-% \verb=\begin{document}= (i.e., using a command in the preamble
-% will never execute them) and if nobody has declared any code for
-% them, then they are not added to the command code ever. For
+% \verb=\begin{document}=\footnote{More specifically, they are
+% inserted in the commands after the \hook{begindocument} hook, so
+% they are also not present while \LaTeX{} is reading the
+% \texttt{.aux} file.} (i.e., using a command in the preamble
+% will never execute the hook) and if nobody has declared any code
+% for them, then they are not added to the command code ever. For
% example, if we have the following definition
%\begin{verbatim}
% \newcommand\foo[2]{Code #1 for #2!}
@@ -90,23 +106,27 @@
%\end{verbatim}
% then, after |\begin{document}| the definition of \cs[no-index]{foo} will be:
%\begin{verbatim}
-% \renewcommand\foo[2]{\UseHook{cmd/foo/before}Code #1 for #2!}
+% \renewcommand\foo[2]{%
+% \UseHookWithArguments{cmd/foo/before}{2}{#1}{#2}%
+% Code #1 for #2!}
%\end{verbatim}
% and similarly \verb=\AddToHook{cmd/foo/after}{<after code>}=
% alters the definition to
%\begin{verbatim}
-% \renewcommand\foo[2]{Code #1 for #2!\UseHook{cmd/foo/after}}
+% \renewcommand\foo[2]{%
+% Code #1 for #2!%
+% \UseHookWithArguments{cmd/foo/after}{2}{#1}{#2}}
%\end{verbatim}
%
% In other words, the mechanism is similar to what \pkg{etoolbox}
% offers with \tn{pretocmd} and \tn{apptocmd} with the important
-% differences
+% differences
% \begin{itemize}
% \item
%
% that code can be prepended or appended (i.e., added to the
% hooks) even if the command itself is not defined, because the
-% defining package has not yet been loaded
+% defining package has not yet been loaded;
%
% \item
%
@@ -197,6 +217,7 @@
%
%
% \section{Package Author Interface}
+% \label{sec:pkg-author}
%
% The \hook{cmd} hooks are, by default, available for all commands
% that can be patched to add the hooks. For some commands, however,
@@ -206,9 +227,10 @@
%
% If you are a package author and you want to add the hooks to your
% own commands in the proper position you can define the command and
-% manually add the \cs{UseHook} calls inside the command in the proper
-% positions, and manually define the hooks with \cs{NewHook} or
-% \cs{NewReversedHook}. When the hooks are explicitly defined,
+% manually add the \cs{UseHookWithArguments} calls inside the command in
+% the proper positions, and manually define the hooks with
+% \cs{NewHookWithArguments} or \cs{NewReversedHookWithArguments}.
+% When the hooks are explicitly defined,
% patching is not attempted so you can make sure your command works
% properly. For example, an (admittedly not really useful) command
% that typesets its contents in a framed box with width optionally
@@ -230,26 +252,27 @@
% \begin{verbatim}
% \newcommand\fancybox{\@ifnextchar({\@fancybox}{\@fancybox(5cm)}}
% \def\@fancybox(#1)#2{\fbox{%
-% \UseHook{cmd/fancybox/before}%
-% \parbox{#1}{#2}%
-% \UseHook{cmd/fancybox/after}}}
-% \NewHook{cmd/fancybox/before}
-% \NewReversedHook{cmd/fancybox/after}
+% \UseHookWithArguments{cmd/fancybox/before}{2}{#1}{#2}%
+% \parbox{#1}{#2}%
+% \UseHookWithArguments{cmd/fancybox/after}{2}{#1}{#2}}}
+% \NewHookWithArguments{cmd/fancybox/before}{2}
+% \NewReversedHookWithArguments{cmd/fancybox/after}{2}
% \end{verbatim}
% then the hooks will be executed where they should and no patching
% will be attempted. It is important that the hooks are declared with
-% \cs{NewHook} or \cs{NewReversedHook}, otherwise the command hook
+% \cs{NewHookWithArguments} or \cs{NewReversedHookWithArguments},
+% otherwise the command hook
% code will try to patch the command. Note also that the call to
-% |\UseHook{cmd/fancybox/before}| does not need to be in the
-% definition of \cs[no-index]{fancybox}, but anywhere it makes sense
+% |\UseHookWithArguments{cmd/fancybox/before}| does not need to be in
+% the definition of \cs[no-index]{fancybox}, but anywhere it makes sense
% to insert it (in this case in the internal
% \cs[no-index]{@fancybox}).
%
% Alternatively, if for whatever reason your command does not support
% the generic hooks provided here, you can disable a hook with
-% \cs{DisableHook}\footnote{Please use \cs{DisableHook} if at all, only
-% on hooks that you \enquote{own}, i.e., for commands that your
-% package or class defines and not second guess
+% \cs{DisableGenericHook}\footnote{Please use \cs{DisableGenericHook} if
+% at all, only on hooks that you \enquote{own}, i.e., for commands
+% your package or class defines and not second guess
% whether or not hooks of other packages should get disabled!}, so
% that when someone tries to add code to it they will get an error.
% Or if you don't want the error, you can simply declare the hook with
@@ -270,6 +293,55 @@
% If you do that then both hooks automatically work and are patched
% into the right places.
%
+% \subsection{Arguments and redefining commands}
+% \label{sec:redef-warn}
+%
+% The code in \pkg{ltcmdhooks} does its best to find out how many
+% arguments a given command has, and to insert the appropriate call to
+% \cs{UseHookWithArguments}, so that the arguments seen by the hook are
+% exactly those grabbed by the command (the hook, after all, is a macro
+% call, so the arguments have to be placed in the right order, or they
+% won't match).
+%
+% When using the package writer interface, as discussed in
+% section~\ref{sec:pkg-author}, to change the position of the hooks in
+% your commands, you are also free to change how the hook code in your
+% command sees its arguments. When a \hook{cmd} hook is declared with
+% \cs{NewHook} (or \cs{NewHookWithArguments} or other variations of
+% that), it loses its \enquote{generic} nature and works as a regular
+% hook. This means that you may choose to declare it without
+% arguments regardless if the command takes arguments or not, or
+% declare it with arguments, even if the command takes none.
+%
+% However, this flexibility should not be abused. When using a
+% nonstandard configuration for the hook arguments, think reasonably:
+% a user will expect that the argument \verb|#1| in the hook corresponds
+% to the argument's first argument, and so on. Any other configuration
+% is likely to cause confusion and, if used, will have to be well
+% documented.
+%
+% This flexibility, however, allows you to \enquote{correct} the
+% arguments for the hooks. For example, \LaTeX's \cs{refstepcounter}
+% has a single argument, the name of the counter. The \pkg{cleveref}
+% package adds an optional argument to \cs{refstepcounter}, making the
+% name of the counter argument \verb|#2|. If the author of
+% \pkg{cleveref} wanted, for whatever reason, to add hooks to
+% \cs{refstepcounter}, to preserve compatibility he could write
+% something along the lines of:
+% \begin{verbatim}
+% \NewHookWithArguments{cmd/refstepcounter/before}{1}
+% \renewcommand\refstepcounter[2][<default>]{%
+% \UseHookWithArguments{cmd/refstepcounter/before}{1}{#2}%
+% <code for \refstepcounter>}
+% \end{verbatim}
+% so that the mandatory argument, which is arg \verb|#2| in the
+% definition, would still be seen as \verb|#1| in the hook code.
+%
+% Another possibility would be to place the optional argument as the
+% second argument for the hook, so that people looking for it would be
+% able to use it. In either case, it would have to be well documented
+% to cause as little confusion as possible.
+%
% \MaybeStop{\setlength\IndexMin{200pt} \PrintIndex }
%
%
@@ -366,10 +438,13 @@
% \end{macro}
% \end{macro}
%
-% \begin{macro}{\c_@@_hash_tl}
-% A constant token list that contains two parameter tokens.
+% \begin{macro}{\c_@@_hash_tl,\c_@@_hashes_tl}
+% Two constant token lists that contain one and two parameter tokens.
+% \changes{v1.0g}{2023/04/06}
+% {Rename to \cs{c_@@_hashes_tl} and add \cs{c_@@_hash_tl} (hook-args).}
% \begin{macrocode}
-\tl_const:Nn \c_@@_hash_tl { # # }
+\tl_const:Nn \c_@@_hash_tl { # }
+\tl_const:Nn \c_@@_hashes_tl { # # }
% \end{macrocode}
% \end{macro}
%
@@ -702,7 +777,7 @@
%
% \changes{v1.0f}{2021/10/20}
% {Correct patching by expansion+redefinition when the macro
-% contains a parameter tokens (gh/697).}
+% contains a parameter token (gh/697).}
% Patching with expansion+redefinition is trickier than it looks like
% at first glance. Suppose the simple definition:
% \begin{verbatim}
@@ -756,6 +831,8 @@
% parameter token, so that this case can be handled like the previous
% one.
% \begin{macrocode}
+%<latexrelease>\IncludeInRelease{2023/06/01}{\@@_patch_expand_redefine:NNnn}
+%<latexrelease> {cmd~hooks~with~args}
\cs_new_protected:Npn \@@_patch_expand_redefine:NNnn #1 #2 #3 #4
{
\@@_patch_debug:x { ++~command~can~be~patched~without~rescanning }
@@ -779,14 +856,14 @@
% should be identical to the \meta{parameter text} used when
% originally defining that macro.
% \item[\cs{l_@@_replace_text_tl}] will contain braced pairs of
-% \cs{c_@@_hash_tl}\meta{num} to feed to the macro when expanded.
+% \cs{c_@@_hashes_tl}\meta{num} to feed to the macro when expanded.
% This token list as well as the previous will have the first item
% surrounded by |[|\ldots|]| in the case of an optional argument.
% \end{description}
%
-% The use of \cs{c_@@_hash_tl} here is to differentiate actual
+% The use of \cs{c_@@_hashes_tl} here is to differentiate actual
% parameters in the macro from parameter tokens in the original
-% definition of the macro. Later on, \cs{c_@@_hash_tl} is either
+% definition of the macro. Later on, \cs{c_@@_hashes_tl} is either
% replaced by actual parameter tokens, or expanded into them.
% \begin{macrocode}
\int_compare:nNnTF { \l_@@_patch_num_args_int } > { \c_zero_int }
@@ -795,7 +872,7 @@
% We'll first check if the command has any parameter token in its
% definition (feeding it empty arguments), and set \cs{@@_exp_not:n}
% accordingly. \cs{@@_exp_not:n} will be used later to either leave
-% \cs{c_@@_hash_tl} or expand it, and also to remember the result of
+% \cs{c_@@_hashes_tl} or expand it, and also to remember the result of
% \cs{@@_if_has_hash:nTF} to avoid testing twice (the test can be
% rather slow).
% \begin{macrocode}
@@ -814,20 +891,22 @@
% \end{macrocode}
% Here we'll conditionally add |[|\ldots|]| around the first
% parameter:
+% \changes{v1.0g}{2023/04/06}
+% {Rename to \cs{c_@@_hashes_tl} (hook-args).}
% \begin{macrocode}
\bool_if:NTF #1
- { \@@_tmp:w \tl_set:Nx { [ \c_@@_hash_tl 1 ] } }
- { \@@_tmp:w \tl_set:Nx { { \c_@@_hash_tl 1 } } }
+ { \@@_tmp:w \tl_set:Nx { [ \c_@@_hashes_tl 1 ] } }
+ { \@@_tmp:w \tl_set:Nx { { \c_@@_hashes_tl 1 } } }
% \end{macrocode}
% Then, for every parameter from the second, just add it normally:
% \begin{macrocode}
\int_step_inline:nnn { 2 } { \l_@@_patch_num_args_int }
- { \@@_tmp:w \tl_put_right:Nx { { \c_@@_hash_tl ##1 } } }
+ { \@@_tmp:w \tl_put_right:Nx { { \c_@@_hashes_tl ##1 } } }
% \end{macrocode}
% Now, if the command has any parameter token in its definition
% (then \cs{@@_exp_not:n} is \cs{exp_not:n}), call
% \cs{@@_double_hashes:n} to double them, and replace every
-% \cs{c_@@_hash_tl} by |#|:
+% \cs{c_@@_hashes_tl} by |#|:
% \begin{macrocode}
\tl_set:Nx \l_@@_replace_text_tl
{ \exp_not:N #2 \exp_not:V \l_@@_replace_text_tl }
@@ -875,22 +954,110 @@
{ \exp_not:N \@@_make_prefixes:w \cs_prefix_spec:N #2 / / }
}
% \end{macrocode}
-% Finally, call \cs{@@_redefine_with_hooks:Nnnn} with the macro being
+% Here we redefine the hook to have the right number of arguments.
+% Disabling the hook, undefining the \verb|parameter| token list then
+% calling \cs{@@_make_usable:nn} are enough to redefine the hook to
+% the extent we want. Code stored in the hook and other metadata
+% about it are not lost in the process.
+% \changes{v1.0h}{2023/05/21}
+% {Changes to allow support arguments in cmd hooks (cmd-args).}
+% \begin{macrocode}
+ \@@_disable:n { cmd / #3 / #4 }
+ \cs_undefine:c { c_@@_cmd / #3 / #4_parameter_tl }
+ \@@_make_usable:nn { cmd / #3 / #4 } { \l_@@_patch_num_args_int }
+% \end{macrocode}
+% Now call \cs{@@_redefine_with_hooks:Nnnn} with the macro being
% redefined in |#1|, then \cs{UseHook}|{cmd/<name>/before}| in |#2| or
% \cs{UseHook}|{cmd/<name>/after}| in |#3| (one is always empty), and
% in |#4| the \meta{replacement text} of the macro.
% \begin{macrocode}
- \use:x
+ \use:e
{
\@@_redefine_with_hooks:Nnnn \exp_not:N #2
\str_if_eq:nnTF {#4} { after }
{ \use_ii_i:nn }
{ \use:nn }
- { { \@@_exp_not:NN \exp_not:N \UseHook { cmd / #3 / #4 } } }
+ { {
+ \@@_exp_not:NN \exp_not:N \UseHookWithArguments
+ { cmd / #3 / #4 } { \int_use:N \l_@@_patch_num_args_int }
+ \@@_braced_parameter:n { cmd / #3 / #4 }
+ } }
{ { } }
{ \@@_exp_not:NN \exp_not:V \l_@@_replace_text_tl }
}
+% \end{macrocode}
+% Finally, update the hook code.
+% \begin{macrocode}
+ \@@_update_hook_code:n { cmd / #3 / #4 }
}
+%<latexrelease>\EndIncludeInRelease
+%<latexrelease>\IncludeInRelease{2021/06/01}{\@@_patch_expand_redefine:NNnn}
+%<latexrelease> {cmd~hooks~with~args}
+%<latexrelease>\cs_gset_protected:Npn \@@_patch_expand_redefine:NNnn #1 #2 #3 #4
+%<latexrelease> {
+%<latexrelease> \@@_patch_debug:x { ++~command~can~be~patched~without~rescanning }
+%<latexrelease> \int_set:Nn \l_@@_patch_num_args_int
+%<latexrelease> {
+%<latexrelease> \exp_args:Nf \str_count:n { \cs_argument_spec:N #2 } / 2
+%<latexrelease> \bool_if:NT #1 { -1 }
+%<latexrelease> }
+%<latexrelease> \int_compare:nNnTF { \l_@@_patch_num_args_int } > { \c_zero_int }
+%<latexrelease> {
+%<latexrelease> \tl_set:Nx \l_@@_tmpa_tl { \bool_if:NTF #1 { [ ] } { { } } }
+%<latexrelease> \int_step_inline:nnn { 2 } { \l_@@_patch_num_args_int }
+%<latexrelease> { \tl_put_right:Nn \l_@@_tmpa_tl { { } } }
+%<latexrelease> \exp_args:NNo \exp_args:No \@@_if_has_hash:nTF
+%<latexrelease> { \exp_after:wN #2 \l_@@_tmpa_tl }
+%<latexrelease> { \cs_set_eq:NN \@@_exp_not:n \exp_not:n }
+%<latexrelease> { \cs_set_eq:NN \@@_exp_not:n \use:n }
+%<latexrelease> \cs_set_protected:Npn \@@_tmp:w ##1 ##2
+%<latexrelease> {
+%<latexrelease> ##1 \l_@@_param_text_tl { \use:n ##2 }
+%<latexrelease> ##1 \l_@@_replace_text_tl { \@@_exp_not:n {##2} }
+%<latexrelease> }
+%<latexrelease> \bool_if:NTF #1
+%<latexrelease> { \@@_tmp:w \tl_set:Nx { [ \c_@@_hash_tl 1 ] } }
+%<latexrelease> { \@@_tmp:w \tl_set:Nx { { \c_@@_hash_tl 1 } } }
+%<latexrelease> \int_step_inline:nnn { 2 } { \l_@@_patch_num_args_int }
+%<latexrelease> { \@@_tmp:w \tl_put_right:Nx { { \c_@@_hash_tl ##1 } } }
+%<latexrelease> \tl_set:Nx \l_@@_replace_text_tl
+%<latexrelease> { \exp_not:N #2 \exp_not:V \l_@@_replace_text_tl }
+%<latexrelease> \tl_set:Nx \l_@@_replace_text_tl
+%<latexrelease> {
+%<latexrelease> \token_if_eq_meaning:NNTF \@@_exp_not:n \exp_not:n
+%<latexrelease> { \exp_args:NNV \exp_args:No \@@_double_hashes:n }
+%<latexrelease> { \exp_args:NV \exp_not:o }
+%<latexrelease> \l_@@_replace_text_tl
+%<latexrelease> }
+%<latexrelease> \cs_set_eq:NN \@@_def_cmd:w \tex_gdef:D
+%<latexrelease> \cs_set_eq:NN \@@_exp_not:NN \prg_do_nothing:
+%<latexrelease> }
+%<latexrelease> {
+%<latexrelease> \tl_clear:N \l_@@_param_text_tl
+%<latexrelease> \tl_set_eq:NN \l_@@_replace_text_tl #2
+%<latexrelease> \cs_set_eq:NN \@@_def_cmd:w \tex_xdef:D
+%<latexrelease> \cs_set:Npn \@@_exp_not:NN ##1 { \exp_not:N ##1 \exp_not:N }
+%<latexrelease> }
+%<latexrelease> \group_begin:
+%<latexrelease> \int_set:Nn \tex_escapechar:D { `\/ }
+%<latexrelease> \use:x
+%<latexrelease> {
+%<latexrelease> \group_end:
+%<latexrelease> \tl_set:Nx \exp_not:N \l_@@_patch_prefixes_tl
+%<latexrelease> { \exp_not:N \@@_make_prefixes:w \cs_prefix_spec:N #2 / / }
+%<latexrelease> }
+%<latexrelease> \use:x
+%<latexrelease> {
+%<latexrelease> \@@_redefine_with_hooks:Nnnn \exp_not:N #2
+%<latexrelease> \str_if_eq:nnTF {#4} { after }
+%<latexrelease> { \use_ii_i:nn }
+%<latexrelease> { \use:nn }
+%<latexrelease> { { \@@_exp_not:NN \exp_not:N \UseHook { cmd / #3 / #4 } } }
+%<latexrelease> { { } }
+%<latexrelease> { \@@_exp_not:NN \exp_not:V \l_@@_replace_text_tl }
+%<latexrelease> }
+%<latexrelease> }
+%<latexrelease>\EndIncludeInRelease
% \end{macrocode}
%
% Now that all the needed tools are ready, without further ado we'll
@@ -973,7 +1140,7 @@
% }
% \cs{@@_double_hashes:n} loops through the token list |#1| and
% duplicates any catcode~6 token, and expands tokens \cs{ifx}-equal to
-% \cs{c_@@_hash_tl}, and leaves all other tokens \cs{notexpanded} with
+% \cs{c_@@_hashes_tl}, and leaves all other tokens \cs{notexpanded} with
% \cs{exp_not:N}. Unfortunately pairs of explicit catcode~1 and
% catcode~2 character tokens are normalised to |{|$_1$ and |}|$_1$
% because it's not feasible to expandably detect the character code
@@ -1000,26 +1167,32 @@
% \end{macrocode}
%
% \cs{@@_double_hashes_output:N} checks for the end of the token list,
-% then checks if the token is \cs{c_@@_hash_tl}, and if so just leaves
+% then checks if the token is \cs{c_@@_hashes_tl}, and if so just leaves
% it.
+% \changes{v1.0g}{2023/04/06}
+% {Add case for \cs{c_@@_hashes_tl} (hook-args).}
% \begin{macrocode}
\cs_new:Npn \@@_double_hashes_output:N #1
{
\if_meaning:w \q_@@_recursion_tail #1
\@@_double_hashes_stop:w
\fi:
- \if_meaning:w \c_@@_hash_tl #1
+ \if:w ?
+ \if_meaning:w \c_@@_hash_tl #1 ! \fi:
+ \if_meaning:w \c_@@_hashes_tl #1 ! \fi:
+ ?
+ \else:
% \end{macrocode}
% (this \cs{use_i:nnnn} uses \cs{fi:} and consumes \cs{use:n}, the
% whole \cs{if_catcode:w} block, and the \cs{exp_not:N}, leaving just
-% |#1| which is \cs{c_@@_hash_tl}.)
+% |#1| which is \cs{c_@@_hashes_tl}.)
% \begin{macrocode}
\use_i:nnnn
\fi:
\use:n
{
% \end{macrocode}
-% If |#1| is not \cs{c_@@_hash_tl}, then check if its catcode is~6,
+% If |#1| is not \cs{c_@@_hashes_tl}, then check if its catcode is~6,
% and if so, leave it doubled in \cs{exp_not:n} and consume the
% following |\exp_not:N #1|.
% \begin{macrocode}
@@ -1080,10 +1253,10 @@
% \begin{macrocode}
\cs_new_protected:Npn \@@_retokenize_patch:Nnn #1 #2 #3
{
- \@@_patch_debug:x { ..~command~can~only~be~patched~by~rescanning }
\str_if_eq:eeTF { \cs_argument_spec:N #1 } { }
{ \@@_patch_expand_redefine:NNnn \c_false_bool #1 {#2} {#3} }
{
+ \@@_patch_debug:x { ..~command~can~only~be~patched~by~rescanning }
% \end{macrocode}
%
% Otherwise, we start the actual patching by retokenization job. The
@@ -1144,6 +1317,8 @@
% \cs{@@_cmd_if_scanable:NnTF} and \cs{@@_patch_retokenize:Nnnn} if
% the former returns \meta{true}, plus some debug messages.
% \begin{macrocode}
+%<latexrelease>\IncludeInRelease{2023/06/01}{\@@_try_patch_with_catcodes:Nnnnw}
+%<latexrelease> {cmd~hooks~with~args}
\cs_new_protected:Npn \@@_try_patch_with_catcodes:Nnnnw #1 #2 #3 #4
{
\quark_if_recursion_tail_stop_do:nn {#4} { \use:n }
@@ -1152,7 +1327,7 @@
{
\@@_patch_debug:x { ++~macro~can~be~retokenized~cleanly }
\@@_patch_debug:x { ==~retokenizing~macro~now }
- \@@_patch_retokenize:Nnnn #1 {#2} {#3} {#4}
+ \@@_patch_retokenize:Nnnn #1 { cmd / #2 / #3 } {#3} {#4}
\use_i_delimit_by_q_recursion_stop:nw \use_none:n
}
{
@@ -1160,6 +1335,26 @@
\@@_try_patch_with_catcodes:Nnnnw #1 {#2} {#3}
}
}
+%<latexrelease>\EndIncludeInRelease
+%<latexrelease>\IncludeInRelease{2021/06/01}{\@@_try_patch_with_catcodes:Nnnnw}
+%<latexrelease> {cmd~hooks~with~args}
+%<latexrelease>\cs_gset_protected:Npn \@@_try_patch_with_catcodes:Nnnnw #1 #2 #3 #4
+%<latexrelease> {
+%<latexrelease> \quark_if_recursion_tail_stop_do:nn {#4} { \use:n }
+%<latexrelease> \@@_patch_debug:x { ++~trying~to~patch~by~retokenization }
+%<latexrelease> \@@_cmd_if_scanable:NnTF {#1} {#4}
+%<latexrelease> {
+%<latexrelease> \@@_patch_debug:x { ++~macro~can~be~retokenized~cleanly }
+%<latexrelease> \@@_patch_debug:x { ==~retokenizing~macro~now }
+%<latexrelease> \@@_patch_retokenize:Nnnn #1 {#2} {#3} {#4}
+%<latexrelease> \use_i_delimit_by_q_recursion_stop:nw \use_none:n
+%<latexrelease> }
+%<latexrelease> {
+%<latexrelease> \@@_patch_debug:x { --~macro~cannot~be~retokenized~cleanly }
+%<latexrelease> \@@_try_patch_with_catcodes:Nnnnw #1 {#2} {#3}
+%<latexrelease> }
+%<latexrelease> }
+%<latexrelease>\EndIncludeInRelease
% \end{macrocode}
% \end{macro}
%
@@ -1267,15 +1462,86 @@
% \end{macro}
%
%
+% \begin{macro}{\@@_guess_arg_count:NN}
+% \begin{macro}{\@@_guess_arg_count:wN}
+% \begin{macro}{\@@_guess_arg_count:nw}
+% Looks at the parameter text of a macro, and counts the parameters
+% by looking at the number after a \verb|#|, and checking if they are
+% sequential. This macro assumes that all parameters are marked with
+% hashes, and not other characters, and that there is no
+% \enquote{trick parameter}.
+% \changes{v1.0h}{2023/05/21}
+% {Macro added (cmd-args).}
+% \begin{macrocode}
+%<latexrelease>\IncludeInRelease{2023/06/01}{\@@_guess_arg_count:NN}
+%<latexrelease> {cmd~hooks~with~args}
+\cs_new_protected:Npn \@@_guess_arg_count:NN #1
+ {
+ \exp_after:wN \@@_guess_arg_count:wN
+ \token_to_meaning:N #1 \s_@@_mark
+ }
+\exp_last_unbraced:NNNNo
+\cs_new_protected:Npx \@@_guess_arg_count:wN
+ #1 { \tl_to_str:n { macro: } } #2 \s_@@_mark #3
+ {
+ \int_set:Nn #3
+ {
+ \exp_not:N \@@_guess_arg_count:nw { 0 } #2
+ \c_hash_str 0 \s_@@_mark
+ }
+ }
+\use:e
+ { \cs_new:Npn \exp_not:N \@@_guess_arg_count:nw #1 #2 \c_hash_str #3 }
+ {
+ \int_compare:nNnTF { #1 + 1 } = {#3}
+ { \@@_guess_arg_count:nw {#3} }
+ { #1 \@@_use_none_delimit_by_s_mark:w }
+ }
+%<latexrelease>\EndIncludeInRelease
+%<latexrelease>\IncludeInRelease{2021/06/01}{\@@_guess_arg_count:NN}
+%<latexrelease> {cmd~hooks~with~args}
+%<latexrelease>\cs_undefine:N \@@_guess_arg_count:NN
+%<latexrelease>\EndIncludeInRelease
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
%
% \begin{macro}{\@@_patch_retokenize:Nnnn}
% Then, if \cs{@@_cmd_if_scanable:NnTF} returned true, we can go on
% and patch the command.
% \begin{macrocode}
+%<latexrelease>\IncludeInRelease{2023/06/01}{\@@_patch_retokenize:Nnnn}
+%<latexrelease> {cmd~hooks~with~args}
\cs_new_protected:Npn \@@_patch_retokenize:Nnnn #1 #2 #3 #4
{
+% Here, when patching by retokenization, we can only guess the number
+% of arguments of the macro.
+% \changes{v1.0h}{2023/05/21}
+% {Changes to allow support arguments in cmd hooks (cmd-args).}
+% \begin{macrocode}
+ \@@_guess_arg_count:NN #1 \l_@@_patch_num_args_int
% \end{macrocode}
-% Start off by making some things \tn{relax} to avoid lots of
+%
+% Then we redefine the hook to have the right number of arguments.
+% Disabling the hook, undefining the \verb|parameter| token list then
+% calling \cs{@@_make_usable:nn} are enough to redefine the hook to
+% the extent we want. Code stored in the hook and other metadata
+% about it are not lost in the process.
+% \begin{macrocode}
+ \@@_disable:n {#2}
+ \cs_undefine:c { c_@@_#2_parameter_tl }
+ \@@_make_usable:nn {#2} { \l_@@_patch_num_args_int }
+ \tl_set:Ne \l_@@_tmpa_tl
+ { \exp_args:Ne \tl_to_str:n { \@@_braced_parameter:n {#2} } }
+ \use:x
+ {
+ \str_replace_all:Nnn \exp_not:N \l_@@_tmpa_tl
+ { #### } { \c_hash_str }
+ }
+% \end{macrocode}
+% Then, make make some things \tn{relax} to avoid lots of
% \tn{noexpand} below.
% \begin{macrocode}
\cs_set_eq:NN \kerneltmpDoNotUse \scan_stop:
@@ -1301,10 +1567,18 @@
####1 \def \kerneltmpDoNotUse ####2
{
\str_if_eq:nnT {#3} { before }
- { \token_to_str:N \UseHook { cmd / #2 / #3 } }
+ {
+ \token_to_str:N \UseHookWithArguments {#2}
+ { \int_use:N \l_@@_patch_num_args_int }
+ \l_@@_tmpa_tl
+ }
####3
\str_if_eq:nnT {#3} { after }
- { \token_to_str:N \UseHook { cmd / #2 / #3 } }
+ {
+ \token_to_str:N \UseHookWithArguments {#2}
+ { \int_use:N \l_@@_patch_num_args_int }
+ \l_@@_tmpa_tl
+ }
}
}
% \end{macrocode}
@@ -1328,7 +1602,39 @@
% {Make patching of commands a global operation (gh/674)}
% \begin{macrocode}
\cs_gset_eq:NN #1 \kerneltmpDoNotUse
+% \end{macrocode}
+% Finally, update the hook code.
+% \begin{macrocode}
+ \@@_update_hook_code:n {#2}
}
+%<latexrelease>\EndIncludeInRelease
+%<latexrelease>\IncludeInRelease{2021/06/01}{\@@_patch_retokenize:Nnnn}
+%<latexrelease> {cmd~hooks~with~args}
+%<latexrelease>\cs_gset_protected:Npn \@@_patch_retokenize:Nnnn #1 #2 #3 #4
+%<latexrelease> {
+%<latexrelease> \cs_set_eq:NN \kerneltmpDoNotUse \scan_stop:
+%<latexrelease> \cs_set_eq:NN \@@_tmp:w \scan_stop:
+%<latexrelease> \use:x
+%<latexrelease> {
+%<latexrelease> \cs_set:Npn \@@_tmp:w
+%<latexrelease> ####1 \tl_to_str:n { macro: } ####2 -> ####3 \s_@@_mark
+%<latexrelease> {
+%<latexrelease> ####1 \def \kerneltmpDoNotUse ####2
+%<latexrelease> {
+%<latexrelease> \str_if_eq:nnT {#3} { before }
+%<latexrelease> { \token_to_str:N \UseHook { cmd / #2 / #3 } }
+%<latexrelease> ####3
+%<latexrelease> \str_if_eq:nnT {#3} { after }
+%<latexrelease> { \token_to_str:N \UseHook { cmd / #2 / #3 } }
+%<latexrelease> }
+%<latexrelease> }
+%<latexrelease> \tl_set:Nx \exp_not:N \l_@@_tmpa_tl
+%<latexrelease> { \exp_not:N \@@_tmp:w \token_to_meaning:N #1 \s_@@_mark }
+%<latexrelease> }
+%<latexrelease> \tl_rescan:nV { #4 \@@_patch_required_catcodes: } \l_@@_tmpa_tl
+%<latexrelease> \cs_gset_eq:NN #1 \kerneltmpDoNotUse
+%<latexrelease> }
+%<latexrelease>\EndIncludeInRelease
% \end{macrocode}
% \end{macro}
%
diff --git a/Master/texmf-dist/source/latex-dev/base/ltfilehook.dtx b/Master/texmf-dist/source/latex-dev/base/ltfilehook.dtx
index d43ffc857dc..e10a5416e58 100644
--- a/Master/texmf-dist/source/latex-dev/base/ltfilehook.dtx
+++ b/Master/texmf-dist/source/latex-dev/base/ltfilehook.dtx
@@ -1,7 +1,7 @@
% \iffalse meta-comment
%
% Copyright (C) 2020-2023
-% Frank Mittelbach, Phelype Oleinik & LaTeX Team
+% Frank Mittelbach, Phelype Oleinik and The LaTeX Project
%
% This file is part of the LaTeX base system.
% -------------------------------------------
@@ -31,8 +31,8 @@
%%% From File: ltfilehook.dtx
%
% \begin{macrocode}
-\providecommand\ltfilehookversion{v1.0n}
-\providecommand\ltfilehookdate{2022/08/18}
+\providecommand\ltfilehookversion{v1.0o}
+\providecommand\ltfilehookdate{2023/04/02}
% \end{macrocode}
%
%<*driver>
@@ -1229,8 +1229,10 @@
% This auxiliary compares \cs{\meta{filename}} with
% \cs{csname\cs{endcsname}} to check if the empty |.tex| file was
% requested.
+% \changes{v1.0o}{2023/04/02}
+% {Make \cs{@set@curr@file@aux} \cs{long} gh/942}
% \begin{macrocode}
-\def\@set@curr@file@aux#1{%
+\long\def\@set@curr@file@aux#1{%
\expandafter\ifx\csname\endcsname#1%
.tex\else\string#1\fi}
% \end{macrocode}
diff --git a/Master/texmf-dist/source/latex-dev/base/ltfiles.dtx b/Master/texmf-dist/source/latex-dev/base/ltfiles.dtx
index 042565299a6..3bac7ea0b22 100644
--- a/Master/texmf-dist/source/latex-dev/base/ltfiles.dtx
+++ b/Master/texmf-dist/source/latex-dev/base/ltfiles.dtx
@@ -32,7 +32,7 @@
%<*driver>
% \fi
\ProvidesFile{ltfiles.dtx}
- [2023/01/05 v1.2s LaTeX Kernel (File Handling)]
+ [2023/05/17 v1.2t LaTeX Kernel (File Handling)]
% \iffalse
\documentclass{ltxdoc}
\GetFileInfo{ltfiles.dtx}
@@ -1202,6 +1202,9 @@
% \changes{v1.0t}{1995/05/25}{(CAR) added \cs{long}}
% \changes{v1.2d}{2019/10/26}{quote on openin}
% \changes{v1.2k}{2021/03/12}{Allow unbalanced conditionals (gh/530)}
+% \changes{v1.2t}{2023/05/15}{Use \pkg{expl3} file existence test}
+% \begin{macro}{\IfFileExists@}
+% \changes{v1.2t}{2023/05/15}{Macro added}
% Argument |#1| is |\@curr@file| so catcode 12 string with no quotes.
%
% The original definition picked up arguments |#2| and |#3| in a
@@ -1211,23 +1214,35 @@
% \cs{secondoftwo}. However, that changes how |#| is interpreted
% and so we can't do that nowaways without invalidating a lot of
% code. Therefore the somewhat curious construction near the end.
+%
+% Earlier versions used |\openin| here, but this led to two
+% code paths, one in \pkg{expl3} and one here. To avoid that,
+% and as the \pkg{expl3} approach works by expansion, we use
+% that here. As we need the file name to include the path,
+% the actual \pkg{expl3} function used is not the file existence
+% test!
% \begin{macrocode}
%</2ekernel>
%<*2ekernel|latexrelease>
-%<latexrelease>\IncludeInRelease{2021/06/01}%
-%<latexrelease> {\IfFileExists@}{manage unbalanced conditionals}
+%<latexrelease>\IncludeInRelease{2023/05/01}%
+%<latexrelease> {\IfFileExists@}{IfFileExists}
\long\def \IfFileExists@#1#2#3{%
- \openin\@inputcheck"#1" %
- \ifeof\@inputcheck
- \ifx\input@path\@undefined
- \let\reserved@a\@secondoftwo
+ \edef\@filef@und{\IfFileExists@@{#1}}%
+% \end{macrocode}
+% The \pkg{expl3} function regards an empty argument as nothing at all,
+% but the \LaTeXe{} convention is that this is equal to the special
+% \texttt{.tex} file.
+% \begin{macrocode}
+ \ifx\@filef@und\@empty
+ \if\relax\detokenize{#1}\relax
+ \let\reserved@a\@firstoftwo
+ \def\@filef@und{".tex" }%
\else
- \def\reserved@a{\@iffileonpath{#1}}%
+ \let\reserved@a\@secondoftwo
\fi
\else
- \closein\@inputcheck
- \edef\@filef@und{"#1" }%
\let\reserved@a\@firstoftwo
+ \edef\@filef@und{"\@filef@und" }%
\fi
% \end{macrocode}
% This is just there so that any |#| inside |#2| or |#3| needs
@@ -1236,10 +1251,35 @@
\expandafter\def\expandafter\reserved@a
\expandafter{\reserved@a{#2}{#3}}%
\reserved@a}
+\ExplSyntaxOn
+\cs_new_eq:NN \IfFileExists@@ \file_full_name:n
+\ExplSyntaxOff
%</2ekernel|latexrelease>
%<latexrelease>\EndIncludeInRelease
+%<latexrelease>\IncludeInRelease{2021/06/01}%
+%<latexrelease> {\IfFileExists@}{IfFileExists}
+%<latexrelease>
+%<latexrelease>\long\def \IfFileExists@#1#2#3{%
+%<latexrelease> \openin\@inputcheck"#1" %
+%<latexrelease> \ifeof\@inputcheck
+%<latexrelease> \ifx\input@path\@undefined
+%<latexrelease> \let\reserved@a\@secondoftwo
+%<latexrelease> \else
+%<latexrelease> \def\reserved@a{\@iffileonpath{#1}}%
+%<latexrelease> \fi
+%<latexrelease> \else
+%<latexrelease> \closein\@inputcheck
+%<latexrelease> \edef\@filef@und{"#1" }%
+%<latexrelease> \let\reserved@a\@firstoftwo
+%<latexrelease> \fi
+%<latexrelease> \expandafter\def\expandafter\reserved@a
+%<latexrelease> \expandafter{\reserved@a{#2}{#3}}%
+%<latexrelease>\reserved@a}
+%<latexrelease>\let\IfFileExists@@\@undefined
+%<latexrelease>\EndIncludeInRelease
+%<latexrelease>
%<latexrelease>\IncludeInRelease{2019/10/01}%
-%<latexrelease> {\IfFileExists@}{manage unbalanced conditionals}
+%<latexrelease> {\IfFileExists@}{IfFileExists}
%<latexrelease>
%<latexrelease>\long\def \IfFileExists@#1#2#3{%
%<latexrelease> \openin\@inputcheck"#1" %
@@ -1257,7 +1297,7 @@
%<latexrelease> \reserved@a}
%<latexrelease>\EndIncludeInRelease
%<latexrelease>\IncludeInRelease{0000/00/00}%
-%<latexrelease> {\IfFileExists@}{manage unbalanced conditionals}
+%<latexrelease> {\IfFileExists@}{IfFileExists}
%<latexrelease>
%<latexrelease>\let\IfFileExists@\@undefined
%<latexrelease>
@@ -1266,7 +1306,7 @@
%<*2ekernel>
% \end{macrocode}
% \end{macro}
-%
+% \end{macro}
%
%
%
diff --git a/Master/texmf-dist/source/latex-dev/base/ltfinal.dtx b/Master/texmf-dist/source/latex-dev/base/ltfinal.dtx
index 9fa6bbc856e..1e39e293e08 100644
--- a/Master/texmf-dist/source/latex-dev/base/ltfinal.dtx
+++ b/Master/texmf-dist/source/latex-dev/base/ltfinal.dtx
@@ -33,7 +33,7 @@
%<*driver>
% \fi
\ProvidesFile{ltfinal.dtx}
- [2022/11/30 v2.2y LaTeX Kernel (Final Settings)]
+ [2023/04/20 v2.3b LaTeX Kernel (Final Settings)]
% \iffalse
\documentclass{ltxdoc}
\GetFileInfo{ltfinal.dtx}
@@ -1062,6 +1062,24 @@
\fi % End of reset block for 8-bit engines
% \end{macrocode}
%
+% \begin{macro}{\BCPdata}
+% \changes{v2.3a}{2023/04/16}{Command added}
+% A stub for use by \pkg{babel}, \pkg{polyglossia}, etc.
+% \begin{macrocode}
+\ExplSyntaxOn
+\newcommand*\BCPdata[1]{
+ \str_case:nn {#1}
+ {
+ { language } { en }
+ { region } { US }
+ { script } { Latn }
+ { tag } { en-US }
+ }
+}
+\ExplSyntaxOff
+% \end{macrocode}
+% \end{macro}
+%
% \begin{macro}{\MakeUppercase}
% \begin{macro}{\MakeLowercase}
% \begin{macro}{\MakeTitlecase}
@@ -1069,6 +1087,9 @@
% \begin{macro}{\AddToNoCaseChangeList}
% \begin{macro}{\CaseSwitch}
% \begin{macro}{\DeclareCaseChangeEquivalent}
+% \begin{macro}{\DeclareLowercaseMapping}
+% \begin{macro}{\DeclareTitlecaseMapping}
+% \begin{macro}{\DeclareUppercaseMapping}
% \begin{macro}{\@uclclist}
%
%
@@ -1088,6 +1109,7 @@
% \changes{v2.2x}{2022/10/26}{Introduce optional argument for case-changing commands}
% \changes{v2.2x}{2022/10/26}{Make case changing commands language-aware}
% \changes{v2.2x}{2022/10/26}{Auto-detect \pkg{babel} locale}
+% \changes{v2.3a}{2023/04/11}{Use new generic mechanism to detect locale}
% Wrappers around the L3 case changing functions.
% |\protected| to make them mostly safe as replacements for |uppercase|
% and |\lowercase|.
@@ -1121,33 +1143,24 @@
{
\cs_set_nopar:Npn \reserved@a { }
\tl_if_blank:nTF {#2}
- { \@@text@case@aux@ }
- { \keys_set:nn { __kernel } {#2} }
- \use:c { text_ #1 case:Vn } \reserved@a {#3}
- }
-\cs_new_protected:Npn \@@text@case@aux@ { }
-\tl_gput_right:Nn \@kernel@after@begindocument
- {
- \@ifpackageloaded { babel }
{
- \@ifpackagelater { babel } { 2020-01-15 }
+ \str_set:Nx \reserved@a
+ { \BCPdata { casing } }
+ \str_if_empty:NT \reserved@a
{
- \cs_gset_protected:Npn \@@text@case@aux@
- {
- \str_set:Nx \reserved@a
- { \localeinfo* { tag.bcp47 } }
- }
+ \str_set:Nx \reserved@a
+ { \BCPdata { language } }
}
- { }
}
- { }
+ { \keys_set:nn { __kernel } {#2} }
+ \use:c { text_ #1 case:Vn } \reserved@a {#3}
}
-\exp_args_generate:n { cnx }
% \end{macrocode}
% The odd use of \emph{three} spaces here is needed as \pkg{ltcmd} uses the
% name with one and two spaces to give a `friendly' error message for a runaway
% argument: that means we can't use it here.
% \begin{macrocode}
+\exp_args_generate:n { cnx }
\cs_set_protected:Npn \reserved@a #1
{
\cs_generate_variant:cn { text_ \str_lowercase:n {#1} case:nn } { V }
@@ -1161,36 +1174,33 @@
\reserved@a { Title }
% \end{macrocode}
% \changes{v2.2y}{2022/11/30}{Set \cs{oe}/\cs{OE} equal to act as a marker for \pkg{babel}}
+% \changes{v2.2z}{2023/03/28}{Use groups for gh/1021}
% Currently, \pkg{babel} uses the equivalence of \cs{oe} and \cs{OE} to force casing of
% some material, most notably in \cs{today}. To enable that to work, we have to set those
% commands equal even though the current case changing code does not work using this
% approach.
% \begin{macrocode}
\cs_new_protected:cpn { MakeLowercase \c_space_tl \c_space_tl \c_space_tl } [#1] #2
- {
- \let \kernel@saved@OE \OE
+ {{
\let \OE \oe
\@@text@case@aux { lower } {#1} {#2}
- \let \OE \kernel@saved@OE
- }
+ }}
\cs_new_protected:cpn { MakeUppercase \c_space_tl \c_space_tl \c_space_tl } [#1] #2
- {
- \let \kernel@saved@oe \oe
+ {{
\let \oe \OE
\@@text@case@aux { upper } {#1} {#2}
- \let \oe \kernel@saved@oe
- }
+ }}
\cs_new_protected:cpn { MakeTitlecase \c_space_tl \c_space_tl \c_space_tl } [#1] #2
- {
- \let \kernel@saved@oe \oe
+ {{
\let \oe \OE
\@@text@case@aux { title } {#1} {#2}
- \let \oe \kernel@saved@oe
- }
+ }}
% \end{macrocode}
%
% \changes{v2.2u}{2022/06/02}{Add \cs{NoCaseChange}}
% \changes{v2.2u}{2022/06/30}{Add \cs{AddToNoCaseChangeList}}
+% \changes{v2.3b}{2023/04/19}{Add \cs{DeclareLowercaseMapping},
+% \cs{DeclareTitlecaseMapping} and \cs{DeclareUppercaseMapping}}
% |\NoCaseChange| protects its argument from the case change functions.
%
% |\AddToNoCaseChangeList| Allows new commands to protect their arguments, eg
@@ -1204,6 +1214,27 @@
\cs_new_eq:NN \CaseSwitch \text_case_switch:nnnn
\cs_new_eq:NN \DeclareCaseChangeEquivalent
\text_declare_case_equivalent:Nn
+\NewDocumentCommand \DeclareLowercaseMapping { o m m }
+ {
+ \IFNoValueTF {#1}
+ { \text_declare_lowercase_mapping:nn }
+ { \text_declare_lowercase_mapping:nnn {#1} }
+ {#2} {#3}
+ }
+\NewDocumentCommand \DeclareTitlecaseMapping { o m m }
+ {
+ \IFNoValueTF {#1}
+ { \text_declare_titlecase_mapping:nn }
+ { \text_declare_titlecase_mapping:nnn {#1} }
+ {#2} {#3}
+ }
+\NewDocumentCommand \DeclareUppercaseMapping { o m m }
+ {
+ \IFNoValueTF {#1}
+ { \text_declare_uppercase_mapping:nn }
+ { \text_declare_uppercase_mapping:nnn {#1} }
+ {#2} {#3}
+ }
\ExplSyntaxOff
% \end{macrocode}
%
@@ -1222,6 +1253,9 @@
% \end{macro}
% \end{macro}
% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
%
% \changes{v1.0h}{1994/05/13}{Added output enc stuff}
% \changes{v1.0i}{1994/05/16}{moved output enc stuff to lfonts}
diff --git a/Master/texmf-dist/source/latex-dev/base/ltfssbas.dtx b/Master/texmf-dist/source/latex-dev/base/ltfssbas.dtx
index 019fca9abaa..fda3d1ca4b0 100644
--- a/Master/texmf-dist/source/latex-dev/base/ltfssbas.dtx
+++ b/Master/texmf-dist/source/latex-dev/base/ltfssbas.dtx
@@ -35,7 +35,7 @@
%
%
\ProvidesFile{ltfssbas.dtx}
- [2022/07/04 v3.2k LaTeX Kernel (NFSS Basic Macros)]
+ [2023/04/01 v3.2l LaTeX Kernel (NFSS Basic Macros)]
% \iffalse
\documentclass{ltxdoc}
\begin{document}
@@ -1050,11 +1050,22 @@
% {\cs{def} $\to$ \cs{edef} for \cs{math@version}.}
% \changes{v1.2g}{1990/02/16}{\cs{@nomath} added.}
% \changes{v2.1a}{1994/01/17}{New math font setup}
+% \changes{v3.2l}{2023/04/01}{Reset frozen mathversion gh/1028}
% \begin{macrocode}
\DeclareRobustCommand\mathversion[1]
{\@nomath\mathversion
\expandafter\ifx\csname mv@#1\endcsname\relax
\@latex@error{Math version `#1' is not defined}\@eha\else
+% \end{macrocode}
+% If there has been a frozen math version reset locally. See GH 1028.
+% \begin{macrocode}
+ \ifcsname mv@\math@version @frozen\endcsname
+ \expandafter\let
+ \csname mv@\math@version @frozen\expandafter\endcsname
+ \csname mv@\math@version\endcsname
+ \fi
+% \end{macrocode}
+% \begin{macrocode}
\edef\math@version{#1}%
% \end{macrocode}
% We need to force a math font setup both now and at the point
diff --git a/Master/texmf-dist/source/latex-dev/base/lthooks.dtx b/Master/texmf-dist/source/latex-dev/base/lthooks.dtx
index 1255c63a8c6..c0efe2c9038 100644
--- a/Master/texmf-dist/source/latex-dev/base/lthooks.dtx
+++ b/Master/texmf-dist/source/latex-dev/base/lthooks.dtx
@@ -1,7 +1,7 @@
% \iffalse meta-comment
%
% Copyright (C) 2020-2023
-% Frank Mittelbach, Phelype Oleinik & LaTeX Team
+% Frank Mittelbach, Phelype Oleinik, The LaTeX Project
%
% This file is part of the LaTeX base system.
% -------------------------------------------
@@ -31,8 +31,8 @@
%%% From File: lthooks.dtx
%
% \begin{macrocode}
-\def\lthooksversion{v1.0v}
-\def\lthooksdate{2022/06/15}
+\def\lthooksversion{v1.1d}
+\def\lthooksdate{2023/05/21}
% \end{macrocode}
%
%<*driver>
@@ -148,7 +148,6 @@
% the current package name. See section~\ref{sec:default-label}.
% \end{function}
%
-%
% \begin{function}{\NewMirroredHookPair}
% \begin{syntax}
% \cs{NewMirroredHookPair} \Arg{hook-1} \Arg{hook-2}
@@ -156,7 +155,45 @@
% A shorthand for
% \cs{NewHook}\Arg{hook-1}\cs{NewReversedHook}\Arg{hook-2}.
%
-% The \meta{hooks} can be specified using the dot-syntax to denote
+% The \meta{hook} can be specified using the dot-syntax to denote
+% the current package name. See section~\ref{sec:default-label}.
+% \end{function}
+%
+%
+% \begin{function}{\NewHookWithArguments}
+% \begin{syntax}
+% \cs{NewHookWithArguments} \Arg{hook} \Arg{number}
+% \end{syntax}
+% Creates a new \meta{hook} whose code takes \meta{number} arguments,
+% and otherwise works exactly like \cs{NewHook}.
+% Section~\ref{sec:hook-args} explains hooks with arguments.
+%
+% The \meta{hook} can be specified using the dot-syntax to denote
+% the current package name. See section~\ref{sec:default-label}.
+% \end{function}
+%
+% \begin{function}{\NewReversedHookWithArguments}
+% \begin{syntax}
+% \cs{NewReversedHookWithArguments} \Arg{hook} \Arg{number}
+% \end{syntax}
+% Like \cs{NewReversedHook}, but creates a hook whose code takes
+% \meta{number} arguments.
+% Section~\ref{sec:hook-args} explains hooks with arguments.
+%
+% The \meta{hook} can be specified using the dot-syntax to denote
+% the current package name. See section~\ref{sec:default-label}.
+% \end{function}
+%
+% \begin{function}{\NewMirroredHookPairWithArguments}
+% \begin{syntax}
+% \cs{NewMirroredHookPairWithArguments} \Arg{hook-1} \Arg{hook-2} \Arg{number}
+% \end{syntax}
+% A shorthand for
+% \cs{NewHookWithArguments}\Arg{hook-1}\Arg{number}\\
+% \cs{NewReversedHookWithArguments}\Arg{hook-2}\Arg{number}.
+% Section~\ref{sec:hook-args} explains hooks with arguments.
+%
+% The \meta{hook} can be specified using the dot-syntax to denote
% the current package name. See section~\ref{sec:default-label}.
% \end{function}
%
@@ -173,9 +210,9 @@
% \begin{syntax}
% \cs{DisableGenericHook} \Arg{hook}
% \end{syntax}
-% After this declaration\footnotemark{} the \meta{hook} is no longer usable: Any
-% attempt to add further code to it will result in an error and any
-% use, e.g., via \cs{UseHook}, will simply do nothing.
+% After this declaration\footnotemark{} the \meta{hook} is no longer
+% usable: Any further attempt to add code to it will result in an
+% error and any use, e.g., via \cs{UseHook}, will simply do nothing.
%
% This is intended to be used with generic command hooks (see
% \texttt{ltcmdhooks-doc}) as depending on the definition of the
@@ -215,7 +252,7 @@
% \begin{syntax}
% \cs{UseHook} \Arg{hook}
% \end{syntax}
-% Execute the hook code inside a command or environment.
+% Execute the code stored in the \meta{hook}.
%
% Before \verb=\begin{document}= the fast execution code for a hook
% is not set up, so in order to use a hook there it is explicitly
@@ -227,14 +264,30 @@
% A leading |.| is treated literally.
% \end{function}
%
+% \begin{function}{\UseHookWithArguments}
+% \begin{syntax}
+% \cs{UseHookWithArguments} \Arg{hook} \Arg{number} \Arg{arg_1} \ldots \Arg{arg_n}
+% \end{syntax}
+% Execute the code stored in the \meta{hook} and pass the arguments
+% \Arg{arg_1} through \Arg{arg_n} to the \meta{hook}. Otherwise, it
+% works exactly like \cs{UseHook}.
+% The \meta{number} should be the number of arguments declared for
+% the hook. If the hook is not declared, this command does nothing
+% and it will remove \meta{number} items from the input.
+% Section~\ref{sec:hook-args} explains hooks with arguments.
+%
+% The \meta{hook} \emph{cannot} be specified using the dot-syntax.
+% A leading |.| is treated literally.
+% \end{function}
+%
% \begin{function}{\UseOneTimeHook}
% \begin{syntax}
% \cs{UseOneTimeHook} \Arg{hook}
% \end{syntax}
% Some hooks are only used (and can be only used) in one place, for
% example, those in \verb=\begin{document}= or
-% \verb=\end{document}=. Once we have passed that point adding to
-% the hook through a defined \cs[no-index]{\meta{addto-cmd}} command (e.g.,
+% \verb=\end{document}=. From that point onwards, adding to the hook
+% through a defined \cs[no-index]{\meta{addto-cmd}} command (e.g.,
% \cs{AddToHook} or \cs{AtBeginDocument}, etc.\@) would have no
% effect (as would the use of such a command inside the hook code
% itself). It is therefore customary to redefine
@@ -250,15 +303,30 @@
% section~\ref{sec:default-label} for details.
%
% Using \cs{UseOneTimeHook} several times with the same
-% \Arg{hook} means that it only executes the first time it is used.
+% \Arg{hook} means that it only executes the first time it is used.
% For example, if it is used in a command that can be called several times
-% then the hook executes during only the \emph{first} invocation of that
+% then the hook executes during only the \emph{first} invocation of that
% command; this allows its use as an \enquote{initialization hook}.
%
% Mixing \cs{UseHook} and \cs{UseOneTimeHook} for the same
% \Arg{hook} should be avoided, but if this is done then neither will execute
% after the first \cs{UseOneTimeHook}.
+% \end{function}
%
+% \begin{function}{\UseOneTimeHookWithArguments}
+% \begin{syntax}
+% \cs{UseOneTimeHookWithArguments} \Arg{hook} \Arg{number} \Arg{arg_1} \ldots \Arg{arg_n}
+% \end{syntax}
+% Works exactly like \cs{UseOneTimeHook}, but passes arguments
+% \Arg{arg_1} through \Arg{arg_n} to the \meta{hook}.
+% The \meta{number} should be the number of arguments declared for
+% the hook. If the hook is not declared, this command does nothing
+% and it will remove \meta{number} items from the input.
+%
+% It should be noted that after a one-time hook is used, it is no
+% longer possible to use \cs{AddToHookWithArguments} or similar with
+% that hook. \cs{AddToHook} continues to work as normal.
+% Section~\ref{sec:hook-args} explains hooks with arguments.
% \end{function}
%
%
@@ -294,6 +362,34 @@
% See section~\ref{sec:default-label}.
% \end{function}
%
+% \begin{function}{\AddToHookWithArguments}
+% \begin{syntax}
+% \cs{AddToHookWithArguments} \Arg{hook}\oarg{label}\Arg{code}
+% \end{syntax}
+% Works exactly like \cs{AddToHook}, except that the \meta{code} can
+% access the arguments passed to the hook using \verb|#1|, \verb|#2|,
+% \ldots, \verb|#n| (up to the number of arguments declared for the
+% hook). If the \meta{code} should contain \emph{parameter tokens}
+% (\verb|#|) that are not supposed to be understood as the arguments
+% of the hook, such tokens should be doubled. For example, with
+% \cs{AddToHook} one can write:
+%\begin{verbatim}
+% \AddToHook{myhook}{\def\foo#1{Hello, #1!}}
+%\end{verbatim}
+% but to achieve the same with \cs{AddToHookWithArguments}, one should
+% write:
+%\begin{verbatim}
+% \AddToHookWithArguments{myhook}{\def\foo##1{Hello, ##1!}}
+%\end{verbatim}
+% because in the latter case, \verb|#1| refers to the first argument
+% of the hook \hook{myhook}.
+% Section~\ref{sec:hook-args} explains hooks with arguments.
+%
+% The \meta{hook} and \meta{label} can be specified using the
+% dot-syntax to denote the current package name.
+% See section~\ref{sec:default-label}.
+% \end{function}
+%
% \begin{function}{\RemoveFromHook}
% \begin{syntax}
% \cs{RemoveFromHook} \Arg{hook}\oarg{label}
@@ -403,6 +499,19 @@
% \end{function}\footnotetext{There is
% no mechanism to reorder such code chunks (or delete them).}
%
+% \begin{function}{\AddToHookNextWithArguments}
+% \begin{syntax}
+% \cs{AddToHookNextWithArguments} \Arg{hook}\Arg{code}
+% \end{syntax}
+% Works exactly like \cs{AddToHookNext}, but the \meta{code} can
+% contain references to the arguments of the \meta{hook} as described
+% for \cs{AddToHookWithArguments} above.
+% Section~\ref{sec:hook-args} explains hooks with arguments.
+%
+% The \meta{hook} can be specified using the dot-syntax to denote
+% the current package name. See section~\ref{sec:default-label}.
+% \end{function}
+%
%
%
% \begin{function}{\ClearHookNext}
@@ -511,10 +620,10 @@
% package's hooks, so the dot-syntax doesn't make much sense.
%
% In some cases, for example in large packages, one may want to separate
-% it in logical parts, but still use the main package name as
+% the code in logical parts, but still use the main package name as the
% \meta{label}, then the \meta{default label} can be set using
-% \cs{SetDefaultHookLabel} or
-% \cs{PushDefaultHookLabel}\verb={..}=\,\ldots\cs{PopDefaultHookLabel}.
+% \cs{PushDefaultHookLabel}\verb={...}=\,\ldots\cs{PopDefaultHookLabel}
+% or \cs{SetDefaultHookLabel}\verb={...}=.
%
% \begin{function}{\PushDefaultHookLabel,\PopDefaultHookLabel}
% \begin{syntax}
@@ -906,8 +1015,11 @@
% section even in \texttt{expl3} packages, but the choice is yours.
%
%
-% \begin{function}
-% {\hook_new:n,\hook_new_reversed:n,\hook_new_pair:nn}
+% \begin{function}{
+% \hook_new:n,
+% \hook_new_reversed:n,
+% \hook_new_pair:nn
+% }
% \begin{syntax}
% \cs{hook_new:n} \Arg{hook}
% \cs{hook_new_reversed:n} \Arg{hook}
@@ -923,6 +1035,27 @@
% the current package name. See section~\ref{sec:default-label}.
% \end{function}
%
+% \begin{function}{
+% \hook_new_with_args:nn,
+% \hook_new_reversed_with_args:nn,
+% \hook_new_pair_with_args:nnn
+% }
+% \begin{syntax}
+% \cs{hook_new_with_args:nn} \Arg{hook} \Arg{number}
+% \cs{hook_new_reversed_with_args:nn} \Arg{hook} \Arg{number}
+% \cs{hook_new_pair_with_args:nnn} \Arg{hook-1} \Arg{hook-2} \Arg{number}
+% \end{syntax}
+% Creates a new \meta{hook} with normal or reverse ordering of code
+% chunks, that takes \meta{number} arguments from the input stream
+% when it is used. \cs{hook_new_pair_with_args:nn} creates a pair of
+% such hooks with \Arg{hook-2} being a reversed hook.
+% If a hook name is already taken, an error is raised and the hook
+% is not created.
+%
+% The \meta{hook} can be specified using the dot-syntax to denote
+% the current package name. See section~\ref{sec:default-label}.
+% \end{function}
+%
%
%
% \begin{function}{\hook_disable_generic:n}
@@ -958,37 +1091,62 @@
%
%
%
-% \begin{function}{\hook_use:n}
+% \begin{function}{\hook_use:n,\hook_use:nnw}
% \begin{syntax}
% \cs{hook_use:n} \Arg{hook}
+% \cs{hook_use:nnw} \Arg{hook} \Arg{number} \Arg{arg_1} \ldots \Arg{arg_n}
% \end{syntax}
% Executes the \Arg{hook} code followed (if set up) by the code for next
% invocation only, then empties that next invocation code.
+% \cs{hook_use:nnw} should be used for hooks declared with arguments,
+% and should be followed by as many brace groups as the declared
+% number of arguments.
+% The \meta{number} should be the number of arguments declared for
+% the hook. If the hook is not declared, this command does nothing
+% and it will remove \meta{number} items from the input.
%
% The \meta{hook} \emph{cannot} be specified using the dot-syntax.
% A leading |.| is treated literally.
% \end{function}
%
-% \begin{function}{\hook_use_once:n}
+% \begin{function}{\hook_use_once:n,\hook_use_once:nnw}
% \begin{syntax}
% \cs{hook_use_once:n} \Arg{hook}
+% \cs{hook_use_once:nnw} \Arg{hook} \Arg{number} \Arg{arg_1} \ldots \Arg{arg_n}
% \end{syntax}
% Changes the \Arg{hook} status so that from now on any addition to
% the hook code is executed immediately. Then execute any
% \Arg{hook} code already set up.
+% \cs{hook_use_once:nnw} should be used for hooks declared with arguments,
+% and should be followed by as many brace groups as the declared
+% number of arguments.
+% The \meta{number} should be the number of arguments declared for
+% the hook. If the hook is not declared, this command does nothing
+% and it will remove \meta{number} items from the input.
%
% The \meta{hook} \emph{cannot} be specified using the dot-syntax.
% A leading |.| is treated literally.
% \end{function}
%
-% \begin{function}{\hook_gput_code:nnn}
+% \begin{function}{
+% \hook_gput_code:nnn,
+% \hook_gput_code_with_args:nnn
+% }
% \begin{syntax}
% \cs{hook_gput_code:nnn} \Arg{hook} \Arg{label} \Arg{code}
+% \cs{hook_gput_code_with_args:nnn} \Arg{hook} \Arg{label} \Arg{code}
% \end{syntax}
% Adds a chunk of \meta{code} to the \meta{hook} labeled
% \meta{label}. If the label already exists the \meta{code} is
% appended to the already existing code.
%
+% If \cs{hook_gput_code_with_args:nnn} is used, the \meta{code}
+% can access the arguments passed to \cs{hook_use:nnw}
+% (or~\cs{hook_use_once:nnw}) with \verb|#1|, \verb|#2|, \ldots,
+% \verb|#n| (up to the number of arguments declared for the hook).
+% In that case, if an actual parameter token should be added to the
+% code, it should be doubled.
+%
% If code is added to an external \meta{hook} (of the kernel or
% another package) then the convention is to use the package name
% as the \meta{label} not some internal module name or some other
@@ -999,18 +1157,26 @@
% See section~\ref{sec:default-label}.
% \end{function}
%
-% \begin{function}
-% {\hook_gput_next_code:nn}
+% \begin{function}{
+% \hook_gput_next_code:nn,
+% \hook_gput_next_code_with_args:nn,
+% }
% \begin{syntax}
% \cs{hook_gput_next_code:nn} \Arg{hook} \Arg{code}
% \end{syntax}
% Adds a chunk of \meta{code} for use only in the next invocation of the
% \meta{hook}. Once used it is gone.
%
+% If \cs{hook_gput_next_code_with_args:nn} is used, the \meta{code}
+% can access the arguments passed to \cs{hook_use:nnw}
+% (or~\cs{hook_use_once:nnw}) with \verb|#1|, \verb|#2|, \ldots,
+% \verb|#n| (up to the number of arguments declared for the hook).
+% In that case, if an actual parameter token should be added to the
+% code, it should be doubled.
+%
% This is simpler than \cs{hook_gput_code:nnn}, the code is simply
% appended to the hook in the order of declaration at the very end,
% i.e., after all standard code for the hook got executed.
-%
% Thus if one needs to undo what the standard does one has to do
% that as part of \meta{code}.
%
@@ -1019,8 +1185,7 @@
% \end{function}
%
%
-% \begin{function}
-% {\hook_gclear_next_code:n}
+% \begin{function}{\hook_gclear_next_code:n}
% \begin{syntax}
% \cs{hook_gclear_next_code:n} \Arg{hook}
% \end{syntax}
@@ -1240,7 +1405,7 @@
% \begin{itshape}\begin{color}{blue} ...
% \end{itshape}\end{color}
%\end{verbatim}
-% and an error message that \verb=\begin{color}= ended by
+% and an error message saying that \verb=\begin{color}= was ended by
% \verb=\end{itshape}=.
% With \hook{env/quote/after} declared as a reversed hook the
% execution order is reversed and so all environments are closed in
@@ -1377,9 +1542,9 @@
% you typically do not know what kind of variable parts may come up
% in real documents.
%
-% For example, \pkg{babel} may want to provide hooks such as
-% \hook{babel/\meta{language}/afterextras}. Language support in
-% \pkg{babel} is often done through external language
+% For example, \pkg{babel} provides hooks such as
+% \hook{babel/\meta{language}/afterextras}. However, language
+% support in \pkg{babel} is often done through external language
% packages. Thus doing the activation for all languages inside the
% core \pkg{babel} code is not a viable approach. Instead it needs
% to be done by each language package (or by the user who wants to
@@ -1396,6 +1561,125 @@
% conciderably.
%
%
+% \subsection{Hooks with arguments}
+% \label{sec:hook-args}
+%
+% Sometimes it is necessary to pass contextual information to a hook,
+% and, for one reason or another, it is not feasible to store such
+% information in macros. To serve this purpose, hooks can be
+% declared with arguments, so that the programmer can pass along the
+% data necessary for the code in the hook to function properly.
+%
+% A hook with arguments works mostly like a regular hook, and most
+% commands that work for regular hooks, also work for hooks that take
+% arguments. The differences are when the hook is declared
+% (\cs{NewHookWithArguments} is used instead of \cs{NewHook}), then
+% code can be added with both \cs{AddToHook} and
+% \cs{AddToHookWithArguments}, and when the hook is used
+% (\cs{UseHookWithArguments} instead of \cs{UseHook}).
+%
+% \medskip
+%
+% A hook with arguments must be declared as such (before it is first
+% used, as all regular hooks) using
+% \cs{NewHookWithArguments}\Arg{hook}\Arg{number}. All code added to
+% that hook can then use \verb|#1| to access the first argument,
+% \verb|#2| to access the second, and so forth up to the number of
+% arguments declared. However, it is still possible to add code with
+% references to the arguments of a hook that was not yet declared
+% (we will discuss that later). At their core, hooks are macros, so
+% \TeX's limit of 9~arguments applies, and a low-level \TeX{} error
+% is raised if you try to reference an argument number that doesn't
+% exist.
+%
+% \medskip
+%
+% To use a hook with arguments, just write
+% \cs{UseHookWithArguments}\Arg{hook}\Arg{number} followed by a
+% braced list of the arguments. For example, if the hook \hook{test}
+% takes three arguments, write:
+%\begin{verbatim}
+% \UseHookWithArguments{test}{3}{arg-1}{arg-2}{arg-3}
+%\end{verbatim}
+% then, in the \meta{code} of the hook, all instances of \verb|#1|
+% will be replaced by \verb|arg-1|, \verb|#2| by \verb|arg-2| and so
+% on. If, at the point of usage, the programmer provides more
+% arguments than the hook is declared to take, the excess arguments
+% are simply ignored by the hook. Behaviour is
+% unpredictable\footnote
+% {The hook \emph{will} take the declared number of arguments, and
+% what will happen depends on what was grabbed, and what the hook
+% code does with its arguments.}
+% if too few arguments are provided. If the hook isn't declared,
+% \meta{number} arguments are removed from the input stream.
+%
+% \medskip
+%
+% Adding code to a hook with arguments can be done with
+% \cs{AddToHookWithArguments} as well as with the regular
+% \cs{AddToHook}, to achieve different outcomes. The main difference
+% when it comes to adding code to a hook, in this case, is firstly
+% the possibility of accessing a hook's arguments, of course, and
+% second, how parameter tokens (\verb|#|$_6$) are treated.
+%
+% Using \cs{AddToHook} in a hook that takes arguments will work as it
+% does for all other hooks. This allows a package developer to add
+% arguments to a hook that otherwise had none without having to worry
+% about compatibility. This means that, for example:
+%\begin{verbatim}
+% \AddToHook{test}{\def\foo#1{Hello, #1!}}
+%\end{verbatim}
+% will define the same macro \cs[no-index]{foo} regardless if the
+% hook \hook{test} takes arguments or not.
+%
+% Using \cs{AddToHookWithArguments} allows the \meta{code} added to
+% access the arguments of the hook with \verb|#1|, \verb|#2|, and so
+% forth, up to the number of the arguments declared in the hook.
+% This means that if one wants to add a \verb|#|$_6$ to the
+% \meta{code} that token must be doubled in the input. The same
+% definition from above, using \cs{AddToHookWithArguments}, needs to
+% be rewritten:
+%\begin{verbatim}
+% \AddToHookWithArguments{test}{\def\foo##1{Hello, ##1!}}
+%\end{verbatim}
+%
+% Extending the above example to use the hook arguments, we could
+% rewrite something like (now from declaration to usage, to get the
+% whole picture):
+%\begin{verbatim}
+% \NewHookWithArguments{test}{1}
+% \AddToHookWithArguments{test}{%
+% \typeout{Defining foo with "#1"}
+% \def\foo##1{Hello, ##1! Some text after: #1}%
+% }
+% \UseHook{test}{Howdy!}
+% \ShowCommand\foo
+%\end{verbatim}
+% Running the code above prints in the terminal:
+%\begin{verbatim}
+% Defining foo with "Howdy!"
+% > \foo=macro:
+% #1->Hello, #1! Some text after: Howdy!.
+%\end{verbatim}
+% Note how \verb|##1| in the call to \cs{AddToHookWithArguments}
+% became \verb|#1|, and the \verb|#1| was replaced by the argument
+% passed to the hook. Should the hook be used again, with a
+% different argument, the definition would naturally change.
+%
+% \bigskip
+%
+% It is possible to add code referencing a hook's arguments before
+% such hook is declared and the number of hooks is fixed. However,
+% if some code is added to the hook, that references more arguments
+% than will be declared for the hook, there will be a low-level
+% \TeX{} error about an \enquote{Illegal parameter number} at the
+% time the hook is declared, which will be hard to track down because
+% at that point \TeX{} can't know whence the offending code came
+% from. Thus it is important that package writers explicitly
+% document how many arguments (if any) each hook can take, so users
+% of those packages know how many arguments can be referenced, and
+% equally important, what each argument means.
+%
% \subsection{Private \LaTeX{} kernel hooks}
%
% There are a few places where it is absolutely essential for
@@ -1461,7 +1745,7 @@
% package/class name if called inside such a file
% (see section~\ref{sec:default-label}).
%
-% This way one can add further code to the hook using
+% This way one can add code to the hook using
% \cs{AddToHook} or \cs{AtBeginDocument} using a different label
% and explicitly order the code chunks as necessary, e.g., run some
% code before or after another package's code. When using the
@@ -1746,10 +2030,10 @@
%
% \subsection{Hooks provided by \cs{end}\texttt{\{document\}}}
%
-% \LaTeXe{} always provided \cs{AtEndDocument} to add code to the
-% execution of \verb=\end{document}= just in front of the code that
+% \LaTeXe{} has always provided \cs{AtEndDocument} to add code to the
+% \verb=\end{document}=, just in front of the code that
% is normally executed there. While this was a big improvement over
-% the situation in \LaTeX\,2.09 it was not flexible enough for a
+% the situation in \LaTeX\,2.09, it was not flexible enough for a
% number of use cases and so packages, such as \pkg{etoolbox},
% \pkg{atveryend} and others patched \cs{enddocument} to add
% additional points where code could be hooked into.
@@ -2095,13 +2379,37 @@
% \end{macrocode}
% \end{macro}
%
-% \begin{macro}[int]{\tl_gremove_once:Nx,\tl_show:x,\tl_log:x}
+% \begin{macro}{\c_@@_empty_tl}
+% \begin{macro}{\c_@@_nine_parameters_tl}
+% An empty token list, and one containing nine parameters.
+% \changes{v1.1a}{2023/04/06}
+% {Add auxiliary token lists (hook-args).}
+% \begin{macrocode}
+\tl_const:Nn \c_@@_empty_tl { }
+\tl_const:Nn \c_@@_nine_parameters_tl { #1#2#3#4#5#6#7#8#9 }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}[int]{
+% \tl_gremove_once:Nx,
+% \tl_show:x,
+% \tl_log:x,
+% \tl_set:Ne,
+% \cs_replacement_spec:c,
+% \prop_put:Nne,
+% \str_count:e
+% }
% Some variants of \pkg{expl3} functions.
% \fmiinline{should probably be moved to expl3}
% \begin{macrocode}
\cs_generate_variant:Nn \tl_gremove_once:Nn { Nx }
\cs_generate_variant:Nn \tl_show:n { x }
\cs_generate_variant:Nn \tl_log:n { x }
+\cs_generate_variant:Nn \tl_set:Nn { Ne }
+\cs_generate_variant:Nn \cs_replacement_spec:N { c }
+\cs_generate_variant:Nn \prop_put:Nnn { Nne }
+\cs_generate_variant:Nn \str_count:n { e }
% \end{macrocode}
% \end{macro}
%
@@ -2112,15 +2420,20 @@
% \end{macrocode}
% \end{macro}
%
-% \begin{macro}{\@@_clean_to_scan:w}
+% \begin{macro}{
+% \@@_use_none_delimit_by_s_mark:w,
+% \@@_use_i_delimit_by_s_mark:nw
+% }
% Removes tokens until the next \cs{s_@@_mark}.
+% \changes{v1.1a}{2023/04/06}
+% {Use standard naming scheme (hook-args).}
% \begin{macrocode}
-\cs_new:Npn \@@_clean_to_scan:w #1 \s_@@_mark { }
+\cs_new:Npn \@@_use_none_delimit_by_s_mark:w #1 \s_@@_mark { }
+\cs_new:Npn \@@_use_i_delimit_by_s_mark:nw #1 #2 \s_@@_mark {#1}
% \end{macrocode}
% \end{macro}
%
-% \begin{macro}{\@@_tl_set:Nn,\@@_tl_set:Nx,
-% \@@_tl_set:cn,\@@_tl_set:cx}
+% \begin{macro}{\@@_tl_set:cn}
% Private copies of a few \pkg{expl3} functions. \pkg{l3debug} will
% only add debugging to the public names, not to these copies, so we
% don't have to use \cs{debug_suspend:} and \cs{debug_resume:}
@@ -2130,44 +2443,43 @@
% copied because in \pkg{expl3} they use
% \cs[no-index]{__kernel_tl_(g)set:Nx}, which is also patched by
% \pkg{l3debug}.
-% \changes{v1.0h}{2021/01/07}{Manually define some \pkg{l3tl} commands
+% \changes{v1.0h}{2021/01/07}{Manually define some \pkg{l3tl} commands
% to work around \pkg{expl3} changes}
+% \changes{v1.1a}{2023/04/06}
+% {Clean-up unused variants (hook-args).}
% \begin{macrocode}
-\cs_new_protected:Npn \@@_tl_set:Nn #1#2
- { \cs_set_nopar:Npx #1 { \__kernel_exp_not:w {#2} } }
-\cs_new_protected:Npn \@@_tl_set:Nx #1#2
- { \cs_set_nopar:Npx #1 {#2} }
-\cs_generate_variant:Nn \@@_tl_set:Nn { c }
-\cs_generate_variant:Nn \@@_tl_set:Nx { c }
+\cs_new_protected:Npn \@@_tl_set:cn #1#2
+ { \cs_set_nopar:cpx {#1} { \__kernel_exp_not:w {#2} } }
% \end{macrocode}
% \end{macro}
%
-% \begin{macro}{\@@_tl_gset:Nn,\@@_tl_gset:No,\@@_tl_gset:Nx,
+% \begin{macro}{\@@_tl_gset:Nn,\@@_tl_gset:Nx,
% \@@_tl_gset:cn,\@@_tl_gset:co,\@@_tl_gset:cx}
% Same as above.
% \begin{macrocode}
\cs_new_protected:Npn \@@_tl_gset:Nn #1#2
{ \cs_gset_nopar:Npx #1 { \__kernel_exp_not:w {#2} } }
-\cs_new_protected:Npn \@@_tl_gset:No #1#2
- { \cs_gset_nopar:Npx #1 { \__kernel_exp_not:w \exp_after:wN {#2} } }
\cs_new_protected:Npn \@@_tl_gset:Nx #1#2
{ \cs_gset_nopar:Npx #1 {#2} }
-\cs_generate_variant:Nn \@@_tl_gset:Nn { c }
-\cs_generate_variant:Nn \@@_tl_gset:No { c }
+\cs_generate_variant:Nn \@@_tl_gset:Nn { c, co }
\cs_generate_variant:Nn \@@_tl_gset:Nx { c }
% \end{macrocode}
% \end{macro}
%
-% \begin{macro}{\@@_tl_gput_right:Nn,\@@_tl_gput_right:No,\@@_tl_gput_right:cn}
+% \begin{macro}{
+% \@@_tl_gput_right:Nn,
+% \@@_tl_gput_right:Ne,
+% \@@_tl_gput_right:cn,
+% }
% Same as above.
% \begin{macrocode}
\cs_new_protected:Npn \@@_tl_gput_right:Nn #1#2
{ \@@_tl_gset:Nx #1 { \__kernel_exp_not:w \exp_after:wN { #1 #2 } } }
-\cs_generate_variant:Nn \@@_tl_gput_right:Nn { No, cn }
+\cs_generate_variant:Nn \@@_tl_gput_right:Nn { Ne, cn }
% \end{macrocode}
% \end{macro}
%
-% \begin{macro}{\@@_tl_gput_left:Nn,\@@_tl_gput_left:No}
+% \begin{macro}{\@@_tl_gput_left:Nn}
% Same as above.
% \begin{macrocode}
\cs_new_protected:Npn \@@_tl_gput_left:Nn #1#2
@@ -2175,7 +2487,6 @@
\@@_tl_gset:Nx #1
{ \__kernel_exp_not:w {#2} \__kernel_exp_not:w \exp_after:wN {#1} }
}
-\cs_generate_variant:Nn \@@_tl_gput_left:Nn { No }
% \end{macrocode}
% \end{macro}
%
@@ -2202,7 +2513,11 @@
%
% \DescribeMacro{\g_@@_\meta{hook}_code_prop}
% \DescribeMacro{\@@\textvisiblespace\meta{hook}}
+% \DescribeMacro{\g_@@_\meta{hook}_reversed_tl}
+% \DescribeMacro{\g_@@_\meta{hook}_declared_tl}
+% \DescribeMacro{\g_@@_\meta{hook}_parameter_tl}
% \DescribeMacro{\@@_next\textvisiblespace\meta{hook}}
+% \DescribeMacro{\@@_toplevel\textvisiblespace\meta{hook}}
% Hooks have a name (called \meta{hook} in the description below)
% and for each hook we have to
% provide a number of data structures. These are
@@ -2232,12 +2547,17 @@
% so that it can be identified. The |-| character is used because
% $\meta{reversed}1$ is $+1$ for normal hooks and $-1$ for reversed
% ones.
-
+%
% \item[{\cs[no-index]{g_@@_\meta{hook}_declared_tl}}] This token
-% list serves as marker for the hook being officially declared. Its
+% list serves as a marker for the hook being officially declared. Its
% existence is tested to raise an error in case another declaration
% is attempted.
%
+% \item[{\cs[no-index]{c_@@_\meta{hook}_parameter_tl}}] This token
+% list stores the parameter text for a declared hook (its existence
+% almost completely intersects the token list above), which is used
+% for managing hooks with arguments.
+%
% \item[\cs{@@_toplevel\textvisiblespace\meta{hook}}] This token list stores the code
% inserted in the hook from the user's document, in the |top-level|
% label. This label is special, and doesn't participate in sorting.
@@ -2367,45 +2687,92 @@
% \subsubsection{Setting hooks up}
%
%
-% \begin{macro}{\hook_new:n,\@@_new:n}
+% \begin{macro}{
+% \hook_new:n,
+% \hook_new_with_args:nn
+% }
+% \begin{macro}{@@_new:nn}
% The \cs{hook_new:n} declaration declares a new hook and expects
% the hook \meta{name} as its argument, e.g.,
% \hook{begindocument}.
+% \changes{v1.1a}{2023/04/06}
+% {Add \cs{hook_new_with_args:nn} (hook-args).}
% \begin{macrocode}
+%<latexrelease>\IncludeInRelease{2023/06/01}{\hook_new_with_args:nn}
+%<latexrelease> {Hooks~with~args}
\cs_new_protected:Npn \hook_new:n #1
- { \@@_normalize_hook_args:Nn \@@_new:n {#1} }
+ { \@@_normalize_hook_args:Nn \@@_new:nn {#1} { 0 } }
+\cs_new_protected:Npn \hook_new_with_args:nn #1 #2
+ { \@@_normalize_hook_args:Nn \@@_new:nn {#1} {#2} }
% \end{macrocode}
%
% \begin{macrocode}
-\cs_new_protected:Npn \@@_new:n #1
+\cs_new_protected:Npn \@@_new:nn #1 #2
{
% \end{macrocode}
% We check if the hook was already \emph{explicitly} declared with
% \cs{hook_new:n}, and if it already exists we complain, otherwise set
% the \enquote{created} flag for the hook so that it errors next time
% \cs{hook_new:n} is used.
+% \changes{v1.1d}{2023/05/21}
+% {Changes to allow support arguments in cmd hooks (cmd-args).}
% \begin{macrocode}
\@@_if_declared:nTF {#1}
{ \msg_error:nnn { hooks } { exists } {#1} }
{
\tl_new:c { g_@@_#1_declared_tl }
- \@@_make_usable:n {#1}
+ \cs_undefine:c { @@~#1 }
+ \cs_undefine:c { c_@@_#1_parameter_tl }
+ \@@_make_usable:nn {#1} {#2}
+% \end{macrocode}
+% In case there is already code in a hook, but it's undeclared, run
+% \cs{@@_update_hook_code:n} to make it ready to be executed (see test
+% \texttt{lthooks-034}).
+% \changes{v1.1a}{2023/04/06}
+% {Update hook code after declaring.}
+% \begin{macrocode}
+ \@@_update_hook_code:n {#1}
}
}
+%<latexrelease>\EndIncludeInRelease
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macrocode}
+%<latexrelease>\IncludeInRelease{2020/10/01}{\hook_new_with_args:nn}
+%<latexrelease> {Hooks~with~args}
+%<latexrelease>\cs_gset_protected:Npn \hook_new:n #1
+%<latexrelease> { \@@_normalize_hook_args:Nn \@@_new:n {#1} }
+%<latexrelease>\cs_undefine:N \@@_new:nn
+%<latexrelease>\cs_gset_protected:Npn \@@_new:n #1
+%<latexrelease> {
+%<latexrelease> \@@_if_declared:nTF {#1}
+%<latexrelease> { \msg_error:nnn { hooks } { exists } {#1} }
+%<latexrelease> {
+%<latexrelease> \tl_new:c { g_@@_#1_declared_tl }
+%<latexrelease> \@@_make_usable:n {#1}
+%<latexrelease> }
+%<latexrelease> }
+%<latexrelease>\cs_gset_protected:Npn \hook_new_with_args:nn #1 { }
+%<latexrelease>\EndIncludeInRelease
% \end{macrocode}
% \end{macro}
%
%
%
-% \begin{macro}{\@@_make_usable:n}
+% \begin{macro}{\@@_make_usable:nn}
%
% This initializes all hook data structures for the hook but if
% used on its own doesn't mark the hook as declared (as
% \cs{hook_new:n} does, so a later \cs{hook_new:n} on that hook will
% not result in an error. This command is internally used by
-% \cs{hook_gput_code:n} when adding code to a generic hook.
+% \cs{hook_gput_code:nnn} when adding code to a generic hook.
+% \changes{v1.1a}{2023/04/06}
+% {Changes to add hook arguments (hook-args).}
% \begin{macrocode}
-\cs_new_protected:Npn \@@_make_usable:n #1
+%<latexrelease>\IncludeInRelease{2023/06/01}{\@@_make_usable:nn}
+%<latexrelease> {Hooks~with~args}
+\cs_new_protected:Npn \@@_make_usable:nn #1 #2
{
% \end{macrocode}
% Now we check if the hook's data structure can be safely created
@@ -2414,29 +2781,70 @@
% allocate the necessary data structures for the new hook,
% otherwise just do nothing.
% \begin{macrocode}
- \tl_if_exist:cF { @@~#1 }
+ \@@_if_usable:nF {#1}
{
\seq_gput_right:Nn \g_@@_all_seq {#1}
% \end{macrocode}
+% Here we'll define the \cs[no-index]{c_@@_\meta{hook}_parameter_tl}
+% to hold a run of parameters up to the number of arguments of the
+% hook (\verb|#2|).
+% \begin{macrocode}
+ \__kernel_cs_parm_from_arg_count:nnF
+ { \tl_const:cn { c_@@_#1_parameter_tl } } {#2}
+ {
+ \msg_error:nnnn { hooks } { too-many-args } {#1} {#2}
+ \tl_const:cx { c_@@_#1_parameter_tl }
+ { \exp_not:V \c_@@_nine_parameters_tl }
+ }
+% \end{macrocode}
+% After that, use \cs{@@_normalise_cs_args:nn} to correct the number
+% of parameters of the macros
+% \cs[no-index]{@@_toplevel\textvisiblespace\meta{hook}} and
+% \cs[no-index]{@@_next\textvisiblespace\meta{hook}}. We need to be
+% able to add
+% code with arguments to a hook without prior knowledge of the number
+% of arguments of that hook, so \pkg{lthooks} assumes~9 until the
+% hook is properly declared and the number of arguments is known.
+% \cs{@@_normalise_cs_args:nn} does the normalisation by using the
+% \cs[no-index]{c_@@_\meta{hook}_parameter_tl} defined just above.
+% \begin{macrocode}
+ \@@_normalise_cs_args:nn { _toplevel } {#1}
+ \@@_normalise_cs_args:nn { _next } {#1}
+% \end{macrocode}
% This is only used by the actual code of the current hook, so
% declare it normally:
% \begin{macrocode}
- \tl_new:c { @@~#1 }
+ \@@_code_gset:nn {#1} { }
% \end{macrocode}
% Now ensure that the base data structure for the hook exists:
% \begin{macrocode}
\@@_init_structure:n {#1}
% \end{macrocode}
+% The call to \cs{@@_normalise_code_pool:n} will correct any improper
+% reference to arguments that don't exist in the hook, raising a
+% low-level \TeX{} error and doubling the offending parameter tokens.
+% It has to be done after \cs{@@_init_structure:n} because it
+% operates on \cs[no-index]{g_@@_\meta{hook}_code_prop}.
+% \begin{macrocode}
+ \@@_normalise_code_pool:n {#1}
+% \end{macrocode}
% The \cs{g_@@_\meta{hook}_labels_clist} holds the sorted list of
% labels (once it got sorted). This is used only for debugging.
+% These are defined conditionally, in case \cs{@@_make_usable:nn}
+% is being used to redefine a hook.
+% \changes{v1.1d}{2023/05/21}
+% {Changes to allow support arguments in cmd hooks (cmd-args).}
% \begin{macrocode}
- \clist_new:c { g_@@_#1_labels_clist }
+ \clist_if_exist:cF { g_@@_#1_labels_clist }
+ {
+ \clist_new:c { g_@@_#1_labels_clist }
% \end{macrocode}
% Some hooks should reverse the default order of code chunks. To
% signal this we have a token list which is empty for normal hooks
% and contains a \verb=-= for reversed hooks.
% \begin{macrocode}
- \tl_new:c { g_@@_#1_reversed_tl }
+ \tl_new:c { g_@@_#1_reversed_tl }
+ }
% \end{macrocode}
% The above is all in L3 convention, but we also provide an
% interface to legacy \LaTeXe{} hooks of the form \cs{@...hook},
@@ -2454,9 +2862,28 @@
\@@_include_legacy_code_chunk:n {#1}
}
}
+%<latexrelease>\EndIncludeInRelease
% \end{macrocode}
-% \end{macro}
%
+% \begin{macrocode}
+%<latexrelease>\IncludeInRelease{2020/10/01}{\@@_make_usable:nn}
+%<latexrelease> {Hooks~with~args}
+%<latexrelease>\cs_undefine:N \@@_make_usable:nn
+%<latexrelease>\cs_gset_protected:Npn \@@_make_usable:n #1
+%<latexrelease> {
+%<latexrelease> \tl_if_exist:cF { @@~#1 }
+%<latexrelease> {
+%<latexrelease> \seq_gput_right:Nn \g_@@_all_seq {#1}
+%<latexrelease> \tl_new:c { @@~#1 }
+%<latexrelease> \@@_init_structure:n {#1}
+%<latexrelease> \clist_new:c { g_@@_#1_labels_clist }
+%<latexrelease> \tl_new:c { g_@@_#1_reversed_tl }
+%<latexrelease> \@@_include_legacy_code_chunk:n {#1}
+%<latexrelease> }
+%<latexrelease> }
+%<latexrelease>\EndIncludeInRelease
+% \end{macrocode}
+% \end{macro}
%
%
% \begin{macro}{\@@_init_structure:n}
@@ -2472,49 +2899,124 @@
% \cs{@@_init_structure:n} the first time anything is added to it.
% Initializing a hook just with \cs{@@_init_structure:n} will not
% make it usable with \cs{hook_use:n}.
+% \changes{v1.1a}{2023/04/06}
+% {Changes to add hook arguments (hook-args).}
% \begin{macrocode}
+%<latexrelease>\IncludeInRelease{2023/06/01}{\@@_init_structure:n}
+%<latexrelease> {Hooks~with~args}
\cs_new_protected:Npn \@@_init_structure:n #1
{
\@@_if_structure_exist:nF {#1}
{
\prop_new:c { g_@@_#1_code_prop }
- \tl_new:c { @@_toplevel~#1 }
- \tl_new:c { @@_next~#1 }
+ \@@_toplevel_gset:nn {#1} { }
+ \@@_next_gset:nn {#1} { }
}
}
+%<latexrelease>\EndIncludeInRelease
% \end{macrocode}
-% \end{macro}
-%
%
+% \begin{macrocode}
+%<latexrelease>\IncludeInRelease{2020/10/01}{\@@_init_structure:n}
+%<latexrelease> {Hooks~with~args}
+%<latexrelease>\cs_gset_protected:Npn \@@_init_structure:n #1
+%<latexrelease> {
+%<latexrelease> \@@_if_structure_exist:nF {#1}
+%<latexrelease> {
+%<latexrelease> \prop_new:c { g_@@_#1_code_prop }
+%<latexrelease> \tl_new:c { @@_toplevel~#1 }
+%<latexrelease> \tl_new:c { @@_next~#1 }
+%<latexrelease> }
+%<latexrelease> }
+%<latexrelease>\EndIncludeInRelease
+% \end{macrocode}
+% \end{macro}
%
-% \begin{macro}{\hook_new_reversed:n,\@@_new_reversed:n}
+% \begin{macro}{
+% \hook_new_reversed:n,
+% \hook_new_reversed_with_args:nn
+% }
+% \begin{macro}{\@@_new_reversed:nn}
%
% Declare a new hook. The default ordering of code chunks is
% reversed, signaled by setting the token list to a minus sign.
+% \changes{v1.1a}{2023/04/06}
+% {Add \cs{hook_new_reversed_with_args:nn} (hook-args).}
% \begin{macrocode}
+%<latexrelease>\IncludeInRelease{2023/06/01}{\hook_new_reversed_with_args:nn}
+%<latexrelease> {Hooks~with~args}
\cs_new_protected:Npn \hook_new_reversed:n #1
- { \@@_normalize_hook_args:Nn \@@_new_reversed:n {#1} }
-\cs_new_protected:Npn \@@_new_reversed:n #1
+ { \@@_normalize_hook_args:Nn \@@_new_reversed:nn {#1} { 0 } }
+\cs_new_protected:Npn \hook_new_reversed_with_args:nn #1 #2
+ { \@@_normalize_hook_args:Nn \@@_new_reversed:nn {#1} {#2} }
+\cs_new_protected:Npn \@@_new_reversed:nn #1 #2
{
- \@@_new:n {#1}
+ \@@_if_declared:nTF {#1}
+ { \msg_error:nnn { hooks } { exists } {#1} }
+ {
+ \@@_new:nn {#1} {#2}
+ \tl_gset:cn { g_@@_#1_reversed_tl } { - }
+ }
+ }
+%<latexrelease>\EndIncludeInRelease
% \end{macrocode}
-% If the hook already exists the above will generate an error
-% message, so the next line should be executed (but it is --- too
-% bad).
+%
% \begin{macrocode}
- \tl_gset:cn { g_@@_#1_reversed_tl } { - }
- }
+%<latexrelease>\IncludeInRelease{2020/10/01}{\hook_new_reversed_with_args:nn}
+%<latexrelease> {Hooks~with~args}
+%<latexrelease>\cs_gset_protected:Npn \hook_new_reversed:n #1
+%<latexrelease> { \@@_normalize_hook_args:Nn \@@_new_reversed:n {#1} }
+%<latexrelease>\cs_undefine:N \@@_new_reversed:nn
+%<latexrelease>\cs_gset_protected:Npn \@@_new_reversed:n #1
+%<latexrelease> {
+%<latexrelease> \@@_new:n {#1}
+%<latexrelease> \tl_gset:cn { g_@@_#1_reversed_tl } { - }
+%<latexrelease> }
+%<latexrelease>\cs_undefine:N \@@_new_reversed:nn
+%<latexrelease>\cs_gset_protected:Npn \hook_new_reversed_with_args:nn #1 #2 { }
+%<latexrelease>\EndIncludeInRelease
% \end{macrocode}
% \end{macro}
+% \end{macro}
%
-%
-%
-%
-% \begin{macro}{\hook_new_pair:nn}
+% \begin{macro}{\hook_new_pair:nn,\hook_new_pair_with_args:nnn}
% A shorthand for declaring a normal and a (matching) reversed hook in one go.
+% \changes{v1.1a}{2023/04/06}
+% {Add \cs{hook_new_pair_with_args:nnn} (hook-args).}
% \begin{macrocode}
+%<latexrelease>\IncludeInRelease{2023/06/01}{\hook_new_pair_with_args:nnn}
+%<latexrelease> {Hooks~with~args}
\cs_new_protected:Npn \hook_new_pair:nn #1#2
- { \hook_new:n {#1} \hook_new_reversed:n {#2} }
+ { \@@_normalize_hook_args:Nnn \@@_new_pair:nnn {#1} {#2} { 0 } }
+\cs_new_protected:Npn \hook_new_pair_with_args:nnn #1#2#3
+ { \@@_normalize_hook_args:Nnn \@@_new_pair:nnn {#1} {#2} {#3} }
+\cs_new_protected:Npn \@@_new_pair:nnn #1 #2 #3
+ {
+ \@@_if_declared:nTF {#1}
+ { \msg_error:nnn { hooks } { exists } {#1} }
+ {
+ \@@_if_declared:nTF {#2}
+ { \msg_error:nnn { hooks } { exists } {#2} }
+ {
+ \@@_new:nn {#1} {#3}
+ \@@_new_reversed:nn {#2} {#3}
+ }
+ }
+ }
+%<latexrelease>\EndIncludeInRelease
+% \end{macrocode}
+%
+% \begin{macrocode}
+%<latexrelease>\IncludeInRelease{2020/10/01}{\hook_new_pair_with_args:nnn}
+%<latexrelease> {Hooks~with~args}
+%<latexrelease>\cs_gset_protected:Npn \hook_new_pair:nn #1#2
+%<latexrelease> {
+%<latexrelease> \hook_new:n {#1}
+%<latexrelease> \hook_new_reversed:n {#2}
+%<latexrelease> }
+%<latexrelease>\cs_gset_protected:Npn \hook_new_pair_with_args:nnn #1#2#3
+%<latexrelease> { }
+%<latexrelease>\EndIncludeInRelease
% \end{macrocode}
% \end{macro}
%
@@ -2531,6 +3033,8 @@
% \textbf{Warning: this support will vanish in future releases!}
% \end{quote}
% \begin{macrocode}
+%<latexrelease>\IncludeInRelease{2023/06/01}{\@@_include_legacy_code_chunk:n}
+%<latexrelease> {Hooks~with~args}
\cs_new_protected:Npn \@@_include_legacy_code_chunk:n #1
{
% \end{macrocode}
@@ -2538,15 +3042,27 @@
% needs to be done.
% \begin{macrocode}
\tl_if_exist:cT { @#1hook }
+ {
% \end{macrocode}
% Of course if the legacy hook exists but is empty, there is no need
% to add anything under \texttt{legacy} the legacy label.
% \begin{macrocode}
- {
\tl_if_empty:cF { @#1hook }
{
- \exp_args:Nnnv \@@_hook_gput_code_do:nnn {#1}
- { legacy } { @#1hook }
+% \end{macrocode}
+% Here we set \cs{@@_replacing_args_false:} because no legacy code
+% will reference hook arguments.
+% \changes{v1.1b}{2023/04/16}
+% {\cs{@@_replacing_args_false:} in
+% \cs{@@_include_legacy_code_chunk:n}.}
+% \begin{macrocode}
+ \@@_replacing_args_false:
+ \use:e
+ {
+ \@@_hook_gput_code_do:nnn {#1} { legacy }
+ { \exp_not:v { @#1hook } }
+ }
+ \@@_replacing_args_reset:
% \end{macrocode}
% Once added to the hook, we need to clear it otherwise it might
% get added again later if the hook data gets updated.
@@ -2555,6 +3071,22 @@
}
}
}
+%<latexrelease>\EndIncludeInRelease
+%<latexrelease>\IncludeInRelease{2020/10/01}{\@@_include_legacy_code_chunk:n}
+%<latexrelease> {Hooks~with~args}
+%<latexrelease>\cs_gset_protected:Npn \@@_include_legacy_code_chunk:n #1
+%<latexrelease> {
+%<latexrelease> \tl_if_exist:cT { @#1hook }
+%<latexrelease> {
+%<latexrelease> \tl_if_empty:cF { @#1hook }
+%<latexrelease> {
+%<latexrelease> \exp_args:Nnnv \@@_hook_gput_code_do:nnn
+%<latexrelease> {#1} { legacy } { @#1hook }
+%<latexrelease> \@@_tl_gclear:c { @#1hook }
+%<latexrelease> }
+%<latexrelease> }
+%<latexrelease> }
+%<latexrelease>\EndIncludeInRelease
% \end{macrocode}
% \end{macro}
%
@@ -2579,8 +3111,8 @@
% if the hook is disabled.
%
% \begin{macrocode}
-%<latexrelease>\IncludeInRelease{2021/06/01}%
-%<latexrelease> {\hook_disable_generic:n}{Disable~hooks}
+%<latexrelease>\IncludeInRelease{2021/06/01}{\hook_disable_generic:n}
+%<latexrelease> {Disable~hooks}
% \end{macrocode}
%
% \begin{macrocode}
@@ -2595,7 +3127,7 @@
{
\bool_lazy_and:nnTF
{ \tl_if_exist_p:c { g_@@_#1_declared_tl } }
- { ! \tl_if_exist_p:c { @@~#1 } }
+ { ! \cs_if_exist_p:c { @@~#1 } }
{ \prg_return_true: }
{ \prg_return_false: }
}
@@ -2603,8 +3135,8 @@
% \end{macrocode}
%
% \begin{macrocode}
-%<latexrelease>\IncludeInRelease{2020/10/01}
-%<latexrelease> {\hook_disable_generic:n}{Disable~hooks}
+%<latexrelease>\IncludeInRelease{2020/10/01}{\hook_disable_generic:n}
+%<latexrelease> {Disable~hooks}
%<latexrelease>
%<latexrelease>\cs_new_protected:Npn \hook_disable_generic:n #1 {}
%<latexrelease>
@@ -2619,9 +3151,11 @@
% The \cs{hook_activate_generic:n} declaration declares a new hook if it
% wasn't declared already, in which case it only checks that the
% already existing hook is not a reversed hook.
+% \changes{v1.1a}{2023/04/06}
+% {Changes to add hook arguments (hook-args).}
% \begin{macrocode}
-%<latexrelease>\IncludeInRelease{2021/06/01}%
-%<latexrelease> {\hook_activate_generic:n}{Providing~hooks}
+%<latexrelease>\IncludeInRelease{2023/06/01}{\hook_activate_generic:n}
+%<latexrelease> {Providing~hooks}
% \end{macrocode}
%
% \begin{macrocode}
@@ -2646,7 +3180,7 @@
\@@_if_declared:nF {#1}
{
\tl_new:c { g_@@_#1_declared_tl }
- \@@_make_usable:n {#1}
+ \@@_make_usable:nn {#1} { 0 }
\tl_gset:cx { g_@@_#1_reversed_tl }
{ \@@_if_generic_reversed:nT {#1} { - } }
% \end{macrocode}
@@ -2660,21 +3194,40 @@
}
}
% \end{macrocode}
-% \end{macro}
-% \end{macro}
%
% \begin{macrocode}
%<latexrelease>\EndIncludeInRelease
% \end{macrocode}
%
% \begin{macrocode}
-%<latexrelease>\IncludeInRelease{2020/10/01}
-%<latexrelease> {\hook_activate_generic:n}{Providing~hooks}
-%<latexrelease>
-%<latexrelease>\cs_new_protected:Npn \hook_activate_generic:n #1 {}
-%<latexrelease>
+%<latexrelease>\IncludeInRelease{2021/06/01}{\hook_activate_generic:n}
+%<latexrelease> {Providing~hooks}
+%<latexrelease>\cs_gset_protected:Npn \@@_activate_generic:nn #1 #2
+%<latexrelease> {
+%<latexrelease> \@@_if_disabled:nTF {#1}
+%<latexrelease> { \msg_warning:nnn { hooks } { activate-disabled } {#1} }
+%<latexrelease> {
+%<latexrelease> \@@_if_declared:nF {#1}
+%<latexrelease> {
+%<latexrelease> \tl_new:c { g_@@_#1_declared_tl }
+%<latexrelease> \@@_make_usable:n {#1}
+%<latexrelease> \tl_gset:cx { g_@@_#1_reversed_tl }
+%<latexrelease> { \@@_if_generic_reversed:nT {#1} { - } }
+%<latexrelease> \@@_update_hook_code:n {#1}
+%<latexrelease> }
+%<latexrelease> }
+%<latexrelease> }
+%<latexrelease>\EndIncludeInRelease
+% \end{macrocode}
+%
+% \begin{macrocode}
+%<latexrelease>\IncludeInRelease{2020/10/01}{\hook_activate_generic:n}
+%<latexrelease> {Providing~hooks}
+%<latexrelease>\cs_gset_protected:Npn \hook_activate_generic:n #1 { }
%<latexrelease>\EndIncludeInRelease
% \end{macrocode}
+% \end{macro}
+% \end{macro}
%
%
% \subsection{Parsing a label}
@@ -2965,63 +3518,109 @@
%
% \subsection{Adding or removing hook code}
%
-% \begin{macro}{\hook_gput_code:nnn}
-% \begin{macro}{\@@_gput_code:nnn,\@@_hook_gput_code_do:nnn}
+% \begin{macro}{\hook_gput_code:nnn,\hook_gput_code_with_args:nnn}
+% \begin{macro}{
+% \@@_gput_code:nnn,
+% \@@_gput_code_store:nnn,
+% \@@_hook_gput_code_do:nnn,
+% \@@_prop_gput_labeled_cleanup:nnn,
+% \@@_prop_gput_labeled_do:Nnnn
+% }
%
% With \cs{hook_gput_code:nnn}\Arg{hook}\Arg{label}\Arg{code} a
% chunk of \meta{code} is added to an existing \meta{hook} labeled
% with \meta{label}.
% \changes{v1.0o}{2021/07/22}{Do not queue removals (gh/625)}
+% \changes{v1.1a}{2023/04/06}
+% {Add \cs{hook_gput_code_with_args:nnn} (hook-args).}
% \begin{macrocode}
-\cs_new_protected:Npn \hook_gput_code:nnn #1 #2
- { \@@_normalize_hook_args:Nnn \@@_gput_code:nnn {#1} {#2} }
+%<latexrelease>\IncludeInRelease{2023/06/01}{\hook_gput_code_with_args:nnn}
+%<latexrelease> {Hooks~with~args}
+\cs_new_protected:Npn \hook_gput_code:nnn #1 #2 #3
+ {
+ \@@_replacing_args_false:
+ \@@_normalize_hook_args:Nnn \@@_gput_code:nnn {#1} {#2} {#3}
+ \@@_replacing_args_reset:
+ }
+\cs_new_protected:Npn \hook_gput_code_with_args:nnn #1 #2 #3
+ {
+ \@@_replacing_args_true:
+ \@@_normalize_hook_args:Nnn \@@_gput_code:nnn {#1} {#2} {#3}
+ \@@_replacing_args_reset:
+ }
% \end{macrocode}
%
+% If \cs{AddToHookWithArguments} was used, do some sanity checking,
+% and if it's not possible to use arguments at this point, fall back
+% to regular \cs{AddToHook} by using \cs{@@_replacing_args_false:}.
+% \changes{v1.1a}{2023/04/06}
+% {Changes to add hook arguments (hook-args).}
% \begin{macrocode}
\cs_new_protected:Npn \@@_gput_code:nnn #1 #2 #3
{
+ \@@_chk_args_allowed:nn {#1} { AddToHook }
% \end{macrocode}
-% First check if the code should be executed immediately, rather than
+% Then check if the code should be executed immediately, rather than
% stored:
% \changes{v1.0r}{2021/09/06}{Use dedicated conditional (gh/606)}
% \begin{macrocode}
\@@_if_execute_immediately:nTF {#1}
- {#3}
{
% \end{macrocode}
+% \cs{AddToHookWithArguments} can't be used on one-time hooks (that
+% were already used).
+% \begin{macrocode}
+ \@@_if_replacing_args:TF
+ {
+ \msg_error:nnnn { hooks } { one-time-args }
+ {#1} { AddToHook }
+ }
+ { }
+ \use:n
+ }
+ { \@@_gput_code_store:nnn {#1} {#2} }
+ {#3}
+ }
+% \end{macrocode}
+%
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_gput_code_store:nnn #1 #2 #3
+ {
+% \end{macrocode}
% Then check if the hook is usable.
% \begin{macrocode}
- \@@_if_usable:nTF {#1}
+ \@@_if_usable:nTF {#1}
% \end{macrocode}
% If so we simply add (or append) the new code to the property list
% holding different chunks for the hook. At \verb=\begin{document}=
% this is then sorted into a token list for fast execution.
% \begin{macrocode}
- {
- \@@_hook_gput_code_do:nnn {#1} {#2} {#3}
+ {
+ \@@_hook_gput_code_do:nnn {#1} {#2} {#3}
% \end{macrocode}
% However, if there is an update within the document we need to alter
% this execution code which is done by
% \cs{@@_update_hook_code:n}. In the preamble this does nothing.
% \begin{macrocode}
- \@@_update_hook_code:n {#1}
- }
+ \@@_update_hook_code:n {#1}
+ }
% \end{macrocode}
%
% If the hook is not usable, before giving up, check if it's not
% disabled and otherwise try to declare it as a generic hook, if its
% name matches one of the valid patterns.
% \begin{macrocode}
- {
- \@@_if_disabled:nTF {#1}
- { \msg_error:nnn { hooks } { hook-disabled } {#1} }
- { \@@_try_declaring_generic_hook:nnn {#1} {#2} {#3} }
- }
+ {
+ \@@_if_disabled:nTF {#1}
+ { \msg_error:nnn { hooks } { hook-disabled } {#1} }
+ { \@@_try_declaring_generic_hook:nnn {#1} {#2} {#3} }
}
}
% \end{macrocode}
%
% This macro will unconditionally add a chunk of code to the given hook.
+% \changes{v1.1a}{2023/04/06}
+% {Changes to add hook arguments (hook-args).}
% \begin{macrocode}
\cs_new_protected:Npn \@@_hook_gput_code_do:nnn #1 #2 #3
{
@@ -3046,31 +3645,161 @@
\str_if_eq:eeTF { top-level } { \@@_currname_or_default: }
{
% \end{macrocode}
-% If the hook's basic structure does not exist, we need to declare it
-% with \cs{@@_init_structure:n}.
+% If the hook's basic structure does not exist, we need to declare it
+% with \cs{@@_init_structure:n}.
% \begin{macrocode}
\@@_init_structure:n {#1}
- \@@_tl_gput_right:cn { @@_toplevel~#1 } {#3}
+% \end{macrocode}
+% Then append to the \verb|_toplevel| container for the hook.
+% \begin{macrocode}
+ \@@_cs_gput_right:nnn { _toplevel } {#1} {#3}
}
{ \msg_error:nnn { hooks } { misused-top-level } {#1} }
}
{
- \prop_get:cnNTF { g_@@_#1_code_prop } {#2} \l_@@_return_tl
+% \end{macrocode}
+% When adding to the code pool, we have to double hashes if
+% \cs{AddToHook} was used (\verb|replacing_args| is false), so that
+% later it is turned into a single parameter token, rather than a
+% parameter to the hook macro.
+% \begin{macrocode}
+ \exp_args:Nx \@@_prop_gput_labeled_cleanup:nnn
{
- \prop_gput:cno { g_@@_#1_code_prop } {#2}
- { \l_@@_return_tl #3 }
+ \@@_if_replacing_args:TF
+ { \exp_not:n }
+ { \@@_double_hashes:n }
+ {#3}
}
- { \prop_gput:cnn { g_@@_#1_code_prop } {#2} {#3} }
+ {#1} {#2}
}
}
% \end{macrocode}
+%
+% Adds code to a hook's code pool.
+% \changes{v1.1a}{2023/04/06}
+% {Macro added (hook-args).}
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_prop_gput_labeled_cleanup:nnn #1 #2 #3
+ {
+ \tl_set:Nn \l_@@_return_tl {#1}
+ \@@_if_replacing_args:TF
+ {
+ \@@_if_usable:nT {#2}
+ {
+ \@@_set_normalise_fn:nn {#2}
+ { Invalid~code~added~\msg_line_context: }
+ \@@_normalise_fn:nn {#3} {#1}
+ \prop_get:NnN \l_@@_work_prop {#3} \l_@@_return_tl
+ }
+ }
+ { }
+ \exp_args:NcV \@@_prop_gput_labeled_do:Nnn
+ { g_@@_#2_code_prop } \l_@@_return_tl {#3}
+ }
+\cs_new_protected:Npn \@@_prop_gput_labeled_do:Nnn #1 #2 #3
+ {
+ \prop_get:NnNTF #1 {#3} \l_@@_return_tl
+ { \prop_gput:Nno #1 {#3} { \l_@@_return_tl #2 } }
+ { \prop_gput:Nnn #1 {#3} {#2} }
+ }
+% \end{macrocode}
+%
+% \begin{macrocode}
+%<latexrelease>\EndIncludeInRelease
+% \end{macrocode}
+%
+% \begin{macrocode}
+%<latexrelease>\IncludeInRelease{2020/10/01}{\hook_gput_code:nnn}
+%<latexrelease> {Providing~hooks}
+%<latexrelease>\cs_gset_protected:Npn \hook_gput_code:nnn #1 #2
+%<latexrelease> { \@@_normalize_hook_args:Nnn \@@_gput_code:nnn {#1} {#2} }
+%<latexrelease>\cs_gset_protected:Npn \@@_gput_code:nnn #1 #2 #3
+%<latexrelease> {
+%<latexrelease> \@@_if_execute_immediately:nTF {#1}
+%<latexrelease> {#3}
+%<latexrelease> {
+%<latexrelease> \@@_if_usable:nTF {#1}
+%<latexrelease> {
+%<latexrelease> \@@_hook_gput_code_do:nnn {#1} {#2} {#3}
+%<latexrelease> \@@_update_hook_code:n {#1}
+%<latexrelease> }
+%<latexrelease> {
+%<latexrelease> \@@_if_disabled:nTF {#1}
+%<latexrelease> { \msg_error:nnn { hooks } { hook-disabled } {#1} }
+%<latexrelease> { \@@_try_declaring_generic_hook:nnn {#1} {#2} {#3} }
+%<latexrelease> }
+%<latexrelease> }
+%<latexrelease> }
+%<latexrelease>\cs_gset_protected:Npn \@@_hook_gput_code_do:nnn #1 #2 #3
+%<latexrelease> {
+%<latexrelease> \@@_debug:n{\iow_term:x{****~ Add~ to~
+%<latexrelease> \@@_if_usable:nF {#1} { undeclared~ }
+%<latexrelease> hook~ #1~ (#2)
+%<latexrelease> \on@line\space <-~ \tl_to_str:n{#3}} }
+%<latexrelease> \str_if_eq:nnTF {#2} { top-level }
+%<latexrelease> {
+%<latexrelease> \str_if_eq:eeTF { top-level } { \@@_currname_or_default: }
+%<latexrelease> {
+%<latexrelease> \@@_init_structure:n {#1}
+%<latexrelease> \@@_tl_gput_right:cn { @@_toplevel~#1 } {#3}
+%<latexrelease> }
+%<latexrelease> { \msg_error:nnn { hooks } { misused-top-level } {#1} }
+%<latexrelease> }
+%<latexrelease> {
+%<latexrelease> \prop_get:cnNTF { g_@@_#1_code_prop } {#2} \l_@@_return_tl
+%<latexrelease> {
+%<latexrelease> \prop_gput:cno { g_@@_#1_code_prop } {#2}
+%<latexrelease> { \l_@@_return_tl #3 }
+%<latexrelease> }
+%<latexrelease> { \prop_gput:cnn { g_@@_#1_code_prop } {#2} {#3} }
+%<latexrelease> }
+%<latexrelease> }
+%<latexrelease>\cs_gset_protected:Npn \hook_gput_code_with_args:nnn #1#2#3 { }
+%<latexrelease>\EndIncludeInRelease
+% \end{macrocode}
% \end{macro}
% \end{macro}
%
+% \begin{macro}{\@@_chk_args_allowed:nn}
+% This macro checks if it is possible to add code with references to
+% a hook's arguments for hook \verb|#1|. It only does something if
+% the function being run is \verb|replacing_args|. This macro will
+% error if the hook is declared and takes no arguments, then it will
+% set \cs{@@_replacing_args_false:} so that the macro which called it
+% will add the code normally.
+% \changes{v1.1a}{2023/04/06}
+% {Macro added (hook-args).}
+% \begin{macrocode}
+%<latexrelease>\IncludeInRelease{2023/06/01}{\@@_chk_args_allowed:nn}
+%<latexrelease> {Hooks~with~args}
+\cs_new_protected:Npn \@@_chk_args_allowed:nn #1 #2
+ {
+ \@@_if_replacing_args:TF
+ {
+ \@@_if_declared:nT {#1}
+ { \tl_if_empty:cT { c_@@_#1_parameter_tl } { \use_ii:nn } }
+ \use_none:n
+ {
+ \msg_error:nnnn { hooks } { without-args } {#1} {#2}
+ \@@_replacing_args_false:
+ }
+ }
+ { }
+ }
+%<latexrelease>\EndIncludeInRelease
+%<latexrelease>\IncludeInRelease{2020/10/01}{\@@_chk_args_allowed:nn}
+%<latexrelease> {Hooks~with~args}
+%<latexrelease>\cs_undefine:N \@@_chk_args_allowed:nn
+%<latexrelease>\EndIncludeInRelease
+% \end{macrocode}
+% \end{macro}
+%
% \begin{macro}{\@@_gput_undeclared_hook:nnn}
% Often it may happen that a package $A$ defines a hook \verb=foo=,
% but package $B$, that adds code to that hook, is loaded before $A$.
% In such case we need to add code to the hook before its declared.
+% An implicitly declared hook doesn't have arguments (in principle),
+% so use \cs{c_false_bool} here.
% \begin{macrocode}
\cs_new_protected:Npn \@@_gput_undeclared_hook:nnn #1 #2 #3
{
@@ -3098,24 +3827,43 @@
% \cs{hook_gput_next_code:nn} if the generic hook was declared, or
% to \cs{@@_gput_next_do:nn} otherwise.
% \changes{v1.0p}{2021/08/25}{Standardise generic hook names (gh/648)}
+% \changes{v1.1d}{2023/05/21}
+% {Changes to allow support arguments in cmd hooks (cmd-args).}
% \begin{macrocode}
-%<latexrelease>\IncludeInRelease{2021/11/15}{\@@_try_declaring_generic_hook:nnn}
-%<latexrelease> {Standardise~generic~hook~names}
+%<latexrelease>\IncludeInRelease{2023/06/01}{\@@_try_declaring_generic_hook:nnn}
+%<latexrelease> {Hooks~with~args}
\cs_new_protected:Npn \@@_try_declaring_generic_hook:nnn #1
{
\@@_try_declaring_generic_hook:wnTF #1 / / / \scan_stop: {#1}
- \hook_gput_code:nnn
+ \@@_gput_code:nnn
\@@_gput_undeclared_hook:nnn
{#1}
}
\cs_new_protected:Npn \@@_try_declaring_generic_next_hook:nn #1
{
\@@_try_declaring_generic_hook:wnTF #1 / / / \scan_stop: {#1}
- \hook_gput_next_code:nn
+ \@@_gput_next_code:nn
\@@_gput_next_do:nn
{#1}
}
%<latexrelease>\EndIncludeInRelease
+%<latexrelease>\IncludeInRelease{2021/11/15}{\@@_try_declaring_generic_hook:nnn}
+%<latexrelease> {Standardise~generic~hook~names}
+%<latexrelease>\cs_gset_protected:Npn \@@_try_declaring_generic_hook:nnn #1
+%<latexrelease> {
+%<latexrelease> \@@_try_declaring_generic_hook:wnTF #1 / / / \scan_stop: {#1}
+%<latexrelease> \hook_gput_code:nnn
+%<latexrelease> \@@_gput_undeclared_hook:nnn
+%<latexrelease> {#1}
+%<latexrelease> }
+%<latexrelease>\cs_gset_protected:Npn \@@_try_declaring_generic_next_hook:nn #1
+%<latexrelease> {
+%<latexrelease> \@@_try_declaring_generic_hook:wnTF #1 / / / \scan_stop: {#1}
+%<latexrelease> \hook_gput_next_code:nn
+%<latexrelease> \@@_gput_next_do:nn
+%<latexrelease> {#1}
+%<latexrelease> }
+%<latexrelease>\EndIncludeInRelease
%<latexrelease>\IncludeInRelease{2020/10/01}{\@@_try_declaring_generic_hook:nnn}
%<latexrelease> {Standardise~generic~hook~names}
%<latexrelease>\cs_new_protected:Npn \@@_try_declaring_generic_hook:nnn #1
@@ -3170,9 +3918,11 @@
% \end{macro}
%
% \begin{macro}[TF]{\@@_try_declaring_generic_hook:wn}
+% \changes{v1.1a}{2023/04/06}
+% {Changes to add hook arguments (hook-args).}
% \begin{macrocode}
-%<latexrelease>\IncludeInRelease{2021/11/15}{\@@_try_declaring_generic_hook:wn}%
-%<latexrelease> {Standardise~generic~hook~names}
+%<latexrelease>\IncludeInRelease{2023/06/01}{\@@_try_declaring_generic_hook:wn}
+%<latexrelease> {Hooks~with~args}
\prg_new_protected_conditional:Npnn \@@_try_declaring_generic_hook:wn
#1 / #2 / #3 / #4 \scan_stop: #5 { TF }
{
@@ -3188,18 +3938,25 @@
% For some commands this will not be possible, in which case
% \cs{@@_patch_cmd_or_delay:Nnn} (defined in \texttt{ltcmdhooks})
% will generate an appropriate error message.
+% \changes{v1.1d}{2023/05/21}
+% {Changes to allow support arguments in cmd hooks (cmd-args).}
% \begin{macrocode}
\str_if_eq:nnT {#1} { cmd }
- { \@@_try_put_cmd_hook:n {#5} }
+ {
+ \@@_try_put_cmd_hook:n {#5}
+ \@@_make_usable:nn {#5} { 9 }
+ \use_none:nnn
+ }
% \end{macrocode}
%
% Declare the hook always even if it can't really be used (error
% message generated elsewhere).
%
-% Here we use \cs{@@_make_usable:n}, so that a \cs{hook_new:n} is still
-% possible later.
+% Here we use \cs{@@_make_usable:nn}, so that a \cs{hook_new:n} is
+% still possible later. Generic hooks (except \hook{cmd} hooks) take
+% no arguments, so use zero as the second argument.
% \begin{macrocode}
- \@@_make_usable:n {#5}
+ \@@_make_usable:nn {#5} { 0 }
}
\@@_if_generic_reversed:nT {#5}
{ \tl_gset:cn { g_@@_#5_reversed_tl } { - } }
@@ -3285,6 +4042,37 @@
% \end{macro}
%
% \begin{macrocode}
+%<latexrelease>\IncludeInRelease{2021/11/15}{\@@_try_declaring_generic_hook:wn}
+%<latexrelease> {Standardise~generic~hook~names}
+%<latexrelease>\prg_new_protected_conditional:Npnn \@@_try_declaring_generic_hook:wn
+%<latexrelease> #1 / #2 / #3 / #4 \scan_stop: #5 { TF }
+%<latexrelease> {
+%<latexrelease> \@@_if_generic:nTF {#5}
+%<latexrelease> {
+%<latexrelease> \@@_if_usable:nF {#5}
+%<latexrelease> {
+%<latexrelease> \str_if_eq:nnT {#1} { cmd }
+%<latexrelease> { \@@_try_put_cmd_hook:n {#5} }
+%<latexrelease> \@@_make_usable:n {#5}
+%<latexrelease> }
+%<latexrelease> \@@_if_generic_reversed:nT {#5}
+%<latexrelease> { \tl_gset:cn { g_@@_#5_reversed_tl } { - } }
+%<latexrelease> \prg_return_true:
+%<latexrelease> }
+%<latexrelease> {
+%<latexrelease> \@@_if_deprecated_generic:nTF {#5}
+%<latexrelease> {
+%<latexrelease> \@@_deprecated_generic_warn:n {#5}
+%<latexrelease> \exp_after:wN \@@_declare_deprecated_generic:NNn
+%<latexrelease> \exp:w % \exp_end:
+%<latexrelease> }
+%<latexrelease> { \prg_return_false: }
+%<latexrelease> }
+%<latexrelease> }
+%<latexrelease>\EndIncludeInRelease
+% \end{macrocode}
+%
+% \begin{macrocode}
%<latexrelease>\IncludeInRelease{2021/06/01}{\@@_try_declaring_generic_hook:wn}
%<latexrelease> {Support~cmd~hooks}
%<latexrelease>\prg_new_protected_conditional:Npnn \@@_try_declaring_generic_hook:wn
@@ -3316,7 +4104,7 @@
% \end{macrocode}
%
% \begin{macrocode}
-%<latexrelease>\IncludeInRelease{2020/10/01}{\@@_try_declaring_generic_hook:wn}%
+%<latexrelease>\IncludeInRelease{2020/10/01}{\@@_try_declaring_generic_hook:wn}
%<latexrelease> {Support~cmd~hooks}
%<latexrelease>\prg_new_protected_conditional:Npnn \@@_try_declaring_generic_hook:wn
%<latexrelease> #1 / #2 / #3 / #4 \scan_stop: #5 { TF }
@@ -3338,7 +4126,6 @@
%<latexrelease> { \prg_return_false: }
%<latexrelease> }
%<latexrelease> }
-%<latexrelease>
%<latexrelease>\EndIncludeInRelease
% \end{macrocode}
% \end{macro}
@@ -3350,24 +4137,10 @@
% |file/foo.tex/before|). If it is a file-specific hook, then it
% executes the \meta{true} branch, otherwise \meta{false}.
% \begin{macrocode}
-%<latexrelease>\IncludeInRelease{2021/11/15}{\@@_if_file_hook:w}%
+%<latexrelease>\IncludeInRelease{2021/11/15}{\@@_if_file_hook:w}
%<latexrelease> {Standardise~generic~hook~names}
-\prg_new_conditional:Npnn \@@_if_file_hook:w
- #1 / #2 \s_@@_mark #3 { TF }
- {
- \@@_if_generic:nTF {#3}
- {
- \str_if_eq:nnTF {#1} { file }
- { \prg_return_true: }
- { \prg_return_false: }
- }
- { \prg_return_false: }
- }
%<latexrelease>\EndIncludeInRelease
-% \end{macrocode}
-%
-% \begin{macrocode}
-%<latexrelease>\IncludeInRelease{2020/10/01}{\@@_if_file_hook:w}%
+%<latexrelease>\IncludeInRelease{2020/10/01}{\@@_if_file_hook:w}
%<latexrelease> {Standardise~generic~hook~names}
%<latexrelease>\prg_new_conditional:Npnn \@@_if_file_hook:w
%<latexrelease> #1 / #2 / #3 \s_@@_mark { TF }
@@ -3394,7 +4167,7 @@
% \begin{macro}[EXP]{\@@_strip_double_slash:n,\@@_strip_double_slash:w}
%
% \begin{macrocode}
-%<latexrelease>\IncludeInRelease{2021/11/15}{\@@_file_hook_normalize:n}%
+%<latexrelease>\IncludeInRelease{2021/11/15}{\@@_file_hook_normalize:n}
%<latexrelease> {Standardise~generic~hook~names}
%<latexrelease>\EndIncludeInRelease
% \end{macrocode}
@@ -3406,7 +4179,7 @@
% like \verb|\def\input@path{{./mypath/}}|, in which case a hook would
% have to be \verb|\AddToHook{file/./mypath//file.tex/after}|.
% \begin{macrocode}
-%<latexrelease>\IncludeInRelease{2020/10/01}{\@@_file_hook_normalize:n}%
+%<latexrelease>\IncludeInRelease{2020/10/01}{\@@_file_hook_normalize:n}
%<latexrelease> {Standardise~generic~hook~names}
%<latexrelease>\cs_new:Npn \@@_file_hook_normalize:n #1
%<latexrelease> { \@@_strip_double_slash:n {#1} }
@@ -3453,7 +4226,7 @@
% The generic hooks used when loading a file
% \end{description}
% \begin{macrocode}
-%<latexrelease>\IncludeInRelease{2021/11/15}{\c_@@_generics_prop}%
+%<latexrelease>\IncludeInRelease{2021/11/15}{\c_@@_generics_prop}
%<latexrelease> {Standardise~generic~hook~names}
\clist_map_inline:nn { cmd , env , file , package , class , include }
{
@@ -3482,7 +4255,7 @@
% \end{macrocode}
%
% \begin{macrocode}
-%<latexrelease>\IncludeInRelease{2020/10/01}{\c_@@_generics_prop}%
+%<latexrelease>\IncludeInRelease{2020/10/01}{\c_@@_generics_prop}
%<latexrelease> {Standardise~generic~hook~names}
%<latexrelease>\prop_const_from_keyval:Nn \c_@@_generics_prop
%<latexrelease> {cmd=,env=,file=,package=,class=,include=}
@@ -3496,13 +4269,13 @@
% The following generic hooks are supposed to use reverse ordering
% (the |ii| and |iii| names are kept for the deprecation cycle):
% \begin{macrocode}
-%<latexrelease>\IncludeInRelease{2021/11/15}{\c_@@_generics_reversed_ii_prop}%
+%<latexrelease>\IncludeInRelease{2021/11/15}{\c_@@_generics_reversed_ii_prop}
%<latexrelease> {Standardise~generic~hook~names}
%<latexrelease>\EndIncludeInRelease
% \end{macrocode}
%
% \begin{macrocode}
-%<latexrelease>\IncludeInRelease{2020/10/01}{\c_@@_generics_reversed_ii_prop}%
+%<latexrelease>\IncludeInRelease{2020/10/01}{\c_@@_generics_reversed_ii_prop}
%<latexrelease> {Standardise~generic~hook~names}
%<latexrelease>\prop_const_from_keyval:Nn \c_@@_generics_reversed_ii_prop {after=,end=}
%<latexrelease>\prop_const_from_keyval:Nn \c_@@_generics_reversed_iii_prop {after=}
@@ -3511,13 +4284,46 @@
% \end{macrocode}
% \end{macro}
%
+%
+% \begin{macro}{
+% \c_@@_parameter_cmd/./before_tl,\c_@@_parameter_cmd/./after_tl,
+% }
+% Token lists defining the number of arguments for a given type of
+% generic hook.
+% \changes{v1.1d}{2023/05/21}
+% {Token lists added (cmd-args).}
+% \begin{macrocode}
+%<latexrelease>\IncludeInRelease{2023/06/01}{\c_@@_parameter_cmd/./before_tl}
+%<latexrelease> {Hooks~with~args}
+% \end{macrocode}
+%
+% \hook{cmd} hooks are declared with 9 arguments because they have a
+% variable number of arguments (depending on the command they are
+% attached to), so we use the maximum here.
+% \begin{macrocode}
+\tl_const:cn { c_@@_parameter_cmd/./before_tl } { #1#2#3#4#5#6#7#8#9 }
+\tl_const:cn { c_@@_parameter_cmd/./after_tl } { #1#2#3#4#5#6#7#8#9 }
+% \end{macrocode}
+%
+% \begin{macrocode}
+%<latexrelease>\EndIncludeInRelease
+%<latexrelease>\IncludeInRelease{2020/10/01}{\c_@@_parameter_cmd/./before_tl}
+%<latexrelease> {Hooks~with~args}
+%<latexrelease>\EndIncludeInRelease
+% \end{macrocode}
+% \end{macro}
+%
% \begin{macro}{\hook_gremove_code:nn}
% \begin{macro}{\@@_gremove_code:nn}
%
% With \cs{hook_gremove_code:nn}\Arg{hook}\Arg{label} any code
% for \meta{hook} stored under \meta{label} is removed.
% \changes{v1.0o}{2021/07/22}{Do not queue removals (gh/625)}
+% \changes{v1.1a}{2023/04/06}
+% {Changes to add hook arguments (hook-args).}
% \begin{macrocode}
+%<latexrelease>\IncludeInRelease{2023/06/01}{\hook_gremove_code:nn}
+%<latexrelease> {Hooks~with~args}
\cs_new_protected:Npn \hook_gremove_code:nn #1 #2
{ \@@_normalize_hook_args:Nnn \@@_gremove_code:nn {#1} {#2} }
\cs_new_protected:Npn \@@_gremove_code:nn #1 #2
@@ -3542,8 +4348,8 @@
\str_if_eq:nnTF {#2} {*}
{
\prop_gclear:c { g_@@_#1_code_prop }
- \@@_tl_gclear:c { @@_toplevel~#1 }
- \@@_tl_gclear:c { @@_next~#1 }
+ \@@_toplevel_gset:nn {#1} { }
+ \@@_next_gset:nn {#1} { }
}
{
% \end{macrocode}
@@ -3551,7 +4357,7 @@
% there is under the same label.
% \begin{macrocode}
\str_if_eq:nnTF {#2} { top-level }
- { \@@_tl_gclear:c { @@_toplevel~#1 } }
+ { \@@_toplevel_gset:nn {#1} { } }
{
\prop_gpop:cnNF { g_@@_#1_code_prop } {#2} \l_@@_return_tl
{ \msg_warning:nnnn { hooks } { cannot-remove } {#1} {#2} }
@@ -3576,14 +4382,542 @@
{ \msg_warning:nnnn { hooks } { cannot-remove } {#1} {#2} }
}
}
+%<latexrelease>\EndIncludeInRelease
+% \end{macrocode}
+%
+% \begin{macrocode}
+%<latexrelease>\IncludeInRelease{2023/06/01}{\hook_gremove_code:nn}
+%<latexrelease> {Hooks~with~args}
+%<latexrelease>\cs_new_protected:Npn \@@_gremove_code:nn #1 #2
+%<latexrelease> {
+%<latexrelease> \@@_if_structure_exist:nTF {#1}
+%<latexrelease> {
+%<latexrelease> \str_if_eq:nnTF {#2} {*}
+%<latexrelease> {
+%<latexrelease> \prop_gclear:c { g_@@_#1_code_prop }
+%<latexrelease> \@@_tl_gclear:c { @@_toplevel~#1 }
+%<latexrelease> \@@_tl_gclear:c { @@_next~#1 }
+%<latexrelease> }
+%<latexrelease> {
+%<latexrelease> \str_if_eq:nnTF {#2} { top-level }
+%<latexrelease> { \@@_tl_gclear:c { @@_toplevel~#1 } }
+%<latexrelease> {
+%<latexrelease> \prop_gpop:cnNF { g_@@_#1_code_prop } {#2} \l_@@_return_tl
+%<latexrelease> { \msg_warning:nnnn { hooks } { cannot-remove } {#1} {#2} }
+%<latexrelease> }
+%<latexrelease> }
+%<latexrelease> \@@_if_usable:nT {#1}
+%<latexrelease> { \@@_update_hook_code:n {#1} }
+%<latexrelease> }
+%<latexrelease> {
+%<latexrelease> \@@_if_deprecated_generic:nTF {#1}
+%<latexrelease> {
+%<latexrelease> \@@_deprecated_generic_warn:n {#1}
+%<latexrelease> \@@_do_deprecated_generic:Nn \@@_gremove_code:nn {#1} {#2}
+%<latexrelease> }
+%<latexrelease> { \msg_warning:nnnn { hooks } { cannot-remove } {#1} {#2} }
+%<latexrelease> }
+%<latexrelease> }
+%<latexrelease>\EndIncludeInRelease
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\@@_cs_gput_right:nnn}
+% \begin{macro}{\@@_code_gset_auxi:nnnn,\@@_code_gset_auxi:eeen}
+% This macro is used to append code to the \verb|toplevel| and
+% \verb|next| token lists, trating them correctly depending on their
+% number of arguments, and depending if the code being added should
+% have parameter tokens understood as parameters, or doubled to be
+% stored as parameter tokens.
+% \changes{v1.1a}{2023/04/06}
+% {Macro added (hook-args).}
+% \begin{macrocode}
+%<latexrelease>\IncludeInRelease{2023/06/01}{\@@_cs_gput_right:nnn}
+%<latexrelease> {Hooks~with~args}
+\cs_new_protected:Npn \@@_cs_gput_right:nnn #1 #2 #3
+ {
+% \end{macrocode}
+% The auxiliary \cs{@@_code_gset_auxi:eeen} just does the assignment
+% at the end. Its first argument is the parameter text of the macro,
+% which is chosen here depending if
+% \cs[no-index]{c_@@_\meta{hook}_parameter_tl} exists, if the hook is
+% declared, and if it's a generic hook.
+% \begin{macrocode}
+ \cs_if_exist:cF { @@#1~#2 }
+ { \@@_code_gset_aux:nnn {#1} {#2} { } }
+ \@@_code_gset_auxi:eeen
+ {
+ \@@_if_declared:nTF {#2}
+ { \tl_use:c { c_@@_#2_parameter_tl } }
+ {
+ \@@_if_generic:nTF {#2}
+ { \@@_generic_parameter:n {#2} }
+ { \c_@@_nine_parameters_tl }
+ }
+ }
+% \end{macrocode}
+% Here we take the existing code in the macro, expand it with as many
+% arguments as it takes, then double the hashes so the code can be
+% reused. \pho{Maybe can be improved. The case of adding to an empty
+% cs can be optimised by quickly checking \cs{cs_replacement_spec}.}
+% \begin{macrocode}
+ {
+ \exp_args:NNo \exp_args:No \@@_double_hashes:n
+ {
+ \cs:w @@#1~#2 \exp_last_unbraced:Ne \cs_end:
+ { \@@_braced_cs_parameter:n { @@#1~#2 } }
+ }
+ }
+% \end{macrocode}
+% Now the new code: if we are replacing arguments, then hashes are
+% left untouched, otherwise they are doubled.
+% \begin{macrocode}
+ {
+ \@@_if_replacing_args:TF
+ { \exp_not:n }
+ { \@@_double_hashes:n }
+ {#3}
+ }
+% \end{macrocode}
+% And finally, the csname which we'll define with all the above.
+% \begin{macrocode}
+ { @@#1~#2 }
+ }
+% \end{macrocode}
+%
+% And as promised, the auxiliary that does the definition.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_code_gset_auxi:nnnn #1 #2 #3 #4
+ { \cs_gset:cpn {#4} #1 { #2 #3 } }
+\cs_generate_variant:Nn \@@_code_gset_auxi:nnnn { eeen }
+% \end{macrocode}
+%
+% \begin{macrocode}
+%<latexrelease>\EndIncludeInRelease
+%<latexrelease>\IncludeInRelease{2020/10/01}{\@@_cs_gput_right:nnn}
+%<latexrelease> {Hooks~with~args}
+%<latexrelease>\cs_undefine:N \@@_cs_gput_right:nnn
+%<latexrelease>\cs_undefine:N \@@_code_gset_auxi:nnnn
+%<latexrelease>\EndIncludeInRelease
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{
+% \@@_code_gset:nn,\@@_code_gset:ne,
+% \@@_toplevel_gset:nn,
+% \@@_next_gset:nn,
+% \@@_code_gset_aux:nnn
+% }
+% These macros define
+% \cs[no-index]{@@\meta{type}\textvisiblespace\meta{hook}} (with
+% \meta{type} being \verb|_next|, \verb|_toplevel|, or empty) with the
+% given code and the parameters stored in
+% \cs[no-index]{c_@@_\meta{hook}_parameter_tl} (or none, if that
+% doesn't exist).
+% \changes{v1.1a}{2023/04/06}
+% {Macro added (hook-args).}
+% \begin{macrocode}
+%<latexrelease>\IncludeInRelease{2023/06/01}{\@@_code_gset:nn}
+%<latexrelease> {Hooks~with~args}
+\cs_new_protected:Npn \@@_code_gset:nn
+ { \@@_code_gset_aux:nnn { } }
+\cs_new_protected:Npn \@@_toplevel_gset:nn
+ { \@@_code_gset_aux:nnn { _toplevel } }
+\cs_new_protected:Npn \@@_next_gset:nn
+ { \@@_code_gset_aux:nnn { _next } }
+\cs_new_protected:Npn \@@_code_gset_aux:nnn #1 #2 #3
+ {
+ \cs_gset:cpn { @@#1~#2 \exp_last_unbraced:Ne }
+ { \@@_parameter:n {#2} }
+ {#3}
+ }
+\cs_generate_variant:Nn \@@_code_gset:nn { ne }
+% \end{macrocode}
+%
+% \begin{macrocode}
+%<latexrelease>\EndIncludeInRelease
+%<latexrelease>\IncludeInRelease{2020/10/01}{\@@_code_gset:nn}
+%<latexrelease> {Hooks~with~args}
+%<latexrelease>\cs_undefine:N \@@_code_gset:nn
+%<latexrelease>\cs_undefine:N \@@_toplevel_gset:nn
+%<latexrelease>\cs_undefine:N \@@_next_gset:nn
+%<latexrelease>\cs_undefine:N \@@_code_gset_aux:nnn
+%<latexrelease>\EndIncludeInRelease
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_normalise_cs_args:nn}
+% This macro normalises the parameters of the macros
+% \cs[no-index]{@@\meta{type}\textvisiblespace\meta{hook}} to take the
+% right number of arguments after a hook is declared. At this point
+% we know \cs[no-index]{c_@@_\meta{hook}_parameter_tl} exists, so use
+% that to count the arguments and use that as \meta{parameter text}
+% for the newly (re)defined macro.
+% \changes{v1.1a}{2023/04/06}
+% {Macro added (hook-args).}
+% \begin{macrocode}
+%<latexrelease>\IncludeInRelease{2023/06/01}{\@@_normalise_cs_args:nn}
+%<latexrelease> {Hooks~with~args}
+\cs_new_protected:Npn \@@_normalise_cs_args:nn #1 #2
+ {
+ \cs_if_exist:cT { @@#1~#2 }
+ {
+ \@@_code_gset_auxi:eeen
+ { \tl_use:c { c_@@_#2_parameter_tl } }
+ {
+ \exp_args:NNo \exp_args:No \@@_double_hashes:n
+ {
+ \cs:w @@#1~#2 \exp_last_unbraced:Ne \cs_end:
+ { \@@_braced_cs_parameter:n { @@#1~#2 } }
+ }
+ }
+ { }
+ { @@#1~#2 }
+ }
+ }
+%<latexrelease>\EndIncludeInRelease
+% \end{macrocode}
+%
+% \begin{macrocode}
+%<latexrelease>\IncludeInRelease{2020/10/01}{\@@_normalise_cs_args:nn}
+%<latexrelease> {Hooks~with~args}
+%<latexrelease>\cs_undefine:N \@@_normalise_cs_args:nn
+%<latexrelease>\EndIncludeInRelease
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_normalise_code_pool:n}
+% \begin{macro}{\@@_set_normalise_fn:nn}
+% This one's a bit of a hack. It takes a hook, and iterates over its
+% code pool (\cs[no-index]{g_@@_\meta{hook}_code_prop}), redefining
+% each code label to use only valid arguments. This is used when, for
+% example, a code is added referencing arguments \verb|#1| and
+% \verb|#2|, but the hook has only \verb|#1|. In this example, every
+% reference to \verb|#2| is changed to \verb|##2|. This is done
+% because otherwise \TeX{} will throw a low-level error every time
+% some change happens to the hook (code is added, a rule is set, etc),
+% which can get quite repetitive for no good reason.
+% \changes{v1.1a}{2023/04/06}
+% {Macro added (hook-args).}
+% \begin{macrocode}
+%<latexrelease>\IncludeInRelease{2023/06/01}{\@@_normalise_code_pool:n}
+%<latexrelease> {Hooks~with~args}
+\cs_new_protected:Npn \@@_normalise_code_pool:n #1
+ {
+% \end{macrocode}
+% First, call \cs{@@_set_normalise_fn:nn} with the hook name to set
+% everything up, then we'll loop over the
+% hook's code pool applying the normalisation above. After that's
+% done, copy the temporary property list back to the hook's.
+% \begin{macrocode}
+ \@@_set_normalise_fn:nn {#1} { Offending~label:~'##1' }
+ \prop_clear:N \l_@@_work_prop
+ \prop_map_function:cN { g_@@_#1_code_prop } \@@_normalise_fn:nn
+ \prop_gset_eq:cN { g_@@_#1_code_prop } \l_@@_work_prop
+ }
+% \end{macrocode}
+%
+% The sole purpose of this function is to define
+% \cs{@@_normalise_fn:nn}, which will then do the correcting of the
+% code being added to the hook.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_set_normalise_fn:nn #1 #2
+ {
+% \end{macrocode}
+% To start, we define two auxiliary token lists.
+% \cs[no-index]{l_@@_tmpb_tl} contains:
+%\begin{verbatim}
+% {\c__hook_hashes_tl 1}
+% {\c__hook_hashes_tl 2}
+% ...
+% {\c__hook_hashes_tl 9}
+%\end{verbatim}
+% \begin{macrocode}
+ \cs_set:Npn \@@_tmp:w ##1##2##3##4##5##6##7##8##9 { }
+ \tl_set:Ne \l_@@_tmpb_tl
+ { \@@_braced_cs_parameter:n { @@_tmp:w } }
+ \group_begin:
+ \@@_tl_set:cn { c_@@_hash_tl } { \exp_not:N \c_@@_hashes_tl }
+ \use:e
+ {
+ \group_end:
+ \tl_set:Nn \exp_not:N \l_@@_tmpb_tl { \l_@@_tmpb_tl }
+ }
+% \end{macrocode}
+% And \cs[no-index]{l_@@_tmpa_tl} contains:
+%\begin{verbatim}
+% {\c__hook_hash_tl 1}
+% {\c__hook_hash_tl 2}
+% ...
+% {\c__hook_hash_tl <n>}
+%\end{verbatim}
+% with \meta{n} being the number of arguments declared for the hook.
+% \begin{macrocode}
+ \exp_last_unbraced:NNf
+ \cs_set:Npn \@@_tmp:w { \@@_parameter:n {#1} } { }
+ \tl_set:Ne \l_@@_tmpa_tl { \@@_braced_cs_parameter:n { @@_tmp:w } }
+% \end{macrocode}
+% Now this function does the fun part. It is meant to be used with
+% \cs{prop_map_function:NN}, taking a label name in \verb|##1| and the
+% code stored in that label in \verb|##2|.
+% \begin{macrocode}
+ \cs_gset_protected:Npx \@@_normalise_fn:nn ##1 ##2
+ {
+% \end{macrocode}
+% Here we'll define two auxiliary macros: the first one throws an
+% error when it detects an invalid argument reference. It piggybacks
+% on \TeX's low-level \enquote{Illegal parameter number} error, but it
+% defines a weirdly-named control sequence so that the error comes out
+% nicely formatted. For example, if the label \enquote{badpkg} adds
+% some code that references argument \verb|#3| in the hook
+% \enquote{foo}, which takes only two arguments, the error will be:
+%\begin{verbatim}
+% ! Illegal parameter number in definition of hook 'foo'.
+% (hooks) Offending label: 'badpkg'.
+% <to be read again>
+% 3
+%\end{verbatim}
+% At the point of this definition, the error is raised if the code
+% happens to reference an invalid argument. If it was possible to
+% detect that this definition raised no error, the next step would be
+% unnecessary. We'll do all this in a group so this weird definition
+% doesn't leak out, and set \cs{tex_escapechar:D} to $-1$ so this hack
+% shows up extra nice in the case of an error.
+% \begin{macrocode}
+ \group_begin:
+ \int_set:Nn \tex_escapechar:D { -1 }
+ \cs_set:cpn
+ {
+ hook~'#1'. ^^J
+ (hooks) \prg_replicate:nn { 13 } { ~ }
+ #2 % more message text
+ }
+ \exp_not:v { c_@@_#1_parameter_tl }
+ {##2}
+ \group_end:
+% \end{macrocode}
+% This next macro, with a much less fabulous name, takes always nine
+% arguments, and it just transfers the code \verb|##2| under the label
+% \verb|##1| to the temporary property list. The first \meta{n}
+% arguments are taken from \cs[no-index]{l_@@_tmpa_tl}, and the other
+% $9-\meta{n}$ taken from \cs[no-index]{l_@@_tmpb_tl} (which contains
+% twice as many \verb|#| tokens as the former). Then,
+% \cs{@@_double_hashes:n} is used to double non-argument hashes, and
+% expand the \cs{c_@@_hash_tl} and \cs{c_@@_hashes_tl} to the actual
+% parameter tokens.
+% \begin{macrocode}
+ \cs_set:Npn \exp_not:N \@@_tmp:w
+ \exp_not:V \c_@@_nine_parameters_tl
+ {
+ \prop_put:Nne \exp_not:N \l_@@_work_prop
+ {##1} { \exp_not:N \@@_double_hashes:n {##2} }
+ }
+% \end{macrocode}
+% This next macro, with a much less fabulous name, takes always nine
+% arguments, and it just transfers the code \verb|##2| under the label
+% \verb|##1| to the temporary property list. The first \meta{n}
+% arguments are taken from \cs[no-index]{l_@@_tmpa_tl}, and the other
+% $9-\meta{n}$ taken from \cs[no-index]{l_@@_tmpb_tl} (which contains
+% twice as many \verb|#| tokens as the former). Then,
+% \cs{@@_double_hashes:n} is used to double non-argument hashes, and
+% expand the \cs{c_@@_hash_tl} and \cs{c_@@_hashes_tl} to the actual
+% parameter tokens.
+% \begin{macrocode}
+ \exp_not:N \@@_tmp:w
+ \exp_not:V \l_@@_tmpa_tl
+ \exp_args:No \exp_not:o
+ { \exp_after:wN \@@_tmp:w \l_@@_tmpb_tl }
+ }
+ }
+\cs_new_eq:NN \@@_normalise_fn:nn ?
+%<latexrelease>\EndIncludeInRelease
+% \end{macrocode}
+%
+% \begin{macrocode}
+%<latexrelease>\IncludeInRelease{2020/10/01}{\@@_normalise_code_pool:n}
+%<latexrelease> {Hooks~with~args}
+%<latexrelease>\cs_undefine:N \@@_normalise_code_pool:n
+%<latexrelease>\EndIncludeInRelease
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[pTF]{\@@_cs_if_empty:c}
+% Check if the expansion of a control sequence is empty by looking at
+% its replacement text.
+% \changes{v1.1a}{2023/04/06}
+% {Macro added (hook-args).}
+% \begin{macrocode}
+%<latexrelease>\IncludeInRelease{2023/06/01}{\@@_cs_if_empty:c}
+%<latexrelease> {Hooks~with~args}
+\prg_new_conditional:Npnn \@@_cs_if_empty:c #1 { p, T, F, TF }
+ {
+ \if:w \scan_stop: \@@_replacement_spec:c {#1} \scan_stop:
+ \prg_return_true:
+ \else:
+ \prg_return_false:
+ \fi:
+ }
+\cs_new:Npn \@@_replacement_spec:c #1
+ {
+ \exp_args:Nc \token_if_macro:NT {#1}
+ { \cs_replacement_spec:c {#1} }
+ }
+%<latexrelease>\EndIncludeInRelease
+% \end{macrocode}
+%
+% \begin{macrocode}
+%<latexrelease>\IncludeInRelease{2020/10/01}{\@@_cs_if_empty:c}
+%<latexrelease> {Hooks~with~args}
+%<latexrelease>\cs_undefine:N \@@_cs_if_empty:c
+%<latexrelease>\EndIncludeInRelease
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\@@_braced_cs_parameter:n}
+% \begin{macro}{\@@_braced_hidden_loop:w}
+% \begin{macro}{\@@_cs_parameter_count:N}
+% \begin{macro}{\@@_cs_parameter_count:w,\@@_cs_end:w}
+% Looks at the \meta{parameter text} of a control sequence, and
+% returns a run of \enquote{hidden} braced parameters for that macro.
+% This works as long as the macros take a simple run of zero to nine
+% arguments. The parameters are \enquote{hidden} because the
+% parameter tokens are returned inside \cs{c_@@_hash_tl} instead of
+% explicitly, so that \cs{@@_double_hashes:n} won't touch these.
+% \changes{v1.1a}{2023/04/06}
+% {Macro added (hook-args).}
+% \begin{macrocode}
+%<latexrelease>\IncludeInRelease{2023/06/01}{\@@_braced_cs_parameter:n}
+%<latexrelease> {Hooks~with~args}
+\cs_new:Npn \@@_braced_cs_parameter:n #1
+ {
+ \exp_last_unbraced:Ne \@@_braced_hidden_loop:w
+ { \exp_args:Nc \@@_cs_parameter_count:N {#1} } ? \s_@@_mark
+ }
+\cs_new:Npn \@@_braced_hidden_loop:w #1
+ {
+ \if:w ? #1
+ \@@_use_i_delimit_by_s_mark:nw
+ \fi:
+ { \exp_not:N \c_@@_hash_tl #1 }
+ \@@_braced_hidden_loop:w
+ }
+\cs_new:Npn \@@_cs_parameter_count:N #1
+ {
+ \exp_last_unbraced:Nf \@@_cs_parameter_count:w
+ { \token_if_macro:NT #1 { \cs_parameter_spec:N #1 } }
+ ? \@@_cs_end:w ? \@@_cs_end:w ? \@@_cs_end:w
+ ? \@@_cs_end:w ? \@@_cs_end:w ? \@@_cs_end:w
+ ? \@@_cs_end:w ? \@@_cs_end:w ? \@@_cs_end:w
+ \s_@@_mark
+ }
+\cs_new:Npn \@@_cs_parameter_count:w #1#2 #3#4 #5#6 #7#8
+ { #2 #4 #6 #8 \@@_cs_parameter_count:w }
+\cs_new:Npn \@@_cs_end:w #1 \s_@@_mark { }
+%<latexrelease>\EndIncludeInRelease
+% \end{macrocode}
+%
+% This function can't be undefined when rolling back because it's used
+% at the end of this module to adequate the hook data structures to
+% previous versions.
+% \begin{macrocode}
+%<latexrelease>\IncludeInRelease{2020/10/01}{\@@_braced_cs_parameter:n}
+%<latexrelease> {Hooks~with~args}
+%<latexrelease>\EndIncludeInRelease
% \end{macrocode}
% \end{macro}
% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\@@_braced_parameter:n}
+% \begin{macro}{\@@_braced_real_loop:w}
+% This one is used in simpler cases, where no special handling of
+% hashes is required. This is used only inside
+% \cs{@@_initialize_hook_code:n}, so it assumes
+% \cs[no-index]{c_@@_\meta{hook}_parameter_tl} is defined, but should
+% work otherwise.
+% \changes{v1.1a}{2023/04/06}
+% {Macro added (hook-args).}
+% \begin{macrocode}
+%<latexrelease>\IncludeInRelease{2023/06/01}{\@@_braced_parameter:n}
+%<latexrelease> {Hooks~with~args}
+\cs_new:Npn \@@_braced_parameter:n #1
+ {
+ \if_case:w
+ \int_eval:n
+ { \exp_args:Nv \str_count:n { c_@@_#1_parameter_tl } / 3 }
+ \exp_stop_f:
+ \or: {##1}
+ \or: {##1} {##2}
+ \or: {##1} {##2} {##3}
+ \or: {##1} {##2} {##3} {##4}
+ \or: {##1} {##2} {##3} {##4} {##5}
+ \or: {##1} {##2} {##3} {##4} {##5} {##6}
+ \or: {##1} {##2} {##3} {##4} {##5} {##6} {##7}
+ \or: {##1} {##2} {##3} {##4} {##5} {##6} {##7} {##8}
+ \or: {##1} {##2} {##3} {##4} {##5} {##6} {##7} {##8} {##9}
+ \else:
+ \msg_expandable_error:nnn { latex2e } { should-not-happen }
+ { Invalid~parameter~spec. }
+ \fi:
+ }
+%<latexrelease>\EndIncludeInRelease
+% \end{macrocode}
+%
+% \begin{macrocode}
+%<latexrelease>\IncludeInRelease{2020/10/01}{\@@_braced_parameter:n}
+%<latexrelease> {Hooks~with~args}
+%<latexrelease>\cs_undefine:N \@@_braced_parameter:n
+%<latexrelease>\EndIncludeInRelease
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\@@_parameter:n}
+% This is just a shortcut to \verb|e|- or \verb|f|-expand to the
+% \meta{parameter text} of the hook.
+% \changes{v1.1a}{2023/04/06}
+% {Macro added (hook-args).}
+% \begin{macrocode}
+%<latexrelease>\IncludeInRelease{2023/06/01}{\@@_parameter:n}
+%<latexrelease> {Hooks~with~args}
+\cs_new:Npn \@@_parameter:n #1
+ {
+ \cs:w c_@@_
+ \tl_if_exist:cTF { c_@@_#1_parameter_tl }
+ { #1_parameter } { empty }
+ _tl \cs_end:
+ }
+\cs_new:Npn \@@_generic_parameter:n #1
+ { \@@_generic_parameter:w #1 / / / \s_@@_mark }
+\cs_new:Npn \@@_generic_parameter:w #1 / #2 / #3 / #4 \s_@@_mark
+ {
+ \cs_if_exist_use:cF { c_@@_parameter_#1/./#3_tl }
+ { \c_@@_empty_tl }
+ }
+%<latexrelease>\EndIncludeInRelease
+% \end{macrocode}
+%
+% \begin{macrocode}
+%<latexrelease>\IncludeInRelease{2020/10/01}{\@@_parameter:n}
+%<latexrelease> {Hooks~with~args}
+%<latexrelease>\cs_undefine:N \@@_parameter:n
+%<latexrelease>\cs_undefine:N \@@_generic_parameter:n
+%<latexrelease>\EndIncludeInRelease
+% \end{macrocode}
+% \end{macro}
+%
+%
+% \subsection{Setting rules for hooks code}
%
% \begin{macro}{
% \g_@@_??_code_prop,
% \@@~??,
% \g_@@_??_reversed_tl,
+% \c_@@_??_parameter_tl,
% }
%
% Initially these variables simply used an empty ``label'' name (not
@@ -3597,11 +4931,11 @@
% lot, the code should be fast, so this is not done with \texttt{c}
% expansion in the code later on.
%
-% \cs{@@\textvisiblespace??} isn't used, but it has to be defined to trick
-% the code into thinking that \texttt{??} is actually a hook.
+% \cs{@@\textvisiblespace??} isn't used, but it has to be defined to
+% trick the code into thinking that \texttt{??} is actually a hook.
% \begin{macrocode}
-\prop_new:c {g_@@_??_code_prop}
-\prop_new:c {@@~??}
+\prop_new:c { g_@@_??_code_prop }
+\prop_new:c { @@~?? }
% \end{macrocode}
%
% Default rules are always given in normal ordering (never in
@@ -3610,11 +4944,23 @@
% \texttt{after} becomes \texttt{before})
% because those rules are applied first and then the order is reversed.
% \begin{macrocode}
-\tl_new:c {g_@@_??_reversed_tl}
+\tl_new:c { g_@@_??_reversed_tl }
% \end{macrocode}
-% \end{macro}
%
-% \subsection{Setting rules for hooks code}
+% The parameter text for the \enquote{default} hook is empty.
+% \changes{v1.1a}{2023/04/06}
+% {Token list added (hook-args).}
+% \begin{macrocode}
+%<latexrelease>\IncludeInRelease{2023/06/01}{\c_@@_??_parameter_tl}
+%<latexrelease> {Hooks~with~args}
+\tl_const:cn { c_@@_??_parameter_tl } { }
+%<latexrelease>\EndIncludeInRelease
+%<latexrelease>\IncludeInRelease{2020/10/01}{\c_@@_??_parameter_tl}
+%<latexrelease> {Hooks~with~args}
+%<latexrelease>\cs_undefine:c { c_@@_??_parameter_tl }
+%<latexrelease>\EndIncludeInRelease
+% \end{macrocode}
+% \end{macro}
%
% \begin{macro}{\hook_gset_rule:nnnn}
% \begin{macro}{\@@_gset_rule:nnnn}
@@ -3645,13 +4991,13 @@
\@@_deprecated_generic_warn:n {#1}
\@@_do_deprecated_generic:Nn \@@_gset_rule:nnnn {#1}
{#2} {#3} {#4}
- \@@_clean_to_scan:w
+ \@@_use_none_delimit_by_s_mark:w
}
\@@_if_execute_immediately:nT {#1}
{
\msg_error:nnnnnn { hooks } { rule-too-late }
{#1} {#2} {#3} {#4}
- \@@_clean_to_scan:w
+ \@@_use_none_delimit_by_s_mark:w
}
% \end{macrocode}
% First we ensure the basic data structure of the hook exists:
@@ -3840,44 +5186,82 @@
% \begin{macro}{\@@_initialize_all:}
% Initialize all known hooks (at \verb=\begin{document}=), i.e.,
% update the fast execution token lists to hold the necessary code
-% in the right order.
+% in the right order.
+% \changes{v1.1a}{2023/04/06}
+% {Changes to add hook arguments (hook-args).}
% \begin{macrocode}
-\cs_new_protected:Npn \@@_initialize_all: {
+%<latexrelease>\IncludeInRelease{2023/06/01}{\@@_initialize_all:}
+%<latexrelease> {Hooks~with~args}
+\cs_new_protected:Npn \@@_initialize_all:
+ {
% \end{macrocode}
% First we change \cs{@@_update_hook_code:n} which so far was a
% no-op to now initialize one hook. This way any later updates to
% the hook will run that code and also update the execution token
% list.
% \begin{macrocode}
- \cs_gset_eq:NN \@@_update_hook_code:n \@@_initialize_hook_code:n
+ \cs_gset_eq:NN \@@_update_hook_code:n \@@_initialize_hook_code:n
% \end{macrocode}
% Now we loop over all hooks that have been defined and update each
-% of them.
+% of them. Here we have to determine if the hook has arguments so
+% that auxiliaries know what to do with hashes. We look at
+% \cs[no-index]{c_@@_\meta{hook}_parameter_tl}, if it has any
+% parameters, and set \verb|replacing_args| accordingly.
% \begin{macrocode}
- \@@_debug:n { \prop_gclear:N \g_@@_used_prop }
- \seq_map_inline:Nn \g_@@_all_seq
+ \@@_debug:n { \prop_gclear:N \g_@@_used_prop }
+ \seq_map_inline:Nn \g_@@_all_seq
{
+ \tl_if_empty:cTF { c_@@_##1_parameter_tl }
+ { \@@_replacing_args_false: }
+ { \@@_replacing_args_true: }
\@@_update_hook_code:n {##1}
+ \@@_replacing_args_reset:
}
% \end{macrocode}
% If we are debugging we show results hook by hook for all hooks
% that have data.
% \begin{macrocode}
- \@@_debug:n
- { \iow_term:x{^^JAll~ initialized~ (non-empty)~ hooks:}
- \prop_map_inline:Nn \g_@@_used_prop
- { \iow_term:x{^^J~ ##1~ ->~
- \exp_not:v {@@~##1}~ }
- }
- }
+ \@@_debug:n
+ {
+ \iow_term:x { ^^J All~initialized~(non-empty)~hooks: }
+ \prop_map_inline:Nn \g_@@_used_prop
+ {
+ \iow_term:x
+ { ^^J ~ ##1 ~ -> ~ \cs_replacement_spec:c { @@~##1 } ~ }
+ }
+ }
% \end{macrocode}
% After all hooks are initialized we change the ``use'' to just
% call the hook code and not initialize it (as it was done in the
% preamble.
% \begin{macrocode}
- \cs_gset_eq:NN \hook_use:n \@@_use_initialized:n
- \cs_gset_eq:NN \@@_preamble_hook:n \use_none:n
-}
+ \@@_post_initialization_defs:
+ }
+% \end{macrocode}
+%
+% \begin{macrocode}
+%<latexrelease>\EndIncludeInRelease
+%<latexrelease>\IncludeInRelease{2020/10/01}{\@@_initialize_all:}
+%<latexrelease> {Hooks~with~args}
+%<latexrelease>\cs_gset_protected:Npn \@@_initialize_all:
+%<latexrelease> {
+%<latexrelease> \cs_gset_eq:NN \@@_update_hook_code:n \@@_initialize_hook_code:n
+%<latexrelease> \@@_debug:n { \prop_gclear:N \g_@@_used_prop }
+%<latexrelease> \seq_map_inline:Nn \g_@@_all_seq
+%<latexrelease> { \@@_update_hook_code:n {##1} }
+%<latexrelease> \@@_debug:n
+%<latexrelease> {
+%<latexrelease> \iow_term:x{^^JAll~ initialized~ (non-empty)~ hooks:}
+%<latexrelease> \prop_map_inline:Nn \g_@@_used_prop
+%<latexrelease> {
+%<latexrelease> \iow_term:x
+%<latexrelease> { ^^J ~ ##1 ~ -> ~ \cs_replacement_spec:c { @@~##1 } ~ }
+%<latexrelease> }
+%<latexrelease> }
+%<latexrelease> \cs_gset_eq:NN \hook_use:n \@@_use_initialized:n
+%<latexrelease> \cs_gset_eq:NN \@@_preamble_hook:n \use_none:n
+%<latexrelease> }
+%<latexrelease>\EndIncludeInRelease
% \end{macrocode}
% \end{macro}
%
@@ -3887,7 +5271,11 @@
% the preamble this is selectively done in case a hook gets used
% and at \verb=\begin{document}= this is done for all hooks and
% afterwards only if the hook code changes.
+% \changes{v1.1a}{2023/04/06}
+% {Changes to add hook arguments (hook-args).}
% \begin{macrocode}
+%<latexrelease>\IncludeInRelease{2023/06/01}{\@@_initialize_hook_code:n}
+%<latexrelease> {Hooks~with~args}
\cs_new_protected:Npn \@@_initialize_hook_code:n #1
{
\@@_debug:n
@@ -3915,10 +5303,15 @@
{
\prop_if_empty:cTF { g_@@_#1_code_prop }
{
- \@@_tl_gset:co { @@~#1 }
+ \@@_code_gset:ne {#1}
{
- \cs:w @@_toplevel~#1 \exp_after:wN \cs_end:
- \cs:w @@_next~#1 \cs_end:
+% \end{macrocode}
+% The hook may take arguments, so we add a run of braced parameters
+% after the \verb|_next| and \verb|_toplevel| macros, so that the
+% arguments passed to the hook are forwarded to them.
+% \begin{macrocode}
+ \exp_not:c { @@_toplevel~#1 } \@@_braced_parameter:n {#1}
+ \exp_not:c { @@_next~#1 } \@@_braced_parameter:n {#1}
}
}
{
@@ -3958,6 +5351,42 @@
}
}
}
+%<latexrelease>\EndIncludeInRelease
+% \end{macrocode}
+%
+% \begin{macrocode}
+%<latexrelease>\IncludeInRelease{2020/10/01}{\@@_initialize_hook_code:n}
+%<latexrelease> {Hooks~with~args}
+%<latexrelease>\cs_gset_protected:Npn \@@_initialize_hook_code:n #1
+%<latexrelease> {
+%<latexrelease> \@@_debug:n
+%<latexrelease> { \iow_term:x { ^^J Update~code~for~hook~'#1' \on@line :^^J } }
+%<latexrelease> \@@_include_legacy_code_chunk:n {#1}
+%<latexrelease> \@@_if_usable:nT {#1}
+%<latexrelease> {
+%<latexrelease> \prop_if_empty:cTF { g_@@_#1_code_prop }
+%<latexrelease> {
+%<latexrelease> \@@_tl_gset:co { @@~#1 }
+%<latexrelease> {
+%<latexrelease> \cs:w @@_toplevel~#1 \exp_after:wN \cs_end:
+%<latexrelease> \cs:w @@_next~#1 \cs_end:
+%<latexrelease> }
+%<latexrelease> }
+%<latexrelease> {
+%<latexrelease> \@@_if_reversed:nTF {#1}
+%<latexrelease> { \cs_set_eq:NN \@@_tl_gput:Nn \@@_tl_gput_left:Nn
+%<latexrelease> \cs_set_eq:NN \@@_clist_gput:NV \clist_gput_left:NV }
+%<latexrelease> { \cs_set_eq:NN \@@_tl_gput:Nn \@@_tl_gput_right:Nn
+%<latexrelease> \cs_set_eq:NN \@@_clist_gput:NV \clist_gput_right:NV }
+%<latexrelease> \prop_set_eq:Nc \l_@@_work_prop { g_@@_#1_code_prop }
+%<latexrelease> \@@_initialize_single:ccn
+%<latexrelease> { @@~#1 } { g_@@_#1_labels_clist } {#1}
+%<latexrelease> \@@_debug:n
+%<latexrelease> { \exp_args:NNx \prop_gput:Nnn \g_@@_used_prop {#1} { } }
+%<latexrelease> }
+%<latexrelease> }
+%<latexrelease> }
+%<latexrelease>\EndIncludeInRelease
% \end{macrocode}
% \end{macro}
%
@@ -4034,7 +5463,12 @@
% ^^A #1 <- \@@~#1
% ^^A #2 <- \g_@@_#1_labels_clist
% ^^A #3 <- #1
+%
+% \changes{v1.1a}{2023/04/06}
+% {Changes to add hook arguments (hook-args).}
% \begin{macrocode}
+%<latexrelease>\IncludeInRelease{2023/06/01}{\@@_initialize_single:NNn}
+%<latexrelease> {Hooks~with~args}
\cs_new_protected:Npn \@@_initialize_single:NNn #1#2#3
{
% \end{macrocode}
@@ -4181,15 +5615,103 @@
% time execution (\verb=#3=). These should normally be empty. The
% |top-level| code is added with \cs{@@_tl_gput:Nn} as that might
% change for a reversed hook (then |top-level| is the very first code
-% chunk added). The |next| code is always added last.
-% \begin{macrocode}
- \exp_args:NNo \@@_tl_gput:Nn #1 { \cs:w @@_toplevel~#3 \cs_end: }
- \@@_tl_gput_right:No #1 { \cs:w @@_next~#3 \cs_end: }
+% chunk added). The |next| code is always added last (to the right).
+% The hook may take arguments, so we add a run of braced parameters
+% after the \verb|_next| and \verb|_toplevel| macros, so that the
+% arguments passed to the hook are forwarded to them.
+% \begin{macrocode}
+ \exp_args:NNe \@@_tl_gput:Nn #1
+ { \exp_not:c { @@_toplevel~#3 } \@@_braced_parameter:n {#3} }
+ \@@_tl_gput_right:Ne #1
+ { \exp_not:c { @@_next~#3 } \@@_braced_parameter:n {#3} }
+ \use:e
+ {
+ \cs_gset:cpn { @@~#3 } \use:c { c_@@_#3_parameter_tl }
+ { \exp_not:V #1 }
+ }
}
% \end{macrocode}
%
% \begin{macrocode}
\cs_generate_variant:Nn \@@_initialize_single:NNn { cc }
+%<latexrelease>\EndIncludeInRelease
+% \end{macrocode}
+%
+% \begin{macrocode}
+%<latexrelease>\IncludeInRelease{2020/10/01}{\@@_initialize_single:NNn}
+%<latexrelease> {Hooks~with~args}
+%<latexrelease>\cs_new_protected:Npn \@@_initialize_single:NNn #1#2#3
+%<latexrelease> {
+%<latexrelease> \seq_clear:N \l_@@_labels_seq
+%<latexrelease> \int_zero:N \l_@@_labels_int
+%<latexrelease> \tl_set:Nn \l_@@_cur_hook_tl {#3}
+%<latexrelease> \prop_map_inline:Nn \l_@@_work_prop
+%<latexrelease> {
+%<latexrelease> \int_incr:N \l_@@_labels_int
+%<latexrelease> \seq_put_right:Nn \l_@@_labels_seq {##1}
+%<latexrelease> \@@_tl_set:cn { \@@_tl_csname:n {##1} } { 0 }
+%<latexrelease> \seq_clear_new:c { \@@_seq_csname:n {##1} }
+%<latexrelease> }
+%<latexrelease> \prop_map_inline:Nn \l_@@_work_prop
+%<latexrelease> {
+%<latexrelease> \prop_map_inline:Nn \l_@@_work_prop
+%<latexrelease> {
+%<latexrelease> \@@_if_label_case:nnnnn {##1} {####1}
+%<latexrelease> { \prop_map_break: }
+%<latexrelease> { \@@_apply_label_pair:nnn {##1} {####1} }
+%<latexrelease> { \@@_apply_label_pair:nnn {####1} {##1} }
+%<latexrelease> {#3}
+%<latexrelease> }
+%<latexrelease> }
+%<latexrelease> \@@_debug:n { \@@_debug_label_data:N \l_@@_work_prop }
+%<latexrelease> \tl_set:Nn \l_@@_rear_tl { 0 }
+%<latexrelease> \tl_set:cn { \@@_tl_csname:n { 0 } } { 0 }
+%<latexrelease> \seq_map_inline:Nn \l_@@_labels_seq
+%<latexrelease> {
+%<latexrelease> \int_compare:nNnT { \cs:w \@@_tl_csname:n {##1} \cs_end: } = 0
+%<latexrelease> {
+%<latexrelease> \tl_set:cn { \@@_tl_csname:n { \l_@@_rear_tl } }{##1}
+%<latexrelease> \tl_set:Nn \l_@@_rear_tl {##1}
+%<latexrelease> }
+%<latexrelease> }
+%<latexrelease> \tl_set_eq:Nc \l_@@_front_tl { \@@_tl_csname:n { 0 } }
+%<latexrelease> \@@_tl_gclear:N #1
+%<latexrelease> \clist_gclear:N #2
+%<latexrelease> \bool_while_do:nn { ! \str_if_eq_p:Vn \l_@@_front_tl { 0 } }
+%<latexrelease> {
+%<latexrelease> \int_decr:N \l_@@_labels_int
+%<latexrelease> \prop_get:NVN \l_@@_work_prop \l_@@_front_tl \l_@@_return_tl
+%<latexrelease> \exp_args:NNV \@@_tl_gput:Nn #1 \l_@@_return_tl
+%<latexrelease> \@@_clist_gput:NV #2 \l_@@_front_tl
+%<latexrelease> \@@_debug:n{ \iow_term:x{Handled~ code~ for~ \l_@@_front_tl} }
+%<latexrelease> \seq_map_inline:cn { \@@_seq_csname:n { \l_@@_front_tl } }
+%<latexrelease> {
+%<latexrelease> \tl_set:cx { \@@_tl_csname:n {##1} }
+%<latexrelease> { \int_eval:n
+%<latexrelease> { \cs:w \@@_tl_csname:n {##1} \cs_end: - 1 }
+%<latexrelease> }
+%<latexrelease> \int_compare:nNnT
+%<latexrelease> { \cs:w \@@_tl_csname:n {##1} \cs_end: } = 0
+%<latexrelease> {
+%<latexrelease> \tl_set:cn { \@@_tl_csname:n { \l_@@_rear_tl } } {##1}
+%<latexrelease> \tl_set:Nn \l_@@_rear_tl {##1}
+%<latexrelease> }
+%<latexrelease> }
+%<latexrelease> \tl_set_eq:Nc \l_@@_front_tl
+%<latexrelease> { \@@_tl_csname:n { \l_@@_front_tl } }
+%<latexrelease> }
+%<latexrelease> \int_compare:nNnF \l_@@_labels_int = 0
+%<latexrelease> {
+%<latexrelease> \iow_term:x{====================}
+%<latexrelease> \iow_term:x{Error:~ label~ rules~ are~ incompatible:}
+%<latexrelease> \@@_debug_label_data:N \l_@@_work_prop
+%<latexrelease> \iow_term:x{====================}
+%<latexrelease> }
+%<latexrelease> \exp_args:NNo \@@_tl_gput:Nn #1 { \cs:w @@_toplevel~#3 \cs_end: }
+%<latexrelease> \@@_tl_gput_right:No #1 { \cs:w @@_next~#3 \cs_end: }
+%<latexrelease> }
+%<latexrelease>\cs_generate_variant:Nn \@@_tl_gput_right:Nn { No }
+%<latexrelease>\EndIncludeInRelease
% \end{macrocode}
% \end{macro}
%
@@ -4444,7 +5966,11 @@
{ \@@_log_cmd:x { >~\@spaces #1 } }
% \end{macrocode}
%
+% \changes{v1.1a}{2023/04/06}
+% {Changes to add hook arguments (hook-args).}
% \begin{macrocode}
+%<latexrelease>\IncludeInRelease{2023/06/01}{\@@_log:nN}
+%<latexrelease> {Hooks~with~args}
\cs_new_protected:Npn \@@_log:nN #1 #2
{
\@@_if_deprecated_generic:nT {#1}
@@ -4455,7 +5981,20 @@
}
\@@_preamble_hook:n {#1}
\@@_log_cmd:x
- { ^^J ->~The~ \@@_if_generic:nT {#1} { generic~ } hook~'#1': }
+ {
+ ^^J ->~The~
+ \@@_if_generic:nT {#1} { generic~ }
+ hook~'#1'
+ \@@_if_disabled:nF {#1}
+ {
+ \exp_args:Nf \@@_print_args:nn {#1}
+ {
+ \int_eval:n
+ { \str_count:e { \@@_parameter:n {#1} } / 3 }
+ }
+ }
+ :
+ }
% \end{macrocode}
%
% \begin{macrocode}
@@ -4471,7 +6010,12 @@
{ \@@_log_line_indent:x { --- } }
{
\prop_map_inline:cn { g_@@_#1_code_prop }
- { \@@_log_line_indent:x { ##1~->~\tl_to_str:n {##2} } }
+ {
+ \exp_after:wN \cs_set:Npn \exp_after:wN \@@_tmp:w
+ \c_@@_nine_parameters_tl {##2}
+ \@@_log_line_indent:x
+ { ##1~->~\cs_replacement_spec:N \@@_tmp:w }
+ }
}
% \end{macrocode}
%
@@ -4485,9 +6029,9 @@
}
\@@_log_line_indent:x
{
- \tl_if_empty:cTF { @@_toplevel~#1 }
+ \@@_cs_if_empty:cTF { @@_toplevel~#1 }
{ --- }
- { -> ~ \exp_args:Nv \tl_to_str:n { @@_toplevel~#1 } }
+ { -> ~ \cs_replacement_spec:c { @@_toplevel~#1 } }
}
% \end{macrocode}
%
@@ -4495,7 +6039,7 @@
\@@_log_line:x { Extra~code~for~next~invocation: }
\@@_log_line_indent:x
{
- \tl_if_empty:cTF { @@_next~#1 }
+ \@@_cs_if_empty:cTF { @@_next~#1 }
{ --- }
% \end{macrocode}
%
@@ -4503,7 +6047,10 @@
% the first tokens (the code to clear itself) so we call a helper
% command to get rid of them.
% \begin{macrocode}
- { ->~ \exp_args:Nv \@@_log_next_code:n { @@_next~#1 } }
+ {
+ -> ~ \exp_last_unbraced:Nf \@@_log_next_code:w
+ { \cs_replacement_spec:c { @@_next~#1 } }
+ }
}
% \end{macrocode}
%
@@ -4549,7 +6096,7 @@
\@spaces
\clist_if_empty:cTF { g_@@_#1_labels_clist }
{ --- }
- { \clist_use:cn {g_@@_#1_labels_clist} { ,~ } }
+ { \clist_use:cn { g_@@_#1_labels_clist } { ,~ } }
}
}
{
@@ -4563,15 +6110,139 @@
}
}
}
+%<latexrelease>\EndIncludeInRelease
+%
+%<latexrelease>\IncludeInRelease{2020/10/01}{\@@_log:nN}
+%<latexrelease> {Hooks~with~args}
+%<latexrelease>\cs_new_protected:Npn \@@_log:nN #1 #2
+%<latexrelease> {
+%<latexrelease> \@@_if_deprecated_generic:nT {#1}
+%<latexrelease> {
+%<latexrelease> \@@_deprecated_generic_warn:n {#1}
+%<latexrelease> \@@_do_deprecated_generic:Nn \@@_log:nN {#1} #2
+%<latexrelease> \exp_after:wN \use_none:nnnnnnnnn \use_none:nnnnn
+%<latexrelease> }
+%<latexrelease> \@@_preamble_hook:n {#1}
+%<latexrelease> \@@_log_cmd:x
+%<latexrelease> { ^^J ->~The~ \@@_if_generic:nT {#1} { generic~ } hook~'#1': }
+%<latexrelease> \@@_if_usable:nF {#1}
+%<latexrelease> { \@@_log_line:x { The~hook~is~not~declared. } }
+%<latexrelease> \@@_if_disabled:nT {#1}
+%<latexrelease> { \@@_log_line:x { The~hook~is~disabled. } }
+%<latexrelease> \hook_if_empty:nTF {#1}
+%<latexrelease> { #2 { The~hook~is~empty } }
+%<latexrelease> {
+%<latexrelease> \@@_log_line:x { Code~chunks: }
+%<latexrelease> \prop_if_empty:cTF { g_@@_#1_code_prop }
+%<latexrelease> { \@@_log_line_indent:x { --- } }
+%<latexrelease> {
+%<latexrelease> \prop_map_inline:cn { g_@@_#1_code_prop }
+%<latexrelease> { \@@_log_line_indent:x { ##1~->~\tl_to_str:n {##2} } }
+%<latexrelease> }
+%<latexrelease> \@@_log_line:x
+%<latexrelease> {
+%<latexrelease> Document-level~(top-level)~code
+%<latexrelease> \@@_if_usable:nT {#1}
+%<latexrelease> { ~(executed~\@@_if_reversed:nTF {#1} {first} {last} ) } :
+%<latexrelease> }
+%<latexrelease> \@@_log_line_indent:x
+%<latexrelease> {
+%<latexrelease> \tl_if_empty:cTF { @@_toplevel~#1 }
+%<latexrelease> { --- }
+%<latexrelease> { -> ~ \exp_args:Nv \tl_to_str:n { @@_toplevel~#1 } }
+%<latexrelease> }
+%<latexrelease> \@@_log_line:x { Extra~code~for~next~invocation: }
+%<latexrelease> \@@_log_line_indent:x
+%<latexrelease> {
+%<latexrelease> \tl_if_empty:cTF { @@_next~#1 }
+%<latexrelease> { --- }
+%<latexrelease> { ->~ \exp_args:Nv \@@_log_next_code:n { @@_next~#1 } }
+%<latexrelease> }
+%<latexrelease> \@@_log_line:x { Rules: }
+%<latexrelease> \bool_set_true:N \l_@@_tmpa_bool
+%<latexrelease> \@@_list_rules:nn {#1}
+%<latexrelease> {
+%<latexrelease> \bool_set_false:N \l_@@_tmpa_bool
+%<latexrelease> \@@_log_line_indent:x
+%<latexrelease> {
+%<latexrelease> ##2~ with~
+%<latexrelease> \str_if_eq:nnT {##3} {??} { default~ }
+%<latexrelease> relation~ ##1
+%<latexrelease> }
+%<latexrelease> }
+%<latexrelease> \bool_if:NT \l_@@_tmpa_bool
+%<latexrelease> { \@@_log_line_indent:x { --- } }
+%<latexrelease> \bool_lazy_and:nnTF
+%<latexrelease> { \@@_if_usable_p:n {#1} }
+%<latexrelease> { ! \hook_if_empty_p:n {#1} }
+%<latexrelease> {
+%<latexrelease> \@@_log_line:x
+%<latexrelease> {
+%<latexrelease> Execution~order
+%<latexrelease> \bool_if:NTF \l_@@_tmpa_bool
+%<latexrelease> { \@@_if_reversed:nT {#1} { ~(after~reversal) } }
+%<latexrelease> { ~(after~
+%<latexrelease> \@@_if_reversed:nT {#1} { reversal~and~ }
+%<latexrelease> applying~rules)
+%<latexrelease> } :
+%<latexrelease> }
+%<latexrelease> #2 % \tl_show:n
+%<latexrelease> {
+%<latexrelease> \@spaces
+%<latexrelease> \clist_if_empty:cTF { g_@@_#1_labels_clist }
+%<latexrelease> { --- }
+%<latexrelease> { \clist_use:cn { g_@@_#1_labels_clist } { ,~ } }
+%<latexrelease> }
+%<latexrelease> }
+%<latexrelease> {
+%<latexrelease> \@@_log_line:x { Execution~order: }
+%<latexrelease> #2
+%<latexrelease> {
+%<latexrelease> \@spaces Not~set~because~the~hook~ \@@_if_usable:nTF {#1}
+%<latexrelease> { code~pool~is~empty }
+%<latexrelease> { is~\@@_if_disabled:nTF {#1} {disabled} {undeclared} }
+%<latexrelease> }
+%<latexrelease> }
+%<latexrelease> }
+%<latexrelease> }
+%<latexrelease>\EndIncludeInRelease
% \end{macrocode}
%
% \begin{macro}{\@@_log_next_code:n}
% To display the code for next invocation only (i.e., from
-% \cs{AddToHookNext} we have to remove the first two tokens at the
-% front which are \cs{tl_gclear:N} and the token list to clear.
+% \cs{AddToHookNext} we have to remove the string
+% \cs{@@_clear_next:n}\Arg{hook}, so the simplest is to use a macro
+% delimited by a \verb|}|$_12$.
+% \changes{v1.1a}{2023/04/06}
+% {Changes to add hook arguments (hook-args).}
+% \begin{macrocode}
+%<latexrelease>\IncludeInRelease{2023/06/01}{\@@_log_next_code:n}
+%<latexrelease> {Hooks~with~args}
+\exp_last_unbraced:NNNNo
+\cs_new:Npn \@@_log_next_code:w #1 \c_right_brace_str { }
+%<latexrelease>\EndIncludeInRelease
+%<latexrelease>\IncludeInRelease{2020/10/01}{\@@_log_next_code:n}
+%<latexrelease> {Hooks~with~args}
+%<latexrelease>\cs_gset:Npn \@@_log_next_code:n #1
+%<latexrelease> { \exp_args:No \tl_to_str:n { \use_none:nn #1 } }
+%<latexrelease>\EndIncludeInRelease
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_print_args:n}
+% Pretty-prints the number of arguments of a hook.
% \begin{macrocode}
-\cs_new:Npn \@@_log_next_code:n #1
- { \exp_args:No \tl_to_str:n { \use_none:nn #1 } }
+\cs_new:Npn \@@_print_args:nn #1 #2
+ {
+ \int_compare:nNnT {#2} > { 0 }
+ {
+ \@@_if_declared:nT {#1} { \use_none:nnn }
+ \@@_if_cmd_hook:nT {#1}
+ { \use_i:nnn { ~ (unknown ~ } }
+ \use:n { ~ (#2 ~ }
+ argument \int_compare:nNnT {#2} > { 1 } { s } )
+ }
+ }
% \end{macrocode}
% \end{macro}
%
@@ -4656,15 +6327,34 @@
% \subsection{Specifying code for next invocation}
%
% \begin{macro}{\hook_gput_next_code:nn}
+% \changes{v1.1a}{2023/04/06}
+% {Add \cs{hook_gput_next_code_with_args:nn} (hook-args).}
% \begin{macrocode}
-\cs_new_protected:Npn \hook_gput_next_code:nn #1
- { \@@_normalize_hook_args:Nn \@@_gput_next_code:nn {#1} }
+%<latexrelease>\IncludeInRelease{2023/06/01}{\hook_gput_next_code:nn}
+%<latexrelease> {Hooks~with~args}
+\cs_new_protected:Npn \hook_gput_next_code:nn #1 #2
+ {
+ \@@_replacing_args_false:
+ \@@_normalize_hook_args:Nn \@@_gput_next_code:nn {#1} {#2}
+ \@@_replacing_args_reset:
+ }
+\cs_new_protected:Npn \hook_gput_next_code_with_args:nn #1 #2
+ {
+ \@@_replacing_args_true:
+ \@@_normalize_hook_args:Nn \@@_gput_next_code:nn {#1} {#2}
+ \@@_replacing_args_reset:
+ }
+%<latexrelease>\EndIncludeInRelease
+%<latexrelease>\IncludeInRelease{2020/10/01}{\hook_gput_next_code:nn}
+%<latexrelease> {Hooks~with~args}
+%<latexrelease>\cs_gset_protected:Npn \hook_gput_next_code:nn #1
+%<latexrelease> { \@@_normalize_hook_args:Nn \@@_gput_next_code:nn {#1} }
+%<latexrelease>\cs_gset_protected:Npn \hook_gput_next_code_with_args:nn #1 #2 { }
+%<latexrelease>\EndIncludeInRelease
% \end{macrocode}
% \end{macro}
%
-% \begin{macro}{\@@_gput_next_code:nn,
-% \@@_gput_next_do:nn,
-% \@@_gput_next_do:Nnn}
+% \begin{macro}{\@@_gput_next_code:nn}
% \begin{macrocode}
\cs_new_protected:Npn \@@_gput_next_code:nn #1 #2
{
@@ -4672,20 +6362,17 @@
{ \msg_error:nnn { hooks } { hook-disabled } {#1} }
{
\@@_if_structure_exist:nTF {#1}
- { \@@_gput_next_do:nn {#1} {#2} }
- { \@@_try_declaring_generic_next_hook:nn {#1} {#2} }
+ { \@@_gput_next_do:nn }
+ { \@@_try_declaring_generic_next_hook:nn }
+ {#1} {#2}
}
}
% \end{macrocode}
+% \end{macro}
%
-% \begin{macrocode}
-\cs_new_protected:Npn \@@_gput_next_do:nn #1
- {
- \exp_args:Nc \@@_gput_next_do:Nnn
- { @@_next~#1 } {#1}
- }
-% \end{macrocode}
-% First check if the ``next code'' token list is empty: if so we need
+% \begin{macro}{\@@_gput_next_do:nn}
+% Start by sanity-checking with \cs{@@_chk_args_allowed:nn}.
+% Then check if the ``next code'' token list is empty: if so we need
% to add a \cs{tl_gclear:c} to clear it, so the code lasts for one
% usage only. The token list is cleared early so that nested usages
% don't get lost. \cs{tl_gclear:c} is used instead of
@@ -4694,38 +6381,74 @@
% that would make an infinite loop. Also in case the main code token
% list is empty, the hook code has to be updated to add the next
% execution token list.
+% \changes{v1.1a}{2023/04/06}
+% {Changes to add hook arguments (hook-args).}
+% \changes{v1.1c}{2023/04/19}
+% {Initialise hook structure when adding 'next' code (gh/1052).}
% \begin{macrocode}
-\cs_new_protected:Npn \@@_gput_next_do:Nnn #1 #2
+%<latexrelease>\IncludeInRelease{2023/06/01}{\@@_gput_next_do:nn}
+%<latexrelease> {Hooks~with~args}
+\cs_new_protected:Npn \@@_gput_next_do:nn #1
{
- \tl_if_empty:cT { @@~#2 }
- { \@@_update_hook_code:n {#2} }
- \tl_if_empty:NT #1
- { \@@_tl_gset:Nn #1 { \@@_clear_next:n {#2} } }
- \@@_tl_gput_right:Nn #1
+ \@@_init_structure:n {#1}
+ \@@_chk_args_allowed:nn {#1} { AddToHookNext }
+ \@@_cs_if_empty:cT { @@~#1 }
+ { \@@_update_hook_code:n {#1} }
+ \@@_cs_if_empty:cT { @@_next~#1 }
+ { \@@_next_gset:nn {#1} { \@@_clear_next:n {#1} } }
+ \@@_cs_gput_right:nnn { _next } {#1}
}
+%<latexrelease>\EndIncludeInRelease
+%<latexrelease>\IncludeInRelease{2020/10/01}{\@@_gput_next_do:nn}
+%<latexrelease> {Hooks~with~args}
+%<latexrelease>\cs_gset_protected:Npn \@@_gput_next_do:nn #1
+%<latexrelease> {
+%<latexrelease> \exp_args:Nc \@@_gput_next_do:Nnn
+%<latexrelease> { @@_next~#1 } {#1}
+%<latexrelease> }
+%<latexrelease>\cs_gset_protected:Npn \@@_gput_next_do:Nnn #1 #2
+%<latexrelease> {
+%<latexrelease> \tl_if_empty:cT { @@~#2 }
+%<latexrelease> { \@@_update_hook_code:n {#2} }
+%<latexrelease> \tl_if_empty:NT #1
+%<latexrelease> { \@@_tl_gset:Nn #1 { \@@_clear_next:n {#2} } }
+%<latexrelease> \@@_tl_gput_right:Nn #1
+%<latexrelease> }
+%<latexrelease>\EndIncludeInRelease
% \end{macrocode}
% \end{macro}
%
-%
-%
-% \begin{macro}{\hook_gclear_next_code:n,\@@_clear_next:n}
+% \begin{macro}{\hook_gclear_next_code:n}
% Discard anything set up for next invocation of the hook.
% \changes{v1.0o}{2021/07/27}{Macro made public}
% \begin{macrocode}
\cs_new_protected:Npn \hook_gclear_next_code:n #1
{ \@@_normalize_hook_args:Nn \@@_clear_next:n {#1} }
-\cs_new_protected:Npn \@@_clear_next:n #1
- { \cs_gset_eq:cN { @@_next~#1 } \c_empty_tl }
% \end{macrocode}
% \end{macro}
%
+% \begin{macro}{\@@_clear_next:n}
+% \changes{v1.1a}{2023/04/06}
+% {Changes to add hook arguments (hook-args).}
+% \begin{macrocode}
+%<latexrelease>\IncludeInRelease{2023/06/01}{\@@_clear_next:n}
+%<latexrelease> {Hooks~with~args}
+\cs_new_protected:Npn \@@_clear_next:n #1
+ { \@@_next_gset:nn {#1} { } }
+%<latexrelease>\EndIncludeInRelease
+%<latexrelease>\IncludeInRelease{2020/10/01}{\@@_clear_next:n}
+%<latexrelease> {Hooks~with~args}
+%<latexrelease>\cs_gset_protected:Npn \@@_clear_next:n #1
+%<latexrelease> { \cs_gset_eq:cN { @@_next~#1 } \c_empty_tl }
+%<latexrelease>\EndIncludeInRelease
+% \end{macrocode}
+% \end{macro}
%
%
% \subsection{Using the hook}
%
% \begin{macro}{\hook_use:n}
% \begin{macro}[EXP]{\@@_use_initialized:n}
-% \begin{macro}{\@@_use_undefined:w,\@@_use_end:}
% \begin{macro}{\@@_preamble_hook:n}
% \cs{hook_use:n} as defined here is used in the preamble, where
% hooks aren't initialized by default. \cs{@@_use_initialized:n} is
@@ -4750,24 +6473,50 @@
% \verb=\csname ...\endcsname= construct \cs{tl_if_exist:c} is
% careful to avoid this.
% \begin{macrocode}
-%<latexrelease>\IncludeInRelease{2021/11/15}{\hook_use:n}
-%<latexrelease> {Standardise~generic~hook~names}
+%<latexrelease>\IncludeInRelease{2023/06/01}{\hook_use:n}
+%<latexrelease> {Hooks~with~args}
\cs_new_protected:Npn \hook_use:n #1
{
- \tl_if_exist:cT { @@~#1 }
- {
- \@@_preamble_hook:n {#1}
- \cs:w @@~#1 \cs_end:
- }
+ \@@_preamble_hook:n {#1}
+ \@@_use_initialized:n {#1}
}
\cs_new:Npn \@@_use_initialized:n #1
{
\if_cs_exist:w @@~#1 \cs_end:
- \cs:w @@~#1 \exp_after:wN \cs_end:
+ \cs:w @@~#1 \use_i:nn
\fi:
+ \use_none:n
+ \cs_end:
}
\cs_new_protected:Npn \@@_preamble_hook:n #1
- { \@@_initialize_hook_code:n {#1} }
+ {
+ \if_cs_exist:w @@~#1 \cs_end:
+ \@@_initialize_hook_code:n {#1}
+ \fi:
+ }
+%<latexrelease>\EndIncludeInRelease
+% \end{macrocode}
+%
+% \begin{macrocode}
+%<latexrelease>\IncludeInRelease{2021/11/15}{\hook_use:n}
+%<latexrelease> {Standardise~generic~hook~names}
+%<latexrelease>\cs_new_protected:Npn \hook_use:n #1
+%<latexrelease> {
+%<latexrelease> \tl_if_exist:cT { @@~#1 }
+%<latexrelease> {
+%<latexrelease> \@@_preamble_hook:n {#1}
+%<latexrelease> \cs:w @@~#1 \cs_end:
+%<latexrelease> }
+%<latexrelease> }
+%<latexrelease>\cs_new:Npn \@@_use_initialized:n #1
+%<latexrelease> {
+%<latexrelease> \if_cs_exist:w @@~#1 \cs_end:
+%<latexrelease> \cs:w @@~#1 \exp_after:wN \cs_end:
+%<latexrelease> \fi:
+%<latexrelease> }
+%<latexrelease>\cs_new_protected:Npn \@@_preamble_hook:n #1
+%<latexrelease> { \@@_initialize_hook_code:n {#1} }
+%<latexrelease>\cs_new:Npn \hook_use:nnw #1 { }
%<latexrelease>\EndIncludeInRelease
% \end{macrocode}
%
@@ -4799,13 +6548,69 @@
%<latexrelease>\cs_new_protected:Npn \@@_preamble_hook:n #1
%<latexrelease> { \@@_initialize_hook_code:n {#1} }
%<latexrelease>\cs_new_eq:NN \@@_use_end: \cs_end:
+%<latexrelease>\cs_new:Npn \hook_use:nnw #1 { }
%<latexrelease>\EndIncludeInRelease
% \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
+%
+%
+% \begin{macro}{\hook_use:nnw}
+% \begin{macro}[EXP]{\@@_use_initialized:nnw}
+% \changes{v1.1a}{2023/04/06}
+% {Add \cs{hook_use:nnw} (hook-args).}
+% \begin{macrocode}
+%<latexrelease>\IncludeInRelease{2023/06/01}{\hook_use:nnw}
+%<latexrelease> {Hooks~with~args}
+\cs_new_protected:Npn \hook_use:nnw #1
+ {
+ \@@_preamble_hook:n {#1}
+ \@@_use_initialized:nnw {#1}
+ }
+\cs_new:Npn \@@_use_initialized:nnw #1 #2
+ {
+ \cs:w
+ \if_cs_exist:w @@~#1 \cs_end:
+ @@~#1
+ \else:
+ use_none: \prg_replicate:nn {#2} { n }
+ \fi:
+ \cs_end:
+ }
+%<latexrelease>\EndIncludeInRelease
+%<latexrelease>\IncludeInRelease{2020/10/01}{\hook_use:nnw}
+%<latexrelease> {Hooks~with~args}
+%<latexrelease>\cs_gset:Npn \hook_use:nnw #1 #2
+%<latexrelease> { \use:c { use_none: \prg_replicate:nn {#2} { n } } }
+%<latexrelease>\EndIncludeInRelease
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+%
+% \begin{macro}{\@@_post_initialization_defs:}
+% \changes{v1.1a}{2023/04/06}
+% {Macro added (hook-args).}
+% \begin{macrocode}
+%<latexrelease>\IncludeInRelease{2023/06/01}{\@@_post_initialization_defs:}
+%<latexrelease> {Hooks~with~args}
+\cs_new_protected:Npn \@@_post_initialization_defs:
+ {
+ \cs_gset_eq:NN \hook_use:n \@@_use_initialized:n
+ \cs_gset_eq:NN \hook_use:nnw \@@_use_initialized:nnw
+ \cs_gset_eq:NN \@@_preamble_hook:n \use_none:n
+ \cs_gset_eq:NN \@@_post_initialization_defs: \prg_do_nothing:
+ }
+%<latexrelease>\EndIncludeInRelease
+%<latexrelease>\IncludeInRelease{2020/10/01}{\@@_post_initialization_defs:}
+%<latexrelease> {Hooks~with~args}
+%<latexrelease>\cs_undefine:N \@@_post_initialization_defs:
+%<latexrelease>\EndIncludeInRelease
+% \end{macrocode}
% \end{macro}
%
+%
% \begin{macro}[EXP]{\@@_use:wn}
% \begin{macro}{\@@_try_file_hook:n,\@@_if_usable_use:n}
% \cs{@@_use:wn} does a quick check to test if the current hook is a
@@ -4861,8 +6666,7 @@
% \end{macro}
% \end{macro}
%
-% \begin{macro}{\hook_use_once:n}
-% \begin{macro}{\@@_use_once:n}
+% \begin{macro}{\hook_use_once:n,\hook_use_once:nnw}
% For hooks that can and should be used only once we have a special
% use command that further inhibits the hook from getting more code
% added to it. This has the effect that any
@@ -4874,20 +6678,80 @@
% documented to not trim spaces.
%
% \changes{v1.0r}{2021/09/06}{Clean up after \cs{UseOneTimeHook} (gh/606)}
+% \changes{v1.1a}{2023/04/06}
+% {Add \cs{hook_use_once:nnw} (hook-args).}
% \begin{macrocode}
+%<latexrelease>\IncludeInRelease{2023/06/01}{\hook_use_once:nnw}
+%<latexrelease> {Hooks~with~args}
\cs_new_protected:Npn \hook_use_once:n #1
{
\@@_if_execute_immediately:nF {#1}
- { \@@_normalize_hook_args:Nn \@@_use_once:n { \use:n {#1} } }
+ { \@@_normalize_hook_args:Nn \@@_use_once:nn { \use:n {#1} } { 0 } }
}
-\cs_new_protected:Npn \@@_use_once:n #1
+\cs_new_protected:Npn \hook_use_once:nnw #1 #2
+ {
+ \@@_if_execute_immediately:nF {#1}
+ { \@@_normalize_hook_args:Nn \@@_use_once:nn { \use:n {#1} } {#2} }
+ }
+%<latexrelease>\EndIncludeInRelease
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macrocode}
+%<latexrelease>\IncludeInRelease{2020/10/01}{\hook_use_once:nnw}
+%<latexrelease> {Hooks~with~args}
+%<latexrelease>\cs_gset_protected:Npn \hook_use_once:n #1
+%<latexrelease> {
+%<latexrelease> \@@_if_execute_immediately:nF {#1}
+%<latexrelease> { \@@_normalize_hook_args:Nn \@@_use_once:n { \use:n {#1} } }
+%<latexrelease> }
+%<latexrelease>\cs_gset:Npn \hook_use_once:nnw #1 #2
+%<latexrelease> { \use:c { use_none: \prg_replicate:nn {#2} { n } } }
+%<latexrelease>\EndIncludeInRelease
+% \end{macrocode}
+%
+% \begin{macro}{\@@_use_once:nn}
+% \changes{v1.1a}{2023/04/06}
+% {Changes to add hook arguments (hook-args).}
+% \begin{macrocode}
+%<latexrelease>\IncludeInRelease{2023/06/01}{\@@_use_once:nn}
+%<latexrelease> {Hooks~with~args}
+\cs_new_protected:Npn \@@_use_once:nn #1 #2
{
\@@_preamble_hook:n {#1}
\@@_use_once_set:n {#1}
- \@@_use_initialized:n {#1}
- \@@_use_once_clear:n {#1}
+% \end{macrocode}
+% When a hook has arguments, the call to \cs{@@_use_initialized:n},
+% should be the very last thing to happen, otherwise the arguments
+% grabbed will be wrong. So, to clean up after the hook we need to
+% cheat a bit and sneak the cleanup code at the end of the hook,
+% along with the next execution code.
+% \begin{macrocode}
+ \@@_replacing_args_false:
+ \@@_cs_gput_right:nnn { _next } {#1} { \@@_use_once_clear:n {#1} }
+ \@@_replacing_args_reset:
+ \@@_if_usable:nTF {#1}
+ { \@@_use_initialized:n {#1} }
+ {
+ \int_compare:nNnT {#2} > { 0 }
+ { \use:c { use_none: \prg_replicate:nn {#2} { n } } }
+ }
}
+%<latexrelease>\EndIncludeInRelease
+%
+%<latexrelease>\IncludeInRelease{2020/10/01}{\@@_use_once:nn}
+%<latexrelease> {Hooks~with~args}
+%<latexrelease>\cs_gset_protected:Npn \@@_use_once:n #1
+%<latexrelease> {
+%<latexrelease> \@@_preamble_hook:n {#1}
+%<latexrelease> \@@_use_once_set:n {#1}
+%<latexrelease> \@@_use_initialized:n {#1}
+%<latexrelease> \@@_use_once_clear:n {#1}
+%<latexrelease> }
+%<latexrelease>\cs_undefine:N \@@_use_once:nn
+%<latexrelease>\EndIncludeInRelease
% \end{macrocode}
+% \end{macro}
%
% \begin{macro}{\@@_use_once_set:n}
% \begin{macro}{\@@_use_once_clear:n}
@@ -4900,43 +6764,60 @@
% \cs{hook_use_once:n} will expand to nothing.
% \changes{v1.0r}{2021/09/06}{Clean up after \cs{UseOneTimeHook} (gh/606)}
% \changes{v1.0u}{2022/05/13}{Check if prop exists to avoid l3debug error}
+% \changes{v1.1a}{2023/04/06}
+% {Changes to add hook arguments (hook-args).}
% \begin{macrocode}
+%<latexrelease>\IncludeInRelease{2023/06/01}{\@@_use_once_clear:n}
+%<latexrelease> {Hooks~with~args}
\cs_new_protected:Npn \@@_use_once_set:n #1
{ \@@_tl_gset:cn { g_@@_#1_reversed_tl } { I } }
\cs_new_protected:Npn \@@_use_once_clear:n #1
{
- \@@_tl_gclear:c { @@~#1 }
- \@@_tl_gclear:c { @@_next~#1 }
- \@@_tl_gclear:c { @@_toplevel~#1 }
+ \@@_code_gset:nn {#1} { }
+ \@@_next_gset:nn {#1} { }
+ \@@_toplevel_gset:nn {#1} { }
\prop_gclear_new:c { g_@@_#1_code_prop }
}
+%<latexrelease>\EndIncludeInRelease
+% \end{macrocode}
+%
+% \begin{macrocode}
+%<latexrelease>\IncludeInRelease{2020/10/01}{\@@_use_once_clear:n}
+%<latexrelease> {Hooks~with~args}
+%<latexrelease>\cs_new_protected:Npn \@@_use_once_clear:n #1
+%<latexrelease> {
+%<latexrelease> \@@_tl_gclear:c { @@~#1 }
+%<latexrelease> \@@_tl_gclear:c { @@_next~#1 }
+%<latexrelease> \@@_tl_gclear:c { @@_toplevel~#1 }
+%<latexrelease> \prop_gclear_new:c { g_@@_#1_code_prop }
+%<latexrelease> }
+%<latexrelease>\EndIncludeInRelease
% \end{macrocode}
-% \end{macro}
-% \end{macro}
% \end{macro}
% \end{macro}
%
% \begin{macro}[pTF]{\@@_if_execute_immediately:n}
-% To check whether the code being added should be executed immediately (that
-% is, if the hook is a one-time hook), we check if it's usable (it
-% can't be one-time if it was not already usable), then we check that
+% To check whether the code being added should be executed immediately
+% (that is, if the hook is a one-time hook), we check if
% \cs[no-index]{g_@@_\meta{hook}_reversed_tl} is |I|. The gymnastics
% around \cs{if:w} is there to allow the |reversed| token list to be
% empty.
% \changes{v1.0r}{2021/09/06}{Macro added (gh/606)}
+% \changes{v1.1a}{2023/04/06}
+% {Changes to add hook arguments (hook-args).}
% \begin{macrocode}
\prg_new_conditional:Npnn \@@_if_execute_immediately:n #1 { T, F, TF }
{
- \@@_if_usable:nTF {#1}
- {
- \exp_after:wN \@@_clean_to_scan:w
- \if:w I \cs:w g_@@_#1_reversed_tl \cs_end:
- \s_@@_mark \prg_return_true:
- \else:
- \s_@@_mark \prg_return_false:
+ \exp_after:wN \@@_use_none_delimit_by_s_mark:w
+ \if:w I
+ \if_cs_exist:w g_@@_#1_reversed_tl \cs_end:
+ \cs:w g_@@_#1_reversed_tl \exp_after:wN \cs_end:
\fi:
- }
- { \prg_return_false: }
+ X
+ \s_@@_mark \prg_return_true:
+ \else:
+ \s_@@_mark \prg_return_false:
+ \fi:
}
% \end{macrocode}
% \end{macro}
@@ -4963,30 +6844,57 @@
%
% All other states can only be queried with internal tests as the
% different states are irrelevant for package code.
-
+%
% \begin{macro}[pTF]{\hook_if_empty:n}
% Test if a hook is empty (that is, no code was added to that hook).
% A \meta{hook} being empty means that all three of its
% \cs{g_@@_\meta{hook}_code_prop}, its
% \cs{@@_toplevel\textvisiblespace\meta{hook}} and its
% \cs{@@_next\textvisiblespace\meta{hook}} are empty.
+% \changes{v1.1a}{2023/04/06}
+% {Changes to add hook arguments (hook-args).}
+% \changes{v1.1c}{2023/04/19}
+% {Simpler and faster version (gh/1052).}
% \begin{macrocode}
+%<latexrelease>\IncludeInRelease{2023/06/01}{\hook_if_empty:n}
+%<latexrelease> {Hooks~with~args}
\prg_new_conditional:Npnn \hook_if_empty:n #1 { p , T , F , TF }
{
- \@@_if_structure_exist:nTF {#1}
- {
- \bool_lazy_and:nnTF
- { \prop_if_empty_p:c { g_@@_#1_code_prop } }
- {
- \bool_lazy_and_p:nn
- { \tl_if_empty_p:c { @@_toplevel~#1 } }
- { \tl_if_empty_p:c { @@_next~#1 } }
- }
- { \prg_return_true: }
- { \prg_return_false: }
- }
- { \prg_return_true: }
+ \if:w
+ T
+ \prop_if_exist:cT { g_@@_#1_code_prop }
+ { \prop_if_empty:cF { g_@@_#1_code_prop } { F } }
+ \@@_cs_if_empty:cF { @@_toplevel~#1 } { F }
+ \@@_cs_if_empty:cF { @@_next~#1 } { F }
+ T
+ \prg_return_true:
+ \else:
+ \prg_return_false:
+ \fi:
}
+%<latexrelease>\EndIncludeInRelease
+% \end{macrocode}
+%
+% \begin{macrocode}
+%<latexrelease>\IncludeInRelease{2020/10/01}{\hook_if_empty:n}
+%<latexrelease> {Hooks~with~args}
+%<latexrelease>\prg_new_conditional:Npnn \hook_if_empty:n #1 { p , T , F , TF }
+%<latexrelease> {
+%<latexrelease> \@@_if_structure_exist:nTF {#1}
+%<latexrelease> {
+%<latexrelease> \bool_lazy_and:nnTF
+%<latexrelease> { \prop_if_empty_p:c { g_@@_#1_code_prop } }
+%<latexrelease> {
+%<latexrelease> \bool_lazy_and_p:nn
+%<latexrelease> { \tl_if_empty_p:c { @@_toplevel~#1 } }
+%<latexrelease> { \tl_if_empty_p:c { @@_next~#1 } }
+%<latexrelease> }
+%<latexrelease> { \prg_return_true: }
+%<latexrelease> { \prg_return_false: }
+%<latexrelease> }
+%<latexrelease> { \prg_return_true: }
+%<latexrelease> }
+%<latexrelease>\EndIncludeInRelease
% \end{macrocode}
% \end{macro}
%
@@ -4994,15 +6902,15 @@
% \begin{macro}[pTF]{\@@_if_usable:n}
% A hook is usable if the
% token list that stores the sorted code for that hook,
-% \cs[no-index]{@@~\meta{hook}}, exists. The property list
-% \cs[no-index]{g_@@_\meta{hook}_code_prop} cannot be used here
+% \cs[no-index]{@@\textvisiblespace\meta{hook}}, exists. The property
+% list \cs[no-index]{g_@@_\meta{hook}_code_prop} cannot be used here
% because often it is necessary to add code to a hook without knowing
% if such hook was already declared, or even if it will ever be
% (for example, in case the package that defines it isn't loaded).
% \begin{macrocode}
\prg_new_conditional:Npnn \@@_if_usable:n #1 { p , T , F , TF }
{
- \tl_if_exist:cTF { @@~#1 }
+ \cs_if_exist:cTF { @@~#1 }
{ \prg_return_true: }
{ \prg_return_false: }
}
@@ -5046,7 +6954,7 @@
% \begin{macrocode}
\prg_new_conditional:Npnn \@@_if_reversed:n #1 { p , T , F , TF }
{
- \exp_after:wN \@@_clean_to_scan:w
+ \exp_after:wN \@@_use_none_delimit_by_s_mark:w
\if:w - \cs:w g_@@_#1_reversed_tl \cs_end:
\s_@@_mark \prg_return_true:
\else:
@@ -5086,6 +6994,37 @@
% \end{macro}
% \end{macro}
%
+% \begin{macro}[pTF]{\@@_if_cmd_hook:n}
+% \begin{macro}[pTF]{\@@_if_cmd_hook:w}
+% An internal conditional that checks if a given hook is a valid
+% generic \hook{cmd} hook.
+% \changes{v1.1d}{2023/05/21}
+% {Changes to allow support arguments in cmd hooks (cmd-args).}
+% \begin{macrocode}
+%<latexrelease>\IncludeInRelease{2023/06/01}{\@@_if_cmd_hook:n}
+%<latexrelease> {Hooks~with~args}
+\prg_new_conditional:Npnn \@@_if_cmd_hook:n #1 { T }
+ { \@@_if_cmd_hook:w #1 / / / \s_@@_mark }
+\cs_new:Npn \@@_if_cmd_hook:w #1 / #2 / #3 / #4 \s_@@_mark
+ {
+ \if:w Y
+ \str_if_eq:nnF {#1} { cmd } { N }
+ \tl_if_exist:cF { c_@@_generic_#1/./#3_tl } { N }
+ Y
+ \prg_return_true:
+ \else:
+ \prg_return_false:
+ \fi:
+ }
+%<latexrelease>\EndIncludeInRelease
+%<latexrelease>\IncludeInRelease{2020/10/01}{\@@_if_cmd_hook:n}
+%<latexrelease> {Hooks~with~args}
+%<latexrelease>\cs_undefine:N \@@_if_cmd_hook:nT
+%<latexrelease>\EndIncludeInRelease
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
% \begin{macro}[pTF]{\@@_if_generic_reversed:n}
% An internal conditional that checks if a name belongs to a generic
% reversed hook.
@@ -5103,6 +7042,50 @@
% \end{macrocode}
% \end{macro}
%
+% \begin{macro}[EXP]{\@@_if_replacing_args:TF}
+% \begin{macro}[EXP]{\@@_misused_if_replacing_args:nn}
+% \begin{macro}{\@@_replacing_args_true:}
+% \begin{macro}{\@@_replacing_args_false:}
+% \begin{macro}{\@@_replacing_args_reset:}
+% \begin{macro}{\g_@@_replacing_stack_seq}
+% An internal conditional that checks if the code being added to the
+% hook contains arguments.
+% \changes{v1.1a}{2023/04/06}
+% {Macro added (hook-args).}
+% \begin{macrocode}
+\seq_new:N \g_@@_replacing_stack_seq
+\cs_new:Npn \@@_misused_if_replacing_args:nn #1 #2
+ {
+ \msg_expandable_error:nnn { latex2e } { should-not-happen }
+ { Misused~\@@_if_replacing_args:. }
+ }
+\cs_new:Npn \@@_if_replacing_args:TF
+ { \@@_misused_if_replacing_args:nn }
+\cs_new_protected:Npn \@@_replacing_args_true:
+ {
+ \seq_gpush:No \g_@@_replacing_stack_seq
+ { \@@_if_replacing_args:TF }
+ \cs_set:Npn \@@_if_replacing_args:TF { \use_i:nn }
+ }
+\cs_new_protected:Npn \@@_replacing_args_false:
+ {
+ \seq_gpush:No \g_@@_replacing_stack_seq
+ { \@@_if_replacing_args:TF }
+ \cs_set:Npn \@@_if_replacing_args:TF { \use_ii:nn }
+ }
+\cs_new_protected:Npn \@@_replacing_args_reset:
+ {
+ \seq_gpop:NN \g_@@_replacing_stack_seq \l_@@_return_tl
+ \cs_gset_eq:NN \@@_if_replacing_args:TF \l_@@_return_tl
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
% \subsection{Messages}
%
% Hook errors are LaTeX kernel errors:
@@ -5137,6 +7120,55 @@
Please~ use~ a~ different~ name~ for~ your~ hook.}
% \end{macrocode}
%
+% \begin{macrocode}
+%<latexrelease>\IncludeInRelease{2023/06/01}{too-many-args}
+%<latexrelease> {Hooks~with~args}
+% \end{macrocode}
+%
+% \changes{v1.1a}{2023/04/06}
+% {Messages 'too-many-args', 'without-args' and 'one-time-args' added (hook-args).}
+% \begin{macrocode}
+\msg_new:nnnn { hooks } { too-many-args }
+ { Too~many~arguments~for~hook~'#1'. }
+ {
+ You~tried~to~declare~a~hook~with~#2~arguments,~but~a~
+ hook~can~only~have~up~to~nine.~LaTeX~will~define~this~
+ hook~with~nine~arguments.
+ }
+% \end{macrocode}
+%
+% \begin{macrocode}
+\msg_new:nnnn { hooks } { without-args }
+ { Hook~'#1'~has~no~arguments. }
+ {
+ You~tried~to~use~\iow_char:N\\#2WithArguments~
+ on~a~hook~that~takes~no~arguments.\\
+ Check~the~usage~of~the~hook~or~use~\iow_char:N\\#2~instead.\\
+ \\
+ LaTeX~will~use~\iow_char:N\\#2.
+ }
+% \end{macrocode}
+%
+% \begin{macrocode}
+\msg_new:nnnn { hooks } { one-time-args }
+ { You~can't~have~arguments~in~used~one-time~hook~'#1'. }
+ {
+ You~tried~to~use~\iow_char:N\\#2WithArguments~
+ on~a~one-time~hook~that~has~already~been~used.~
+ You~have~to~add~the~code~before~the~hook~is~used,~
+ or~add~the~code~without~arguments~using~\iow_char:N\\#2~instead.\\
+ \\
+ LaTeX~will~use~\iow_char:N\\#2.
+ }
+% \end{macrocode}
+%
+% \begin{macrocode}
+%<latexrelease>\EndIncludeInRelease
+%<latexrelease>\IncludeInRelease{2020/10/01}{too-many-args}
+%<latexrelease> {Hooks~with~args}
+%<latexrelease>\EndIncludeInRelease
+% \end{macrocode}
+%
%
% \begin{macrocode}
\msg_new:nnnn { hooks } { hook-disabled }
@@ -5278,17 +7310,49 @@
% \begin{macro}{\NewHook,\NewReversedHook,\NewMirroredHookPair}
% Declaring new hooks \ldots
% \begin{macrocode}
-\NewDocumentCommand \NewHook { m }{ \hook_new:n {#1} }
-\NewDocumentCommand \NewReversedHook { m }{ \hook_new_reversed:n {#1} }
-\NewDocumentCommand \NewMirroredHookPair { mm }{ \hook_new_pair:nn {#1}{#2} }
+\NewDocumentCommand \NewHook { m }
+ { \hook_new:n {#1} }
+\NewDocumentCommand \NewReversedHook { m }
+ { \hook_new_reversed:n {#1} }
+\NewDocumentCommand \NewMirroredHookPair { mm }
+ { \hook_new_pair:nn {#1}{#2} }
+% \end{macrocode}
+% \end{macro}
+%
+%
+%
+% \begin{macro}{
+% \NewHookWithArguments,
+% \NewReversedHookWithArguments,
+% \NewMirroredHookPairWithArguments
+% }
+% Declaring new hooks with arguments\ldots
+% \changes{v1.1a}{2023/04/06}
+% {Add \cs{NewHookWithArguments} (hook-args).}
+% \begin{macrocode}
+%<latexrelease>\IncludeInRelease{2023/06/01}{\NewHookWithArguments}
+%<latexrelease> {Hooks~with~args}
+\NewDocumentCommand \NewHookWithArguments { mm }
+ { \hook_new_with_args:nn {#1} {#2} }
+\NewDocumentCommand \NewReversedHookWithArguments { mm }
+ { \hook_new_reversed_with_args:nn {#1} {#2} }
+\NewDocumentCommand \NewMirroredHookPairWithArguments { mmm }
+ { \hook_new_pair_with_args:nnn {#1} {#2} {#3} }
+%<latexrelease>\EndIncludeInRelease
+%<latexrelease>\IncludeInRelease{2023/06/01}{\NewHookWithArguments}
+%<latexrelease> {Hooks~with~args}
+%<latexrelease>\cs_new_protected:Npn \NewHookWithArguments #1 #2 { }
+%<latexrelease>\cs_new_protected:Npn \NewReversedHookWithArguments #1 #2 { }
+%<latexrelease>\cs_new_protected:Npn \NewMirroredHookPairWithArguments #1 #2 #3 { }
+%<latexrelease>\EndIncludeInRelease
% \end{macrocode}
% \end{macro}
%
%
%
% \begin{macrocode}
-%<latexrelease>\IncludeInRelease{2021/06/01}%
-%<latexrelease> {\hook_activate_generic:n}{Providing~hooks}
+%<latexrelease>\IncludeInRelease{2021/06/01}{\ActivateGenericHook}
+%<latexrelease> {Providing~hooks}
% \end{macrocode}
%
% \begin{macro}{\ActivateGenericHook}
@@ -5296,7 +7360,8 @@
% \changes{v1.0m}{2021/04/29}{Add \cs{ProvideHook} etc.}
% \changes{v1.0o}{2021/08/02}{Change name}
% \begin{macrocode}
-\NewDocumentCommand \ActivateGenericHook { m }{ \hook_activate_generic:n {#1} }
+\NewDocumentCommand \ActivateGenericHook { m }
+ { \hook_activate_generic:n {#1} }
% \end{macrocode}
% \end{macro}
%
@@ -5304,32 +7369,57 @@
% Disabling a generic hook.
% \changes{v1.0o}{2021/08/02}{Change name}
% \begin{macrocode}
-\NewDocumentCommand \DisableGenericHook { m }{ \hook_disable_generic:n {#1} }
+\NewDocumentCommand \DisableGenericHook { m }
+ { \hook_disable_generic:n {#1} }
% \end{macrocode}
% \end{macro}
%
% \begin{macrocode}
%<latexrelease>\EndIncludeInRelease
-%<latexrelease>\IncludeInRelease{2020/10/01}
-%<latexrelease> {\hook_activate_generic:n}{Providing~hooks}
-%<latexrelease>
-%<latexrelease>\def \ActivateGenericHook#1{}
-%<latexrelease>
+% \end{macrocode}
+%
+% \begin{macrocode}
+%<latexrelease>\IncludeInRelease{2020/10/01}{\ActivateGenericHook}
+%<latexrelease> {Providing~hooks}
+%<latexrelease>\def \ActivateGenericHook #1 { }
+%<latexrelease>\def \DisableGenericHook #1 { }
%<latexrelease>\EndIncludeInRelease
% \end{macrocode}
%
%
-% \begin{macro}{\AddToHook}
+% \begin{macro}{\AddToHook,\AddToHookWithArguments}
+% \changes{v1.1a}{2023/04/06}
+% {Add \cs{AddToHookWithArguments} (hook-args).}
% \begin{macrocode}
+%<latexrelease>\IncludeInRelease{2023/06/01}{\AddToHookWithArguments}
+%<latexrelease> {Hooks~with~args}
\NewDocumentCommand \AddToHook { m o +m }
{ \hook_gput_code:nnn {#1} {#2} {#3} }
+\NewDocumentCommand \AddToHookWithArguments { m o +m }
+ { \hook_gput_code_with_args:nnn {#1} {#2} {#3} }
+%<latexrelease>\EndIncludeInRelease
+%<latexrelease>\IncludeInRelease{2020/10/01}{\AddToHookWithArguments}
+%<latexrelease> {Hooks~with~args}
+%<latexrelease>\cs_new_protected:Npn \AddToHookWithArguments #1 #2 #3 { }
+%<latexrelease>\EndIncludeInRelease
% \end{macrocode}
% \end{macro}
%
-% \begin{macro}{\AddToHookNext}
+% \begin{macro}{\AddToHookNext,\AddToHookNextWithArguments}
+% \changes{v1.1a}{2023/04/06}
+% {Add \cs{AddToHookNextWithArguments} (hook-args).}
% \begin{macrocode}
+%<latexrelease>\IncludeInRelease{2023/06/01}{\AddToHookNextWithArguments}
+%<latexrelease> {Hooks~with~args}
\NewDocumentCommand \AddToHookNext { m +m }
{ \hook_gput_next_code:nn {#1} {#2} }
+\NewDocumentCommand \AddToHookNextWithArguments { m +m }
+ { \hook_gput_next_code_with_args:nn {#1} {#2} }
+%<latexrelease>\EndIncludeInRelease
+%<latexrelease>\IncludeInRelease{2020/10/01}{\AddToHookNextWithArguments}
+%<latexrelease> {Hooks~with~args}
+%<latexrelease>\cs_new_protected:Npn \AddToHookNextWithArguments #1 #2 { }
+%<latexrelease>\EndIncludeInRelease
% \end{macrocode}
% \end{macro}
%
@@ -5396,12 +7486,29 @@
%
%
%
-% \begin{macro}{\UseHook,\UseOneTimeHook}
+% \begin{macro}{
+% \UseHook,
+% \UseOneTimeHook,
+% \UseHookWithArguments,
+% \UseOneTimeHookWithArguments,
+% }
% Avoid the overhead of \pkg{xparse} and its protection that we
% don't want here (since the hook should vanish without trace if empty)!
+% \changes{v1.1a}{2023/04/06}
+% {Add \cs{UseHookWithArguments} (hook-args).}
% \begin{macrocode}
+%<latexrelease>\IncludeInRelease{2023/06/01}{\UseHookWithArguments}
+%<latexrelease> {Hooks~with~args}
\cs_new:Npn \UseHook { \hook_use:n }
\cs_new:Npn \UseOneTimeHook { \hook_use_once:n }
+\cs_new:Npn \UseHookWithArguments { \hook_use:nnw }
+\cs_new:Npn \UseOneTimeHookWithArguments { \hook_use_once:nnw }
+%<latexrelease>\EndIncludeInRelease
+%<latexrelease>\IncludeInRelease{2020/10/01}{\UseHookWithArguments}
+%<latexrelease> {Hooks~with~args}
+%<latexrelease>\cs_new:Npn \UseHookWithArguments #1 #2 { }
+%<latexrelease>\cs_new:Npn \UseOneTimeHookWithArguments #1 #2 { }
+%<latexrelease>\EndIncludeInRelease
% \end{macrocode}
% \end{macro}
%
@@ -5462,7 +7569,7 @@
% \end{macrocode}
% \end{macro}
%
-% \begin{macro}[EXP]{\IfHookExistsTF}
+% \begin{macro}[EXP,int]{\IfHookExistsTF}
% Marked for removal and no longer documented in the doc section!
% \phoinline{\cs{IfHookExistsTF} is used in \texttt{jlreq.cls},
% \texttt{pxatbegshi.sty}, \texttt{pxeverysel.sty},
@@ -5484,7 +7591,7 @@
% \changes{v1.0p}{2021/08/20}{Added deprecation warnings for
% old generic hook commands (gh/638)}
%
-% \begin{macro}{
+% \begin{macro}[int]{
% \hook_disable:n,
% \hook_provide:n,
% \hook_provide_reversed:n,
@@ -5529,7 +7636,7 @@
% \end{macrocode}
% \end{macro}
%
-% \begin{macro}{
+% \begin{macro}[int]{
% \DisableHook,
% \ProvideHook,
% \ProvideReversedHook,
@@ -5596,8 +7703,10 @@
%<@@=>
% \end{macrocode}
%
-% \begin{macro}{\@expl@@@initialize@all@@,
-% \@expl@@@hook@curr@name@pop@@}
+% \begin{macro}[int]{
+% \@expl@@@initialize@all@@,
+% \@expl@@@hook@curr@name@pop@@
+% }
%
% \InternalDetectionOff
% \begin{macrocode}
@@ -5620,8 +7729,8 @@
% to be for \cs{AddToHook} vice versa (gh/401)}
% \begin{macrocode}
%
-%<latexrelease>\IncludeInRelease{0000/00/00}%
-%<latexrelease> {lthooks}{The~hook~management}%
+%<latexrelease>\IncludeInRelease{0000/00/00}{lthooks}
+%<latexrelease> {The~hook~management}%
%<latexrelease>
%<latexrelease>\def \NewHook#1{}
%<latexrelease>\def \NewReversedHook#1{}
@@ -5656,10 +7765,56 @@
%<latexrelease>\long\def \IfHookEmptyTF #1#2#3{#2}
%<latexrelease>
%<latexrelease>\EndModuleRelease
+% \end{macrocode}
+%
+% \begin{macrocode}
+%<@@=hook>
+% \end{macrocode}
+%
+% \changes{v1.1a}{2023/04/06}
+% {Add dedicated rollback code to revert data structures (hook-args).}
+% \begin{macrocode}
+%<latexrelease>\cs:w @@_rollback_tidying: \cs_end:
+%<latexrelease>\bool_lazy_and:nnT
+%<latexrelease> { \int_compare_p:nNn { \sourceLaTeXdate } > { 20230600 } }
+%<latexrelease> { \int_compare_p:nNn { \requestedLaTeXdate } < { 20230601 } }
+%<latexrelease> {
+%<latexrelease> \cs_gset_protected:Npn \@@_rollback_tidying:
+%<latexrelease> {
+%<latexrelease> \@latex@error { Rollback~code~executed~twice }
+%<latexrelease> {
+%<latexrelease> Something~went~wrong~(unless~this~was~
+%<latexrelease> done~on~purpose~in~a~testing~environment).
+%<latexrelease> }
+%<latexrelease> \use_none:nnnn
+%<latexrelease> }
+%<latexrelease> \cs_set:Npn \@@_tmp:w #1 #2
+%<latexrelease> {
+%<latexrelease> \@@_tl_gset:cx { @@#1~#2 }
+%<latexrelease> {
+%<latexrelease> \exp_args:No \exp_not:o
+%<latexrelease> {
+%<latexrelease> \cs:w @@#1~#2 \exp_last_unbraced:Ne \cs_end:
+%<latexrelease> { \@@_braced_cs_parameter:n { @@#1~#2 } }
+%<latexrelease> }
+%<latexrelease> }
+%<latexrelease> }
+%<latexrelease> \seq_map_inline:Nn \g_@@_all_seq
+%<latexrelease> {
+%<latexrelease> \exp_after:wN \cs_gset_nopar:Npn
+%<latexrelease> \cs:w g_@@_#1_code_prop \exp_args:NNo \exp_args:No
+%<latexrelease> \cs_end: { \cs:w g_@@_#1_code_prop \cs_end: }
+%<latexrelease> \@@_tmp:w { _toplevel } {#1}
+%<latexrelease> \@@_tmp:w { _next } {#1}
+%<latexrelease> }
+%<latexrelease> }
\ExplSyntaxOff
%</2ekernel|latexrelease>
% \end{macrocode}
%
+% \begin{macrocode}
+%<@@=>
+% \end{macrocode}
%
% \Finale
%
diff --git a/Master/texmf-dist/source/latex-dev/base/ltlists.dtx b/Master/texmf-dist/source/latex-dev/base/ltlists.dtx
index afde14e0709..d43df93a54e 100644
--- a/Master/texmf-dist/source/latex-dev/base/ltlists.dtx
+++ b/Master/texmf-dist/source/latex-dev/base/ltlists.dtx
@@ -31,7 +31,7 @@
%<*driver>
% \fi
\ProvidesFile{ltlists.dtx}
- [2020/12/05 v1.0t LaTeX Kernel (List Environments)]
+ [2023/05/17 v1.0t LaTeX Kernel (List Environments)]
% \iffalse
\documentclass{ltxdoc}
\GetFileInfo{ltlists.dtx}
@@ -68,7 +68,6 @@
% \begin{quote}
% |\list|\marg{LABEL}\marg{COMMANDS} ... |\endlist|
% \end{quote}
-%
% which can be invoked by the user as the list environment. The LABEL
% argument specifies item labeling. COMMANDS contains commands for
% changing the horizontal and vertical spacing parameters.
@@ -187,7 +186,7 @@
% |\hsize|.
%
% Here are the parameters of a list that can be set by commands in
-% the |\list|'s COMMANDS argument. These parameters are all TeX
+% the |\list|'s COMMANDS argument. These parameters are all \TeX{}
% skips or dimensions (defined by |\newskip| or |\newdimen|), so the
% usual \TeX\ or \LaTeX\ commands can be used to set them. The
% commands will be executed in vmode if and only if the |\list| was
@@ -228,7 +227,7 @@
% label.
% \item[\cs{labelwidth}:] nominal width of box that contains the label.
% If the natural width of the
-% label $< =$ \cs{labelwidth},
+% label $\leq$ \cs{labelwidth},
% then the label is flushed right inside a box
% of width \cs{labelwidth} (with an \cs{hfil}).
% Otherwise,
diff --git a/Master/texmf-dist/source/latex-dev/base/ltmarks.dtx b/Master/texmf-dist/source/latex-dev/base/ltmarks.dtx
index 3dc4b493ace..677534dd27c 100644
--- a/Master/texmf-dist/source/latex-dev/base/ltmarks.dtx
+++ b/Master/texmf-dist/source/latex-dev/base/ltmarks.dtx
@@ -1,7 +1,8 @@
% \iffalse meta-comment
%
-%% File: ltmarks.dtx (C) Copyright 2022
-% Frank Mittelbach, LaTeX Team
+%% File: ltmarks.dtx
+%% Copyright (C) 2022-2023
+%% Frank Mittelbach, The LaTeX Project
%
% It may be distributed and/or modified under the conditions of the
% LaTeX Project Public License (LPPL), either version 1.3c of this
diff --git a/Master/texmf-dist/source/latex-dev/base/ltmath.dtx b/Master/texmf-dist/source/latex-dev/base/ltmath.dtx
index 746a3077fb5..3b1518dd2eb 100644
--- a/Master/texmf-dist/source/latex-dev/base/ltmath.dtx
+++ b/Master/texmf-dist/source/latex-dev/base/ltmath.dtx
@@ -38,7 +38,7 @@
%<*driver>
% \fi
\ProvidesFile{ltmath.dtx}
- [2022/09/07 v1.2m LaTeX Kernel (Math Setup)]
+ [2023/05/13 v1.2n LaTeX Kernel (Math Setup)]
% \iffalse
%</driver>
%
@@ -1132,9 +1132,29 @@
\fi
% \end{macrocode}
%
+% \begin{macro}{\eqno}
+% \begin{macro}{\leqno}
+% \changes{v1.2n}{2023/05/13}{add \cs{ignorespaces} gh/1059}
+% Ensure the (deprecated) \verb|$$..\eqno 1 $$| ignores spaces.
% \begin{macrocode}
%</2ekernel>
+%<*2ekernel|latexrelease>
+%<latexrelease>\IncludeInRelease{2023/06/01}%
+%<latexrelease> {\eqno}{add ignorespaces to eqno}%
+\let\@kernel@eqno\eqno
+\let\@kernel@leqno\leqno
+\protected\def\eqno{\@kernel@eqno\aftergroup\ignorespaces}
+\protected\def\leqno{\@kernel@leqno\aftergroup\ignorespaces}
+%</2ekernel|latexrelease>
+%<latexrelease>\EndIncludeInRelease
+%<latexrelease>\IncludeInRelease{0000/00/00}%
+%<latexrelease> {\eqno}{add ignorespaces to eqno}%
+%<latexrelease>\let\eqno\@kernel@eqno
+%<latexrelease>\let\leqno\@kernel@leqno
+%<latexrelease>\EndIncludeInRelease
% \end{macrocode}
+% \end{macro}
+% \end{macro}
%
%
%
@@ -1322,6 +1342,5 @@
% \end{environment}
%
%
-%
% \Finale
%
diff --git a/Master/texmf-dist/source/latex-dev/base/ltmeta.dtx b/Master/texmf-dist/source/latex-dev/base/ltmeta.dtx
index 31c5d8dbeec..daaa71626bb 100644
--- a/Master/texmf-dist/source/latex-dev/base/ltmeta.dtx
+++ b/Master/texmf-dist/source/latex-dev/base/ltmeta.dtx
@@ -1,7 +1,8 @@
% \iffalse meta-comment
%
-%% File: ltmeta.dtx (C) Copyright 2021, 2022
-% Frank Mittelbach, LaTeX Team
+%% File: ltmeta.dtx
+%% Copyright (C) 2021-2023
+%% Frank Mittelbach, The LaTeX Project
%
% It may be distributed and/or modified under the conditions of the
% LaTeX Project Public License (LPPL), either version 1.3c of this
diff --git a/Master/texmf-dist/source/latex-dev/base/ltpara.dtx b/Master/texmf-dist/source/latex-dev/base/ltpara.dtx
index 7c96c72fc70..9c1a95ee61b 100644
--- a/Master/texmf-dist/source/latex-dev/base/ltpara.dtx
+++ b/Master/texmf-dist/source/latex-dev/base/ltpara.dtx
@@ -1,7 +1,8 @@
% \iffalse meta-comment
%
-%% File: ltpara.dtx (C) Copyright 2020-2023
-% Frank Mittelbach, LaTeX Team
+%% File: ltpara.dtx
+%% Copyright (C) 2020-2023
+%% Frank Mittelbach, The LaTeX Project
%
% It may be distributed and/or modified under the conditions of the
% LaTeX Project Public License (LPPL), either version 1.3c of this
diff --git a/Master/texmf-dist/source/latex-dev/base/ltplain.dtx b/Master/texmf-dist/source/latex-dev/base/ltplain.dtx
index 1bdff344f73..89e5017300f 100644
--- a/Master/texmf-dist/source/latex-dev/base/ltplain.dtx
+++ b/Master/texmf-dist/source/latex-dev/base/ltplain.dtx
@@ -32,7 +32,7 @@
%<*driver>
% \fi
\ProvidesFile{ltplain.dtx}
- [2022/01/25 v2.3h LaTeX Kernel (Plain TeX)]
+ [2023/04/15 v2.3i LaTeX Kernel (Plain TeX)]
% \iffalse
\documentclass{ltxdoc}
\GetFileInfo{ltplain.dtx}
@@ -660,6 +660,10 @@
\def\extrafloats#1{%
\ifnum#1>\z@
\count@\numexpr\float@count-1\relax
+% \end{macrocode}
+% \changes{v2.3i}{2023/04/15}{Protect box 255 in lualatex gh/1041}
+% \begin{macrocode}
+ \ifnum\count@<266 \ch@ck0\m@ne\insert\fi
\ch@ck0\count@\count
\ch@ck1\count@\dimen
\ch@ck2\count@\skip
@@ -668,8 +672,12 @@
\global\expandafter\e@alloc@chardef
\csname bx@\the\float@count\endcsname\float@count
\@cons\@freelist{\csname bx@\the\float@count\endcsname}%
-\expandafter
-\extrafloats\expandafter{\numexpr#1-1\relax}%
+% \end{macrocode}
+% \changes{v2.3i}{2023/04/15}{unwind numexpr and ifnum nesting}
+% \begin{macrocode}
+\expandafter\extrafloats\expandafter{\the\numexpr#1-1\expandafter}%
+% \end{macrocode}
+% \begin{macrocode}
\fi}%
% \end{macrocode}
%
@@ -880,7 +888,6 @@
% but the code is commented out if no special value needs to be set.
% INITEX makes all parameters zero except where noted.
%
-% \begin{oldcomments}
% \begin{macrocode}
\pretolerance=100
\tolerance=200 % INITEX sets this to 10000
@@ -897,10 +904,14 @@
\brokenpenalty=100
\predisplaypenalty=10000
% \end{macrocode}
+%
+% \begin{macrocode}
% \postdisplaypenalty=0
% \interlinepenalty=0
% \floatingpenalty=0, set during \insert
% \outputpenalty=0, set before TeX enters \output
+% \end{macrocode}
+%
% \begin{macrocode}
\doublehyphendemerits=10000
\finalhyphendemerits=5000
@@ -971,6 +982,8 @@
% \begin{macrocode}
\uchyph=1
% \end{macrocode}
+%
+% \begin{macrocode}
% \lefthyphenmin=2 \righthyphenmin=3 set below
% \globaldefs=0
% \maxdeadcycles=25 % INITEX does this
@@ -978,21 +991,29 @@
% \fam=0
% \mag=1000 % INITEX does this
% \escapechar=`\\ % INITEX does this
+% \end{macrocode}
+%
% \begin{macrocode}
\defaulthyphenchar=`\-
\defaultskewchar=-1
% \end{macrocode}
+%
+% \begin{macrocode}
% \endlinechar=`\^^M % INITEX does this
% \newlinechar=-1 \LaTeX\ sets this in ltdefns.dtx.
+% \end{macrocode}
+%
% \begin{macrocode}
\delimiterfactor=901
% \end{macrocode}
+%
+% \begin{macrocode}
% \time=now % TeX does this at beginning of job
% \day=now % TeX does this at beginning of job
% \month=now % TeX does this at beginning of job
% \year=now % TeX does this at beginning of job
+% \end{macrocode}
%
-% \end{oldcomments}
% In \LaTeX{} we don't want box information in the transcript
% unless we do a full tracing.
% \changes{v1.0g}{1994/04/28}{Turn off overfull box tracing in log}
@@ -1012,26 +1033,36 @@
\boxmaxdepth=\maxdimen
% \end{macrocode}
%
-% \begin{oldcomments}
+% \begin{macrocode}
% \lineskiplimit=0pt, changed by \normalbaselines
+% \end{macrocode}
+%
% \begin{macrocode}
\delimitershortfall=5pt
\nulldelimiterspace=1.2pt
\scriptspace=0.5pt
% \end{macrocode}
+%
+% \begin{macrocode}
% \mathsurround=0pt
% \predisplaysize=0pt, set before TeX enters $$
% \displaywidth=0pt, set before TeX enters $$
% \displayindent=0pt, set before TeX enters $$
+% \end{macrocode}
+%
% \begin{macrocode}
\parindent=20pt
% \end{macrocode}
+%
+% \begin{macrocode}
% \hangindent=0pt, zeroed by TeX after each paragraph
% \hoffset=0pt
% \voffset=0pt
%
% \baselineskip=0pt, changed by \normalbaselines
% \lineskip=0pt, changed by \normalbaselines
+% \end{macrocode}
+%
% \begin{macrocode}
\parskip=0pt plus 1pt
\abovedisplayskip=12pt plus 3pt minus 9pt
@@ -1039,19 +1070,26 @@
\belowdisplayskip=12pt plus 3pt minus 9pt
\belowdisplayshortskip=7pt plus 3pt minus 4pt
% \end{macrocode}
+%
+% \begin{macrocode}
% \leftskip=0pt
% \rightskip=0pt
+% \end{macrocode}
+%
% \begin{macrocode}
\topskip=10pt
\splittopskip=10pt
% \end{macrocode}
+%
+% \begin{macrocode}
% \tabskip=0pt
% \spaceskip=0pt
% \xspaceskip=0pt
+% \end{macrocode}
+%
% \begin{macrocode}
\parfillskip=0pt plus 1fil
% \end{macrocode}
-% \end{oldcomments}
%
%
% \begin{macro}{\normalbaselineskip}
@@ -1215,7 +1253,7 @@
\gdef\obeylines{\catcode`\^^M\active%
\let^^M\obeyedline%
% \end{macrocode}
-%
+%
% The next line ending the definition is rather curious and it took
% me awhile to understand why rollback fails. The problem is the
% following: if \texttt{latexrelease} is used, then blocks of
diff --git a/Master/texmf-dist/source/latex-dev/base/ltshipout.dtx b/Master/texmf-dist/source/latex-dev/base/ltshipout.dtx
index 1b3cabcfc86..b19814a6fd4 100644
--- a/Master/texmf-dist/source/latex-dev/base/ltshipout.dtx
+++ b/Master/texmf-dist/source/latex-dev/base/ltshipout.dtx
@@ -1,7 +1,7 @@
% \iffalse meta-comment
%%
%% Copyright (C) 2020-2023
-%% Frank Mittelbach, LaTeX Team
+%% Frank Mittelbach, The LaTeX Project
%%
%
% This file is part of the LaTeX base system.
diff --git a/Master/texmf-dist/source/latex-dev/base/ltspace.dtx b/Master/texmf-dist/source/latex-dev/base/ltspace.dtx
index 672ab927292..1dbfefc7b1d 100644
--- a/Master/texmf-dist/source/latex-dev/base/ltspace.dtx
+++ b/Master/texmf-dist/source/latex-dev/base/ltspace.dtx
@@ -32,7 +32,7 @@
%<*driver>
% \fi
\ProvidesFile{ltspace.dtx}
- [2022/11/28 v1.3o LaTeX Kernel (spacing)]
+ [2023/03/22 v1.3p LaTeX Kernel (spacing)]
% \iffalse
\documentclass{ltxdoc}
\GetFileInfo{ltspace.dtx}
@@ -308,8 +308,10 @@
% \end{macro}
%
% \begin{macro}{\samepage}
+% \changes{v1.3p}{2023/03/22}{Add \cs{predisplaypenalty} setting (gh/1022)}
% \begin{macrocode}
\DeclareRobustCommand\samepage{\interlinepenalty\@M
+ \predisplaypenalty\@M
\postdisplaypenalty\@M
\interdisplaylinepenalty\@M
\@beginparpenalty\@M
diff --git a/Master/texmf-dist/source/latex-dev/base/ltvers.dtx b/Master/texmf-dist/source/latex-dev/base/ltvers.dtx
index da131765aca..beed347903a 100644
--- a/Master/texmf-dist/source/latex-dev/base/ltvers.dtx
+++ b/Master/texmf-dist/source/latex-dev/base/ltvers.dtx
@@ -115,7 +115,7 @@
{2023-06-01}
%</2ekernel|latexrelease>
%<*2ekernel>
-\def\patch@level{-2}
+\def\patch@level{-3}
% \end{macrocode}
%
% \begin{macro}{\development@branch@name}
diff --git a/Master/texmf-dist/source/latex-dev/base/ltxdoc.dtx b/Master/texmf-dist/source/latex-dev/base/ltxdoc.dtx
index 78b6de4bcce..e147c9d22fe 100644
--- a/Master/texmf-dist/source/latex-dev/base/ltxdoc.dtx
+++ b/Master/texmf-dist/source/latex-dev/base/ltxdoc.dtx
@@ -30,7 +30,7 @@
%
%<class>\NeedsTeXFormat{LaTeX2e}
%<class>\ProvidesClass{ltxdoc}
-%<class> [2022/06/22 v2.1i Standard LaTeX documentation class]
+%<class> [2023/03/28 v2.1j Standard LaTeX documentation class]
%
%<*driver>
\documentclass{ltxdoc}
@@ -182,9 +182,13 @@
%
% Support rolling back \pkg{doc} to version 2:
% \changes{v2.1e}{2022/05/27}{Support rolling back doc to version 2}
+% \changes{v2.1j}{2023/03/28}{Define \cs{cs} if doc is rolled back to v2 (gh/981)}
% \begin{macrocode}
\let\ltxdoc@doc@version\@empty % use current version by default
-\DeclareOption{doc2}{\def\ltxdoc@doc@version{=v2}}
+\DeclareOption{doc2}{%
+ \def\ltxdoc@doc@version{=v2}%
+ \DeclareRobustCommand\cs[1]{\texttt{\bslash #1}}%
+}
% \end{macrocode}
%
% \begin{macrocode}
@@ -670,8 +674,10 @@ Bug reports can be opened (category \texttt{#1}) at\\%
% kernel sources.
%
%
-% Copyright 2006, 2007, 2011 Heiko Oberdiek
-% Copyright 2014-2021 The LaTeX Project
+% Copyright 2006, 2007, 2011
+% Heiko Oberdiek
+% Copyright (C) 2014-2023
+% The LaTeX Project
%
\ProvidesFile{ltxdoc.cfg}%
diff --git a/Master/texmf-dist/source/latex-dev/base/ltxref.dtx b/Master/texmf-dist/source/latex-dev/base/ltxref.dtx
index dcfebf0e7e8..0f842e4312a 100644
--- a/Master/texmf-dist/source/latex-dev/base/ltxref.dtx
+++ b/Master/texmf-dist/source/latex-dev/base/ltxref.dtx
@@ -33,7 +33,7 @@
%<*driver>
% \fi
\ProvidesFile{ltxref.dtx}
- [2022/04/12 v1.1p LaTeX Kernel (Cross Referencing)]
+ [2023/05/16 v1.1q LaTeX Kernel (Cross Referencing)]
% \iffalse
\documentclass{ltxdoc}
\GetFileInfo{ltxref.dtx}
@@ -93,6 +93,15 @@
% to align with the use of \pkg{hyperref}. Without \pkg{hyperref} (or some
% other package using the starred form) the star is simply ignored.
%
+% Note: starting with 2023-06-01 |\label| stores also the current value
+% of |\@currentlabelname| which should typically contain a (sanitized) title.
+% (A reference command |\nameref| is provided by the \pkg{nameref} package.)
+% |\label| also stores |\@currentHref| which if set should refer to a target name
+% for links. This value is set and used by \pkg{hyperref}. Unlike the other values
+% |\@currentHref| should be set globally. A fifth value |\@kernel@reserved@label@data|
+% is reserved for the kernel to allow future extensions of the cross-reference
+% system.
+%
%
% \MaybeStop{}
%
@@ -108,7 +117,8 @@
% incremented by the command \refstepcounter{CNT} , which sets
% \@currentlabel == {CNT}{eval(\p@cnt\theCNT)}. The command
% \label{FOO} then writes the following on file \@auxout :
-% \newlabel{FOO}{{eval(\@currentlabel)}{eval(\thepage)}}
+% \newlabel{FOO}{{eval(\@currentlabel)}{eval(\thepage)}%
+% {eval(\@currentlabelname)}{eval(\@currentHref)}{eval(\@kernel@reserved@label@data)}}
%
% \ref{FOO} ==
% BEGIN
@@ -228,6 +238,10 @@
%
% RmS 93/09/08: Added setting of refundefined switch.
% \begin{macrocode}
+%</2ekernel>
+%<*2ekernel|latexrelease>
+%<latexrelease>\IncludeInRelease{2023/06/01}%
+%<latexrelease> {\@kernel@sref}{store five arguments}%
\def\@setref#1#2#3{%
\ifx#1\relax
\protect\G@refundefinedtrue
@@ -235,19 +249,53 @@
\@latex@warning{Reference `#3' on page \thepage \space
undefined}%
\else
- \expandafter#2#1\null
+ \expandafter#2#1\@empty\@empty\@empty\null
\fi}
% \end{macrocode}
% \begin{macrocode}
-%</2ekernel>
-%<*2ekernel|latexrelease>
+\long\def\@firstoffive#1#2#3#4#5{#1}
+\long\def\@secondoffive#1#2#3#4#5{#2}
+\def\@kernel@sref#1{\expandafter\@setref\csname r@#1\endcsname\@firstoffive{#1}}
+\def\@kernel@spageref#1{\expandafter\@setref\csname r@#1\endcsname
+ \@secondoffive{#1}}
+%<latexrelease>\EndIncludeInRelease
+%<latexrelease>\IncludeInRelease{2022/06/01}%
+%<latexrelease> {\@kernel@sref}{store five arguments}%
+%<latexrelease>\def\@setref#1#2#3{%
+%<latexrelease> \ifx#1\relax
+%<latexrelease> \protect\G@refundefinedtrue
+%<latexrelease> \nfss@text{\reset@font\bfseries ??}%
+%<latexrelease> \@latex@warning{Reference `#3' on page \thepage \space
+%<latexrelease> undefined}%
+%<latexrelease> \else
+%<latexrelease> \expandafter#2#1\null
+%<latexrelease> \fi}
+%<latexrelease>\let\@firstoffive\undefined
+%<latexrelease>\let\@secondoffive\undefined
+%<latexrelease>\def\@kernel@sref#1{\expandafter\@setref\csname r@#1\endcsname\@firstoftwo{#1}}
+%<latexrelease>\def\@kernel@spageref#1{\expandafter\@setref\csname r@#1\endcsname
+%<latexrelease> \@secondoftwo{#1}}
+%<latexrelease>\EndIncludeInRelease
+%<latexrelease>\IncludeInRelease{0000/00/00}%
+%<latexrelease> {\@kernel@sref}{store five arguments}%
+%<latexrelease>\def\@setref#1#2#3{%
+%<latexrelease> \ifx#1\relax
+%<latexrelease> \protect\G@refundefinedtrue
+%<latexrelease> \nfss@text{\reset@font\bfseries ??}%
+%<latexrelease> \@latex@warning{Reference `#3' on page \thepage \space
+%<latexrelease> undefined}%
+%<latexrelease> \else
+%<latexrelease> \expandafter#2#1\null
+%<latexrelease> \fi}
+%<latexrelease>\let\@firstoffive\undefined
+%<latexrelease>\let\@secondoffive\undefined
+%<latexrelease>\let\@kernel@sref\undefined
+%<latexrelease>\let\@kernel@spageref\undefined
+%<latexrelease>\EndIncludeInRelease
%<latexrelease>\IncludeInRelease{2022/06/01}%
%<latexrelease> {\ref}{Add starred reference commands}%
% \end{macrocode}
% \begin{macrocode}
-\def\@kernel@sref#1{\expandafter\@setref\csname r@#1\endcsname\@firstoftwo{#1}}
-\def\@kernel@spageref#1{\expandafter\@setref\csname r@#1\endcsname
- \@secondoftwo{#1}}
\let\@kernel@ref\@kernel@sref
\let\@kernel@pageref\@kernel@spageref
\NewDocumentCommand\ref{s}
@@ -334,6 +382,8 @@
% \begin{macro}{\label}
% \changes{v1.1d}{1994/11/04}{(ASAJ)Added \cs{protected@write}}
% \changes{v1.1d}{1994/11/04}{(ASAJ)Added \cs{protected@edef}}
+% \changes{v1.1q}{2023/05/12}{(UFi)extended to store five arguments}
+% \changes{v1.1q}{2023/05/12}{(UFi)added a hook with argument}
% The commands |\label| and |\refstepcounter| have been changed to
% allow |\protect|'ed commands to work properly. For example,
%\begin{verbatim}
@@ -343,16 +393,27 @@
% to something like |\foo{4.d}|. Change made 20 Jul 88.
%
% \begin{macrocode}
+%</2ekernel>
+%<*2ekernel|latexrelease>
+%<latexrelease>\IncludeInRelease{2023/06/01}%
+%<latexrelease> {\label}{store five label arguments}%
+\providecommand\@currentlabelname{}
+\providecommand\@currentHref{}
+\providecommand\@kernel@reserved@label@data{}
+\NewHookWithArguments{label}{1}
\def\label#1{\@bsphack
+ \begingroup
+ \UseHookWithArguments{label}{1}{#1}%
\protected@write\@auxout{}%
- {\string\newlabel{#1}{{\@currentlabel}{\thepage}}}%
+ {\string\newlabel{#1}{{\@currentlabel}{\thepage}%
+ {\@currentlabelname}{\@currentHref}{\@kernel@reserved@label@data}}}%
+ \endgroup
\@esphack}
+%<latexrelease>\EndIncludeInRelease
% \end{macrocode}
% \end{macro}
%
% \begin{macrocode}
-%</2ekernel>
-%<*2ekernel|latexrelease>
%<latexrelease>\IncludeInRelease{2022/06/01}%
%<latexrelease> {\Ref}{Add starred version}%
% \end{macrocode}
@@ -432,6 +493,16 @@
% \begin{macrocode}
%</2ekernel|latexrelease>
%<latexrelease>\EndIncludeInRelease
+%<latexrelease>\IncludeInRelease{0000/00/00}%
+%<latexrelease> {\label}{store five label arguments}%
+%<latexrelease>\let\@currenttitle\@undefined
+%<latexrelease>\let\@currenttarget\@undefined
+%<latexrelease>\let\@kernel@currentdata\@undefined
+%<latexrelease>\def\label#1{\@bsphack
+%<latexrelease> \protected@write\@auxout{}%
+%<latexrelease> {\string\newlabel{#1}{{\@currentlabel}{\thepage}}}%
+%<latexrelease> \@esphack}
+%<latexrelease>\EndIncludeInRelease
%<latexrelease>\IncludeInRelease{2020/10/01}%
%<latexrelease> {\Ref}{Add starred version}%
%<latexrelease>\def\@currentcounter{}
diff --git a/Master/texmf-dist/source/latex-dev/base/slifonts.fdd b/Master/texmf-dist/source/latex-dev/base/slifonts.fdd
index ec8b802596f..5b66975095c 100644
--- a/Master/texmf-dist/source/latex-dev/base/slifonts.fdd
+++ b/Master/texmf-dist/source/latex-dev/base/slifonts.fdd
@@ -1,6 +1,6 @@
% \iffalse meta-comment
%
-% Copyright 1993-2019
+% Copyright (C) 1993-2023
% The LaTeX Project and any individual authors listed elsewhere
% in this file.
%
diff --git a/Master/texmf-dist/source/latex-dev/base/tulm.fdd b/Master/texmf-dist/source/latex-dev/base/tulm.fdd
index 243cbe30cc7..c8dd8b95fcf 100644
--- a/Master/texmf-dist/source/latex-dev/base/tulm.fdd
+++ b/Master/texmf-dist/source/latex-dev/base/tulm.fdd
@@ -1,6 +1,6 @@
% \iffalse meta-comment
%
-% Copyright 2016-2021
+% Copyright (C) 2016-2023
% The LaTeX Project and any individual authors listed elsewhere
% in this file.
%