[latex3-commits] [git/LaTeX3-latex3-latex2e] lthooks: new ltfilehook version (e9855c00)
Frank Mittelbach
frank.mittelbach at latex-project.org
Tue Jul 14 10:27:31 CEST 2020
Repository : https://github.com/latex3/latex2e
On branch : lthooks
Link : https://github.com/latex3/latex2e/commit/e9855c00939d6a0781d1ef27bddff9e9599025d4
>---------------------------------------------------------------
commit e9855c00939d6a0781d1ef27bddff9e9599025d4
Author: Frank Mittelbach <frank.mittelbach at latex-project.org>
Date: Tue Jul 14 10:27:31 2020 +0200
new ltfilehook version
>---------------------------------------------------------------
e9855c00939d6a0781d1ef27bddff9e9599025d4
base/ltfilehook.dtx | 235 +++++++++---------
base/lthooks.dtx | 324 ++++++++++++++++++-------
required/tools/testfiles/github-0222-input.tlg | 2 +-
3 files changed, 355 insertions(+), 206 deletions(-)
diff --git a/base/ltfilehook.dtx b/base/ltfilehook.dtx
index 6dee9b67..491e3123 100644
--- a/base/ltfilehook.dtx
+++ b/base/ltfilehook.dtx
@@ -355,7 +355,46 @@
% \begin{macrocode}
%<*2ekernel>
% \end{macrocode}
-
+%
+% \subsection{\pkg{expl3} helpers}
+%
+% \begin{macrocode}
+%<@@=filehook>
+% \end{macrocode}
+%
+% \begin{macro}{\CurrentFile}
+% User-level name for use in the file hooks.
+% \begin{macrocode}
+\def\CurrentFile{}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@filehook at set@curr at file,\@@_normalise_file_name:n}
+% This macro sets \cs{CurrentFile} so that it holds the name of the
+% current input file. This macro checks that the file exists, and
+% if so sets \cs{CurrentFile} to expand to the actual file found
+% (regardless, for example, if the user input a |.tex| file without
+% typing in the extension).
+% \begin{macrocode}
+\ExplSyntaxOn
+\tl_new:N \l_@@_internal_a_tl
+\tl_new:N \l_@@_internal_b_tl
+\tl_new:N \l_@@_internal_c_tl
+\cs_new_protected:Npn \@filehook at set@curr at file #1
+ { \exp_args:NV \@@_normalise_file_name:n #1 }
+\cs_new_protected:Npn \@@_normalise_file_name:n #1
+ {
+ \file_if_exist:nTF {#1}
+ {
+ \exp_args:Nx \file_parse_full_name:nNNN
+ { \file_full_name:n {#1} }
+ }
+ { \file_parse_full_name:nNNN {#1} }
+ \l_@@_internal_a_tl \l_@@_internal_b_tl \l_@@_internal_c_tl
+ \tl_set:Nx \CurrentFile { \l_@@_internal_b_tl \l_@@_internal_c_tl }
+ }
+\ExplSyntaxOff
+% \end{macrocode}
%
% \subsection{Declaring the file-related hooks}
%
@@ -365,11 +404,9 @@
% explicitly declare any hook in the code below.
%
% Furthermore, those named \texttt{.../after} or \texttt{.../end} are
-% automatically declared as reversed hooks if fill with code, s this
+% automatically declared as reversed hooks if filled with code, so this
% is also automatically taken care of.
%
-%
-%
% \subsection{Patching \LaTeX{} commands (need proper integration later)}
%
% Most of what we have to do is adding \cs{UseHook} into several
@@ -378,7 +415,7 @@
%<@@=>
% \end{macrocode}
%
-% \begin{macro}{\InputIfFileExists}
+% \begin{macro}{\InputIfFileExists}
% \cs{InputIfFileExists} loads any file if it is available so we
% have to add the hooks \texttt{file/before} and
% \texttt{file/after} in the right places. If the file doesn't
@@ -387,97 +424,69 @@
\let\InputIfFileExists\@undefined
\DeclareRobustCommand \InputIfFileExists[2]{%
\IfFileExists{#1}%
- {%
+ {%
% \end{macrocode}
% If the file exists then \cs{@curr at file} holds its name. But we
% can't rely on that still being true after the file has been
% processed. Thus for using the name in the file hooks we need to
-% preserve the name and then restored it for the \texttt{file/after/...} hook.
+% preserve the name and then restored it for the
+% \texttt{file/after/...} hook.
+%
+% The hook always refers to the \emph{actual} file that will be
+% operated on, regardless of how the user had it written in the
+% document. \pkg{expl3}'s \cs{file_full_name:n} normalises the file
+% name (to factor out differences in the |.tex| extension), and
+% then does a file lookup to take into account a possible path from
+% \cs{l_file_search_path_seq} and \cs{input at path}. However only
+% the file name and extension are returned: the path is removed so
+% that (say) |\AddToHook{file/before/article.cls}{code}| works
+% regardless of where |article.cls| is in the system.
% \begin{macrocode}
- \edef\reserved at a{\@filef at und
- \def\noexpand\@curr at file{\@curr at file}%
- }%
+ \edef\reserved at a{\@filef at und
+ \def\noexpand\CurrentFile{\CurrentFile}%
+ }%
\expandafter\@swaptwoargs\expandafter
- {\reserved at a}%
- {%
- #2%
- \@addtofilelist{#1}%
- \UseHook{file/before}%
+ {\reserved at a}%
+ {%
+ #2%
+ \@addtofilelist{#1}%
+ \UseHook{file/before}%
% \end{macrocode}
% The current file name is available in \cs{@curr at file} so we use
% that in the specific hook.
% \begin{macrocode}
- \UseHook{file/before/\@curr at file}%
- \@@input
- }%
+ \UseHook{file/before/\CurrentFile}%
+ \@@input
+ }%
% \end{macrocode}
% And it is restored here so we can use it once more.
% \begin{macrocode}
- \UseHook{file/after/\@curr at file}%
+ \UseHook{file/after/\CurrentFile}%
\UseHook{file/after}%
}%
}
% \end{macrocode}
-% \end{macro}
-
-
-
-% \begin{macro}{\set at curr@file}
-% The implicit \texttt{.tex} extension added by \cs{input},
-% etc.\ is rather a nuisance than a help imho.
-%
-% So this is an attempt to get to a common state and internally
-% always drop \texttt{.tex}. This works for all my test cases but I
-% guess it rather has to be the other way around (always explicitly
-% add \texttt{.tex} if it is missing and no extension given.
-%
-% We have to do one or the other because otherwise
-% \verb=\input{foo}= and \verb=input{foo.tex}= would try to execute
-% different specific hooks (\texttt{file/before/foo} and
-% \texttt{file/before/foo.tex}) which isn't really what we want!
-% \fmi{fix}
-%
-% \begin{macrocode}
-\begingroup
- \catcode`T=12
- \catcode`E=12
- \catcode`X=12
-% \end{macrocode}
+% \end{macro}
%
+% \begin{macro}{\set at curr@file}
+% Now we just hook into \cs{set at curr@file} to add
+% \cs{@filehook at set@curr at file} at the end, after \cs{@curr at file} is
+% set.
% \begin{macrocode}
-\lowercase{
- \gdef\set at curr@file#1{%
- \begingroup
- \escapechar\m at ne
- \xdef\@curr at file{%
- \expandafter\expandafter\expandafter\unquote at name
- \expandafter\expandafter\expandafter{%
- \expandafter\string
+\def\set at curr@file#1{%
+ \begingroup
+ \escapechar\m at ne
+ \xdef\@curr at file{%
+ \expandafter\expandafter\expandafter\unquote at name
+ \expandafter\expandafter\expandafter{%
+ \expandafter\string
\csname\@firstofone#1\@empty\endcsname}}%
- \expandafter
- \drop at tex@extension at other\@curr at file.TEX\drop at tex@extension at other
- \endgroup
- }
-% \end{macrocode}
-%
-% \begin{macrocode}
- \gdef\drop at tex@extension at other#1.TEX#2\drop at tex@extension at other
- {\gdef\@curr at file{#1}}
+ \endgroup
+ \@filehook at set@curr at file{\@curr at file}%
}
-\endgroup
% \end{macrocode}
% \end{macro}
%
-%
-
-% \begin{macro}{\CurrentFile}
-% User-level name for use in the file hooks.
-% \begin{macrocode}
-\def\CurrentFile{\@curr at file}
-% \end{macrocode}
-% \end{macro}
-
-
% \begin{macro}{\load at onefilewithoptions}
% This macro is used when loading packages or classes.
% \begin{macrocode}
@@ -513,17 +522,19 @@
{\@currname.\@currext}%
{%
% \end{macrocode}
-% When the current extension is \cs{@pkgextension} we are loading a
-% package otherwise (let's hope) a class, so depending on that we
-% execute different hooks.
+% package otherwise, if it is \cs{@clsextension}, a class, so
+% depending on that we execute different hooks. If the extension is
+% neither, then it is another type of file without special hooks.
% \begin{macrocode}
%-----------------------------------------
\ifx\@currext\@pkgextension
\UseHook{package/before}%
\UseHook{package/before/\@currname}%
\else
- \UseHook{class/before}%
- \UseHook{class/before/\@currname}%
+ \ifx\@currext\@clsextension
+ \UseHook{class/before}%
+ \UseHook{class/before/\@currname}%
+ \fi
\fi
%-----------------------------------------
}%
@@ -541,8 +552,10 @@
\UseHook{package/after/\@currname}%
\UseHook{package/after}%
\else
- \UseHook{class/after/\@currname}%
- \UseHook{class/after}%
+ \ifx\@currext\@clsextension
+ \UseHook{class/after/\@currname}%
+ \UseHook{class/after}%
+ \fi
\fi
%-----------------------------------------
\@unprocessedoptions}%
@@ -602,8 +615,10 @@
\UseHook{package/before}%
\UseHook{package/before/\@currname}%
\else
- \UseHook{class/before}%
- \UseHook{class/before/\@currname}%
+ \ifx\@currext\@clsextension
+ \UseHook{class/before}%
+ \UseHook{class/before/\@currname}%
+ \fi
\fi
%-----------------------------------------
\expandafter\let\csname unprocessedoptions-\@currname.\@currext\endcsname
@@ -624,8 +639,10 @@
\UseHook{package/after/\@currname}%
\UseHook{package/after}%
\else
- \UseHook{class/after/\@currname}%
- \UseHook{class/after}%
+ \ifx\@currext\@clsextension
+ \UseHook{class/after/\@currname}%
+ \UseHook{class/after}%
+ \fi
\fi
%-----------------------------------------
\@ifl at ter\@currext{#1}{#3}{}%
@@ -641,22 +658,13 @@
\@reset at ptions}%
\reserved at a}
}{}%
-
-
% \end{macrocode}
% \end{macro}
-% \begin{macro}{\@include#1}
-% This is for handling include hooks. As the code contains a
-% \cs{@for} look we need to disable \texttt{expl3} conventions or
-% chaos will happen :-(.
-% \begin{macrocode}
-\ExplSyntaxOff % code contains ":"
-% \end{macrocode}
-%
+% \begin{macro}{\@include}
% \begin{macrocode}
\def\@include#1 {%
\clearpage
@@ -812,23 +820,6 @@
%<*filehook-draft>
% \end{macrocode}
%
-% \begin{macro}{\drop at tex@extension}
-% This is a helper should vanish. For one it is not correct (as it
-% will do havoc to \texttt{foo.tex.bar.baz}) and dropping the
-% extension is weird anyway.
-% \fmi{fix! when default for .tex changes}
-% \begin{macrocode}
-\def\drop at tex@extension#1{%
- \edef\drop at tex@extension at result{%
- \expandafter
- \drop at tex@extension@\expanded{#1}.tex\drop at tex@extension@}%
- }
-\def\drop at tex@extension@#1.tex#2\drop at tex@extension@{#1}%
-% \end{macrocode}
-% \end{macro}
-%
-%
-%
% \begin{macrocode}
\newcommand\AtBeginOfEveryFile [1]
{\AddToHook{file/before}{#1}}
@@ -862,11 +853,9 @@
% For normal files we drop the \texttt{.tex} extension for now:
% \begin{macrocode}
\newcommand\AtBeginOfFile [2]
- {\drop at tex@extension{file/before/#1}%
- \expandafter\AddToHook\expandafter{\drop at tex@extension at result}{#2}}
+ {\AddToHook{file/before/#1}{#2}}
\newcommand\AtEndOfFile [2]
- {\drop at tex@extension{file/after/#1}%
- \expandafter\AddToHook\expandafter{\drop at tex@extension at result}{#2}}
+ {\AddToHook{file/after/#1}{#2}}
% \end{macrocode}
%
% \begin{macrocode}
@@ -940,11 +929,11 @@
% is only a rough draft.
% \begin{macrocode}
\newcommand\BeforeClass[2]
- {\AddToHook{file/before/#1.cls}{#2} }
+ {\AddToHook{file/before/#1.cls}{#2}}
\newcommand\AfterClass [2]
- {\AddToHook{file/after/#1.cls}{#2} }
+ {\AddToHook{file/after/#1.cls}{#2}}
\newcommand\AfterAtEndOfClass [2]
- {\AddToHook{class/after/#1}{#2} }
+ {\AddToHook{class/after/#1}{#2}}
% \end{macrocode}
%
% \begin{macrocode}
@@ -960,13 +949,11 @@
\newcommand\BeforeFile [2]
{%
\typeout{BeforeFile: #1!!!}%
- \drop at tex@extension{file/before/#1}%
- \expandafter\AddToHook\expandafter{\drop at tex@extension at result}{#2}}
+ \AddToHook{file/before/#1}{#2}}
\newcommand\AfterFile [2]
{%
\typeout{AfterFile: #1!!!}%
- \drop at tex@extension{file/after/#1}%
- \expandafter\AddToHook\expandafter{\drop at tex@extension at result}{#2}}
+ \AddToHook{file/after/#1}{#2}}
% \end{macrocode}
%
% This is missing some interfaces so disabling the package isn't
@@ -1005,7 +992,7 @@
% \begin{macrocode}
\tl_new:N \g_@@_nesting_prefix_tl
-\tl_gset:Nn \g_@@_nesting_prefix_tl {}
+\tl_gset:Nn \g_@@_nesting_prefix_tl { }
% \end{macrocode}
%
% \begin{macrocode}
@@ -1015,7 +1002,7 @@
\iow_term:x {
\g_@@_nesting_prefix_tl \space
( LEVEL~ \int_use:N \g_@@_nesting_level_int \space START )~
- \@curr at file ^^J
+ \CurrentFile ^^J
}
}
% \end{macrocode}
@@ -1030,7 +1017,7 @@
\iow_term:x {
\g_@@_nesting_prefix_tl \space
( LEVEL~ \int_use:N \g_@@_nesting_level_int \space STOP )~
- \@curr at file ^^J
+ \CurrentFile ^^J
}
\int_gdecr:N \g_@@_nesting_level_int
\tl_gset:Nx \g_@@_nesting_prefix_tl
diff --git a/base/lthooks.dtx b/base/lthooks.dtx
index e554a827..7c87d0cf 100644
--- a/base/lthooks.dtx
+++ b/base/lthooks.dtx
@@ -1315,10 +1315,12 @@
%
% \subsection{Declarations}
%
-% \begin{macro}{\l_@@_return_tl}
-% A scratch variable used throughout the package.
+% \begin{macro}{\l_@@_return_tl,\l_@@_tmpa_tl,\l_@@_tmpb_tl}
+% Scratch variables used throughout the package.
% \begin{macrocode}
\tl_new:N \l_@@_return_tl
+\tl_new:N \l_@@_tmpa_tl
+\tl_new:N \l_@@_tmpb_tl
% \end{macrocode}
% \end{macro}
%
@@ -1361,6 +1363,13 @@
% \end{macrocode}
% \end{macro}
%
+% \begin{macro}{\@@_tmp:w}
+% Temporary macro for generic usage.
+% \begin{macrocode}
+\cs_new_eq:NN \@@_tmp:w ?
+% \end{macrocode}
+% \end{macro}
+%
% \begin{macro}{\tl_gremove_once:Nx}
% Some variants of \pkg{expl3} functions. \fmi{should be moved to expl3}
% \begin{macrocode}
@@ -1715,38 +1724,77 @@
% \end{macrocode}
% \end{macro}
% \end{macro}
-
-% \begin{macro}{\@@_try_declaring_generic_hook:nnn}
-% \begin{macro}{\@@_try_declaring_generic_next_hook:nn}
-% \begin{macro}[TF]{\@@_try_declaring_generic_hook:wn}
-% We split the hook name at the first \texttt{/} (if any) and check
-% if that component is one of a predefined set for generic
-% names. We also split off the second component to see if we have
-% to make a reversed hook. In either case the function returns
-% \meta{true} for a generic hook and \meta{false} in other cases.
-%
-% The wrapper \cs{@@_try_declaring_generic_hook:nnn} then defers
-% \cs{hook_gput_code:nnn} if the generic hook was declared, or to
-% \cs{@@_gput_undeclared_hook:nnn} otherwse (the hook was tested for
-% existence before, so at this point if it isn't generic, it doesn't
-% exist).
-%
-% The wrapper \cs{@@_try_declaring_generic_next_hook:nn} for
-% next-execution hooks does the same: it defers the code to
-% \cs{hook_gput_next_code:nn} if the generic hook was declared, or
-% to \cs{@@_gput_next_do:nn} otherwise.
+%
+% \begin{macro}{\@@_gput_undeclared_hook:nnn}
+% Often it may happen that a package $A$ defines a hook \verb=foo=,
+% but package $B$, that adds code to that hook, is loaded before $A$.
+% In such case we need to add code to the hook before it's declared.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_gput_undeclared_hook:nnn #1 #2 #3
+ {
+ \@@_declare:n {#1}
+ \@@_hook_gput_code_do:nnn {#1} {#2} {#3}
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_try_declaring_generic_hook:nnn}
+% \begin{macro}{\@@_try_declaring_generic_next_hook:nn}
+% These entry-level macros just pass the arguments along to the
+% common \cs{@@_try_declaring_generic_hook:nNNnn} with the right
+% functions to execute when some action is to be taken.
+%
+% The wrapper \cs{@@_try_declaring_generic_hook:nnn} then defers
+% \cs{hook_gput_code:nnn} if the generic hook was declared, or to
+% \cs{@@_gput_undeclared_hook:nnn} otherwse (the hook was tested for
+% existence before, so at this point if it isn't generic, it doesn't
+% exist).
+%
+% The wrapper \cs{@@_try_declaring_generic_next_hook:nn} for
+% next-execution hooks does the same: it defers the code to
+% \cs{hook_gput_next_code:nn} if the generic hook was declared, or
+% to \cs{@@_gput_next_do:nn} otherwise.
% \begin{macrocode}
\cs_new_protected:Npn \@@_try_declaring_generic_hook:nnn #1
{
- \@@_try_declaring_generic_hook:wnTF #1 / / / \scan_stop: {#1}
- { \hook_gput_code:nnn {#1} }
- { \@@_gput_undeclared_hook:nnn {#1} }
+ \@@_try_declaring_generic_hook:nNNnn {#1}
+ \hook_gput_code:nnn \@@_gput_undeclared_hook:nnn
}
\cs_new_protected:Npn \@@_try_declaring_generic_next_hook:nn #1
{
+ \@@_try_declaring_generic_hook:nNNnn {#1}
+ \hook_gput_next_code:nn \@@_gput_next_do:nn
+ }
+% \end{macrocode}
+%
+% \begin{macro}{
+% \@@_try_declaring_generic_hook:nNNnn,
+% \@@_try_declaring_generic_hook_split:nNNnn
+% }
+% \begin{macro}[TF]{\@@_try_declaring_generic_hook:wn}
+% \cs{@@_try_declaring_generic_hook:nNNnn} now splits the hook name
+% at the first \texttt{/} (if any) and first checks if it is a
+% file-specific hook (they require some normalisation) using
+% \cs{@@_if_file_hook:wTF}. If not then check it is one of a
+% predefined set for generic names. We also split off the second
+% component to see if we have to make a reversed hook. In either case
+% the function returns \meta{true} for a generic hook and \meta{false}
+% in other cases.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_try_declaring_generic_hook:nNNnn #1
+ {
+ \@@_if_file_hook:wTF #1 / / \s_@@_mark
+ {
+ \exp_args:Ne \@@_try_declaring_generic_hook_split:nNNnn
+ { \exp_args:Ne \@@_file_hook_normalise:n {#1} }
+ }
+ { \@@_try_declaring_generic_hook_split:nNNnn {#1} }
+ }
+\cs_new_protected:Npn \@@_try_declaring_generic_hook_split:nNNnn #1 #2 #3
+ {
\@@_try_declaring_generic_hook:wnTF #1 / / / \scan_stop: {#1}
- { \hook_gput_next_code:nn {#1} }
- { \@@_gput_next_do:nn {#1} }
+ { #2 }
+ { #3 } {#1}
}
\prg_new_protected_conditional:Npnn \@@_try_declaring_generic_hook:wn
#1 / #2 / #3 / #4 \scan_stop: #5 { TF }
@@ -1754,19 +1802,19 @@
\tl_if_empty:nTF {#2}
{ \prg_return_false: }
{
- \clist_if_in:NnTF \c_@@_generics_clist {#1}
+ \prop_if_in:NnTF \c_@@_generics_prop {#1}
{
- \hook_new:n {#5}
+ \hook_if_exist:nF {#5} { \hook_new: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 datastructure accordingly.
% \begin{macrocode}
- \clist_if_in:NnTF \c_@@_generics_reversed_ii_clist {#2}
+ \prop_if_in:NnTF \c_@@_generics_reversed_ii_prop {#2}
{ \tl_gset:cn { g_@@_#5_reversed_tl } { - } }
{
- \clist_if_in:NnT \c_@@_generics_reversed_iii_clist {#3}
+ \prop_if_in:NnT \c_@@_generics_reversed_iii_prop {#3}
{ \tl_gset:cn { g_@@_#5_reversed_tl } { - } }
}
% \end{macrocode}
@@ -1778,26 +1826,75 @@
}
}
% \end{macrocode}
-% \end{macro}
-% \end{macro}
-% \end{macro}
-
-
-% \begin{macro}{\@@_gput_undeclared_hook:nnn}
-% Often it may happen that a package $A$ defines a hook \verb=foo=,
-% but package $B$, that adds code to that hook, is loaded before $A$.
-% In such case we need to add code to the hook before it's declared.
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}[pTF]{\@@_if_file_hook:w}
+% \cs{@@_if_file_hook:wTF} checks if the argument is a valid
+% file-specific hook (not, for example, |file/before|, but
+% |file/before/foo.tex|). If it is a file-specific hook, then it
+% executes the \meta{true} branch, otherwise \meta{false}.
+%
+% A file-specific hook is \texttt{file/\meta{position}/\meta{name}}.
+% If any of these parts don't exist, it is a general file hook or not
+% a file hook at all, so the conditional evaluates to \meta{false}.
+% Otherwise, it checks that the first part is |file| and that the
+% \meta{position} is in the \cs{c_@@_generics_file_prop}.
+%
+% A property list is used here to avoid having to worry with catcodes,
+% because \pkg{expl3}'s file name parsin turns all characters into
+% catcode-12 tokens, which might differ from hand-input letters.
% \begin{macrocode}
-\cs_new_protected:Npn \@@_gput_undeclared_hook:nnn #1 #2 #3
+\prg_new_conditional:Npnn \@@_if_file_hook:w
+ #1 / #2 / #3 \s_@@_mark { TF }
{
- \@@_declare:n {#1}
- \@@_hook_gput_code_do:nnn {#1} {#2} {#3}
+ \str_if_eq:nnTF {#1} { file }
+ {
+ \bool_lazy_or:nnTF
+ { \tl_if_empty_p:n {#3} }
+ { \str_if_eq_p:nn {#3} { / } }
+ { \prg_return_false: }
+ {
+ \prop_if_in:NnTF \c_@@_generics_file_prop {#2}
+ { \prg_return_true: }
+ { \prg_return_false: }
+ }
+ }
+ { \prg_return_false: }
}
% \end{macrocode}
% \end{macro}
+%
+% \begin{macro}[EXP]{\@@_file_hook_normalise: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 normalised by \cs{@@_file_hook_normalise: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 at 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
+ { \@@_strip_double_slash:n {#1} }
+\cs_new:Npn \@@_strip_double_slash:n #1
+ { \@@_strip_double_slash:w #1 // \s_@@_mark }
+\cs_new:Npn \@@_strip_double_slash:w #1 // #2 \s_@@_mark
+ {
+ \tl_if_empty:nTF {#2}
+ {#1}
+ { \@@_strip_double_slash:w #1 / #2 \s_@@_mark }
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+
-% \begin{macro}{\c_@@_generics_clist}
+
+
+% \begin{macro}{\c_@@_generics_prop}
% Clist holding the generic names. We don't provide any user
% interface to this as this is meant to be static.
% \begin{description}
@@ -1807,17 +1904,20 @@
% The generic hooks used when loading a file
% \end{description}
% \begin{macrocode}
-\clist_const:Nn \c_@@_generics_clist {env,file,package,class,include}
+\prop_const_from_keyval:Nn \c_@@_generics_prop
+ {env=,file=,package=,class=,include=}
% \end{macrocode}
% \end{macro}
%
-% \begin{macro}{\c_@@_generics_reversed_ii_clist,
-% \c_@@_generics_reversed_iii_clist}
+% \begin{macro}{\c_@@_generics_reversed_ii_prop,
+% \c_@@_generics_reversed_iii_prop,
+% \c_@@_generics_file_prop}}
% Some of the generic hooks are supposed to use reverse ordering, these are
% the following (only the second or third sub-component is checked):
% \begin{macrocode}
-\clist_const:Nn \c_@@_generics_reversed_ii_clist {after,end}
-\clist_const:Nn \c_@@_generics_reversed_iii_clist {after}
+\prop_const_from_keyval:Nn \c_@@_generics_reversed_ii_prop {after=,end=}
+\prop_const_from_keyval:Nn \c_@@_generics_reversed_iii_prop {after=}
+\prop_const_from_keyval:Nn \c_@@_generics_file_prop {before=,after=}
% \end{macrocode}
% \end{macro}
@@ -2255,9 +2355,8 @@
% call the hook code and not initialize it (as it was done in the
% preamble.
% \begin{macrocode}
- \cs_gset:Npn \hook_use:n ##1 {
- \tl_if_exist:cT{g_@@_##1_code_tl}
- { \cs:w g_@@_##1_code_tl\cs_end: } }
+ \cs_gset_eq:NN \hook_use:n \@@_use_initialized:n
+ \cs_gset_eq:NN \@@_preamble_hook:n \use_none:n
}
% \end{macrocode}
% \end{macro}
@@ -2892,35 +2991,97 @@
}
% \end{macrocode}
% \end{macro}
-
-
-% \subsection{Using the hook}
%
%
+% \subsection{Using the hook}
+%
+% \begin{macro}{\hook_use:n}
+% \begin{macro}[EXP]{\@@_use_initialized:n}
+% \begin{macro}{\@@_preamble_hook:n}
+% \cs{hook_use:n} as defined here is used in the preamble, where
+% hooks aren't initialised by default. \cs{@@_use_initialized:n} is
+% also defined, which is the non-\tn{protected} version for use within
+% the document. Their definition is identical, except for the
+% \cs{@@_preamble_hook:n} (which wouldn't hurt in the expandable
+% version, but it would be an unnecessary extra expansion).
+%
+% \cs{@@_use_initialized:n} holds the expandable definition while in
+% the preamble. \cs{@@_preamble_hook:n} initialises the hook in the
+% preamble, and is redefined to \cs{use_none:n} at |\begin{document}|.
+%
+% Both versions do the same internally: check if the hook exist as
+% given, and if so use it as quickly as possible. If it doesn't
+% exist, the a call to \cs{@@_use:wn} checks for file hooks.
+%
+% At |\begin{document}|, all hooks are initialised, and any change in
+% them causes an update, so \cs{hook_use:n} can be made expandable.
+% This one is better not protected so that it can expand into nothing
+% if containing no code. Also important in case of generic hooks that
+% we do not generate a \cs{relax} as a side effect of checking for a
+% csname. In contrast to the \TeX{} low-level
+% \verb=\csname ...\endcsname= construct \cs{tl_if_exist:c} is
+% careful to avoid this.
+% \begin{macrocode}
+\cs_new_protected:Npn \hook_use:n #1
+ {
+ \tl_if_exist:cTF { g_@@_#1_code_tl }
+ {
+ \@@_preamble_hook:n {#1}
+ \cs:w g_@@_#1_code_tl \cs_end:
+ }
+ { \@@_use:wn #1 / \s_@@_mark {#1} }
+ }
+\cs_new:Npn \@@_use_initialized:n #1
+ {
+ \tl_if_exist:cTF { g_@@_#1_code_tl }
+ { \cs:w g_@@_#1_code_tl \cs_end: }
+ { \@@_use:wn #1 / \s_@@_mark {#1} }
+ }
+\cs_new_protected:Npn \@@_preamble_hook:n #1
+ { \@@_initialize_hook_code:n {#1} }
+% \end{macrocode}
+% \end{macro}
%
+% \begin{macro}[EXP]{\@@_use:wn,\@@_try_file_hook:n,\@@_if_exist_use:n}
+% \cs{@@_use:wn} does a quick check to test if the current hook is a
+% file hook: those need a special treatment. If it is not, the hook
+% does not exist. If it is, then \cs{@@_try_file_hook:n} is called,
+% and checks that that the current hook is a file-specific hook using
+% \cs{@@_if_file_hook:wTF}. If it's not, then it's a generic |file/|
+% hook and is used if it exist.
%
+% If it is a file-specific hook, it passes through the same
+% normalisation as during declaration, and then it is used if defined.
%
-% \begin{macro}{\hook_use:n}
-% This one is better not protected \ldots so that it can expand
-% into nothing if containing no code. Also important in case of
-% generic hooks that we do not generate a \cs{relax} as a side
-% effect of checking for a csname. In contrast to the \TeX{}
-% low-level \verb=\csname ...\endcsname= construct
-% \cs{tl_if_exist:c} is careful to avoid this.
-% In this definition use protected because the initialisation code
-% isn't expandable.
+% \cs{@@_if_exist_use:n} checks if the hook exist, and calls
+% \cs{@@_preamble_hook:n} if so, then uses the hook.
% \begin{macrocode}
-\cs_new_protected:Npn \hook_use:n #1 {
- \tl_if_exist:cT{g_@@_#1_code_tl}
- { \@@_initialize_hook_code:n {#1}
- \cs:w g_@@_#1_code_tl\cs_end:
- }
-}
+\cs_new:Npn \@@_use:wn #1 / #2 \s_@@_mark #3
+ {
+ \str_if_eq:nnTF {#1} { file }
+ { \@@_try_file_hook:n {#3} }
+ { } % Hook doesn't exist
+ }
+\cs_new:Npn \@@_try_file_hook:n #1
+ {
+ \@@_if_file_hook:wTF #1 / / \s_@@_mark
+ {
+ \exp_args:Ne \@@_if_exist_use:n
+ { \exp_args:Ne \@@_file_hook_normalise:n {#1} }
+ }
+ { \@@_if_exist_use:n {#1} } % file/ generic hook (e.g. file/before)
+ }
+\cs_new:Npn \@@_if_exist_use:n #1
+ {
+ \tl_if_exist:cT { g_@@_#1_code_tl }
+ {
+ \@@_preamble_hook:n {#1}
+ \cs:w g_@@_#1_code_tl \cs_end:
+ }
+ }
% \end{macrocode}
-% \end{macro}
-
-
-
+% \end{macro}
+%
% \begin{macro}{\hook_use_once:n}
% For hooks that can and should be used only once we have a special
% use command that remembers the hook name in
@@ -2928,13 +3089,14 @@
% further code added to the hook is executed immediately rather
% than stored in the hook.
% \begin{macrocode}
-\cs_new_protected:Npn \hook_use_once:n #1 {
- \tl_if_exist:cT{g_@@_#1_code_tl}
- {
- \clist_gput_left:Nn \g_@@_execute_immediately_clist {#1}
- \cs:w g_@@_#1_code_tl\cs_end:
- }
-}
+\cs_new_protected:Npn \hook_use_once:n #1
+ {
+ \tl_if_exist:cT { g_@@_#1_code_tl }
+ {
+ \clist_gput_left:Nn \g_@@_execute_immediately_clist {#1}
+ \hook_use:n {#1}
+ }
+ }
% \end{macrocode}
% \end{macro}
diff --git a/required/tools/testfiles/github-0222-input.tlg b/required/tools/testfiles/github-0222-input.tlg
index 068586d9..0aa59da5 100644
--- a/required/tools/testfiles/github-0222-input.tlg
+++ b/required/tools/testfiles/github-0222-input.tlg
@@ -5,6 +5,6 @@ Format: LaTeX2e<2020-10-01>
Main Class: article
Package: verbatim
(.tex File ignored) (.tex File ignored)
-File: "verb-test" (verbatim)
+File: "verb-test.tex" (verbatim)
[1
] (github-0222-input.aux)
More information about the latex3-commits
mailing list.