[latex3-commits] [git/LaTeX3-latex3-latex2e] ltcmdhooks: midnight checkin [WIP] (af5ebc05)

Frank Mittelbach frank.mittelbach at latex-project.org
Sun Apr 18 00:00:31 CEST 2021


Repository : https://github.com/latex3/latex2e
On branch  : ltcmdhooks
Link       : https://github.com/latex3/latex2e/commit/af5ebc05b0799acdb6d1543f4ca2d6f59a913a6a

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

commit af5ebc05b0799acdb6d1543f4ca2d6f59a913a6a
Author: Frank Mittelbach <frank.mittelbach at latex-project.org>
Date:   Sun Apr 18 00:00:31 2021 +0200

    midnight checkin [WIP]


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

af5ebc05b0799acdb6d1543f4ca2d6f59a913a6a
 base/doc/{ltpara-code.tex => ltcmdhooks-code.tex} |   2 +-
 base/doc/{ltpara-doc.tex => ltcmdhooks-doc.tex}   |   2 +-
 base/ltcmdhooks.dtx                               | 372 +---------------------
 base/lthooks.dtx                                  | 237 +++++++++++---
 base/update-lthooks-tests.sh                      |   2 +-
 5 files changed, 209 insertions(+), 406 deletions(-)

diff --git a/base/doc/ltpara-code.tex b/base/doc/ltcmdhooks-code.tex
similarity index 77%
copy from base/doc/ltpara-code.tex
copy to base/doc/ltcmdhooks-code.tex
index 2e5beda3..e54dcf10 100644
--- a/base/doc/ltpara-code.tex
+++ b/base/doc/ltcmdhooks-code.tex
@@ -1,4 +1,4 @@
 % this will typeset documentation + code
 
 \AtBeginDocument{\AlsoImplementation}
-\input{ltpara.dtx}
+\input{ltcmdhooks.dtx}
diff --git a/base/doc/ltpara-doc.tex b/base/doc/ltcmdhooks-doc.tex
similarity index 87%
copy from base/doc/ltpara-doc.tex
copy to base/doc/ltcmdhooks-doc.tex
index c3892b81..1efae5f2 100644
--- a/base/doc/ltpara-doc.tex
+++ b/base/doc/ltcmdhooks-doc.tex
@@ -3,4 +3,4 @@
 \AtBeginDocument{\OnlyDescription
                  \let\tableofcontents\relax
                  }
-\input{ltpara.dtx}
+\input{ltcmdhooks.dtx}
diff --git a/base/ltcmdhooks.dtx b/base/ltcmdhooks.dtx
index a02c479b..b2093b84 100644
--- a/base/ltcmdhooks.dtx
+++ b/base/ltcmdhooks.dtx
@@ -13,8 +13,8 @@
 %
 %%% From File: ltcmdhooks.dtx
 %
-\def\ltcmdhooksversion{v0.9c}
-\def\ltcmdhooksdate{2021/04/16}
+\def\ltcmdhooksversion{v0.9d}
+\def\ltcmdhooksdate{2021/04/17}
 %
 %
 %
@@ -53,8 +53,7 @@
 %
 % \section{Introduction}
 %
-%    This implements generic hooks for commands.
-%
+%    This file implements generic hooks for (arbitrary) commands.
 %    In theory every command \tn[no-index]{\meta{name}} offers now two
 %    associated hooks to which code can be added using \tn{AddToHook}
 %    or \tn{AddToHookNext}.\footnote{In practice this is not supported
@@ -289,150 +288,22 @@
 %
 % Undefines:
 %    \begin{macrocode}
-\cs_undefine:N \@@_new:n
-\cs_undefine:N \c_@@_generics_prop
-\cs_undefine:N \@@_try_declaring_generic_hook:wnTF
+%%\cs_undefine:N \@@_new:n
+%%\cs_undefine:N \c_@@_generics_prop
+%%\cs_undefine:N \@@_try_declaring_generic_hook:wnTF
 \cs_undefine:N \IfHookExistsTF
-\cs_undefine:N \@@_gput_code:nnn
-\cs_undefine:N \@@_gput_next_code:nn
-\cs_undefine:N \@@_log:nN
+%%\cs_undefine:N \@@_gput_code:nnn
+%%\cs_undefine:N \@@_gput_next_code:nn
+%%\cs_undefine:N \@@_log:nN
 % \prg_new_eq_conditional:NNn
 %   \@@_try_declaring_generic_hook:wn \tex_undefined:D { T, F, TF }
 %    \end{macrocode}
 %
-% \section{On the existence of hooks}
-% \label{sec:existence}
-% \pho{Put this section somewhere in the implementation of lthooks.dtx}
-%
-% A hook may be declared in three stages:
-% \begin{description}[format=\cs]
-%   \setlist[itemize]{leftmargin=5cm,format=\cs}
-%   \item[@@_declare:n] initializes the basic data structure for the
-%     hook so that it may contain code.  It creates the hook code pool
-%     (\cs[no-index]{g_@@_\meta{hook}_code_prop}) and the |top-level|
-%     and |next| token lists.  A hook is implicitly declared with
-%     \cs{@@_declare:n} when any is added to it.  A hook declared only
-%     with \cs{@@_declare:n} will not be usable with \cs{hook_use:n}.
-%     This state is detected by \cs{@@_if_exist:n} by
-%     \cs[no-index]{g_@@_\meta{hook}_code_prop} being defined.
-%     \begin{itemize}
-%       \item [@@_if_exist:n]      returns |true|.
-%       \item [@@_if_declared:nTF] returns |false|.
-%       \item [@@_if_created:nTF]  returns |false|.
-%       \item [@@_if_disabled:nTF] returns |false|.
-%     \end{itemize}
-%   \item[@@_create:n] initializes all hook data structures, as done
-%     by \cs{hook_new:n}, except that doing \cs{hook_new:n} on that
-%     hook will not result in an error.  This is done implicitly by
-%     \cs{hook_gput_code:n} when adding code to a generic hook.
-%     This state is detected by \cs{@@_if_declared:n} by
-%     \cs[no-index]{@@~\meta{hook}} being defined.
-%     \begin{itemize}
-%       \item [@@_if_exist:n]      returns |true|.
-%       \item [@@_if_declared:nTF] returns |true|.
-%       \item [@@_if_created:nTF]  returns |false|.
-%       \item [@@_if_disabled:nTF] returns |false|.
-%     \end{itemize}
-%   \item[hook_new:n] same as \cs{@@_create:n} except it also doesn't
-%     allow the hook to be declared again with \cs{hook_new:n}.
-%     This state is detected by \cs{@@_if_created:n} by
-%     \cs[no-index]{g_@@_\meta{hook}_created_tl} being defined.
-%     \begin{itemize}
-%       \item [@@_if_exist:n]      returns |true|.
-%       \item [@@_if_declared:nTF] returns |true|.
-%       \item [@@_if_created:nTF]  returns |true|.
-%       \item [@@_if_disabled:nTF] returns |false|.
-%     \end{itemize}
-% \end{description}
-% A hook may additionally be disabled:
-% \begin{description}[format=\cs]
-%   \setlist[itemize]{leftmargin=5cm,format=\cs}
-%   \item[hook_disable:n] This forces the creation of the
-%     \cs[no-index]{g_@@_\meta{hook}_created_tl} so that the hook
-%     errors when used with \cs{hook_new:n}, then it undefines
-%     \cs[no-index]{@@~\meta{hook}} so that it may not be executed.
-%     Since by using the normal hook declaration commands from above
-%     we can't get this combination, if a hook has a
-%     \cs[no-index]{g_@@_\meta{hook}_created_tl} and not a
-%     \cs[no-index]{@@~\meta{hook}} then it is disabled.
-%     \cs{@@_if_disabled:n} uses that to check if the hook is
-%     disabled.
-%     \begin{itemize}
-%       \item [@@_if_exist:n] may return |true| or |false|.
-%       \item [@@_if_declared:nTF] returns |false|.
-%       \item [@@_if_created:nTF]  returns |true|.
-%       \item [@@_if_disabled:nTF] returns |true|.
-%     \end{itemize}
-% \end{description}
-%
-%    \begin{macrocode}
-\cs_new_protected:Npn \@@_new:n #1
-  {
-%    \end{macrocode}
-%   We check if the hook was already \emph{explicitly} declared with
-%   \cs{hook_new:n}, and if it already exists we complain, otherwise set
-%   the \enquote{created} flag for the hook so that it errors next time
-%   \cs{hook_new:n} is used.
-%    \begin{macrocode}
-    \@@_if_created:nTF {#1}
-      { \msg_error:nnn { hooks } { exists } {#1} }
-      {
-        \tl_new:c { g_@@_#1_created_tl }
-        \@@_create:n {#1}
-      }
-  }
-%    \end{macrocode}
-%
-%    \begin{macrocode}
-\cs_new_protected:Npn \@@_create:n #1
-  {
-%    \end{macrocode}
-%   Now we check if the hook's data structure can be safely created
-%   without \pkg{expl3} raising errors, then
-%   we add the hook name to the list of all hooks and
-%   allocate the necessary data structures for the new hook,
-%   otherwise just do nothing.
-%    \begin{macrocode}
-    \tl_if_exist:cF { @@~#1 }
-      {
-        \seq_gput_right:Nn \g_@@_all_seq {#1}
-%    \end{macrocode}
-%    This is only used by the actual code of the current hook, so
-%    declare it normally:
-%    \begin{macrocode}
-        \tl_new:c { @@~#1 }
-%    \end{macrocode}
-%    Now ensure that the base data structure for the hook exists:
-%    \begin{macrocode}
-        \@@_declare:n {#1}
-%    \end{macrocode}
-%    The \cs{g_@@_\meta{hook}_labels_clist} holds the sorted list of
-%    labels (once it got sorted). This is used only for debugging.
-%    \begin{macrocode}
-        \clist_new:c { g_@@_#1_labels_clist }
-%    \end{macrocode}
-%    Some hooks should reverse the default order of code chunks. To
-%    signal this we have a token list which is empty for normal hooks
-%    and contains a \verb=-= for reversed hooks.
-%    \begin{macrocode}
-        \tl_new:c { g_@@_#1_reversed_tl }
-%    \end{macrocode}
-%    The above is all in L3 convention, but we also provide an
-%    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 at 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}
 %
 % Rename \cs{hook_if_exist:nTF} to \cs{@@_if_declared:nTF}
@@ -463,52 +334,7 @@
 \cs_new_eq:NN \IfHookExistsTF \@@_if_declared:nTF
 %    \end{macrocode}
 %
-% Add \texttt{cmd} to the list of generic hooks.
 %    \begin{macrocode}
-\prop_const_from_keyval:Nn \c_@@_generics_prop
-  {cmd=,env=,file=,package=,class=,include=}
-\prg_new_protected_conditional:Npnn \@@_try_declaring_generic_hook:wn
-    #1 / #2 / #3 / #4 \scan_stop: #5 { TF }
-  {
-    \tl_if_empty:nTF {#2}
-      { \prg_return_false: }
-      {
-        \prop_if_in:NnTF \c_@@_generics_prop {#1}
-          {
-            \@@_if_declared:nF {#5}
-              {
-%    \end{macrocode}
-%    If the hook doesn't exist yet we check if it is a \texttt{cmd}
-%    hook and if so we attempt patching the command in addition to
-%    declaring the hook.
-%
-%    For some commands this will not be possible, in which case
-%    \cs{@@_patch_cmd_or_delay:Nnn} will generate an appropriate error
-%    message.
-%    \begin{macrocode}
-                \str_if_eq:nnT {#1} { cmd }
-                  { \@@_try_put_cmd_hook:n {#5} }
-%    \end{macrocode}
-%
-%    Declare the hook always even if it can't really be used (error
-%    message generated elsewhere).
-%
-%    Here we use \cs{@@_create:n}, so that a \cs{hook_new:n} is still
-%    possible later.
-%    \begin{macrocode}
-                \@@_create:n {#5}
-              }
-            \prop_if_in:NnTF \c_@@_generics_reversed_ii_prop {#2}
-              { \tl_gset:cn { g_@@_#5_reversed_tl } { - } }
-              {
-                \prop_if_in:NnT \c_@@_generics_reversed_iii_prop {#3}
-                  { \tl_gset:cn { g_@@_#5_reversed_tl } { - } }
-              }
-            \prg_return_true:
-          }
-          { \prg_return_false: }
-      }
-  }
 %    \end{macrocode}
 %
 % \begin{macro}{\hook_disable:n}
@@ -542,72 +368,9 @@
 % \end{macro}
 %
 %    \begin{macrocode}
-\cs_new_protected:Npn \@@_gput_code:nnn #1 #2 #3
-  {
-%    \end{macrocode}
-%    First check if the hook was used as a one-time hook:
-%    \begin{macrocode}
-    \prop_if_in:NnTF \g_@@_execute_immediately_prop {#1}
-      {#3}
-      {
-%    \end{macrocode}
-%    Then 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}
-%    If no removal is queued, we are free to add.  Start by checking if
-%    the hook exists.
-%    \begin{macrocode}
-            \@@_if_declared:nTF {#1}
-%    \end{macrocode}
-%    If so we simply add (or append) the new code to the property list
-%    holding different chunks for the hook. At \verb=\begin{document}=
-%    this is then sorted into a token list for fast execution.
-%    \begin{macrocode}
-              {
-                \@@_hook_gput_code_do:nnn {#1} {#2} {#3}
-%    \end{macrocode}
-%    However, if there is an update within the document we need to alter
-%    this execution code which is done by
-%    \cs{@@_update_hook_code:n}. In the preamble this does nothing.
-%    \begin{macrocode}
-                \@@_update_hook_code:n {#1}
-              }
-%    \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}
-              {
-                \@@_if_disabled:nTF {#1}
-                  { \msg_error:nnn { hooks } { hook-disabled } {#1} }
-                  { \@@_try_declaring_generic_hook:nnn {#1} {#2} {#3} }
-              }
-          }
-      }
-  }
 %    \end{macrocode}
 %
 %    \begin{macrocode}
-\cs_new_protected:Npn \@@_gput_next_code:nn #1 #2
-  {
-    \@@_if_disabled:nTF {#1}
-      { \msg_error:nnn { hooks } { hook-disabled } {#1} }
-      {
-        \@@_declare:n {#1}
-        \hook_if_exist:nTF {#1}
-          { \@@_gput_next_do:nn {#1} {#2} }
-          { \@@_try_declaring_generic_next_hook:nn {#1} {#2} }
-      }
-  }
 %    \end{macrocode}
 %
 %    \begin{macrocode}
@@ -621,115 +384,6 @@
 %    \end{macrocode}
 %
 %    \begin{macrocode}
-\cs_new_protected:Npn \@@_log:nN #1 #2
-  {
-    \@@_preamble_hook:n {#1}
-    \@@_log_cmd:x { ^^J ->~The~hook~'#1': }
-%    \end{macrocode}
-%
-%    \begin{macrocode}
-    \@@_if_declared:nF {#1}
-      { \@@_log_line:x { The~hook~is~not~declared. } }
-    \@@_if_disabled:nT {#1}
-      { \@@_log_line:x { The~hook~is~disabled. } }
-    \hook_if_empty:nTF {#1}
-      { #2 { The~hook~is~empty } }
-      {
-        \@@_log_line:x { Code~chunks: }
-        \prop_if_empty:cTF { g_@@_#1_code_prop }
-          { \@@_log_line_indent:x { --- } }
-          {
-            \prop_map_inline:cn { g_@@_#1_code_prop }
-              { \@@_log_line_indent:x { ##1~->~\tl_to_str:n {##2} } }
-          }
-%    \end{macrocode}
-%
-%    If there is code in the |top-level| token list, print it:
-%    \begin{macrocode}
-        \@@_log_line:x
-          {
-            Document-level~(top-level)~code
-            \@@_if_declared:nT {#1}
-              { ~(executed~\@@_if_reversed:nTF {#1} {first} {last} ) } :
-          }
-        \@@_log_line_indent:x
-          {
-            \tl_if_empty:cTF { @@_toplevel~#1 }
-              { --- }
-              { -> ~ \exp_args:Nv \tl_to_str:n { @@_toplevel~#1 } }
-          }
-%    \end{macrocode}
-%
-%    \begin{macrocode}
-        \@@_log_line:x { Extra~code~for~next~invocation: }
-        \@@_log_line_indent:x
-          {
-            \tl_if_empty:cTF { @@_next~#1 }
-              { --- }
-%    \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 { @@_next~#1 } }
-          }
-%    \end{macrocode}
-%
-%   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}
-        \@@_log_line:x { Rules: }
-        \bool_set_true:N \l_@@_tmpa_bool
-        \@@_list_rules:nn {#1}
-          {
-            \bool_set_false:N \l_@@_tmpa_bool
-            \@@_log_line_indent:x
-              {
-                ##2~ with~
-                \str_if_eq:nnT {##3} {??} { default~ }
-                relation~ ##1
-              }
-          }
-        \bool_if:NT \l_@@_tmpa_bool
-          { \@@_log_line_indent:x { --- } }
-%    \end{macrocode}
-%
-%   When the hook is declared (that is, the sorting algorithm is applied
-%   to that hook) and not empty
-%    \begin{macrocode}
-        \bool_lazy_and:nnTF
-            { \@@_if_declared_p:n {#1} }
-            { ! \hook_if_empty_p:n {#1} }
-          {
-            \@@_log_line:x
-              {
-                Execution~order
-                \bool_if:NTF \l_@@_tmpa_bool
-                  { \@@_if_reversed:nT {#1} { ~(after~reversal) } }
-                  { ~(after~
-                    \@@_if_reversed:nT {#1} { reversal~and~ }
-                    applying~rules)
-                  } :
-              }
-            #2 % \tl_show:n
-              {
-                \@spaces
-                \clist_if_empty:cTF { g_@@_#1_labels_clist }
-                  { --- }
-                  { \clist_use:cn {g_@@_#1_labels_clist} { ,~ } }
-              }
-          }
-          {
-            #2
-              {
-                Hook~ \@@_if_declared:nTF {#1}
-                  {code~pool~empty} {not~declared}
-              }
-          }
-      }
-  }
 %    \end{macrocode}
 %
 % \subsection{Variables}
diff --git a/base/lthooks.dtx b/base/lthooks.dtx
index 42668cfb..52a9d163 100644
--- a/base/lthooks.dtx
+++ b/base/lthooks.dtx
@@ -31,8 +31,8 @@
 %%% From File: lthooks.dtx
 %
 %    \begin{macrocode}
-\def\lthooksversion{v1.0j}
-\def\lthooksdate{2021/04/16}
+\def\lthooksversion{v1.0k}
+\def\lthooksdate{2021/04/17}
 %    \end{macrocode}
 %
 %<*driver>
@@ -1455,6 +1455,38 @@
 % \end{function}
 %
 %
+% \subsubsection{Generic hooks for commands}
+%
+%    Similar to environments there are now (at least in theory) two
+%    generic hooks available for any \LaTeX{} command. These are
+%    \begin{description}
+%    \item[\hook{cmd/\meta{name}/before}]
+%
+%       This hook is executed at the very start of the command
+%       execution.
+%
+%    \item[\hook{cmd/\meta{name}/after}]
+%       This hook is executed at the very end of the command body.  It is
+%       implemented as a reversed hook.
+%    \end{description}
+%    In practice there are restrictions and especially the
+%    \hook{after} hook works only with a subset of commands. Details
+%    on restrictions documented in
+%    \texttt{ltcmdhooks-doc.pdf} or with code in
+%    \texttt{ltcmdhooks-code.pdf}.
+%
+%
+%
+%
+% \subsubsection{Generic 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
+%    \cs{input}, \cs{include}, \cs{usepackage}, etc. These are documented in
+%    \texttt{ltfilehook-doc.pdf} or with code in
+%    \texttt{ltfilehook-code.pdf}.
+%
+%
 %
 % \subsubsection{Hooks provided by \cs{begin}\texttt{\{document\}}}
 % \label{sec:begindocument-hooks}
@@ -1630,14 +1662,6 @@
 %    \texttt{ltshipout-code.pdf}.
 %
 %
-% \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
-%    \cs{input}, \cs{include}, \cs{usepackage}, etc. These are documented in
-%    \texttt{ltfilehook-doc.pdf} or with code in
-%    \texttt{ltfilehook-code.pdf}.
-%
 %
 % \subsubsection{Hooks provided in NFSS commands}
 %
@@ -1999,25 +2023,44 @@
 %
 %
 %
-%  \begin{macro}{\hook_new:n}
+%  \begin{macro}{\hook_new:n,\@@_new:n,\@@_create:n}
 %    The \cs{hook_new:n} declaration declare a new hook and expects
 %    the hook \meta{name} as its argument, e.g.,
 %    \hook{begindocument}.
 %    \begin{macrocode}
 \cs_new_protected:Npn \hook_new:n #1
   { \@@_normalize_hook_args:Nn \@@_new:n {#1} }
+%    \end{macrocode}
+%
+%    \begin{macrocode}
 \cs_new_protected:Npn \@@_new:n #1
   {
 %    \end{macrocode}
-%    We check for one of the internal data structures and if it
-%    already exists we complain.
+%   We check if the hook was already \emph{explicitly} declared with
+%   \cs{hook_new:n}, and if it already exists we complain, otherwise set
+%   the \enquote{created} flag for the hook so that it errors next time
+%   \cs{hook_new:n} is used.
 %    \begin{macrocode}
-    \hook_if_exist:nTF {#1}
+    \@@_if_created:nTF {#1}
       { \msg_error:nnn { hooks } { exists } {#1} }
+      {
+        \tl_new:c { g_@@_#1_created_tl }
+        \@@_create:n {#1}
+      }
+  }
+%    \end{macrocode}
+%
+%    \begin{macrocode}
+\cs_new_protected:Npn \@@_create:n #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.
+%   Now we check if the hook's data structure can be safely created
+%   without \pkg{expl3} raising errors, then
+%   we add the hook name to the list of all hooks and
+%   allocate the necessary data structures for the new hook,
+%   otherwise just do nothing.
 %    \begin{macrocode}
+    \tl_if_exist:cF { @@~#1 }
       {
         \seq_gput_right:Nn \g_@@_all_seq {#1}
 %    \end{macrocode}
@@ -2033,7 +2076,7 @@
 %    The \cs{g_@@_\meta{hook}_labels_clist} holds the sorted list of
 %    labels (once it got sorted). This is used only for debugging.
 %    \begin{macrocode}
-        \clist_new:c {g_@@_#1_labels_clist}
+        \clist_new:c { g_@@_#1_labels_clist }
 %    \end{macrocode}
 %    Some hooks should reverse the default order of code chunks. To
 %    signal this we have a token list which is empty for normal hooks
@@ -2055,7 +2098,7 @@
 %
 %    \begin{macrocode}
         \@@_include_legacy_code_chunk:n {#1}
-     }
+      }
   }
 %    \end{macrocode}
 %  \end{macro}
@@ -2152,6 +2195,74 @@
 % \end{macro}
 %
 %
+% \subsection{On the existence of hooks}
+% \label{sec:existence}
+%
+% A hook may be declared in three stages:
+% \begin{description}[format=\cs]
+%   \setlist[itemize]{leftmargin=5cm,format=\cs}
+%   \item[@@_declare:n] initializes the basic data structure for the
+%     hook so that it may contain code.  It creates the hook code pool
+%     (\cs[no-index]{g_@@_\meta{hook}_code_prop}) and the |top-level|
+%     and |next| token lists.  A hook is implicitly declared with
+%     \cs{@@_declare:n} when any is added to it.  A hook declared only
+%     with \cs{@@_declare:n} will not be usable with \cs{hook_use:n}.
+%     This state is detected by \cs{@@_if_exist:n} by
+%     \cs[no-index]{g_@@_\meta{hook}_code_prop} being defined.
+%     \begin{itemize}
+%       \item [@@_if_exist:n]      returns |true|.
+%       \item [@@_if_declared:nTF] returns |false|.
+%       \item [@@_if_created:nTF]  returns |false|.
+%       \item [@@_if_disabled:nTF] returns |false|.
+%     \end{itemize}
+%   \item[@@_create:n] initializes all hook data structures, as done
+%     by \cs{hook_new:n}, except that doing \cs{hook_new:n} on that
+%     hook will not result in an error.  This is done implicitly by
+%     \cs{hook_gput_code:n} when adding code to a generic hook.
+%     This state is detected by \cs{@@_if_declared:n} by
+%     \cs[no-index]{@@~\meta{hook}} being defined.
+%     \begin{itemize}
+%       \item [@@_if_exist:n]      returns |true|.
+%       \item [@@_if_declared:nTF] returns |true|.
+%       \item [@@_if_created:nTF]  returns |false|.
+%       \item [@@_if_disabled:nTF] returns |false|.
+%     \end{itemize}
+%   \item[hook_new:n] same as \cs{@@_create:n} except it also doesn't
+%     allow the hook to be declared again with \cs{hook_new:n}.
+%     This state is detected by \cs{@@_if_created:n} by
+%     \cs[no-index]{g_@@_\meta{hook}_created_tl} being defined.
+%     \begin{itemize}
+%       \item [@@_if_exist:n]      returns |true|.
+%       \item [@@_if_declared:nTF] returns |true|.
+%       \item [@@_if_created:nTF]  returns |true|.
+%       \item [@@_if_disabled:nTF] returns |false|.
+%     \end{itemize}
+% \end{description}
+% A hook may additionally be disabled:
+% \begin{description}[format=\cs]
+%   \setlist[itemize]{leftmargin=5cm,format=\cs}
+%   \item[hook_disable:n] This forces the creation of the
+%     \cs[no-index]{g_@@_\meta{hook}_created_tl} so that the hook
+%     errors when used with \cs{hook_new:n}, then it undefines
+%     \cs[no-index]{@@~\meta{hook}} so that it may not be executed.
+%     Since by using the normal hook declaration commands from above
+%     we can't get this combination, if a hook has a
+%     \cs[no-index]{g_@@_\meta{hook}_created_tl} and not a
+%     \cs[no-index]{@@~\meta{hook}} then it is disabled.
+%     \cs{@@_if_disabled:n} uses that to check if the hook is
+%     disabled.
+%     \begin{itemize}
+%       \item [@@_if_exist:n] may return |true| or |false|.
+%       \item [@@_if_declared:nTF] returns |false|.
+%       \item [@@_if_created:nTF]  returns |true|.
+%       \item [@@_if_disabled:nTF] returns |true|.
+%     \end{itemize}
+% \end{description}
+%
+%
+%
+%
+%
 %
 % \subsection{Parsing a label}
 %
@@ -2313,6 +2424,9 @@
 %    \begin{macrocode}
 \cs_new_protected:Npn \hook_gput_code:nnn #1 #2
   { \@@_normalize_hook_args:Nnn \@@_gput_code:nnn {#1} {#2} }
+%    \end{macrocode}
+%
+%    \begin{macrocode}
 \cs_new_protected:Npn \@@_gput_code:nnn #1 #2 #3
   {
 %    \end{macrocode}
@@ -2336,7 +2450,7 @@
 %    If no removal is queued, we are free to add.  Start by checking if
 %    the hook exists.
 %    \begin{macrocode}
-            \hook_if_exist:nTF {#1}
+            \@@_if_declared:nTF {#1}
 %    \end{macrocode}
 %    If so we simply add (or append) the new code to the property list
 %    holding different chunks for the hook. At \verb=\begin{document}=
@@ -2357,10 +2471,17 @@
 %    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} }
+              {
+                \@@_if_disabled:nTF {#1}
+                  { \msg_error:nnn { hooks } { hook-disabled } {#1} }
+                  { \@@_try_declaring_generic_hook:nnn {#1} {#2} {#3} }
+              }
           }
       }
   }
+%    \end{macrocode}
+%
+%    \begin{macrocode}
 \cs_generate_variant:Nn \@@_gput_code:nnn { nxv }
 %    \end{macrocode}
 %
@@ -2475,12 +2596,18 @@
       }
       { \@@_try_declaring_generic_hook_split:nNNnn {#1} }
   }
+%    \end{macrocode}
+%
+%    \begin{macrocode}
 \cs_new_protected:Npn \@@_try_declaring_generic_hook_split:nNNnn #1 #2 #3
   {
     \@@_try_declaring_generic_hook:wnTF #1 / / / \scan_stop: {#1}
       { #2 }
       { #3 } {#1}
   }
+%    \end{macrocode}
+%
+%    \begin{macrocode}
 \prg_new_protected_conditional:Npnn \@@_try_declaring_generic_hook:wn
     #1 / #2 / #3 / #4 \scan_stop: #5 { TF }
   {
@@ -2489,22 +2616,35 @@
       {
         \prop_if_in:NnTF \c_@@_generics_prop {#1}
           {
-            \hook_if_exist:nF {#5} { \hook_new:n {#5} }
+            \@@_if_declared:nF {#5}
+              {
+%    \end{macrocode}
+%    If the hook doesn't exist yet we check if it is a \texttt{cmd}
+%    hook and if so we attempt patching the command in addition to
+%    declaring the hook.
+%
+%    For some commands this will not be possible, in which case
+%    \cs{@@_patch_cmd_or_delay:Nnn} will generate an appropriate error
+%    message.
+%    \begin{macrocode}
+                \str_if_eq:nnT {#1} { cmd }
+                  { \@@_try_put_cmd_hook:n {#5} }
 %    \end{macrocode}
-%    After having declared the hook we check the second component (for
-%    file hooks) or the third component for environment hooks) and
-%    if it is on the list of components for which we should have declared
-%    a reversed hook we alter the hook data structure accordingly.
+%
+%    Declare the hook always even if it can't really be used (error
+%    message generated elsewhere).
+%
+%    Here we use \cs{@@_create:n}, so that a \cs{hook_new:n} is still
+%    possible later.
 %    \begin{macrocode}
+                \@@_create:n {#5}
+              }
             \prop_if_in:NnTF \c_@@_generics_reversed_ii_prop {#2}
               { \tl_gset:cn { g_@@_#5_reversed_tl } { - } }
               {
                 \prop_if_in:NnT \c_@@_generics_reversed_iii_prop {#3}
                   { \tl_gset:cn { g_@@_#5_reversed_tl } { - } }
               }
-%    \end{macrocode}
-%    Now that we know that the hook is declared we can add the code to it.
-%    \begin{macrocode}
             \prg_return_true:
           }
           { \prg_return_false: }
@@ -2588,14 +2728,16 @@
 %    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{cmd}]
+%      The generic hooks used for commands.
 %    \item[\texttt{env}]
 %      The generic hooks used in \cs{begin} and \cs{end}.
-%    \item[\texttt{file}]
+%    \item[\texttt{file}, \texttt{package}, \texttt{class}, \texttt{include}]
 %      The generic hooks used when loading a file
 %    \end{description}
 %    \begin{macrocode}
 \prop_const_from_keyval:Nn \c_@@_generics_prop
-  {env=,file=,package=,class=,include=}
+     {cmd=,env=,file=,package=,class=,include=}
 %    \end{macrocode}
 %  \end{macro}
 %
@@ -3567,6 +3709,9 @@
   { \@@_log_cmd:x { >~#1 } }
 \cs_new_protected:Npn \@@_log_line_indent:x #1
   { \@@_log_cmd:x { >~\@spaces #1 } }
+%    \end{macrocode}
+%
+%    \begin{macrocode}
 \cs_new_protected:Npn \@@_log:nN #1 #2
   {
     \@@_preamble_hook:n {#1}
@@ -3574,8 +3719,10 @@
 %    \end{macrocode}
 %
 %    \begin{macrocode}
-    \hook_if_exist:nF {#1}
-      { \@@_log_line:x { is~not~declared! } }
+    \@@_if_declared:nF {#1}
+      { \@@_log_line:x { The~hook~is~not~declared. } }
+    \@@_if_disabled:nT {#1}
+      { \@@_log_line:x { The~hook~is~disabled. } }
     \hook_if_empty:nTF {#1}
       { #2 { The~hook~is~empty } }
       {
@@ -3593,7 +3740,7 @@
         \@@_log_line:x
           {
             Document-level~(top-level)~code
-            \hook_if_exist:nT {#1}
+            \@@_if_declared:nT {#1}
               { ~(executed~\@@_if_reversed:nTF {#1} {first} {last} ) } :
           }
         \@@_log_line_indent:x
@@ -3644,7 +3791,7 @@
 %   to that hook) and not empty
 %    \begin{macrocode}
         \bool_lazy_and:nnTF
-            { \hook_if_exist_p:n {#1} }
+            { \@@_if_declared_p:n {#1} }
             { ! \hook_if_empty_p:n {#1} }
           {
             \@@_log_line:x
@@ -3668,7 +3815,7 @@
           {
             #2
               {
-                Hook~ \hook_if_exist:nTF {#1}
+                Hook~ \@@_if_declared:nTF {#1}
                   {code~pool~empty} {not~declared}
               }
           }
@@ -3773,17 +3920,19 @@
 %    \begin{macrocode}
 \cs_new_protected:Npn \hook_gput_next_code:nn #1
   { \@@_normalize_hook_args:Nn \@@_gput_next_code:nn {#1} }
+%    \end{macrocode}
+%
+%    \begin{macrocode}
 \cs_new_protected:Npn \@@_gput_next_code:nn #1 #2
   {
-    \@@_declare:n {#1}
-    \hook_if_exist:nTF {#1}
-      { \@@_gput_next_do:nn {#1} {#2} }
-      { \@@_try_declaring_generic_next_hook:nn {#1} {#2} }
-  }
-\cs_new_protected:Npn \@@_gput_next_do:nn #1
-  {
-    \exp_args:Nc \@@_gput_next_do:Nnn
-      { @@_next~#1 } {#1}
+    \@@_if_disabled:nTF {#1}
+      { \msg_error:nnn { hooks } { hook-disabled } {#1} }
+      {
+        \@@_declare:n {#1}
+        \hook_if_exist:nTF {#1}
+          { \@@_gput_next_do:nn {#1} {#2} }
+          { \@@_try_declaring_generic_next_hook:nn {#1} {#2} }
+      }
   }
 %    \end{macrocode}
 %   First check if the ``next code'' token list is empty:  if so we need
diff --git a/base/update-lthooks-tests.sh b/base/update-lthooks-tests.sh
index 4de8f625..0579ea6c 100644
--- a/base/update-lthooks-tests.sh
+++ b/base/update-lthooks-tests.sh
@@ -10,7 +10,7 @@ l3build save -cconfig-lthooks \
  ltcmdhooks-008 \
  ltcmdhooks-009
 
-
+exit
 
 l3build save -cconfig-lthooks2 \
    lthooks2-002 \





More information about the latex3-commits mailing list.