[latex3-commits] [git/LaTeX3-latex3-latex2e] lthooks: added the version with dot-notation (1d897b16)

Frank Mittelbach frank.mittelbach at latex-project.org
Thu Jul 9 21:57:41 CEST 2020


Repository : https://github.com/latex3/latex2e
On branch  : lthooks
Link       : https://github.com/latex3/latex2e/commit/1d897b16a01bf2533baace4efd59952e6883d9e0

>---------------------------------------------------------------

commit 1d897b16a01bf2533baace4efd59952e6883d9e0
Author: Frank Mittelbach <frank.mittelbach at latex-project.org>
Date:   Thu Jul 9 21:57:41 2020 +0200

    added the version with dot-notation


>---------------------------------------------------------------

1d897b16a01bf2533baace4efd59952e6883d9e0
 base/lthooks.dtx | 414 ++++++++++++++++++++++++++++++++++++++++++++-----------
 1 file changed, 334 insertions(+), 80 deletions(-)

diff --git a/base/lthooks.dtx b/base/lthooks.dtx
index cc33e446..577d9529 100644
--- a/base/lthooks.dtx
+++ b/base/lthooks.dtx
@@ -17,7 +17,7 @@
 % for those people who are interested or want to report an issue.
 %
 %    \begin{macrocode}
-\providecommand\lthooksversion{v0.8r}
+\providecommand\lthooksversion{v0.8s}
 \providecommand\lthooksdate{2020/07/09}
 %    \end{macrocode}
 %
@@ -122,8 +122,8 @@
 %     \cs{NewHook} \Arg{hook}
 %   \end{syntax}
 %   Creates a new \meta{hook}.
-%     If this is a hook provided as part of a package it is suggested that the
-%    \meta{hook} name is always structured as follows:
+%    If this is a hook provided as part of a package it is suggested
+%    that the \meta{hook} name is always structured as follows:
 %    \meta{package-name}\texttt{/}\meta{hook-name}. If necessary you
 %    can further subdivide the name by adding more \texttt{/} parts.
 %    If a hook name is already taken, an error is raised and the hook
@@ -201,7 +201,8 @@
 %    Adds \meta{code} to the \meta{hook} labeled by \meta{label}. If
 %    the optional argument \meta{label} is not provided, if \cs{AddToHook}
 %    is used in a package/class, then the current
-%    package/class name is used, otherwise \hook{top-level} is used.
+%    package/class name is used, otherwise \hook{top-level} is
+%    used~(see section~\ref{sec:default-label}).
 %
 %    If there already exists code under the \meta{label} then the new
 %    \meta{code} is appended to the existing one (even if this is a reversed hook).
@@ -210,29 +211,13 @@
 %
 %    The hook doesn't have to exist for code to be added to
 %    it. However, if it is not declared later then obviously the
-%    added \meta{code} will nevery be executed  This
+%    added \meta{code} will never be executed.  This
 %    allows for hooks to work regardless of package loading order and
 %    enables packages to add to hook of other packages without
 %    worrying whether they are actually used in the current document.
 %    See section~\ref{sec:querying}.
 % \end{function}
 %
-%    It is best practice to use \cs{AddToHook} in packages or classes
-%    without specifying a \meta{label} because then the package or
-%    class name is automatically used which is helpful if rules are
-%    needed, etc.
-%
-%    Using an explicit \meta{label} is only necessary in very specific
-%    situations, e.g., if you want to add several chunks of code into a
-%    single hook and have them placed in different parts of the hook
-%    (by providing some rules).
-%
-%    The other case is when you develop a larger package with several
-%    sub-packages. In that case you may want to use the same
-%    \meta{label} throughout of the sub-packages in order to avoid
-%    that the labels change if you internally reorganize your code.
-%
-%
 % \begin{function}{\RemoveFromHook}
 %   \begin{syntax}
 %     \cs{RemoveFromHook} \Arg{hook}\oarg{label}
@@ -272,8 +257,8 @@
 % changes for no good reason.
 %
 % The above is only needed if one wants to typeset several quotes in a
-% smaller typefac. If the hook is only needed once then
-% \cs{AddToHookNext} is simpler as that resets itself after use.
+% smaller typeface. If the hook is only needed once then
+% \cs{AddToHookNext} is simpler, because it resets itself after one use.
 %
 %
 % \begin{function}{\AddToHookNext}
@@ -296,6 +281,76 @@
 % \end{function}\footnotetext{There is
 %    no mechanism to reorder such code chunks (or delete them).}
 %
+% \subsection{Default labels}
+% \label{sec:default-label}
+%
+% It is best practice to use \cs{AddToHook} in packages or classes
+% \emph{without specifying a \meta{label}} because then the package
+% or class name is automatically used, which is helpful if rules are
+% needed, and avoids mistyping the \meta{label}.
+%
+% Using an explicit \meta{label} is only necessary in very specific
+% situations, e.g., if you want to add several chunks of code into a
+% single hook and have them placed in different parts of the hook
+% (by providing some rules).
+%
+% The other case is when you develop a larger package with several
+% sub-packages. In that case you may want to use the same
+% \meta{label} throughout the sub-packages in order to avoid
+% that the labels change if you internally reorganize your code.
+%
+% It is not enforced, but highly recommended that the label contains the
+% package name to easily identify the source of the code chunk and to
+% prevent clashes.  This should be the standard practice, so this hook
+% management code provides a shortcut to refer to the current package
+% name in a \meta{label}.  In a \meta{label}, a single dot (|.|), or a
+% dot followed by a slash (|./|) denote the \meta{default label}
+% (usually the current package or class
+% name---see~\cs{DeclareDefaultHookLabel}).
+% A \enquote{|.|} or \enquote{|./|} anywhere else in a \meta{label} is
+% treated literally and not replaced.
+% For example, inside the package \texttt{mypackage.sty}, the default
+% label is \texttt{mypackage}, so the instructions:
+% \begin{verbatim}
+%   \AddToHook {hook}[.]{code} % Same as \AddToHook {hook}{code}
+%   \AddToHook {hook}[./sub]{code}
+% \end{verbatim}
+%    are equivalent to:
+% \begin{verbatim}
+%   \AddToHook {hook}[mypackage]{code}
+%   \AddToHook {hook}[mypackage/sub]{code}
+% \end{verbatim}
+%
+% This syntax is available in all \meta{label} arguments, both in
+% the \LaTeXe{} interface, and the \LaTeX3 interface described in
+% section~\ref{sec:l3hook-interface}.
+%
+% The \meta{default label} is automatically set to the name of the
+% current package or class (using \cs{@currname}).  If \cs{@currname}
+% is not set (because the hook command is used outside of a package, or
+% the current file wasn't loaded with \cs{usepackage} or
+% \cs{documentclass}), then the \texttt{top-level} is used as the
+% \meta{default label}.
+%
+% 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
+% \meta{label}, then the \meta{default label} can be set using
+% \cs{DeclareDefaultHookLabel}:
+%
+% \begin{function}{\DeclareDefaultHookLabel}
+%   \begin{syntax}
+%     \cs{DeclareDefaultHookLabel} \Arg{default label}
+%   \end{syntax}
+%   Sets the \meta{default label} to be used in \meta{label} arguments.
+%   If \cs{DeclareDefaultHookLabel} is not used in the
+%   current package, \cs{@currname} is used instead.  If \cs{@currname}
+%   is not set, the code is assumed to be in the main document, in which
+%   case \texttt{top-level} is used.
+%
+%   The effect of \cs{DeclareDefaultHookLabel} holds for the current
+%   file, and is reset to the previous value when the file is closed.
+% \end{function}
+%
 %
 % \subsubsection{Defining relations between hook code}
 %
@@ -341,14 +396,15 @@
 %    \item[\texttt{incompatible-warning}]
 %
 %      Only code for either \meta{label1} or \meta{label2} can appear
-%      for that hook (a way to say that two packages (or parts of
-%      them) are incompatible). A warning is raised if both labels
+%      for that hook (a way to say that two packages---or parts of
+%      them---are incompatible). A warning is raised if both labels
 %      appear in the same hook.
 %
 %    \item[\texttt{incompatible-error}]
 %
 %      Like \texttt{incompatible-error} but instead of a warning a
-%      \LaTeX{} error is raised.
+%      \LaTeX{} error is raised, and the code for both labels are
+%      dropped from that hook until the conflict is resolved.
 %
 %    \item[\texttt{removes}]
 %
@@ -489,6 +545,7 @@
 %
 %
 % \subsection{L3 programming layer (\texttt{expl3}) interfaces}
+% \label{sec:l3hook-interface}
 %
 %
 % This is a quick summary of the \LaTeX3 programming interfaces for
@@ -532,9 +589,7 @@
 %    \fmi{better L3 name?}
 % \end{function}
 %
-% \begin{function}
-%   {\hook_gput_code:nnn,\hook_gput_code:non,
-%    \hook_gput_code:nnv,\hook_gput_code:nov}
+% \begin{function}{\hook_gput_code:nnn}
 %   \begin{syntax}
 %     \cs{hook_gput_code:nnn} \Arg{hook} \Arg{label} \Arg{code}
 %   \end{syntax}
@@ -546,6 +601,9 @@
 %    another package) then the convention is to use the package name
 %    as the \meta{label} not some internal module name or some other
 %    arbitrary string.
+%
+%    The \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}
@@ -566,19 +624,24 @@
 %
 
 
-%  \begin{function}{\hook_gremove_code:nn,\hook_gremove_code:no}
+%  \begin{function}{\hook_gremove_code:nn}
 %   \begin{syntax}
 %     \cs{hook_gremove_code:nn} \Arg{hook} \Arg{label}
 %   \end{syntax}
-%    Removes any code for \meta{hook} labeled \meta{label}. It is okay
-%    if no code has been set up under \meta{label}.\fmi{Is it? Or
-%    should this generate an error?}
+%    Removes any code for \meta{hook} labeled \meta{label}.
+%
+%    If the code for that \meta{label} wasn't yet added to the
+%    \meta{hook}, an order is set so that when some code attempts to add
+%    that label, the removal order takes action and the code is not
+%    added.
 %
 %    If the second argument is \texttt{*}, then all code chunks are
 %    removed. This is rather dangerous as it drops code from other
 %    packages one may not know about, so think twice before using
 %    that!
 %
+%    The \meta{label} can be specified using the dot-syntax to denote
+%    the current package name. See section~\ref{sec:default-label}.
 % \end{function}
 
 
@@ -589,6 +652,11 @@
 %    Relate \meta{label1} with \meta{label2} when used in \meta{hook}.
 %    See \cs{DeclareHookRule} for the allowed \meta{relation}s.
 %    If \meta{hook} is \texttt{??} a default rule is specified.
+%
+%    The \meta{label} can be specified using the dot-syntax to denote
+%    the current package name. See section~\ref{sec:default-label}.
+%    The dot-syntax is parsed in both \meta{label} arguments, but it
+%    usually makes sense to be used in only one of them.
 % \end{function}
 %
 % \begin{function}[pTF]{\hook_if_empty:n}
@@ -1159,6 +1227,15 @@
 %    \end{macrocode}
 % \end{macro}
 %
+% \begin{macro}{\g_@@_hook_curr_name_tl,\g_@@_name_stack_seq}
+%   Default label used for hook commands, and a stack to keep track of
+%   packages within packages.
+%    \begin{macrocode}
+\tl_new:N \g_@@_hook_curr_name_tl
+\seq_new:N \g_@@_name_stack_seq
+%    \end{macrocode}
+% \end{macro}
+%
 % \begin{macro}{\tl_gremove_once:Nx}
 %   Some variants of \pkg{expl3} functions.
 %    \begin{macrocode}
@@ -1166,6 +1243,13 @@
 %    \end{macrocode}
 % \end{macro}
 %
+% \begin{macro}{\s_@@_mark}
+%   Scan mark used for delimited arguments.
+%    \begin{macrocode}
+\scan_new:N \s_@@_mark
+%    \end{macrocode}
+% \end{macro}
+%
 %
 % \subsection{Providing new hooks}
 %
@@ -1296,7 +1380,7 @@
 %  \end{macro}
 
 
-%  \begin{macro}{\@@_provide_legacy_interface:n}
+% \begin{macro}{\@@_provide_legacy_interface:n}
 %    The \LaTeX{} legacy concept for hooks uses with hooks the
 %    following naming scheme in the code: \cs{@...hook}.
 %
@@ -1310,24 +1394,28 @@
 %    unnecessary expansion on each invocation in the document but
 %    keeps the \LaTeXe{} and the L3 coding side properly separated.}
 %    \begin{macrocode}
-\cs_new_protected:Npn \@@_provide_legacy_interface:n #1 {
+\cs_new_protected:Npn \@@_provide_legacy_interface:n #1
+  {
 %    \end{macrocode}
 %    If the \pkg{expl3} code is run with checking on then assigning or
 %    using non L3 names such as \cs{@enddocumenthook} with \pkg{expl3}
 %    functions will trigger warnings so we run this code with
 %    debugging explicitly suspended.
 %    \begin{macrocode}
-  \debug_suspend:
-  \tl_if_exist:cT {@#1hook}
+    \debug_suspend:
+    \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.
 %    \begin{macrocode}
-     { \tl_if_empty:cF {@#1hook}
-       { \tl_if_empty:NTF \@currname
-         { \hook_gput_code:nnv{#1}{legacy}{@#1hook}     }
-         { \hook_gput_code:nov{#1}{\@currname}{@#1hook} } }
-     }
+      {
+        \tl_if_empty:cF { @#1hook }
+          {
+            \@@_gput_code:nxv {#1}
+              { \@@_parse_label_default:Vn \c_novalue_tl { 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).
@@ -1335,23 +1423,108 @@
 %    \cs{tl_gset:co} would complain about \cs{@...hook} not starting
 %    with \cs{g_}.
 %    \begin{macrocode}
-  \tl_gset:co{@#1hook}{\cs:w g_@@_#1_code_tl\cs_end:}
-  \debug_resume:
-}
+    \tl_gset:co{@#1hook}{\cs:w g_@@_#1_code_tl\cs_end:}
+    \debug_resume:
+  }
 %    \end{macrocode}
-%  \end{macro}
+% \end{macro}
+%
+% \subsection{Parsing a label}
+%
+% \begin{macro}[EXP]{\@@_parse_label_default:nn,\@@_parse_label_default:Vn}
+%   This macro checks if a label was given (not \cs{c_novalue_tl}), and
+%   if so, tries to parse the label looking for a leading \verb|.| to
+%   replace for \cs{@currname}.  Otherwise \cs{@@_currname_or_default:n}
+%   is used to pick \cs{@currname} or the fallback value.
+%    \begin{macrocode}
+\cs_new:Npn \@@_parse_label_default:nn #1 #2
+  {
+    \tl_if_novalue:nTF {#1}
+      { \@@_currname_or_default:n {#2} }
+      { \tl_trim_spaces_apply:nN {#1} \@@_parse_dot_label:nn {#2} }
+  }
+\cs_generate_variant:Nn \@@_parse_label_default:nn { V }
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[EXP]{\@@_parse_dot_label:nn}
+% \begin{macro}[EXP]{
+%     \@@_parse_dot_label:nw,
+%     \@@_parse_dot_label_cleanup:w,
+%     \@@_parse_dot_label_aux:nw
+%   }
+%   Start by checking if the label is empty, which raises an error, and
+%   uses the fallback value.  If not,
+%   split the label at a \verb|./|, if any, and check if no tokens are
+%   before the \verb|./|, or if the only character is a \verb|.|.
+%   If these requirements are fulfilled, the leading
+%   \verb|.| is replaced with \cs{@@_currname_or_default:n}.  Otherwise
+%   the label is returned unchanged.
+%    \begin{macrocode}
+\cs_new:Npn \@@_parse_dot_label:nn #1 #2
+  {
+    \tl_if_empty:nTF {#1}
+      {
+        \msg_expandable_error:nnn { hooks } { empty-label } {#2}
+        #2
+      }
+      {
+        \str_if_eq:nnTF {#1} { . }
+          { \@@_currname_or_default:n {#1} }
+          { \@@_parse_dot_label:nw {#2} #1 ./ \s_@@_mark }
+      }
+  }
+\cs_new:Npn \@@_parse_dot_label:nw #1 #2 ./ #3 \s_@@_mark
+  {
+    \tl_if_empty:nTF {#2}
+      { \@@_parse_dot_label_aux:nw {#1} #3 \s_@@_mark }
+      {
+        \tl_if_empty:nTF {#3}
+          {#2}
+          { \@@_parse_dot_label_cleanup:w #2 ./ #3 \s_@@_mark }
+      }
+  }
+\cs_new:Npn \@@_parse_dot_label_cleanup:w #1 ./ \s_@@_mark {#1}
+\cs_new:Npn \@@_parse_dot_label_aux:nw #1 #2 ./ \s_@@_mark
+  { \@@_currname_or_default:n {#1} / #2 }
+%    \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}[EXP]{\@@_currname_or_default:n}
+%   Uses \cs{g_@@_hook_curr_name_tl} if it is set, otherwise tries
+%   \cs{@currname}.  If neither is set, uses the fallback value
+%   \verb|#1| (usually \texttt{top-level}).
+%    \begin{macrocode}
+\cs_new:Npn \@@_currname_or_default:n #1
+  {
+    \tl_if_empty:NTF \g_@@_hook_curr_name_tl
+      {
+        \tl_if_empty:NTF \@currname
+          {#1}
+          { \@currname }
+      }
+      { \g_@@_hook_curr_name_tl }
+  }
+%    \end{macrocode}
+% \end{macro}
 
 
 
-% \begin{macro}{\hook_gput_code:nnn,\hook_gput_code:non,
-%               \hook_gput_code:nnv,\hook_gput_code:nov}
-% \begin{macro}{\@@_hook_gput_code_do:nnn}
+
+% \begin{macro}{\hook_gput_code:nnn}
+% \begin{macro}{\@@_gput_code:nnn,\@@_gput_code:nxv,\@@_hook_gput_code_do:nnn}
 %
 %    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}.
 %    \begin{macrocode}
-\cs_new_protected:Npn \hook_gput_code:nnn #1#2#3
+\cs_new_protected:Npn \hook_gput_code:nnn #1 #2 #3
+  {
+    \exp_args:Nnx \@@_gput_code:nnn {#1}
+      { \@@_parse_label_default:nn {#2} { top-level } } {#3}
+  }
+\cs_new_protected:Npn \@@_gput_code:nnn #1 #2 #3
   {
 %    \end{macrocode}
 %    First we check if the hook exists.
@@ -1383,7 +1556,7 @@
           { \@@_try_declaring_generic_hook:nnn {#1} {#2} {#3} }
       }
   }
-\cs_generate_variant:Nn \hook_gput_code:nnn { non, nnv, nov }
+\cs_generate_variant:Nn \@@_gput_code:nnn { nxv }
 %    \end{macrocode}
 %
 %   This macro will unconditionally add a chunk of code to the given hook.
@@ -1527,13 +1700,19 @@
 %  \end{macro}
 
 
-% \begin{macro}{\hook_gremove_code:nn,\hook_gremove_code:no}
+% \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.
 %    \begin{macrocode}
 \cs_new_protected:Npn \hook_gremove_code:nn #1 #2
   {
+    \exp_args:Nnx \@@_gremove_code:nn {#1}
+      { \@@_parse_label_default:nn {#2} { top-level } }
+  }
+\cs_new_protected:Npn \@@_gremove_code:nn #1 #2
+  {
 %    \end{macrocode}
 %    First check that the hook code pool exists.  \cs{hook_if_exist:nTF}
 %    isn't used here because it should be possible to remove code from a
@@ -1554,11 +1733,11 @@
           {
 %    \end{macrocode}
 %    Check if the label being removed exists in the code pool.  If it does,
-%    just call \cs{@@_remove_code:nn} to do the removal, otherwise mark it
+%    just call \cs{@@_gremove_code_do:nn} to do the removal, otherwise mark it
 %    to be removed.
 %    \begin{macrocode}
             \prop_get:cnNTF { g_@@_#1_code_prop } {#2} \l_@@_return_tl
-              { \@@_remove_code:nn }
+              { \@@_gremove_code_do:nn }
               { \@@_mark_removal:nn }
                   {#1} {#2}
           }
@@ -1570,12 +1749,11 @@
       }
       { \@@_mark_removal:nn {#1} {#2} }
   }
-\cs_generate_variant:Nn \hook_gremove_code:nn {no}
 %    \end{macrocode}
 %
-% \begin{macro}{\@@_remove_code:nn}
+% \begin{macro}{\@@_gremove_code_do:nn}
 %    \begin{macrocode}
-\cs_new_protected:Npn \@@_remove_code:nn #1 #2
+\cs_new_protected:Npn \@@_gremove_code_do:nn #1 #2
   {
     \prop_gremove:cn { g_@@_#1_code_prop } {#2}
 %    \end{macrocode}
@@ -1589,6 +1767,7 @@
 %    \end{macrocode}
 % \end{macro}
 % \end{macro}
+% \end{macro}
 
 
 %
@@ -1733,6 +1912,7 @@
 %  \subsection{Setting rules for hooks code}
 %
 %  \begin{macro}{\hook_gset_rule:nnnn}
+%  \begin{macro}{\@@_gset_rule:nnnn,\@@_gset_rule:nxnx}
 %
 %    \fmi{needs docu correction given new implementation}
 %
@@ -1744,6 +1924,15 @@
 %    \begin{macrocode}
 \cs_new_protected:Npn \hook_gset_rule:nnnn #1#2#3#4
   {
+    \@@_gset_rule:nxnx {#1}
+      { \@@_parse_label_default:nn {#2} { top-level } } {#3}
+      { \@@_parse_label_default:nn {#4} { top-level } }
+  }
+%    \end{macrocode}
+%    
+%    \begin{macrocode}
+\cs_new_protected:Npn \@@_gset_rule:nnnn #1#2#3#4
+  {
 %    \end{macrocode}
 %    First we ensure the basic data structure of the hook exists:
 %    \begin{macrocode}
@@ -1766,8 +1955,10 @@
     \debug_resume:
     \@@_debug_gset_rule:nnnn {#1} {#2} {#3} {#4} % for debugging
   }
+\cs_generate_variant:Nn \@@_gset_rule:nnnn { nxnx }
 %    \end{macrocode}
 % \end{macro}
+% \end{macro}
 %
 % \begin{macro}{\@@_rule_before_gset:nnn, \@@_rule_after_gset:nnn,
 %               \@@_rule_<_gset:nnn, \@@_rule_>_gset:nnn}
@@ -2713,6 +2904,8 @@
     LaTeX~found~two~incompatible~labels~in~the~same~hook.~
     This~indicates~an~incompatibility~between~packages.
   }
+\msg_new:nnn { hooks } { empty-label }
+  { Empty~code~label~\msg_line_context:.~Using~`#1'~instead. }
 %    \end{macrocode}
 %
 %  \subsection{\LaTeXe{} package interface commands}
@@ -2732,16 +2925,11 @@
 %    
 %    \begin{macrocode}
 \NewDocumentCommand \AddToHook { m o +m }
-    {
-      \clist_if_in:NnTF  \g_@@_execute_immediately_clist {#1}
-        { #3 }
-        { \IfValueTF {#2}
-             { \hook_gput_code:nnn {#1}{#2}{#3}             }
-             { \tl_if_empty:NTF \@currname
-               { \hook_gput_code:nnn {#1}{top-level}{#3}  }
-               { \hook_gput_code:non {#1}{\@currname}{#3} } }
-        }
-}
+  {
+    \clist_if_in:NnTF \g_@@_execute_immediately_clist {#1}
+      {#3}
+      { \hook_gput_code:nnn {#1} {#2} {#3} }
+  }
 %    \end{macrocode}
 %  \end{macro}
 
@@ -2749,7 +2937,7 @@
 %    
 %    \begin{macrocode}
 \NewDocumentCommand \AddToHookNext { m +m }
-             { \hook_gput_next_code:nn {#1}{#2} }
+  { \hook_gput_next_code:nn {#1} {#2} }
 %    \end{macrocode}
 %  \end{macro}
 
@@ -2758,15 +2946,78 @@
 %    
 %    \begin{macrocode}
 \NewDocumentCommand \RemoveFromHook { m o }
-{ \IfValueTF {#2}
-             { \hook_gremove_code:nn {#1}{#2}             }
-             { \tl_if_empty:oTF \@currname
-               { \hook_gremove_code:nn {#1}{top-level}       }
-               { \hook_gremove_code:no {#1}{\@currname} } }
-}
+  { \hook_gremove_code:nn {#1} {#2} }
 %    \end{macrocode}
 %  \end{macro}
 %
+% \begin{macro}{\DeclareDefaultHookLabel}
+% \begin{macro}{\@@_curr_name_push:n,\@@_curr_name_pop:}
+%   The token list \cs{g_@@_hook_curr_name_tl} stores the name of the
+%   current package/file to be used as label for hooks.
+%   Providing a consistent interface is tricky, because packages can
+%   be loaded within packages, and some packages may not use
+%   \cs{DeclareDefaultHookLabel} to change the default label (in which case
+%   \cs{@currname} is used, if set).
+%
+%   To pull that off, we keep a stack that contains the default label
+%   for each level of input.  The bottom of the stack contains the
+%   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.
+%    \begin{macrocode}
+\seq_gpush:Nn \g_@@_name_stack_seq { }
+\seq_gpush:Nn \g_@@_name_stack_seq { lthooks }
+%    \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:
+%    \begin{macrocode}
+\cs_new_protected:Npn \@@_curr_name_push:n #1
+  {
+    \seq_gpush:Nn \g_@@_name_stack_seq {#1}
+    \tl_gset:Nn \g_@@_hook_curr_name_tl {#1}
+  }
+%
+%    \end{macrocode}
+%   and when an input is over, the topmost item of the stack is popped,
+%   since the label will not be used again, and \cs{g_@@_hook_curr_name_tl}
+%   is updated to the now topmost item of the stack:
+%    \begin{macrocode}
+\cs_new_protected:Npn \@@_curr_name_pop:
+  {
+    \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 }
+  }
+%    \end{macrocode}
+%
+%   The token list \cs{g_@@_hook_curr_name_tl} is but a mirror of the top
+%   of the stack.
+%
+%   Now define a wrapper that replaces the top of the stack with the
+%   argument, and updates \cs{g_@@_hook_curr_name_tl} accordingly.
+%    \begin{macrocode}
+\NewDocumentCommand \DeclareDefaultHookLabel { m }
+  {
+    \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}
+%
 %
 %
 %
@@ -2774,7 +3025,7 @@
 %    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 }
 %    \end{macrocode}
 %  \end{macro}
 %
@@ -3260,12 +3511,15 @@
 %
 % \subsection{Core hook management code (kernel part)}
 %
+%    This should run in older formats so we can't use
+%    \cs{IfFormatAtLeastTF} right now.
 %    \begin{macrocode}
-\IfFormatAtLeastTF{2020/10/01}{}
-  {\input{lthooks.ltx}
-   \input{ltshipout.ltx}
-   \input{ltfilehook.ltx}
-  }
+\@ifl at t@r\fmtversion{2020/10/01}
+                    {}
+                    {\input{lthooks.ltx}
+                     \input{ltshipout.ltx}
+                     \input{ltfilehook.ltx}
+                    }
 %    \end{macrocode}
 %
 %  \subsection{Package options}





More information about the latex3-commits mailing list.