summaryrefslogtreecommitdiff
path: root/macros/latex-dev/base/lthooks.dtx
diff options
context:
space:
mode:
Diffstat (limited to 'macros/latex-dev/base/lthooks.dtx')
-rw-r--r--macros/latex-dev/base/lthooks.dtx1729
1 files changed, 821 insertions, 908 deletions
diff --git a/macros/latex-dev/base/lthooks.dtx b/macros/latex-dev/base/lthooks.dtx
index 603b472e44..b1e3985704 100644
--- a/macros/latex-dev/base/lthooks.dtx
+++ b/macros/latex-dev/base/lthooks.dtx
@@ -1,29 +1,41 @@
% \iffalse meta-comment
+%%
+%% File: lthooks.dtx (C) Copyright 2020 Frank Mittelbach,
+%% Phelype Oleinik & LaTeX Team
%
-%% File: lthooks.dtx (C) Copyright 2020 Frank Mittelbach, LaTeX Team
-%
-% It may be distributed and/or modified under the conditions of the
-% LaTeX Project Public License (LPPL), either version 1.3c of this
-% license or (at your option) any later version. The latest version
-% of this license is in the file
+% This file is part of the LaTeX base system.
+% -------------------------------------------
%
+% It may be distributed and/or modified under the
+% conditions of the LaTeX Project Public License, either version 1.3c
+% of this license or (at your option) any later version.
+% The latest version of this license is in
% https://www.latex-project.org/lppl.txt
+% and version 1.3c or later is part of all distributions of LaTeX
+% version 2008 or later.
+%
+% This file has the LPPL maintenance status "maintained".
%
+% The list of all files belonging to the LaTeX base distribution is
+% given in the file `manifest.txt'. See also `legal.txt' for additional
+% information.
%
-% The development version of the bundle can be found below
+% The list of derived (unpacked) files belonging to the distribution
+% and covered by LPPL is defined by the unpacking scripts (with
+% extension .ins) which are part of the distribution.
%
-% https://github.com/FrankMittelbach/...
+% \fi
%
-% for those people who are interested or want to report an issue.
+% \iffalse
+%
+%%% From File: lthooks.dtx
%
% \begin{macrocode}
-\providecommand\lthooksversion{v0.9b}
-\providecommand\lthooksdate{2020/07/19}
+\def\lthooksversion{v1.0a}
+\def\lthooksdate{2020/08/31}
% \end{macrocode}
%
%<*driver>
-\RequirePackage[debug]{lthooks}
-
\documentclass{l3doc}
% bug fix fo l3doc.cls
@@ -160,17 +172,14 @@
% the current package name. See section~\ref{sec:default-label}.
% \end{function}
%
-
-
-
+%
+%
+%
% \begin{function}{\UseHook}
% \begin{syntax}
% \cs{UseHook} \Arg{hook}
% \end{syntax}
-% Execute the hook code inside a command or environment.\footnote{For
-% legacy hooks such as \hook{begindocument} it is also
-% possible to call \cs{@...hook}, e.g., \cs{@begindocumenthook},
-% but this syntax is discouraged.}
+% Execute the hook code inside a command or environment.
%
% 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
@@ -258,6 +267,12 @@
%
% \medskip
%
+% In contrast to the \texttt{voids} relationship between two labels
+% in a \cs{DeclareHookrule} this is a destructive operation as the
+% labeled code is removed from the hook data structure, whereas the
+% relationship setting can be undone by providing a different
+% relationship later.
+%
% A useful application for this declaration inside the document body
% is when one wants to temporarily add code to hooks and later remove
% it again, e.g.,
@@ -298,8 +313,19 @@
% used several times before the hook is executed then all code is
% executed in the order in which it was declared.\footnotemark
%
-% The hook doesn't have to exist for code to be added to it. This
-% allows for hooks to work regardless of package loading order.
+% It is possible to nest declarations using the same hook (or
+% different hooks), e.g.,
+% \begin{quote}
+% \cs{AddToHookNext}\Arg{hook}\verb={=\meta{code-1}^^A
+% \cs{AddToHookNext}\Arg{hook}\Arg{code-2}\verb=}=
+% \end{quote}
+% will execute \meta{code-1} next time the \meta{hook} is used and at
+% that point puts \meta{code-2} into the \meta{hook} so that it gets
+% executed on following time the hook is run.
+%
+% A hook doesn't have to exist for code to be added to it. This
+% allows for hooks to work regardless of package loading
+% order.
% See section~\ref{sec:querying}.
%
% The \meta{hook} can be specified using the dot-syntax to denote
@@ -337,7 +363,7 @@
% name---see~\cs{DeclareDefaultHookLabel}).
% A \enquote{|.|} or \enquote{|./|} anywhere else in a \meta{hook} or in
% \meta{label} is treated literally and is not replaced.
-
+%
% For example,
% inside the package \texttt{mypackage.sty}, the default label is
% \texttt{mypackage}, so the instructions:
@@ -345,15 +371,15 @@
% \NewHook {./hook}
% \AddToHook {./hook}[.]{code} % Same as \AddToHook{./hook}{code}
% \AddToHook {./hook}[./sub]{code}
-% \DeclareHookRule{begindocument}{.}{<}{babel}
+% \DeclareHookRule{begindocument}{.}{before}{babel}
% \AddToHook {file/after/foo.tex}{code}
% \end{verbatim}
% are equivalent to:
% \begin{verbatim}
-% \NewHook {mypackage/hook}[mypackage]{code}
+% \NewHook {mypackage/hook}
% \AddToHook {mypackage/hook}[mypackage]{code}
% \AddToHook {mypackage/hook}[mypackage/sub]{code}
-% \DeclareHookRule{begindocument}{mypackage}{<}{babel}
+% \DeclareHookRule{begindocument}{mypackage}{before}{babel}
% \AddToHook {file/after/foo.tex}{code} % unchanged
% \end{verbatim}
%
@@ -376,7 +402,7 @@
% because the hook is most of the time used outside of the package file
% in which it was defined. This syntax is also not available in the hook
% conditionals \cs{IfHookEmptyTF} (and \cs{hook_if_empty:nTF}) and
-% \cs{IfHookExistTF} (and \cs{hook_if_exist:nTF}) because these
+% \cs{IfHookExistsTF} (and \cs{hook_if_exist:nTF}) because these
% conditionals are used in some performance-critical parts of the hook
% management code, and because they are usually used to refer to other
% package's hooks, so the dot-syntax doesn't make much sense.
@@ -426,7 +452,7 @@
% \cs{DeclareHookRule} \Arg{hook}\Arg{label1}\Arg{relation}\Arg{label2}
% \end{syntax}
% Defines a relation between \meta{label1} and \meta{label2} for a
-% given \meta{hook}. If \meta{hook} is \texttt{??} this defines a
+% given \meta{hook}. If \meta{hook} is \texttt{??} this defines a default
% relation for all hooks that use the two labels, i.e., that have
% chunks of code labeled with \meta{label1} and \meta{label2}.
% Rules specific to a given hook take precedence over default
@@ -455,7 +481,7 @@
% \LaTeX{} error is raised, and the code for both labels are
% dropped from that hook until the conflict is resolved.
%
-% \item[\texttt{removes}]
+% \item[\texttt{voids}]
%
% Code for \meta{label1} overwrites code for \meta{label2}. More
% precisely, code for \meta{label2} is dropped for that
@@ -470,10 +496,15 @@
% specified earlier.
%
% \end{itemize}
+% There can only be a single relation between two labels for a
+% given hook,
+% i.e., a later \cs{DeclareHookrule} overwrites any previous
+% delcaration.
%
% 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}
%
%
@@ -553,9 +584,9 @@
% A leading |.| is treated literally.
% \end{function}
%
-% \begin{function}[EXP]{\IfHookExistTF}
+% \begin{function}[EXP]{\IfHookExistsTF}
% \begin{syntax}
-% \cs{IfHookExistTF} \Arg{hook} \Arg{true code} \Arg{false code}
+% \cs{IfHookExistsTF} \Arg{hook} \Arg{true code} \Arg{false code}
% \end{syntax}
% Tests if the \meta{hook} exists (if it was created with either
% \cs{NewHook}, \cs{NewReversedHook}, or \cs{NewMirroredHookPair}), and
@@ -590,10 +621,8 @@
% the code chunks (and their labels) added to it,
% \item
% any rules set up to order them,
-% \fmi{currently this is missing the default rules that apply,
-% guess that needs fixing}
% \item
-% the computed order (if already defined),
+% the computed order in which the chunks are executed,
% \item
% any code executed on the next invocation only.
% \end{itemize}
@@ -605,9 +634,9 @@
%
% \subsubsection{Debugging hook code}
%
-% \begin{function}{\DebugHookOn,\DebugHookOff}
+% \begin{function}{\DebugHooksOn,\DebugHooksOff}
% \begin{syntax}
-% \cs{DebugHookOn}
+% \cs{DebugHooksOn}
% \end{syntax}
% Turn the debugging of hook code on or off. This displays changes
% made to the hook data structures. The output is rather coarse and
@@ -706,8 +735,8 @@
% the current package name. See section~\ref{sec:default-label}.
% \end{function}
%
-
-
+%
+%
% \begin{function}{\hook_gremove_code:nn}
% \begin{syntax}
% \cs{hook_gremove_code:nn} \Arg{hook} \Arg{label}
@@ -728,8 +757,8 @@
% dot-syntax to denote the current package name.
% See section~\ref{sec:default-label}.
% \end{function}
-
-
+%
+%
% \begin{function}{\hook_gset_rule:nnnn}
% \begin{syntax}
% \cs{hook_gset_rule:nnnn} \Arg{hook} \Arg{label1} \Arg{relation} \Arg{label2}
@@ -747,7 +776,7 @@
%
% \begin{function}[pTF]{\hook_if_empty:n}
% \begin{syntax}
-% \cs{hook_if_empty:n} \Arg{hook} \Arg{true code} \Arg{false code}
+% \cs{hook_if_empty:nTF} \Arg{hook} \Arg{true code} \Arg{false code}
% \end{syntax}
% Tests if the \meta{hook} is empty (\emph{i.e.}, no code was added to
% it using either \cs{AddToHook} or \cs{AddToHookNext}), and
@@ -760,7 +789,7 @@
%
% \begin{function}[pTF]{\hook_if_exist:n}
% \begin{syntax}
-% \cs{hook_if_exist:n} \Arg{hook} \Arg{true code} \Arg{false code}
+% \cs{hook_if_exist:nTF} \Arg{hook} \Arg{true code} \Arg{false code}
% \end{syntax}
% Tests if the \meta{hook} exists (if it was created with either
% \cs{NewHook}, \cs{NewReversedHook}, or \cs{NewMirroredHookPair}), and
@@ -938,6 +967,69 @@
%
%
%
+% \subsection{Difference between \enquote{normal} and
+% \enquote{one-time} hooks}
+%
+% When executing a hook a developer has the choice of using
+% either \cs{UseHook} or \cs{UseOneTimeHook} (or their \pkg{expl3}
+% equivalents \cs{hook_use:n} and \cs{hook_use_once:n}).
+% This choice affects how \cs{AddToHook} is handled after the hook
+% has been executed for the first time.
+%
+% With normal hooks adding code via \cs{AddToHook} means that the
+% code chunk is added to the hook data structure and then used each time
+% \cs{UseHook} is called.
+%
+% With one-time hooks it this is handled slightly differently:
+% After \cs{UseOneTimeHook} has been called, any further attempts to
+% add code to the hook via \cs{AddToHook} will simply execute the
+% \meta{code} immediately.
+%
+% This has some consequences one needs to be aware of:
+% \begin{itemize}
+% \item
+%
+% If \meta{code} is added to a normal hook after the hook was
+% executed and it is never executed again for one or the other
+% reason, then this new \meta{code} will never be executed.
+%
+% \item
+%
+% In contrast if that happens with a one-time hook the \meta{code} is
+% executed immediately.
+%
+% \end{itemize}
+% In particular this means that construct such as
+%\begin{quote}
+% \cs{AddToHook}\verb={myhook}=\\
+% \phantom{\cs{AddToHook}}\verb={= \meta{code-1}
+% \cs{AddToHook}\verb={myhook}=\Arg{code-2}
+% \meta{code-3} \verb=}=
+%\end{quote}
+% works for one-time hooks\footnote{This is sometimes used with
+% \cs{AtBeginDocument} which is why it is supported.} (all three
+% code chunks are executed one after another), but it makes little
+% sense with a normal hook, because with a normal hook the first time
+% \verb=\UseHook{myhook}= is executed it would
+% \begin{itemize}
+% \item
+% execute \meta{code-1},
+% \item
+% then execute \verb=\AddToHook{myhook}{code-2}= which adds the
+% code chunk \meta{code-2} to the hook for use on the next invocation,
+% \item
+% and finally execute \meta{code-3}.
+% \end{itemize}
+% The second time \cs{UseHook} is called it would execute the
+% above and in addition \meta{code-2} as that was added as a code
+% chunk to the hook in the meantime. So each time the hook is used
+% another copy of \meta{code-2} is added and so that code chunk
+% is executed $\meta{\# of invocations} -1$ times.
+%
+%
+%
+%
+%
% \subsection{Private \LaTeX{} kernel hooks}
%
% There are a few places where it is absolutely essential for
@@ -1025,6 +1117,21 @@
% This hook is discussed in conjunction with the shipout hooks.
% \end{function}
%
+% \bigskip
+%
+% The few hooks that existed previously in \LaTeXe{} used internally
+% commands such as \cs{@begindocumenthook} and packages sometimes
+% augemented them directly rather than working through
+% \cs{AtBeginDocumement}. For that reason there is currently support
+% for this, that is, if the system detects that such an internal
+% legacy hook command contains code it adds it to the new hook
+% system under the label \texttt{legacy} so that it doesn't get
+% lost.
+%
+% However, over time the remaining cases of direct usage need
+% updating because in one of the future release of \LaTeX{} we will
+% turn this legacy support off, as it does unnecessary slow down
+% the processing.
%
%
% \subsection{\LaTeXe{} commands and environments augmented by
@@ -1052,26 +1159,31 @@
%
% \item[\hook{env/\meta{env}/end}]
%
-% This is executed as part of \cs{end} directly in front of the
+% This hook is executed as part of \cs{end} directly in front of the
% code specific to the end of the environment (e.g., the third
% argument of \cs{newenvironment}).
%
% \item[\hook{env/\meta{env}/after}]
%
-% This is executed as part of \cs{end} after the
+% This hook is executed as part of \cs{end} after the
% code specific to the environment end and after the environment
% group has ended.
% Its scope is therefore not restricted by the environment.
%
-% This hook is implemented as a reversed hook so if two packages
+% The hook is implemented as a reversed hook so if two packages
% add code to \hook{env/\meta{env}/before} and to
% \hook{env/\meta{env}/after} they can add surrounding
% environments and the order of closing them happens in the
% right sequence.
%
% \end{description}
-% In contrast to other hooks these hooks do not need to be declared
-% using \cs{NewHook}.
+% Generic environment hooks are never one-time hooks even with
+% environments that are supposed to appear only once in a
+% document.\footnote{Thus if one adds code to such hooks after the
+% environment has been processed, it will only be executed if the
+% environment appears again and if that doesn't happen the code
+% will never get executed.} In contrast to other hooks there is
+% also no need to declare them using \cs{NewHook}.
%
% The hooks are only executed if \cs{begin}\Arg{env} and
% \cs{end}\Arg{env} is used. If the environment code is executed
@@ -1087,47 +1199,78 @@
% to add the outer hooks, etc.
%
%
+% \begin{function}{\BeforeBeginEnvironment}
+% \begin{syntax}
+% \cs{BeforeBeginEnvironment} \oarg{label} \Arg{code}
+% \end{syntax}
+% This declaration adds to the \hook{env/\meta{env}/before} hook
+% using by default the current package or class name as a label or
+% \texttt{top-level} if used in the document directly.
+% \end{function}
+%
+% \begin{function}{\AtBeginEnvironment}
+% \begin{syntax}
+% \cs{AtBeginEnvironment} \oarg{label} \Arg{code}
+% \end{syntax}
+% Like \cs{BeforeBeginEnvironment} but adds to the \hook{env/\meta{env}/begin} hook.
+% \end{function}
+%
+% \begin{function}{\AtEndEnvironment}
+% \begin{syntax}
+% \cs{AtEndEnvironment} \oarg{label} \Arg{code}
+% \end{syntax}
+% Like \cs{BeforeBeginEnvironment} but adds to the \hook{env/\meta{env}/end} hook.
+% \end{function}
+%
+% \begin{function}{\AfterEndEnvironment}
+% \begin{syntax}
+% \cs{AfterEndEnvironment} \oarg{label} \Arg{code}
+% \end{syntax}
+% Like \cs{BeforeBeginEnvironment} but adds to the \hook{env/\meta{env}/after} hook.
+% \end{function}
+%
+%
+%
%
% \subsubsection{Hooks provided by \cs{begin}\texttt{\{document\}}}
%
% Until 2020 \cs{begin}\texttt{\{document\}} offered exactly one
-% hook that one had to fill using \cs{AtBeginDocument}. Experience
-% has shown that this single hook in one place was not enough and
-% as part of adding the general hook management system a number of
-% additional hooks have been added at this point. The places for
-% hooks have been chosen to provide the same support as offered by
-% external packages, such as \pkg{etoolbox} and others that
-% augmented \cs{document} to gain better control.
-%
-% Supported are now the following hooks:
+% hook that one could add to using
+% \cs{AtBeginDocument}. Experiences over the years have shown that
+% this single hook in one place was not enough and as part of
+% adding the general hook management system a number of additional
+% hooks have been added at this point. The places for these hooks have
+% been chosen to provide the same support as offered by external
+% packages, such as \pkg{etoolbox} and others that augmented
+% \cs{document} to gain better control.
+%
+% Supported are now the following hooks (all of them one-time hooks):
% \begin{description}
%
-% \item[\hook{env/document/before}]
%
-% This is the generic environment hook executed effectively
-% before \verb=\begin{document}= starts, i.e., one can think of
-% it as a hook for code at the end of the preamble section.
+% \item[\hook{begindocument/before}]
%
-% \item[\hook{env/document/begin}]
+% This hook is executed at the very start of \cs{document}, one can
+% think of it as a hook for code at the end of the preamble
+% section and this is how it is used by \pkg{etoolbox}'s
+% \cs{AtEndPreamble}.
%
-% This is the second generic environment hook that is executed
-% after the environment has started its group. But given that for the
-% \texttt{document} environment this group is canceled there is
-% little difference to the previous one as the two are directly
-% executed one after another (the only difference is that in this
-% hook \cs{@currenvir} is now set to \texttt{document} but
-% anybody adding to this hook would know that already).
%
%
% \item[\hook{begindocument}]
%
-% This hook is added to by \cs{AtBeginDocument} and is executed
+% This hook is added to when using \cs{AtBeginDocument} and it is executed
% after the \texttt{.aux} file as be read in and most
% initialization are done, so they can be altered and inspected by
% the hook code. It is followed by a small number of further
% initializations that shouldn't be altered and are therefore
% coming later.
%
+% The hook should not be used to add material for typesetting as
+% we are still in \LaTeX's initialization phase and not in the
+% document body. If such material needs to be added to the document
+% body use the next hook instead.
+%
% \item[\hook{begindocument/end}]
%
% This hook is executed at the end of the \cs{document} code in
@@ -1135,6 +1278,10 @@
% command that follows it is \cs{ignorespaces}.
%
% \end{description}
+% The generic hooks executed by \cs{begin} also exist, i.e.,
+% \hook{env/document/before} and \hook{env/document/begin}, but
+% with this special environment it is better use the dedicated
+% one-time hooks above.
%
%
%
@@ -1156,17 +1303,13 @@
% to add code in various places in a controlled way without the
% need for overwriting or patching the core code.
%
-% Supported are now the following hooks:
+% Supported are now the following hooks (all of them one-time hooks):
% \begin{description}
%
-% \item[\hook{env/document/end}] The generic hook inside \cs{end}.
-%
% \item[\hook{enddocument}]
-
+%
% The hook associated with \cs{AtEndDocument}. It is immediately
-% called after the previous hook so there could be just
-% one.\footnote{We could make \cs{AtEndDocument} just fill the
-% \hook{env/document/end} but maybe that is a bit confusing.}
+% called at the beginning of \cs{enddocument}.
%
% When this hook is executed there may be still unprocessed
% material (e.g., floats on the deferlist) and the hook may add
@@ -1230,6 +1373,16 @@
% page. See section~\ref{sec:shipout} for where to find the details.
%
%
+% It is in also possible to use the generic \hook{env/document/end}
+% hook which is execuded by \cs{end}, i.e., just in front of the
+% first hook above. Note however that the other generic \cs{end}
+% environment hook, i.e., \hook{env/document/after} will never get
+% executed, because by that time \LaTeX{} has finished the document
+% processing.
+%
+%
+%
+%
% \subsubsection{Hooks provided \cs{shipout} operations}
% \label{sec:shipout}
%
@@ -1239,7 +1392,7 @@
% \texttt{ltshipout-code.pdf}.
%
%
-% \subsubsection{Hooks provided file loading operations}
+% \subsubsection{Hooks provided by file loading operations}
%
% There are several hooks added to \LaTeX{}'s
% process of loading file via its high-level interfaces such as
@@ -1248,17 +1401,87 @@
% \texttt{ltfilehook-code.pdf}.
%
%
-
+% \subsubsection{Hooks provided in NFSS commands}
+%
+% In languages that need to support for more than one script in
+% parallel (and thus several sets of fonts), e.g., Latin and
+% Japanese fonts, NFSS font commands, such as \cs{sffamily}, need
+% to switch both the Latin family to ``Sans Serif'' and in addition
+% alter a second set of fonts.
+%
+% To support this several NFSS have hooks in which such support can
+% be added.
+% \begin{description}
+%
+% \item[\hook{rmfamily}]
+%
+% After \cs{rmfamily} has done its initial checks and prepared a
+% any font series update this hook is executed and only
+% afterwards \cs{selectfont}.
+%
+% \item[\hook{sffamily}]
+%
+% Like the \hook{rmfamily} hook but for the \cs{sffamily} command.
+%
+% \item[\hook{ttfamily}]
+%
+% Like the \hook{rmfamily} hook but for the \cs{ttfamily} command.
+%
+% \item[\hook{normalfont}]
+%
+% The \cs{normalfont} command resets font encoding family series
+% and shape to their document defaults. It then executes this
+% hook and finally calls \cs{selectfont}.
+%
+% \item[\hook{expand@font@defaults}]
+%
+% The internal \cs{expand@font@defaults} command expands and
+% saves the current defaults for the meta families (rm/sf/tt) and
+% the meta series (bf/md). If the NFSS machinery has been
+% augmented, e.g., for Chinese or Japanese fonts, then further
+% defaults may need to be set at this point. This can be done in
+% this hook which is executed at the end of this macro.
+%
+% \item[\hook{bfseries/defaults}, \hook{bfseries}]
+%
+% If the \cs{bfdefault} was explicitly changed by the user its
+% new value is used to set the bf series defaults for the meta
+% families (rm/sf/tt) when \cs{bfseries} is called. In the
+% \hook{bfseries/defaults} hook further adjustments can be made
+% in this case. This hook is only executed if such a change is
+% detected. In contrast the \hook{bfseries} hook is always
+% executed just before \cs{selectfont} is called to change to the
+% new series.
+%
+%
+% \item[\hook{mdseries/defaults}, \hook{mdseries}]
+%
+% These two hooks are like the previous ones but used in
+% \cs{mdseries} command.
+%
+% \end{description}
+%
+%
% \StopEventually{\setlength\IndexMin{200pt} \PrintIndex }
%
%
% \section{The Implementation}
+%
+%
+% \subsection{Loading further extensions}
+%
% \begin{macrocode}
%<@@=hook>
% \end{macrocode}
%
+%
+% At the moment the whole module rolls back in one go, but if we
+% make any modifications in later releases this will then need
+% splitting.
% \begin{macrocode}
-%<*2ekernel>
+%<*2ekernel|latexrelease>
+%<latexrelease>\IncludeInRelease{2020/10/01}%
+%<latexrelease> {\NewHook}{The hook management}%
% \end{macrocode}
%
% \begin{macrocode}
@@ -1300,7 +1523,7 @@
% \end{macro}
% \end{macro}
% \end{macro}
-
+%
%
%
% \subsection{Borrowing from internals of other kernel modules}
@@ -1315,6 +1538,13 @@
%
% \subsection{Declarations}
%
+% \begin{macro}{\l_@@_tmpa_bool}
+% Scratch boolean used throughout the package.
+% \begin{macrocode}
+\bool_new:N \l_@@_tmpa_bool
+% \end{macrocode}
+% \end{macro}
+%
% \begin{macro}{\l_@@_return_tl,\l_@@_tmpa_tl,\l_@@_tmpb_tl}
% Scratch variables used throughout the package.
% \begin{macrocode}
@@ -1333,7 +1563,7 @@
% \end{macro}
%
% \begin{macro}{\g_@@_removal_list_prop}
-% A property list to hold delayed removals.
+% A token list to hold delayed removals.
% \begin{macrocode}
\tl_new:N \g_@@_removal_list_tl
% \end{macrocode}
@@ -1346,11 +1576,13 @@
% \end{macrocode}
% \end{macro}
%
-% \begin{macro}{\g_@@_code_temp_prop}
-% A property list to temporarily save the original one so that it
-% isn't permanently changed during sorting.
+% \begin{macro}{\l_@@_work_prop}
+% A property list holding a copy of the
+% \cs[no-index]{g_@@_\meta{hook}_code_prop} of the hook being sorted
+% to work on, so that changes don't act destructively on the hook data
+% structure.
% \begin{macrocode}
-\prop_new:N \g_@@_code_temp_prop
+\prop_new:N \l_@@_work_prop
% \end{macrocode}
% \end{macro}
%
@@ -1387,8 +1619,7 @@
%
% \subsection{Providing new hooks}
%
-% \begin{macro}{\g_@@_..._code_prop,\g_@@_..._rules_prop,
-% \g_@@_..._code_tl,\g_@@_..._next_code_tl}
+% \begin{macro}{\g_@@_..._code_prop,\g_@@_..._code_tl,\g_@@_..._code_next_tl}
%
% Hooks have a \meta{name} and for each hook we have to provide a number of
% data structures. These are
@@ -1398,27 +1629,36 @@
% package names that add code to the hook, but it is possible
% for packages to define other keys.
%
-% \item[\cs{g_@@_\meta{name}_rules_prop}] A property listing holding
-% relation info how the code chunks should be ordered within a
-% hook. This is used for debugging only. The actual rule for a
-% \meta{hook} is stored in a separate token lists named
-% \cs[no-index]{g_@@_\meta{hook}_rule_\meta{label1}\string|\meta{label2}_tl}
-% for a pair of labels.
+% \item[{\cs[no-index]{g_@@_\meta{name}_rule_\meta{label1}\string|\meta{label2}_tl}}]
+% A token list holding the relation between \meta{label1} and
+% \meta{label2} in the \meta{name}. The \meta{labels} are lexically
+% (reverse) sorted to ensure that two labels always point to the same
+% token list. For global rules, the \meta{name} is |??|.
%
% \item[\cs{g_@@_\meta{name}_code_tl}] The code that is actually executed
% when the hook is called in the document is stored in this token
% list. It is constructed from the code chunks applying the
% information.
%
-% \item[\cs{g_@@_\meta{name}_next_code_tl}] Finally there is extra code
+% \item[\cs{g_@@_\meta{name}_reversed_tl}] Some hooks are
+% \enquote{reversed}. This token list stores a |-| for such hook
+% 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{g_@@_\meta{name}_code_next_tl}] Finally there is extra code
% (normally empty) that is used on the next invocation of the hook
% (and then deleted). This can be used to define some special
-% behavior for a single occasion from within the document.
+% behavior for a single occasion from within the document. This token
+% list is called |code_next| rather than |next_code| because otherwise
+% a hook called \meta{name}|_next| would have its code-token list
+% named \cs[no-index]{g_@@_\meta{name}_code_next_tl}, which would
+% clash with the next code-token list of a hook called \meta{name}.
%
% \end{description}
% \end{macro}
-
-
+%
+%
%
%
% \begin{macro}{\hook_new:n}
@@ -1437,7 +1677,7 @@
% already exists we complain.
% \begin{macrocode}
\hook_if_exist:nTF {#1}
- { \ErrorHookExists }
+ { \msg_error:nnn { hooks } { exists } {#1} }
% \end{macrocode}
% Otherwise we add the hook name to the list of all hooks and
% allocate the necessary data structures for the new hook.
@@ -1465,15 +1705,24 @@
\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{} for use in the current kernel. This
-% is done in a separate macro.
-% \begin{macrocode}
- \@@_provide_legacy_interface:n {#1}
+% interface to legacy \LaTeXe{} hooks of the form \cs{@...hook},
+% e.g., \cs{@begindocumenthook}.
+% there have been a few of them and they have been added to
+% using \cs{g@addto@macro}. If there exists such a macro matching
+% the name of the new hook, i.e.,
+% \verb+\@+\meta{hook-name}\texttt{hook} and it is not empty then
+% we add its contents as a code chunk under the label \texttt{legacy}.
+% \begin{quote}
+% \textbf{Warning: this support will vanish in future releases!}
+% \end{quote}
+%
+% \begin{macrocode}
+ \@@_include_legacy_code_chunk:n {#1}
}
}
% \end{macrocode}
% \end{macro}
-
+%
%
%
% \begin{macro}{\@@_declare:n}
@@ -1488,15 +1737,14 @@
\@@_if_exist:nF {#1}
{
\prop_new:c { g_@@_#1_code_prop }
- \tl_new:c { g_@@_#1_next_code_tl }
- \prop_new:c { g_@@_#1_rules_prop } % only for debugging
+ \tl_new:c { g_@@_#1_code_next_tl }
}
}
% \end{macrocode}
% \end{macro}
-
-
-
+%
+%
+%
% \begin{macro}{\hook_new_reversed:n}
%
% Declare a new hook. The default ordering of code chunks is
@@ -1504,11 +1752,16 @@
% \begin{macrocode}
\cs_new_protected:Npn \hook_new_reversed:n #1 {
\hook_new:n {#1}
+% \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 } { - }
}
% \end{macrocode}
% \end{macro}
-
+%
% \begin{macro}{\hook_new_pair:nn}
% A shorthand for declaring a normal and a (matching) reversed hook in one go.
% \begin{macrocode}
@@ -1517,23 +1770,21 @@
}
% \end{macrocode}
% \end{macro}
-
-
-% \begin{macro}{\@@_provide_legacy_interface:n}
+%
+%
+% \begin{macro}{\@@_include_legacy_code_chunk:n}
% The \LaTeX{} legacy concept for hooks uses with hooks the
% following naming scheme in the code: \cs{@...hook}.
%
-% We follow this convention and insert the hook code using this
-% naming scheme in \LaTeXe{}. At least as long as this code is in a
-% package, some such hooks are already filled with data when we move
-% them over to the new scheme. We therefore insert already existing
-% code under the label \texttt{legacy} into the hook management
-% machinery and then replace the \cs{@...hook} with its counterpart
-% which is \cs{g_@@_\#1_code_tl}.\footnote{This means one extra
-% unnecessary expansion on each invocation in the document but
-% keeps the \LaTeXe{} and the L3 coding side properly separated.}
+% If this macro is not empty we add it under the label
+% \texttt{legacy} to the current hook and then empty it globally.
+% This way packages or classes directly manipulating commands such
+% as \cs{@begindocumenthook} still get their hook data added.
+% \begin{quote}
+% \textbf{Warning: this support will vanish in future releases!}
+% \end{quote}
% \begin{macrocode}
-\cs_new_protected:Npn \@@_provide_legacy_interface:n #1
+\cs_new_protected:Npn \@@_include_legacy_code_chunk:n #1
{
% \end{macrocode}
% If the \pkg{expl3} code is run with checking on then assigning or
@@ -1542,32 +1793,34 @@
% debugging explicitly suspended.
% \begin{macrocode}
\debug_suspend:
+% \end{macrocode}
+% If the macro doesn't exist (which is the usual case) then nothing
+% needs to be done.
+% \begin{macrocode}
\tl_if_exist:cT { @#1hook }
% \end{macrocode}
-% Of course if the hook exists but is still empty, there is no need
-% to add anything under \texttt{legacy} or the current package name.
+% 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 }
{
- \@@_gput_code:nxv {#1}
- { \@@_parse_label_default:Vn \c_novalue_tl { legacy } }
- { @#1hook }
- }
- }
+ \exp_args:Nnnv \@@_hook_gput_code_do:nnn {#1}
+ { legacy } { @#1hook }
% \end{macrocode}
-% We need a global definition in case the declaration is done
-% inside a group (which happens below at the end of the file).
-% This is another reason why need to suspend checking, otherwise
-% \cs{tl_gset:co} would complain about \cs{@...hook} not starting
-% with \cs{g_}.
+% Once added to the hook, we need to clear it otherwise it might
+% get added again later if the hook data gets updated.
% \begin{macrocode}
- \tl_gset:co{@#1hook}{\cs:w g_@@_#1_code_tl\cs_end:}
+ \tl_gclear:c { @#1hook }
+ }
+ }
\debug_resume:
}
% \end{macrocode}
% \end{macro}
%
+%
+%
% \subsection{Parsing a label}
%
% \begin{macro}[EXP]{\@@_parse_label_default:nn,\@@_parse_label_default:Vn}
@@ -1647,10 +1900,10 @@
}
% \end{macrocode}
% \end{macro}
-
-
-
-
+%
+%
+%
+%
% \begin{macro}{\hook_gput_code:nnn}
% \begin{macro}{\@@_gput_code:nnn,\@@_gput_code:nxv,\@@_hook_gput_code_do:nnn}
%
@@ -1667,13 +1920,19 @@
\cs_new_protected:Npn \@@_gput_code:nnn #1 #2 #3
{
% \end{macrocode}
-% First we check if the hook exists.
+% First check if the current \meta{hook}/\meta{label} pair was marked
+% for removal, in which case \cs{@@_unmark_removal:nn} is used to
+% remove that mark (once). This may happen when a package removes
+% code from another package which was not yet loaded: the removal
+% order is stored, and at this stage it is executed by not adding to
+% the hook.
% \begin{macrocode}
\@@_if_marked_removal:nnTF {#1} {#2}
{ \@@_unmark_removal:nn {#1} {#2} }
{
% \end{macrocode}
-% First we check if the hook exists.
+% If no removal is queued, we are free to add. Start by checking if
+% the hook exists.
% \begin{macrocode}
\hook_if_exist:nTF {#1}
% \end{macrocode}
@@ -1691,7 +1950,10 @@
\@@_update_hook_code:n {#1}
}
% \end{macrocode}
-%
+%
+% If the hook does not exist, however, before giving up try to
+% declare it as a generic hook, if its name matches one of the valid
+% patterns.
% \begin{macrocode}
{ \@@_try_declaring_generic_hook:nnn {#1} {#2} {#3} }
}
@@ -1699,20 +1961,21 @@
\cs_generate_variant:Nn \@@_gput_code:nnn { nxv }
% \end{macrocode}
%
-% This macro will unconditionally add a chunk of code to the given hook.
+% This macro will unconditionally add a chunk of code to the given hook.
% \begin{macrocode}
\cs_new_protected:Npn \@@_hook_gput_code_do:nnn #1 #2 #3
{
-% However, first some debugging info if debugging is enabled:
+% \end{macrocode}
+% However, first some debugging info if debugging is enabled:
% \begin{macrocode}
\@@_debug:n{\iow_term:x{****~ Add~ to~
\hook_if_exist:nF {#1} { undeclared~ }
hook~ #1~ (#2)
\on@line\space <-~ \tl_to_str:n{#3}} }
% \end{macrocode}
-% Then try to get the code chunk labeled \verb=#2= from the hook.
-% If there's code already there, then append \verb=#3= to that,
-% otherwise just put \verb=#3=.
+% Then try to get the code chunk labeled \verb=#2= from the hook.
+% If there's code already there, then append \verb=#3= to that,
+% otherwise just put \verb=#3=.
% \begin{macrocode}
\prop_get:cnNTF { g_@@_#1_code_prop } {#2} \l_@@_return_tl
{
@@ -1786,7 +2049,7 @@
\@@_if_file_hook:wTF #1 / / \s_@@_mark
{
\exp_args:Ne \@@_try_declaring_generic_hook_split:nNNnn
- { \exp_args:Ne \@@_file_hook_normalise:n {#1} }
+ { \exp_args:Ne \@@_file_hook_normalize:n {#1} }
}
{ \@@_try_declaring_generic_hook_split:nNNnn {#1} }
}
@@ -1867,16 +2130,16 @@
% \end{macrocode}
% \end{macro}
%
-% \begin{macro}[EXP]{\@@_file_hook_normalise:n}
+% \begin{macro}[EXP]{\@@_file_hook_normalize:n}
% \begin{macro}[EXP]{\@@_strip_double_slash:n,\@@_strip_double_slash:w}
% When a file-specific hook is found, before being declared it is
-% lightly normalized by \cs{@@_file_hook_normalise:n}. The current
+% lightly normalized by \cs{@@_file_hook_normalize:n}. The current
% implementation just replaces two consecutive slashes (|//|) by a
% single one, to cope with simple cases where the user did something
% like \verb|\def\input@path{{./mypath/}}|, in which case a hook would
% have to be \verb|\AddToHook{file/after/./mypath//file.tex}|.
% \begin{macrocode}
-\cs_new:Npn \@@_file_hook_normalise:n #1
+\cs_new:Npn \@@_file_hook_normalize:n #1
{ \@@_strip_double_slash:n {#1} }
\cs_new:Npn \@@_strip_double_slash:n #1
{ \@@_strip_double_slash:w #1 // \s_@@_mark }
@@ -1889,13 +2152,9 @@
% \end{macrocode}
% \end{macro}
% \end{macro}
-
-
-
-
-
+%
% \begin{macro}{\c_@@_generics_prop}
-% Clist holding the generic names. We don't provide any user
+% Property list holding the generic names. We don't provide any user
% interface to this as this is meant to be static.
% \begin{description}
% \item[\texttt{env}]
@@ -1920,17 +2179,7 @@
\prop_const_from_keyval:Nn \c_@@_generics_file_prop {before=,after=}
% \end{macrocode}
% \end{macro}
-
-
-% \begin{macro}{\@@_update_hook_code:n}
-% Before \verb=\begin{document}= this does nothing, in the body it
-% reinitializes the hook code using the altered data.
-% \begin{macrocode}
-\cs_new_eq:NN \@@_update_hook_code:n \use_none:n
-% \end{macrocode}
-% \end{macro}
-
-
+%
% \begin{macro}{\hook_gremove_code:nn}
% \begin{macro}{\@@_gremove_code:nn}
%
@@ -1958,10 +2207,7 @@
% \begin{macrocode}
{
\str_if_eq:nnTF {#2} {*}
- {
- \prop_gclear:c { g_@@_#1_code_prop }
- \clist_gclear:c { g_@@_#1_labels_clist } % for debugging only
- }
+ { \prop_gclear:c { g_@@_#1_code_prop } }
{
% \end{macrocode}
% Check if the label being removed exists in the code pool. If it does,
@@ -1979,6 +2225,12 @@
\hook_if_exist:nT {#1}
{ \@@_update_hook_code:n {#1} }
}
+% \end{macrocode}
+%
+% If the code pool for this hook doesn't exist it means that nothing
+% tried to add to it before, so we just queue this removal order for
+% later.
+% \begin{macrocode}
{ \@@_mark_removal:nn {#1} {#2} }
}
% \end{macrocode}
@@ -1986,26 +2238,18 @@
% \begin{macro}{\@@_gremove_code_do:nn}
% \begin{macrocode}
\cs_new_protected:Npn \@@_gremove_code_do:nn #1 #2
- {
- \prop_gremove:cn { g_@@_#1_code_prop } {#2}
-% \end{macrocode}
-% Removing the dropped label from \verb=\g_@@_#1_labels_clist= is
-% rather tricky, because that clists holds the labels as strings
-% (i.e., not ordinary text which is what we have in \verb=#2=).
-% \begin{macrocode}
- \exp_args:Nco \clist_gremove_all:Nn
- { g_@@_#1_labels_clist } { \tl_to_str:n {#2} } % for debugging only
- }
+ { \prop_gremove:cn { g_@@_#1_code_prop } {#2} }
% \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
-
-
%
% \begin{macro}{\@@_mark_removal:nn}
% Marks \meta{label} (\verb=#2=) to be removed from \meta{hook}
-% (\verb=#1=).
+% (\verb=#1=). The number of removals should be fairly small, and
+% \cs{tl_gremove_once:Nx} is fairly efficient even for longer token
+% lists, so we use a single global token list, rather than one for
+% each hook.
% \begin{macrocode}
\cs_new_protected:Npn \@@_mark_removal:nn #1 #2
{
@@ -2044,29 +2288,24 @@
%
% \begin{macro}[rEXP]{\@@_removal_tl:nn}
% Builds a token list with \verb=#1= and \verb=#2= which can only be
-% matched by \verb=#1= and \verb=#2=.
+% matched by \verb=#1= and \verb=#2=. The |&|$_4$ anchors a removal,
+% so that \verb=#1= can't be mistaken by \verb=#2= and vice versa, and
+% the two |$|$_3$ delimit the two arguments
% \begin{macrocode}
\cs_new:Npn \@@_removal_tl:nn #1 #2
{ & \tl_to_str:n {#2} $ \tl_to_str:n {#1} $ }
% \end{macrocode}
% \end{macro}
-
-
-
-
-%
%
%
% \begin{macro}{
-% \g_@@_??_rules_prop,
% \g_@@_??_code_prop,
% \g_@@_??_code_tl,
% \g_@@_??_reversed_tl,
% }
%
-% Default rules applying to all hooks are stored in this property
-% list. Initially it simply used an empty ``label'' name (not two
-% question marks). This was a bit unfortunate, because then
+% Initially these variables simply used an empty ``label'' name (not
+% two question marks). This was a bit unfortunate, because then
% \texttt{l3doc} complains about \verb=__= in the middle of a
% command name when trying to typeset the documentation. However
% using a ``normal'' name such as \texttt{default} has the
@@ -2079,7 +2318,6 @@
% \cs{g_@@_??_code_tl} isn't used, but it has to be defined to trick
% the code into thinking that \verb=??= is actually a hook.
% \begin{macrocode}
-\prop_new:c {g_@@_??_rules_prop}
\prop_new:c {g_@@_??_code_prop}
\prop_new:c {g_@@_??_code_tl}
% \end{macrocode}
@@ -2093,53 +2331,6 @@
\tl_new:c {g_@@_??_reversed_tl}
% \end{macrocode}
% \end{macro}
-
-
-
-% \begin{macro}{\@@_debug_gset_rule:nnnn}
-%
-% \fmi{this needs cleanup and docu correction!}
-%
-% With
-% \cs{@@_debug_gset_rule:nnnn}\Arg{hook}\Arg{label1}\Arg{relation}\Arg{label2}
-% a relation is defined between the two code labels for the given
-% \meta{hook}. The special hook \texttt{??} stands for \emph{any}
-% hook describing a default rule.
-% \begin{macrocode}
-\cs_new_protected:Npn \@@_debug_gset_rule:nnnn #1#2#3#4
- {
-% \end{macrocode}
-% If so we drop any existing rules with the two labels (in case
-% there are any).
-% \begin{macrocode}
- \prop_gremove:cn{g_@@_#1_rules_prop}{#2|#4}
- \prop_gremove:cn{g_@@_#1_rules_prop}{#4|#2}
-% \end{macrocode}
-% Then we add the new one (normalizing the input a bit, e.g., we
-% always use \texttt{before} and not \texttt{after} and
-% instead reorder the labels):
-% \begin{macrocode}
- \str_case_e:nnF {#3}
- {
- {before} { \prop_gput:cnn {g_@@_#1_rules_prop}{#2|#4}{<} }
- {after} { \prop_gput:cnn {g_@@_#1_rules_prop}{#4|#2}{<} }
-% \end{macrocode}
-% More special rule types \ldots
-% \begin{macrocode}
- {incompatible-error} { \prop_gput:cnn {g_@@_#1_rules_prop}{#2|#4}{xE} }
- {incompatible-warning} { \prop_gput:cnn {g_@@_#1_rules_prop}{#2|#4}{xW} }
- {removes} { \prop_gput:cnn {g_@@_#1_rules_prop}{#2|#4}{->} }
-% \end{macrocode}
-% Undo a setting:
-% \begin{macrocode}
- {unrelated}{ \prop_gremove:cn {g_@@_#1_rules_prop}{#2|#4}
- \prop_gremove:cn {g_@@_#1_rules_prop}{#4|#2} }
- }
- { \ERRORunknownrule }
- }
-% \end{macrocode}
-% \end{macro}
-%
%
% \subsection{Setting rules for hooks code}
%
@@ -2188,9 +2379,9 @@
{#1} {#2} {#4}
\@@_update_hook_code:n {#1}
}
- { \ERRORunknownrule }
+ { \msg_error:nnnnnn { hooks } { unknown-rule }
+ {#1} {#2} {#3} {#4} }
\debug_resume:
- \@@_debug_gset_rule:nnnn {#1} {#2} {#3} {#4} % for debugging
}
% \end{macrocode}
% \end{macro}
@@ -2200,10 +2391,10 @@
% \@@_rule_<_gset:nnn, \@@_rule_>_gset:nnn}
% Then we add the new rule. We need to normalize the rules here to
% allow for faster processing later. Given a pair of labels
-% $l_A$ and $l_B$, the rule $l_A>l_B$ is the same as $l_B<l_A$\fmi{}
-% said differently. But normalizing the
-% forms of the rule to a single representation, say, $l_B<l_A$, then
-% the time spent looking for the rules later is considerably reduced.
+% $l_A$ and $l_B$, the rule $l_A>l_B$ is the same as $l_B<l_A$
+% only presented differently. But by normalizing the
+% forms of the rule to a single representation, say, $l_B<l_A$, reduces
+% the time spent looking for the rules later considerably.
%
% Here we do that normalization by using \cs[no-index]{(pdf)strcmp} to
% lexically sort labels $l_A$ and $l_B$ to a fixed order. This order
@@ -2232,11 +2423,11 @@
% \end{macrocode}
% \end{macro}
%
-% \begin{macro}{\@@_rule_removes_gset:nnn}
+% \begin{macro}{\@@_rule_voids_gset:nnn}
% This rule removes (clears, actually) the code from label |#3| if
% label |#2| is in the hook |#1|.
% \begin{macrocode}
-\cs_new_protected:Npn \@@_rule_removes_gset:nnn #1#2#3
+\cs_new_protected:Npn \@@_rule_voids_gset:nnn #1#2#3
{
\tl_gset:cx { g_@@_#1_rule_ \@@_label_pair:nn {#2} {#3} _tl }
{ \@@_label_ordered:nnTF {#2} {#3} { -> } { <- } }
@@ -2299,7 +2490,7 @@
% \end{macro}
%
% \begin{macro}[EXP]{\@@_if_label_case:nnnnn}
-% To avoid doing the string comparison twice in \cs{@@_initialize_single:NNNNn}
+% To avoid doing the string comparison twice in \cs{@@_initialize_single:NNNn}
% (once with \cs{str_if_eq:nn} and again with \cs{@@_label_ordered:nn}),
% we use a three-way branching macro that will compare |#1| and |#2|
% and expand to \cs{use_i:nnn} if they are equal, \cs{use_ii:nn} if
@@ -2314,8 +2505,15 @@
}
% \end{macrocode}
% \end{macro}
-
-
+%
+% \begin{macro}{\@@_update_hook_code:n}
+% Before \verb=\begin{document}= this does nothing, in the body it
+% reinitializes the hook code using the altered data.
+% \begin{macrocode}
+\cs_new_eq:NN \@@_update_hook_code:n \use_none:n
+% \end{macrocode}
+% \end{macro}
+%
% \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
@@ -2349,7 +2547,6 @@
\exp_not:v {g_@@_##1_code_tl}~ }
}
}
-%
% \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
@@ -2360,9 +2557,9 @@
}
% \end{macrocode}
% \end{macro}
-
-
-
+%
+%
+%
% \begin{macro}{\@@_initialize_hook_code:n}
% Initializing or reinitializing the fast execution hook code. In
% the preamble this is selectively done in case a hook gets used
@@ -2373,12 +2570,20 @@
\@@_debug:n{ \iow_term:x{^^JUpdate~ code~ for~ hook~
'#1' \on@line :^^J} }
% \end{macrocode}
-% This does the sorting and the updates. If there aren't any code
+% This does the sorting and the updates.
+% First thing we do is to check if a legacy hook macro exists and
+% if so we add it to the hook under the label \texttt{legacy}. This
+% might make the hook non-empty so we have to do this before
+% the then following test.
+% \begin{macrocode}
+ \@@_include_legacy_code_chunk:n {#1}
+% \end{macrocode}
+% If there aren't any code
% chunks for the current hook, there is no point in even starting
% the sorting routine so we make a quick test for that and in that
% case just update \cs{g_@@_\meta{hook}_code_tl} to hold the next
% code. If there are code chunks we call
-% \cs{@@_initialize_single:NNNNn} and pass to it ready made csnames
+% \cs{@@_initialize_single:NNNn} and pass to it ready made csnames
% as they are needed several times inside. This way we save a bit
% on processing time if we do that up front.
% \begin{macrocode}
@@ -2386,7 +2591,7 @@
{
\prop_if_empty:cTF {g_@@_#1_code_prop}
{ \tl_gset:co {g_@@_#1_code_tl}
- {\cs:w g_@@_#1_next_code_tl \cs_end: } }
+ {\cs:w g_@@_#1_code_next_tl \cs_end: } }
{
% \end{macrocode}
% By default the algorithm sorts the code chunks and then saves the
@@ -2403,38 +2608,39 @@
\cs_set_eq:NN \@@_clist_gput:NV \clist_gput_right:NV }
% \end{macrocode}
%
-% When sorting, some relations (namely \verb|->| \verb|<-|) need to
+% When sorting, some relations (namely \verb|voids|) need to
% act destructively on the code property lists to remove code that
-% shouldn't appear in the sorted hook token list.
+% shouldn't appear in the sorted hook token list, so we temporarily
+% save the old code property list so that it can be restored later.
% \begin{macrocode}
- \prop_gset_eq:Nc \g_@@_code_temp_prop { g_@@_#1_code_prop }
- \@@_initialize_single:ccccn
- { g_@@_#1_code_prop } { g_@@_#1_code_tl }
- { g_@@_#1_next_code_tl } { g_@@_#1_labels_clist }
- {#1}
- \prop_gset_eq:cN { g_@@_#1_code_prop } \g_@@_code_temp_prop
+ \prop_set_eq:Nc \l_@@_work_prop { g_@@_#1_code_prop }
+ \@@_initialize_single:cccn
+ { g_@@_#1_code_tl } { g_@@_#1_code_next_tl }
+ { g_@@_#1_labels_clist } {#1}
% \end{macrocode}
% For debug display we want to keep track of those hooks that
% actually got code added to them, so we record that in plist. We
% use a plist to ensure that we record each hook name only once,
-% i.e., we are only interested in storing the keys and the value is arbitrary
+% i.e., we are only interested in storing the keys and the value is
+% arbitrary.
% \begin{macrocode}
- \@@_debug:n{ \exp_args:NNx \prop_gput:Nnn \g_@@_used_prop {#1}{} }
+ \@@_debug:n{ \exp_args:NNx \prop_gput:Nnn
+ \g_@@_used_prop {#1}{} }
}
}
}
% \end{macrocode}
% \end{macro}
-
-
+%
+%
% \begin{macro}{\g_@@_used_prop}
% All hooks that receive code (for use in debugging display).
% \begin{macrocode}
\prop_new:N\g_@@_used_prop
% \end{macrocode}
% \end{macro}
-
-
+%
+%
%
% \begin{macro}[EXP]{\@@_tl_csname:n,\@@_seq_csname:n}
% It is faster to pass a single token and expand it when necessary
@@ -2446,7 +2652,7 @@
% \end{macrocode}
% \end{macro}
%
-
+%
%
%
% \begin{macro}{\l_@@_labels_seq,\l_@@_labels_int,\l_@@_front_tl,
@@ -2486,11 +2692,11 @@
%
% \end{itemize}
% \end{macro}
-
-
-% \begin{macro}{\@@_initialize_single:NNNNn,\@@_initialize_single:ccccn}
%
-% \cs{@@_initialize_single:NNNNn} implements the sorting of the code
+%
+% \begin{macro}{\@@_initialize_single:NNNn,\@@_initialize_single:cccn}
+%
+% \cs{@@_initialize_single:NNNn} implements the sorting of the code
% chunks for a hook and saves the result in the token list for fast
% execution (\verb=#3=). The arguments are \meta{hook-code-plist},
% \meta{hook-code-tl}, \meta{hook-next-code-tl},
@@ -2506,7 +2712,7 @@
% the moment: a label can't be equal to the number 0! \fmi{Needs
% checking for, just in case}
% \begin{macrocode}
-\cs_new_protected:Npn \@@_initialize_single:NNNNn #1#2#3#4#5 {
+\cs_new_protected:Npn \@@_initialize_single:NNNn #1#2#3#4 {
% \end{macrocode}
%
% \begin{macrocode}
@@ -2520,7 +2726,7 @@
%
% Store the name of the hook:
% \begin{macrocode}
- \tl_set:Nn \l_@@_cur_hook_tl {#5}
+ \tl_set:Nn \l_@@_cur_hook_tl {#4}
% \end{macrocode}
%
% We loop over the property list holding the code and record all
@@ -2530,20 +2736,18 @@
% to ensure that labels named |front|, |rear|, |labels|, or |return|
% don't interact with our code.
% \begin{macrocode}
- \prop_map_inline:Nn #1
+ \prop_map_inline:Nn \l_@@_work_prop
{
\int_incr:N \l_@@_labels_int
\seq_put_right:Nn \l_@@_labels_seq {##1}
- \tl_set:cn { \@@_tl_csname:n {##1} }{0} % the counter k for number of
- % j before k rules
- \seq_clear_new:c { \@@_seq_csname:n {##1} } % sequence of successors to k
- % i.e., k before j rules (stores
- % the names of the j's)
+ \tl_set:cn { \@@_tl_csname:n {##1} }{0}
+ \seq_clear_new:c { \@@_seq_csname:n {##1} }
}
% \end{macrocode}
% Steps T2 and T3: Sort the relevant rules into the data structure\ldots
%
-% This loop constitutes a square matrix of the labels in |#1| in the
+% This loop constitutes a square matrix of the labels in
+% \cs{l_@@_work_prop} in the
% vertical and the horizontal directions. However since the rule
% $l_A\meta{rel}l_B$ is the same as $l_B\meta{rel}^{-1}l_A$ we can cut
% the loop short at the diagonal of the matrix (\emph{i.e.}, when
@@ -2554,29 +2758,29 @@
% \cs{@@_apply_label_pair:nnn}, which takes the properly-ordered pair
% of labels as argument.
% \begin{macrocode}
- \prop_map_inline:Nn #1
+ \prop_map_inline:Nn \l_@@_work_prop
{
- \prop_map_inline:Nn #1
+ \prop_map_inline:Nn \l_@@_work_prop
{
\@@_if_label_case:nnnnn {##1} {####1}
{ \prop_map_break: }
{ \@@_apply_label_pair:nnn {##1} {####1} }
{ \@@_apply_label_pair:nnn {####1} {##1} }
- {#5}
+ {#4}
}
}
% \end{macrocode}
% Take a breath and take a look at the data structures that have
% been set up:
% \begin{macrocode}
- \@@_debug:n { \@@_debug_label_data:N #1 }
+ \@@_debug:n { \@@_debug_label_data:N \l_@@_work_prop }
% \end{macrocode}
%
%
% Step T4:
% \begin{macrocode}
\tl_set:Nn \l_@@_rear_tl { 0 }
- \tl_set:cn { \@@_tl_csname:n { 0 } } { 0 } % really {l_@@_label_ \l_@@_rear_tl _tl}
+ \tl_set:cn { \@@_tl_csname:n { 0 } } { 0 }
\seq_map_inline:Nn \l_@@_labels_seq
{
\int_compare:nNnT { \cs:w \@@_tl_csname:n {##1} \cs_end: } = 0
@@ -2589,8 +2793,8 @@
% \end{macrocode}
%
% \begin{macrocode}
- \tl_gclear:N #2
- \clist_gclear:N #4
+ \tl_gclear:N #1
+ \clist_gclear:N #3
% \end{macrocode}
%
% The whole loop combines steps T5--T7:
@@ -2601,12 +2805,12 @@
% This part is step T5:
% \begin{macrocode}
\int_decr:N \l_@@_labels_int
- \prop_get:NVN #1 \l_@@_front_tl \l_@@_return_tl
- \@@_tl_gput:NV #2 \l_@@_return_tl
+ \prop_get:NVN \l_@@_work_prop \l_@@_front_tl \l_@@_return_tl
+ \@@_tl_gput:NV #1 \l_@@_return_tl
% \end{macrocode}
%
% \begin{macrocode}
- \@@_clist_gput:NV #4 \l_@@_front_tl
+ \@@_clist_gput:NV #3 \l_@@_front_tl
\@@_debug:n{ \iow_term:x{Handled~ code~ for~ \l_@@_front_tl} }
% \end{macrocode}
%
@@ -2617,8 +2821,11 @@
\seq_map_inline:cn { \@@_seq_csname:n { \l_@@_front_tl } }
{
\tl_set:cx { \@@_tl_csname:n {##1} }
- { \int_eval:n { \cs:w \@@_tl_csname:n {##1} \cs_end: - 1 } }
- \int_compare:nNnT { \cs:w \@@_tl_csname:n {##1} \cs_end: } = 0
+ { \int_eval:n
+ { \cs:w \@@_tl_csname:n {##1} \cs_end: - 1 }
+ }
+ \int_compare:nNnT
+ { \cs:w \@@_tl_csname:n {##1} \cs_end: } = 0
{
\tl_set:cn { \@@_tl_csname:n { \l_@@_rear_tl } } {##1}
\tl_set:Nn \l_@@_rear_tl {##1}
@@ -2627,7 +2834,8 @@
% \end{macrocode}
% and step T7:
% \begin{macrocode}
- \tl_set_eq:Nc \l_@@_front_tl { \@@_tl_csname:n { \l_@@_front_tl } }
+ \tl_set_eq:Nc \l_@@_front_tl
+ { \@@_tl_csname:n { \l_@@_front_tl } }
% \end{macrocode}
%
% This is step T8: If we haven't moved the code for all labels
@@ -2644,15 +2852,15 @@
% This is not really the information one needs in the error case
% but will do for now \ldots \fmi{fix}
% \begin{macrocode}
- \@@_debug_label_data:N #1
+ \@@_debug_label_data:N \l_@@_work_prop
\iow_term:x{====================}
}
% \end{macrocode}
-% After we have added all hook code to \verb=#2= we finish it off
+% After we have added all hook code to \verb=#1= we finish it off
% with adding extra code for a one time execution. That is stored
-% in \verb=#3= but is normally empty.
+% in \verb=#2= but is normally empty.
% \begin{macrocode}
- \tl_gput_right:Nn #2 {#3}
+ \tl_gput_right:Nn #1 {#2}
% \end{macrocode}
%
% \begin{macrocode}
@@ -2661,12 +2869,12 @@
% \end{macrocode}
%
% \begin{macrocode}
-\cs_generate_variant:Nn \@@_initialize_single:NNNNn {cccc}
+\cs_generate_variant:Nn \@@_initialize_single:NNNn {ccc}
% \end{macrocode}
% \end{macro}
-
-
-
+%
+%
+%
% \begin{macro}{\@@_tl_gput:NV,\@@_clist_gput:NV}
% These append either on the right (normal hook) or on the left
% (reversed hook). This is setup up in
@@ -2676,8 +2884,8 @@
\cs_new:Npn \@@_clist_gput:NV {\ERROR}
% \end{macrocode}
% \end{macro}
-
-
+%
+%
%
% \begin{macro}{\@@_apply_label_pair:nnn,\@@_label_if_exist_apply:nnnF}
%
@@ -2732,10 +2940,10 @@
}
% \end{macrocode}
% \end{macro}
-
-
-
-
+%
+%
+%
+%
% \begin{macro}{\@@_apply_rule:nnn}
% This is the code executed in steps T2 and T3 while looping through
% the matrix This is part of step T3. We are about to apply the next
@@ -2798,13 +3006,15 @@
%
% \begin{macro}{\@@_apply_rule_->:nnn,\@@_apply_rule_<-:nnn}
% If we see \texttt{\detokenize{->}} we have to drop code for label
-% \verb=#3= and carry on. We could do a little better and trop
+% \verb=#3= and carry on. We could do a little better and drop
% everything for that label since it doesn't matter where we sort
% in the empty code. However that would complicate the algorithm a
-% lot with little gain. So we still unnecessarily try to sort it in
-% and depending on the rules that might result in a loop that is
-% otherwise resolved. If that turns out to be a real issue, we can
-% improve the code.
+% lot with little gain.\footnote{This also hase the advantage that
+% the result of the sorting doesn't change which might otherwise
+% (for unrelated chunks) if we aren't careful.} So we still
+% unnecessarily try to sort it in and depending on the rules that
+% might result in a loop that is otherwise resolved. If that turns
+% out to be a real issue, we can improve the code.
%
% Here the code is removed from \cs{l_@@_cur_hook_tl} rather than
% \verb=#3= because the latter may be \verb=??=, and the default
@@ -2817,9 +3027,10 @@
{
\@@_msg_pair_found:nnn {#1} {#2} {#3}
\iow_term:x{--->~ Drop~ '#2'~ code~ from~
- \iow_char:N \\ g_@@_ \l_@@_cur_hook_tl _code_prop ~ because~ of~ '#1' }
+ \iow_char:N \\ g_@@_ \l_@@_cur_hook_tl _code_prop ~
+ because~ of~ '#1' }
}
- \prop_gput:cnn { g_@@_ \l_@@_cur_hook_tl _code_prop } {#2} { }
+ \prop_put:Nnn \l_@@_work_prop {#2} { }
}
\cs_new_protected:cpn { @@_apply_rule_<-:nnn } #1#2#3
{
@@ -2827,13 +3038,14 @@
{
\@@_msg_pair_found:nnn {#1} {#2} {#3}
\iow_term:x{--->~ Drop~ '#1'~ code~ from~
- \iow_char:N \\ g_@@_ \l_@@_cur_hook_tl _code_prop ~ because~ of~ '#2' }
+ \iow_char:N \\ g_@@_ \l_@@_cur_hook_tl _code_prop ~
+ because~ of~ '#2' }
}
- \prop_gput:cnn { g_@@_ \l_@@_cur_hook_tl _code_prop } {#1} { }
+ \prop_put:Nnn \l_@@_work_prop {#1} { }
}
% \end{macrocode}
% \end{macro}
-
+%
% \begin{macro}{
% \@@_apply_-rule_<:nnn,
% \@@_apply_-rule_>:nnn,
@@ -2851,27 +3063,28 @@
\cs_new_eq:cc { @@_apply_-rule_xW:nnn } { @@_apply_rule_xW:nnn }
% \end{macrocode}
% \end{macro}
-
-
+%
+%
% \begin{macro}{\@@_msg_pair_found:nnn}
% A macro to avoid moving this many tokens around.
% \begin{macrocode}
\cs_new_protected:Npn \@@_msg_pair_found:nnn #1#2#3
{
\iow_term:x{~ \str_if_eq:nnTF {#3} {??} {default} {~normal} ~
- rule~ \@@_label_pair:nn {#1} {#2}:~
- \use:c { g_@@_#3_rule_ \@@_label_pair:nn {#1} {#2} _tl } ~ found}
+ rule~ \@@_label_pair:nn {#1} {#2}:~
+ \use:c { g_@@_#3_rule_ \@@_label_pair:nn {#1} {#2} _tl } ~
+ found}
}
% \end{macrocode}
% \end{macro}
-
-
+%
+%
% \begin{macro}{\@@_debug_label_data:N}
%
% \begin{macrocode}
\cs_new_protected:Npn \@@_debug_label_data:N #1 {
\iow_term:x{Code~ labels~ for~ sorting:}
- \iow_term:x{~ \seq_use:Nnnn\l_@@_labels_seq {~and~}{,~}{~and~} } % fix name!
+ \iow_term:x{~ \seq_use:Nnnn\l_@@_labels_seq {~and~}{,~}{~and~} }
\iow_term:x{^^J Data~ structure~ for~ label~ rules:}
\prop_map_inline:Nn #1
{
@@ -2883,9 +3096,9 @@
}
% \end{macrocode}
% \end{macro}
-
-
-
+%
+%
+%
% \begin{macro}{\hook_log:n}
% This writes out information about the hook given in its argument
% onto the terminal and the \texttt{.log} file.
@@ -2897,6 +3110,7 @@
}
\cs_new_protected:Npn \@@_log:n #1
{
+ \@@_preamble_hook:n {#1}
\iow_term:x{^^JThe~ hook~ '#1':}
% \end{macrocode}
%
@@ -2917,26 +3131,42 @@
% \begin{macrocode}
\iow_term:x{~Extra~ code~ next~ invocation:}
\iow_term:x{\@spaces
- \tl_if_empty:cTF { g_@@_#1_next_code_tl }
- {---} {->~ \str_use:c{g_@@_#1_next_code_tl} } }
+ \tl_if_empty:cTF { g_@@_#1_code_next_tl }
+ {---}
+% \end{macrocode}
+% If the token list is not empty we want to display it but without
+% 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 {g_@@_#1_code_next_tl} } }
% \end{macrocode}
%
-% \fmi{This is currently only displaying the local rules, but it
-% should also show the matching global rules!}
-%
+% Loop through the rules in a hook and for every rule found, print it.
+% If no rule is there, print |---|. The boolean \cs{l_@@_tmpa_bool}
+% here indicates if the hook has no rules.
% \begin{macrocode}
- \iow_term:x{~Rules:}
- \prop_if_empty:cTF {g_@@_#1_rules_prop}
- { \iow_term:x{\@spaces ---} }
- { \prop_map_inline:cn {g_@@_#1_rules_prop}
- { \iow_term:x{\@spaces ##1~ with~ relation~ ##2} }
+ \iow_term:x { ~Rules: }
+ \bool_set_true:N \l_@@_tmpa_bool
+ \@@_list_rules:nn {#1}
+ {
+ \bool_set_false:N \l_@@_tmpa_bool
+ \iow_term:x
+ {
+ \@spaces ##2~ with~
+ \str_if_eq:nnT {##3} {??} { default~ }
+ relation~ ##1 }
}
+ \bool_if:NT \l_@@_tmpa_bool
+ { \iow_term:x { \@spaces --- } }
% \end{macrocode}
%
% \begin{macrocode}
- \hook_if_exist:nT {#1}
+ \bool_lazy_and:nnT
+ { \hook_if_exist_p:n {#1} }
+ { ! \hook_if_empty_p:n {#1} }
{ \iow_term:x { ~Execution~ order
- \prop_if_empty:cTF {g_@@_#1_rules_prop}
+ \bool_if:NTF \l_@@_tmpa_bool
{ \@@_if_reversed:nT {#1}
{ ~ (after~ reversal) }
}
@@ -2944,30 +3174,97 @@
\@@_if_reversed:nT {#1} {reversal~ and~}
applying~ rules)
}
- :
+ :
}
- \iow_term:x { \@spaces
- \clist_if_empty:cTF{g_@@_#1_labels_clist}
- {not~ set~ yet}
- { \clist_use:cnnn {g_@@_#1_labels_clist}
- { ,~ } { ,~ } { ,~ } }
- }
+ \iow_term:x
+ { \@spaces \clist_use:cn {g_@@_#1_labels_clist} { ,~ } }
}
}
{ \iow_term:n { ~The~hook~is~empty. } }
\iow_term:n { }
}
% \end{macrocode}
-%
+%
+% 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.
+% \begin{macrocode}
+\cs_new:Npn \@@_log_next_code:n #1 {
+ \exp_args:No \tl_to_str:n {\use_none:nn #1}
+}
+% \end{macrocode}
% \end{macro}
-
-
-
-% \subsection{Specifying code for next invocation}
%
+% \begin{macro}{\@@_list_rules:nn}
+% \begin{macro}{\@@_list_one_rule:nnn,\@@_list_if_rule_exists:nnnF}
+% This macro takes a \meta{hook} and an \meta{inline function} and
+% loops through each pair of \meta{labels} in the \meta{hook}, and if
+% there is a relation between this pair of \meta{labels}, the
+% \meta{inline function} is executed with |#1|${}={}$\meta{relation},
+% |#2|${}={}$\meta{label_1}\verb=|=\meta{label_2},
+% and |#3|${}={}$\meta{hook} (the latter may be the argument |#1| to
+% \cs{@@_list_rules:nn}, or |??| if it is a default rule).
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_list_rules:nn #1 #2
+ {
+ \cs_set_protected:Npn \@@_tmp:w ##1 ##2 ##3 {#2}
+ \prop_map_inline:cn { g_@@_#1_code_prop }
+ {
+ \prop_map_inline:cn { g_@@_#1_code_prop }
+ {
+ \@@_if_label_case:nnnnn {##1} {####1}
+ { \prop_map_break: }
+ { \@@_list_one_rule:nnn {##1} {####1} }
+ { \@@_list_one_rule:nnn {####1} {##1} }
+ {#1}
+ }
+ }
+ }
+% \end{macrocode}
%
+% These two are quite similar to \cs{@@_apply_label_pair:nnn} and
+% \cs{@@_label_if_exist_apply:nnnF}, respectively, but rather than
+% applying the rule, they pass it to the \meta{inline function}.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_list_one_rule:nnn #1#2#3
+ {
+ \@@_list_if_rule_exists:nnnF {#1} {#2} {#3} { }
+ { \@@_list_if_rule_exists:nnnF {#1} {#2} { ?? } { } }
+ }
+\cs_new_protected:Npn \@@_list_if_rule_exists:nnnF #1#2#3
+ {
+ \if_cs_exist:w g_@@_ #3 _rule_ #1 | #2 _tl \cs_end:
+ \exp_args:Nv \@@_tmp:w
+ { g_@@_ #3 _rule_ #1 | #2 _tl } { #1 | #2 } {#3}
+ \fi:
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
%
+% \begin{macro}{\@@_debug_print_rules:n}
+% A shorthand for debugging that prints similar to \cs{prop_show:N}.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_debug_print_rules:n #1
+ {
+ \iow_term:n { The~hook~#1~contains~the~rules: }
+ \cs_set_protected:Npn \@@_tmp:w ##1
+ {
+ \@@_list_rules:nn {#1}
+ {
+ \iow_term:x
+ {
+ > ##1 {####2} ##1 => ##1 {####1}
+ \str_if_eq:nnT {####3} {??} { ~(default) }
+ }
+ }
+ }
+ \exp_args:No \@@_tmp:w { \use:nn { ~ } { ~ } }
+ }
+% \end{macrocode}
+% \end{macro}
%
+% \subsection{Specifying code for next invocation}
%
% \begin{macro}{\hook_gput_next_code:nn}
%
@@ -2984,10 +3281,29 @@
{ \@@_gput_next_do:nn {#1} {#2} }
{ \@@_try_declaring_generic_next_hook:nn {#1} {#2} }
}
-\cs_new_protected:Npn \@@_gput_next_do:nn #1 #2
+\cs_new_protected:Npn \@@_gput_next_do:nn #1
{
- \tl_gput_right:cn { g_@@_#1_next_code_tl }
- { #2 \tl_gclear:c { g_@@_#1_next_code_tl } }
+ \exp_args:Nc \@@_gput_next_do:Nnn
+ { g_@@_#1_code_next_tl } {#1}
+ }
+% \end{macrocode}
+% First 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
+% \cs{tl_gclear:N} in case the hook is used in an expansion-only
+% context, so the token list doesn't expand before \cs{tl_gclear:N}:
+% 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.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_gput_next_do:Nnn #1 #2
+ {
+ \tl_if_empty:cT { g_@@_#2_code_tl }
+ { \@@_update_hook_code:n {#2} }
+ \tl_if_empty:NT #1
+ { \tl_gset:Nn #1 { \tl_gclear:c { g_@@_#2_code_next_tl } } }
+ \tl_gput_right:Nn #1
}
% \end{macrocode}
% \end{macro}
@@ -3069,7 +3385,7 @@
\@@_if_file_hook:wTF #1 / / \s_@@_mark
{
\exp_args:Ne \@@_if_exist_use:n
- { \exp_args:Ne \@@_file_hook_normalise:n {#1} }
+ { \exp_args:Ne \@@_file_hook_normalize:n {#1} }
}
{ \@@_if_exist_use:n {#1} } % file/ generic hook (e.g. file/before)
}
@@ -3102,7 +3418,7 @@
}
% \end{macrocode}
% \end{macro}
-
+%
% \subsection{Querying a hook}
%
% Simpler data types, like token lists, have three possible states; they
@@ -3129,7 +3445,7 @@
% Test if a hook is empty (that is, no code was added to that hook).
% A hook being empty means that \emph{both} its
% \cs[no-index]{g_@@_\meta{hook}_code_prop} and its
-% \cs[no-index]{g_@@_\meta{hook}_next_code_tl} are empty.
+% \cs[no-index]{g_@@_\meta{hook}_code_next_tl} are empty.
% \begin{macrocode}
\prg_new_conditional:Npnn \hook_if_empty:n #1 { p , T , F , TF }
{
@@ -3137,7 +3453,7 @@
{
\bool_lazy_and:nnTF
{ \prop_if_empty_p:c { g_@@_#1_code_prop } }
- { \tl_if_empty_p:c { g_@@_#1_next_code_tl } }
+ { \tl_if_empty_p:c { g_@@_#1_code_next_tl } }
{ \prg_return_true: }
{ \prg_return_false: }
}
@@ -3145,7 +3461,7 @@
}
% \end{macrocode}
% \end{macro}
-
+%
% \begin{macro}[pTF]{\hook_if_exist:n}
% A canonical way to test if a hook exists. A hook exists if the
% token list that stores the sorted code for that hook,
@@ -3163,7 +3479,7 @@
}
% \end{macrocode}
% \end{macro}
-
+%
% \begin{macro}[pTF]{\@@_if_exist:n}
% An internal check if the hook has already been declared with
% \cs{@@_declare:n}. This means that the hook was already used somehow
@@ -3192,8 +3508,8 @@
}
% \end{macrocode}
% \end{macro}
-
-
+%
+%
% \begin{macro}{\g_@@_execute_immediately_clist}
% List of hooks that from no on should not longer receive code.
% \begin{macrocode}
@@ -3208,21 +3524,57 @@
{
Labels~`#1'~and~`#2'~are~incompatible
\str_if_eq:nnF {#3} {??} { ~in~hook~`#3' } .~
- \int_compare:nNnT {#4} = { 1 }
- { The~code~for~both~labels~will~be~dropped. }
- }
- {
- LaTeX~found~two~incompatible~labels~in~the~same~hook.~
- This~indicates~an~incompatibility~between~packages.
+ \int_compare:nNnTF {#4} = { 1 }
+ { The~ code~ for~ both~ labels~ will~ be~ dropped. }
+ { You~ may~ see~ errors~ later. }
}
+ { LaTeX~found~two~incompatible~labels~in~the~same~hook.~
+ This~indicates~an~incompatibility~between~packages. }
+% \end{macrocode}
+%
+% \begin{macrocode}
+\msg_new:nnnn { hooks } { exists }
+ { Hook~`#1'~ has~ already~ been~ declared. }
+ { There~ already~ exists~ a~ hook~ declaration~ with~ this~
+ name.\\
+ Please~ use~ a~ different~ name~ for~ your~ hook.}
+% \end{macrocode}
+%
+% \begin{macrocode}
\msg_new:nnn { hooks } { empty-label }
{ Empty~code~label~\msg_line_context:.~Using~`#1'~instead. }
% \end{macrocode}
+%
+% \begin{macrocode}
+\msg_new:nnnn { hooks } { unknown-rule }
+ { Unknown~ relationship~ `#3'~
+ between~ labels~ `#2'~ and~ `#4'~
+ \str_if_eq:nnF {#1} {??} { ~in~hook~`#1' }. ~
+ Perhaps~ a~ missspelling?
+ }
+ {
+ The~ relation~ used~ not~ known~ to~ the~ system.~ Allowed~ values~ are~
+ `before'~ or~ `<',~
+ `after'~ or~ `>',~
+ `incompatible-warning',~
+ `incompatible-error',~
+ `voids'~ or~
+ `unrelated'.
+ }
+% \end{macrocode}
+%
+% \begin{macrocode}
+\msg_new:nnn { hooks } { should-not-happen }
+ {
+ ERROR!~This~should~not~happen.~#1 \\
+ Please~report~at~https://github.com/latex3/latex2e.
+ }
+% \end{macrocode}
%
% \subsection{\LaTeXe{} package interface commands}
%
-
-
+%
+%
% \begin{macro}{\NewHook,\NewReversedHook,\NewMirroredHookPair}
% Declaring new hooks \ldots
% \begin{macrocode}
@@ -3231,7 +3583,7 @@
\NewDocumentCommand \NewMirroredHookPair { mm }{ \hook_new_pair:nn {#1}{#2} }
% \end{macrocode}
% \end{macro}
-
+%
% \begin{macro}{\AddToHook}
%
% \begin{macrocode}
@@ -3243,7 +3595,7 @@
}
% \end{macrocode}
% \end{macro}
-
+%
% \begin{macro}{\AddToHookNext}
%
% \begin{macrocode}
@@ -3251,8 +3603,8 @@
{ \hook_gput_next_code:nn {#1} {#2} }
% \end{macrocode}
% \end{macro}
-
-
+%
+%
% \begin{macro}{\RemoveFromHook}
%
% \begin{macrocode}
@@ -3275,32 +3627,15 @@
% default label for the top-level. Since the string \verb|top-level|
% is hardcoded, here this item of the stack is empty. Also, since
% we're in an input level, add \verb|lthooks| to the stack as well.
-% This stack should never go empty, so we loop through \LaTeXe's
-% file name stack, and add empty entries to \cs{g_@@_name_stack_seq}
-% for each item in that stack. The last item is the \verb|top-level|,
-% which also gets an empty entry.
-%
-% Also check for the case we're loading \texttt{lthooks} in the
-% \LaTeXe{} kernel. In that case, \cs{@currname} isn't \verb|lthooks|
-% and just the top-level is added to the stack as an empty entry.
+% This stack should never go empty. An empty entry is added to the
+% stack to account for the \verb|top-level|. The item is empty so
+% that the hard-coded default is used, but a call to
+% \cs{DeclareDefaultHookLabel} will change it if needed.
% \begin{macrocode}
-\str_if_eq:VnTF \@currname { lthooks }
- {
- \seq_gpush:Nn \g_@@_name_stack_seq { lthooks }
- \cs_set_protected:Npn \@@_tmp:w #1 #2 #3
- {
- \quark_if_recursion_tail_stop:n {#1}
- \seq_gput_right:Nn \g_@@_name_stack_seq { }
- \@@_tmp:w
- }
- \exp_after:wN \@@_tmp:w
- \@currnamestack
- \q_recursion_tail \q_recursion_tail
- \q_recursion_tail \q_recursion_stop
- }
- { \seq_gpush:Nn \g_@@_name_stack_seq { } }
+\seq_gpush:Nn \g_@@_name_stack_seq { }
% \end{macrocode}
%
+%
% Two commands keep track of the stack: when a file is input,
% \cs{@@_curr_name_push:n} pushes an (empty by default) label to the
% stack:
@@ -3321,7 +3656,10 @@
\seq_gpop:NN \g_@@_name_stack_seq \l_@@_return_tl
\seq_get:NNTF \g_@@_name_stack_seq \l_@@_return_tl
{ \tl_gset_eq:NN \g_@@_hook_curr_name_tl \l_@@_return_tl }
- { \ERROR_should_not_happen }
+ {
+ \msg_error:nnn { hooks } { should-not-happen }
+ { Tried~to~pop~from~an~empty~default~label~stack. }
+ }
}
% \end{macrocode}
%
@@ -3336,15 +3674,6 @@
\seq_gpop:NN \g_@@_name_stack_seq \l_@@_return_tl
\@@_curr_name_push:n {#1}
}
-% \begin{macrocode}
-%
-% The push and pop macros are injected in \cs{@pushfilename} and
-% \cs{@popfilename} so that they correctly keep track of the label.s
-% \begin{macrocode}
-% TODO! \pho{Properly integrate in the kernel}
-\tl_gput_left:Nn \@pushfilename { \@@_curr_name_push:n { } }
-\tl_gput_left:Nn \@popfilename { \@@_curr_name_pop: }
-% TODO! \pho{Properly integrate in the kernel}
% \end{macrocode}
% \end{macro}
% \end{macro}
@@ -3352,48 +3681,42 @@
%
%
%
-% \begin{macro}{\UseHook}
+% \begin{macro}{\UseHook,\UseOneTimeHook}
% Avoid the overhead of \pkg{xparse} and its protection that we
% don't want here (since the hook should vanish without trace if empty)!
% \begin{macrocode}
-\newcommand \UseHook { \hook_use:n }
+\newcommand \UseHook { \hook_use:n }
+\newcommand \UseOneTimeHook { \hook_use_once:n }
% \end{macrocode}
% \end{macro}
%
-% \begin{macro}{\UseOneTimeHook}
%
-% \begin{macrocode}
-\cs_new_protected:Npn \UseOneTimeHook { \hook_use_once:n }
-% \end{macrocode}
-% \end{macro}
-
-
-
+%
% \begin{macro}{\ShowHook}
%
% \begin{macrocode}
\cs_new_protected:Npn \ShowHook { \hook_log:n }
% \end{macrocode}
% \end{macro}
-
-% \begin{macro}{\DebugHookOn,\DebugHookOff}
+%
+% \begin{macro}{\DebugHooksOn,\DebugHooksOff}
%
% \begin{macrocode}
-\cs_new_protected:Npn \DebugHookOn { \hook_debug_on: }
-\cs_new_protected:Npn \DebugHookOff { \hook_debug_off: }
+\cs_new_protected:Npn \DebugHooksOn { \hook_debug_on: }
+\cs_new_protected:Npn \DebugHooksOff { \hook_debug_off: }
% \end{macrocode}
% \end{macro}
-
-
-
+%
+%
+%
% \begin{macro}{\DeclareHookRule}
%
% \begin{macrocode}
\NewDocumentCommand \DeclareHookRule { m m m m }
-{ \hook_gset_rule:nnnn {#1}{#2}{#3}{#4} }
+ { \hook_gset_rule:nnnn {#1}{#2}{#3}{#4} }
% \end{macrocode}
% \end{macro}
-
+%
% \begin{macro}{\DeclareDefaultHookRule}
% This declaration is only supported before \verb=\begin{document}=.
% \begin{macrocode}
@@ -3406,7 +3729,7 @@
% \begin{macro}{\ClearHookRule}
% A special setup rule that removes an existing relation.
% Basically {@@_rule_gclear:nnn} plus fixing the property list for debugging.
-% \fmi{Need an L3 interface, or maybe it should get dropped}
+% \fmi{Need an L3 interface, or maybe it should get dropped?}
% \begin{macrocode}
\NewDocumentCommand \ClearHookRule { m m m }
{ \hook_gset_rule:nnnn {#1}{#2}{unrelated}{#3} }
@@ -3414,512 +3737,102 @@
% \end{macro}
%
%
-% \begin{macro}{\IfHookExistTF,\IfHookEmptyTF}
+% \begin{macro}{\IfHookExistsTF,\IfHookEmptyTF}
% \begin{macrocode}
-\NewExpandableDocumentCommand \IfHookExistTF { m }
+\NewExpandableDocumentCommand \IfHookExistsTF { m }
{ \hook_if_exist:nTF {#1} }
\NewExpandableDocumentCommand \IfHookEmptyTF { m }
{ \hook_if_empty:nTF {#1} }
% \end{macrocode}
% \end{macro}
-
-
-
-
-% \begin{macro}{\AtBeginDocument}
-%
-% \begin{macrocode}
-\renewcommand\AtBeginDocument{\AddToHook{begindocument}}
-% \end{macrocode}
-% \end{macro}
-
-% \begin{macro}{\AtEndDocument}
-%
-% \begin{macrocode}
-\renewcommand\AtEndDocument {\AddToHook{enddocument}}
-%\renewcommand\AtEndDocument {\AddToHook{env/document/end}} % alternative impl
-% \end{macrocode}
-%
-% \end{macro}
-
-
-
-% \subsection{Set up existing \LaTeXe{} hooks}
-%
-% As we are in a package calling \cs{NewHook} would label any
-% already set up hook code under the package name, but we want it
-% under the name \hook{top-level} so we pretend that \cs{@currname}
-% is empty.
-% \begin{macrocode}
-\begingroup
- \def\@currname{}
-% \end{macrocode}
-%
-% \begin{macrocode}
- \NewHook{begindocument}
- \NewHook{enddocument}
-% \end{macrocode}
-% We need to initialize the mechanism at \verb=\begin{document}=
-% but obviously before everything else, so we sneak\footnote{This
-% needs to move to \cs{document} directly.}
-% \cs{@@_initialize_all:} into the \LaTeXe{} hook name.
-%
-% We can't use \cs{tl_gput_left:Nn} because that complains about
-% \cs{@begindocumenthook} not starting with \cs{g_} so we do this
-% through the backdoor.
-% \begin{macrocode}
-% \tex_global:D\tl_put_left:Nn \@begindocumenthook
-% {\@@_initialize_all:}
-% \end{macrocode}
-% There aren't many other hooks at the moment:
-% \begin{macrocode}
- \NewHook{rmfamily}
- \NewHook{sffamily}
- \NewHook{ttfamily}
- \NewHook{defaultfamily}
-% \end{macrocode}
-% Not checked what this one does and whether it should be there (or
-% is a real ``hook''.
-% \begin{macrocode}
- \NewHook{documentclass}
-% \end{macrocode}
-%
-% \begin{macrocode}
-\endgroup
-% \end{macrocode}
-%
-%
-%
-% \section{Generic hooks for environments}
-%
-%
-% \begin{macrocode}
-\let\begin\relax % avoid redeclaration message
-% \end{macrocode}
-%
-% \begin{macrocode}
-\DeclareRobustCommand*\begin[1]{%
- \UseHook{env/#1/before}%
- \@ifundefined{#1}%
- {\def\reserved@a{\@latex@error{Environment~#1~undefined}\@eha}}%
- {\def\reserved@a{\def\@currenvir{#1}%
- \edef\@currenvline{\on@line}%
- \@execute@begin@hook{#1}%
- \csname #1\endcsname}}%
- \@ignorefalse
- \begingroup\@endpefalse\reserved@a}
-% \end{macrocode}
-%
-% Before the \cs{document} code is executed we have to first undo
-% the \cs{endgroup} as there should be none for this environment to
-% avoid that changes on top-level unnecessarily go to \TeX's
-% savestack, and we have to initialize all hooks in the hook system.
-% So we need to test for this environment name. But once it has be
-% found all this testing is no longer needed and so we redefine
-% \cs{@execute@begin@hook} to simply use the hook
-% \begin{macrocode}
-\def\@execute@begin@hook #1{%
- \expandafter\ifx\csname #1\endcsname\document
- \endgroup
- \gdef\@execute@begin@hook##1{\UseHook{env/##1/begin}}%
- \@@_initialize_all:
- \@execute@begin@hook{#1}%
-% \end{macrocode}
-% If this is an environment before \verb=\begin{document}= we just
-% run the hook.
-% \begin{macrocode}
- \else
- \UseHook{env/#1/begin}%
- \fi
-}
-% \end{macrocode}
-%
-% \begin{macrocode}
-\@namedef{end~}#1{%
- \UseHook{env/#1/end}%
- \csname end#1\endcsname\@checkend{#1}%
- \expandafter\endgroup\if@endpe\@doendpe\fi
- \UseHook{env/#1/after}%
- \if@ignore\@ignorefalse\ignorespaces\fi}%
-% \end{macrocode}
-% Version that fixes tlb3722 but the change should perhaps be made in
-% \pkg{tabularx} instead.
-% \begin{macrocode}
-\@namedef{end~}#1{%
-\romannumeral
-\IfHookEmptyTF{env/#1/end}%
- {\expandafter\z@}%
- {\z@\UseHook{env/#1/end}}%
-\csname end#1\endcsname\@checkend{#1}%
-\expandafter\endgroup\if@endpe\@doendpe\fi
-\UseHook{env/#1/after}%
-\if@ignore\@ignorefalse\ignorespaces\fi}%
-% \end{macrocode}
-%
-%
%
-% We provide 4 high-level hook interfaces directly, the others only when
-% etoolbox is loaded
-% \begin{macrocode}
-\newcommand\AtBeginEnvironment[1] {\AddToHook{env/#1/begin}}
-\newcommand\AtEndEnvironment[1] {\AddToHook{env/#1/end}}
-\newcommand\BeforeBeginEnvironment[1]{\AddToHook{env/#1/before}}
-\newcommand\AfterEndEnvironment[1] {\AddToHook{env/#1/after}}
-% \end{macrocode}
-%
-%
-%
-%
-%
-%
-%
-%
-%
-%
-%
-% \section{Generic hooks for file loads}
%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%5
%
+% \subsection{Internal commands needed elsewhere}
%
+% Here we set up a few horrible (but consistent) \LaTeXe{} names to
+% allow for internal commands to be used outside this module. We
+% have to unset the \texttt{@\/@} since we want double ``at'' sign
+% in place of double underscores.
%
-%
-%
-%
-% \section{Hooks in \cs{begin} document}
-%
-% Can't have \texttt{@{}@} notation here as this is \LaTeXe{} code
-% \ldots{} and makes for puzzling errors if the double \texttt{@}
-% signs get substituted.
% \begin{macrocode}
%<@@=>
-\ExplSyntaxOff
-% \end{macrocode}
-%
-% The \hook{begindocument} hook was already set up earlier, here is now
-% the additional one (which was originally from the \pkg{etoolbox}
-% package under the name \texttt{afterpreamble}.
-% \begin{macrocode}
-\NewHook{begindocument/end}
% \end{macrocode}
%
-%
-
-% \begin{macro}{\document}
+% \begin{macro}{\@expl@@@initialize@all@@,
+% \@expl@@@hook@curr@name@push@@n,
+% \@expl@@@hook@curr@name@pop@@}
%
% \begin{macrocode}
-\def\document{%
+\cs_new_eq:NN \@expl@@@initialize@all@@
+ \__hook_initialize_all:
% \end{macrocode}
-% We do cancel the grouping as part of the \cs{begin} handling
-% (this is now done inside \cs{begin} instead) so that the
-% \hook{env/\meta{env}/begin} hook is not hidden inside \cs{begingroup}
-% \texttt{...} \cs{endgroup}.
-% \begin{macrocode}
-% \endgroup
-% \end{macrocode}
-%
-% \begin{macrocode}
- \@kernel@after@env@document@begin
-% \end{macrocode}
-%
-% Added hook to load \textsf{l3backend} code:
-% \begin{macrocode}
- \@expl@sys@load@backend@@
- \ifx\@unusedoptionlist\@empty\else
- \@latex@warning@no@line{Unused global option(s):^^J%
- \@spaces[\@unusedoptionlist]}%
- \fi
- \@colht\textheight
- \@colroom\textheight \vsize\textheight
- \columnwidth\textwidth
- \@clubpenalty\clubpenalty
- \if@twocolumn
- \advance\columnwidth -\columnsep
- \divide\columnwidth\tw@ \hsize\columnwidth \@firstcolumntrue
- \fi
- \hsize\columnwidth \linewidth\hsize
- \begingroup\@floatplacement\@dblfloatplacement
- \makeatletter\let\@writefile\@gobbletwo
- \global \let \@multiplelabels \relax
- \@input{\jobname.aux}%
- \endgroup
- \if@filesw
- \immediate\openout\@mainaux\jobname.aux
- \immediate\write\@mainaux{\relax}%
- \fi
- \process@table
- \let\glb@currsize\@empty % Force math initialization.
- \normalsize
- \everypar{}%
- \ifx\normalsfcodes\@empty
- \ifnum\sfcode`\.=\@m
- \let\normalsfcodes\frenchspacing
- \else
- \let\normalsfcodes\nonfrenchspacing
- \fi
- \fi
- \ifx\document@default@language\m@ne
- \chardef\document@default@language\language
- \fi
- \@noskipsecfalse
- \let \@refundefined \relax
-% \end{macrocode}
-%
-% \begin{macrocode}
-% \let\AtBeginDocument\@firstofone
-% \@begindocumenthook
- \UseOneTimeHook{begindocument}%
- \@kernel@after@begindocument
-% \end{macrocode}
-%
-% \begin{macrocode}
- \ifdim\topskip<1sp\global\topskip 1sp\relax\fi
- \global\@maxdepth\maxdepth
- \global\let\@begindocumenthook\@undefined
- \ifx\@listfiles\@undefined
- \global\let\@filelist\relax
- \global\let\@addtofilelist\@gobble
- \fi
- \gdef\do##1{\global\let ##1\@notprerr}%
- \@preamblecmds
- \global\let \@nodocument \relax
- \global\let\do\noexpand
-% \end{macrocode}
-%
-% \begin{macrocode}
- \UseOneTimeHook{begindocument/end}%
- \ignorespaces}
-% \end{macrocode}
-%
-% \begin{macrocode}
-\let\@kernel@after@begindocument\@empty
-% \end{macrocode}
-% \end{macro}
-%
-%
-% \begin{macro}{\@kernel@after@env@document@begin,\@kernel@hook@begindocument}
-%
-% \begin{macrocode}
-\edef \@kernel@after@env@document@begin{%
- \let\expandafter\noexpand\csname
- g__hook_env/document/begin_code_tl\endcsname
- \noexpand\@empty}
-% \end{macrocode}
-% \begin{macrocode}
-\let\@kernel@hook@begindocument\@empty
-% \end{macrocode}
-%
-% \end{macro}
%
-%
-% \section{Hooks in \cs{enddocument}}
-%
-%
-%
-% The \hook{enddocument} hook was already set up earlier, here are now
-% the additional ones:
% \begin{macrocode}
-\NewHook{enddocument/afterlastpage}
-\NewHook{enddocument/afteraux}
-\NewHook{enddocument/info}
-\NewHook{enddocument/end}
+\cs_new_eq:NN \@expl@@@hook@curr@name@push@@n
+ \__hook_curr_name_push:n
% \end{macrocode}
-
-
-
-% \begin{macro}{\enddocument}
-%
-%
-% \begin{macrocode}
-\def\enddocument{%
- \UseHook{enddocument}%
- \@kernel@after@enddocument
- \@checkend{document}%
- \clearpage
- \UseHook{enddocument/afterlastpage}%
- \@kernel@after@enddocument@afterlastpage
- \begingroup
- \if@filesw
- \immediate\closeout\@mainaux
- \let\@setckpt\@gobbletwo
- \let\@newl@bel\@testdef
- \@tempswafalse
- \makeatletter \@@input\jobname.aux
- \fi
- \UseHook{enddocument/afteraux}%
-% \end{macrocode}
-% Next hook is expect to contain only code for writing info
-% messages on the terminal.
-% \begin{macrocode}
- \UseHook{enddocument/info}%
- \endgroup
- \UseHook{enddocument/end}%
- \deadcycles\z@\@@end}
-% \end{macrocode}
-% The two kernel hooks above are used by the shipout code.
-% \begin{macrocode}
-\let\@kernel@after@enddocument\@empty
-\let\@kernel@after@enddocument@afterlastpage\@empty
-% \end{macrocode}
-% \end{macro}
-%
%
-%
-% \begin{macro}{\@enddocument@kernel@warnings}
-%
-% \begin{macrocode}
-\def\@enddocument@kernel@warnings{%
- \ifdim \font@submax >\fontsubfuzz\relax
- \@font@warning{Size substitutions with differences\MessageBreak
- up to \font@submax\space have occurred.\@gobbletwo}%
- \fi
- \@defaultsubs
- \@refundefined
- \if@filesw
- \ifx \@multiplelabels \relax
- \if@tempswa
- \@latex@warning@no@line{Label(s) may have changed.
- Rerun to get cross-references right}%
- \fi
- \else
- \@multiplelabels
- \fi
- \fi
-}
-% \end{macrocode}
-%
% \begin{macrocode}
-\AddToHook{enddocument/info}[kernel/filelist]{\@dofilelist}
-\AddToHook{enddocument/info}[kernel/warnings]{\@enddocument@kernel@warnings}
-\DeclareHookRule{enddocument/info}{kernel/filelist}{before}{kernel/warnings}
+\cs_new_eq:NN \@expl@@@hook@curr@name@pop@@
+ \__hook_curr_name_pop:
% \end{macrocode}
% \end{macro}
%
-%
-% \subsection{Adjusting at \pkg{atveryend} interfaces}
-%
-% With the new hook management all of \pkg{atveryend} is taken care
-% of.
-%
-% We therefore prevent the package from loading:
-% \begin{macrocode}
-\expandafter\let\csname ver@atveryend.sty\endcsname\fmtversion
-% \end{macrocode}
-%
-%
-% Here are new definitions for its interfaces now pointing to the
-% hooks in \cs{enddocument}
-% \begin{macrocode}
-\newcommand\AfterLastShipout {\AddToHook{enddocument/afterlastpage}}
-\newcommand\AtVeryEndDocument {\AddToHook{enddocument/afteraux}}
-% \end{macrocode}
-% Next one is a bit of a fake, but the result should normally be as
-% expected. If not one needs to add a rule to sort the code chunks
-% in \hook{enddocument/info}.
-% \begin{macrocode}
-\newcommand\AtEndAfterFileList{\AddToHook{enddocument/info}}
-% \end{macrocode}
-%
-% \begin{macrocode}
-\newcommand\AtVeryVeryEnd {\AddToHook{enddocument/end}}
-% \end{macrocode}
-
-% \begin{macro}{\BeforeClearDocument}
-% This one is the only one we don't implement or rather don't have
-% a dedicated hook in the code.
-% \begin{macrocode}
-\ExplSyntaxOn
-\newcommand\BeforeClearDocument[1]
- { \AtEndDocument{#1}
- \@DEPRECATED{BeforeClearDocument \tl_to_str:n{#1}}
- }
-\cs_new:Npn\@DEPRECATED #1
- {\iow_term:x{======~DEPRECATED~USAGE~#1~==========}}
-% \end{macrocode}
%
% \begin{macrocode}
\ExplSyntaxOff
% \end{macrocode}
-% \end{macro}
-%
-% \begin{macrocode}
-%</2ekernel>
-% \end{macrocode}
-
%
-% \section{A package version of the code for testing}
%
-
-% \begin{macrocode}
-%<*package>
-% \end{macrocode}
-
-
-
-% \begin{macrocode}
-\RequirePackage{xparse}
-\ProvidesExplPackage{lthooks}{\lthooksdate}{\lthooksversion}
- {Hook management interface for LaTeX2e}
+% Rolling back here doesn't undefine the interface commands as they
+% may be used in packages without rollback functionality. So we
+% just make them do nothing which may or may not work depending on
+% the code usage.
+% \begin{macrocode}
+%</2ekernel|latexrelease>
+%<latexrelease>\EndIncludeInRelease
+%<latexrelease>\IncludeInRelease{0000/00/00}%
+%<latexrelease> {\NewHook}{The hook management}%
+%<latexrelease>
+%<latexrelease>\def \NewHook#1{}
+%<latexrelease>\def \NewReversedHook#1{}
+%<latexrelease>\def \NewMirroredHookPair#1#2{}
+%<latexrelease>
+%<latexrelease>\long\def \AddToHook#1#2{}
+%<latexrelease>
+%<latexrelease>\def \AddToHookNext#1{\@gobble@AddToHook@args}
+%<latexrelease>\providecommand\@gobble@AddToHook@args[2][]{}
+%<latexrelease>
+%<latexrelease>\def\RemoveFromHook#1{\@gobble@RemoveFromHook@arg}
+%<latexrelease>\providecommand\@gobble@RemoveFromHook@arg[1][]{}
+%<latexrelease>
+%<latexrelease>\def \UseHook #1{}
+%<latexrelease>\def \UseOneTimeHook #1{}
+%<latexrelease>\def \ShowHook #1{}
+%<latexrelease>\let \DebugHooksOn \@empty
+%<latexrelease>\let \DebugHooksOff\@empty
+%<latexrelease>
+%<latexrelease>\def \DeclareHookRul#1#2#3#4{}
+%<latexrelease>\def \DeclareDefaultHookRule #1#2#3{}
+%<latexrelease>\def \ClearHookRule#1#2#3{}
+% \end{macrocode}
+% If the hook management is not provided we make the test for existence
+% false and the test for empty true in the hope that this is most
+% of the time reasonable. If not a package would need to guard
+% against running in an old kernel.
+% \begin{macrocode}
+%<latexrelease>\def \IfHookExistTF #1#2#3{#3}
+%<latexrelease>\def \IfHookEmptyTF #1#2#3{#2}
+%<latexrelease>
+%<latexrelease>\EndIncludeInRelease
% \end{macrocode}
%
%
-% \subsection{Core hook management code (kernel part)}
-%
-% This should run in older formats so we can't use
-% \cs{IfFormatAtLeastTF} right now.
-% \begin{macrocode}
-\@ifl@t@r\fmtversion{2020/10/01}
- {}
- {\input{lthooks.ltx}
- \input{ltshipout.ltx}
- \input{ltfilehook.ltx}
- }
-% \end{macrocode}
-%
-% \subsection{Package options}
-%
-% For now we offer a simple debug option which turns on a lot of
-% strange \cs{typeout} messages, nothing fancy.
-% \begin{macrocode}
-\ExplSyntaxOn
-% \end{macrocode}
-%
-% \begin{macrocode}
-\hook_debug_off:
-\DeclareOption { debug } { \hook_debug_on:
- \shipout_debug_on: }
-% \end{macrocode}
-%
-%
-% For now we offer a simple debug option which turns on a lot of
-% strange \cs{typeout} messages, nothing fancy.
-% \begin{macrocode}
-\shipout_debug_off:
-\DeclareOption { debug-shipout } { \shipout_debug_on: }
-% \end{macrocode}
-%
-% \begin{macrocode}
-\ProcessOptions
-% \end{macrocode}
-%
-%
-% \subsection{Temporarily patching package until changed}
-%
-%
-%
-% \pkg{filehook} support until that package is patched:
-% \begin{macrocode}
-\RequirePackage{filehook-ltx}
-% \end{macrocode}
-%
-%
-%
-% \begin{macrocode}
-%</package>
-% \end{macrocode}
-%
-%
-%
% \Finale
%
-
-
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+\endinput
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%