summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/source/latex
diff options
context:
space:
mode:
Diffstat (limited to 'Master/texmf-dist/source/latex')
-rw-r--r--Master/texmf-dist/source/latex/base/latexrelease.ins48
-rw-r--r--Master/texmf-dist/source/latex/base/ltclass.dtx200
-rw-r--r--Master/texmf-dist/source/latex/base/ltdefns.dtx13
-rw-r--r--Master/texmf-dist/source/latex/base/ltexpl.dtx123
-rw-r--r--Master/texmf-dist/source/latex/base/ltfilehook.dtx174
-rw-r--r--Master/texmf-dist/source/latex/base/ltfssaxes.dtx2
-rw-r--r--Master/texmf-dist/source/latex/base/ltfssbas.dtx23
-rw-r--r--Master/texmf-dist/source/latex/base/lthooks.dtx830
-rw-r--r--Master/texmf-dist/source/latex/base/ltmath.dtx9
-rw-r--r--Master/texmf-dist/source/latex/base/ltmiscen.dtx15
-rw-r--r--Master/texmf-dist/source/latex/base/ltshipout.dtx22
-rw-r--r--Master/texmf-dist/source/latex/base/ltvers.dtx2
12 files changed, 1108 insertions, 353 deletions
diff --git a/Master/texmf-dist/source/latex/base/latexrelease.ins b/Master/texmf-dist/source/latex/base/latexrelease.ins
index 99af17e8fb6..ffc92374c35 100644
--- a/Master/texmf-dist/source/latex/base/latexrelease.ins
+++ b/Master/texmf-dist/source/latex/base/latexrelease.ins
@@ -81,11 +81,16 @@ extension .ins) which are part of the distribution.
%\keepsilent
\usedir{tex/latex/base}
+% the order should match the order in the format in case there are dependencies
+% (something defined in one module and used in another)
+
\generateFile{latexrelease.sty}{t}{%
\from{ltclass.dtx} {latexreleasefirst,tracerollback}%
\from{ltvers.dtx} {latexrelease}%
\from{latexrelease.dtx}{latexrelease}%
\from{ltdirchk.dtx} {latexrelease}%
+ \from{ltplain.dtx} {latexrelease}%
+ \from{ltluatex.dtx} {latexrelease}% empty
\from{ltexpl.dtx} {latexrelease}% empty
\from{ltdefns.dtx} {latexrelease}%
\from{lthooks.dtx} {latexrelease}% empty % L3 layer module
@@ -93,42 +98,39 @@ extension .ins) which are part of the distribution.
\from{ltcntrl.dtx} {latexrelease}% empty
\from{lterror.dtx} {latexrelease}% empty
\from{ltpar.dtx} {latexrelease}% empty
+ \from{ltspace.dtx} {latexrelease}%
+ \from{ltlogos.dtx} {latexrelease}% empty
+ \from{ltfiles.dtx} {latexrelease}%
+ \from{ltoutenc.dtx} {latexrelease}%
+ \from{ltcounts.dtx} {latexrelease}%
+ \from{ltlength.dtx} {latexrelease}%
+ \from{ltfssbas.dtx} {latexrelease}%
+ \from{ltfssaxes.dtx} {latexrelease}%
+ \from{ltfsstrc.dtx} {latexrelease}%
+ \from{ltfssdcl.dtx} {latexrelease}%
+ \from{ltfssini.dtx} {latexrelease}%
+ \from{fontdef.dtx} {latexrelease}% (covering fontmath and fonttext)
+ \from{ltfntcmd.dtx} {latexrelease}% empty
+ \from{lttextcomp.dtx} {latexrelease}%
+ \from{ltpageno.dtx} {latexrelease}% empty
+ \from{ltxref.dtx} {latexrelease}% empty
+ \from{ltmiscen.dtx} {latexrelease}%
+ \from{ltmath.dtx} {latexrelease}%
\from{ltlists.dtx} {latexrelease}% empty
\from{ltboxes.dtx} {latexrelease}%
\from{lttab.dtx} {latexrelease}% empty
- \from{ltmath.dtx} {latexrelease}%
\from{ltpictur.dtx} {latexrelease}%
\from{ltthm.dtx} {latexrelease}% empty
\from{ltsect.dtx} {latexrelease}% empty
- \from{ltfiles.dtx} {latexrelease}%
- \from{ltoutenc.dtx} {latexrelease}%
- \from{ltcounts.dtx} {latexrelease}%
- \from{ltlength.dtx} {latexrelease}%
\from{ltfloat.dtx} {latexrelease}%
\from{ltidxglo.dtx} {latexrelease}% empty
\from{ltbibl.dtx} {latexrelease}% empty
\from{ltpage.dtx} {latexrelease}% empty
+ \from{ltclass.dtx} {latexrelease,tracerollback}%
\from{ltfilehook.dtx} {latexrelease}% empty % L3 layer module
\from{ltshipout.dtx} {latexrelease}% empty % L3 layer module
\from{ltoutput.dtx} {latexrelease}%
- \from{ltclass.dtx} {latexrelease,tracerollback}%
- \from{ltspace.dtx} {latexrelease}%
- \from{ltlogos.dtx} {latexrelease}% empty
- \from{ltplain.dtx} {latexrelease}%
- \from{ltfssdcl.dtx} {latexrelease}%
- \from{ltfssini.dtx} {latexrelease}%
- \from{fontdef.dtx} {latexrelease}% (covering fontmath and fonttext)
- \from{ltfntcmd.dtx} {latexrelease}% empty
- \from{lttextcomp.dtx} {latexrelease}%
- \from{ltfssbas.dtx} {latexrelease}%
- \from{ltfssaxes.dtx} {latexrelease}%
- \from{ltfsstrc.dtx} {latexrelease}%
- \from{ltfsscmp.dtx} {latexrelease}%
- \from{ltpageno.dtx} {latexrelease}% empty
- \from{ltxref.dtx} {latexrelease}% empty
- \from{ltmiscen.dtx} {latexrelease}%
- \from{ltluatex.dtx} {latexrelease}%
- \from{ltexpl.dtx} {latexrelease}%
+ \from{ltfsscmp.dtx} {latexrelease}% only in latexrelease!
\from{ltfinal.dtx} {latexrelease}%
}
diff --git a/Master/texmf-dist/source/latex/base/ltclass.dtx b/Master/texmf-dist/source/latex/base/ltclass.dtx
index b639ae9410a..c62136c3097 100644
--- a/Master/texmf-dist/source/latex/base/ltclass.dtx
+++ b/Master/texmf-dist/source/latex/base/ltclass.dtx
@@ -33,7 +33,7 @@
%<*driver>
% \fi
\ProvidesFile{ltclass.dtx}
- [2020/10/18 v1.3t LaTeX Kernel (Class & Package Interface)]
+ [2020/12/17 v1.3v LaTeX Kernel (Class & Package Interface)]
% \iffalse
\documentclass{ltxdoc}
\GetFileInfo{ltclass.dtx}
@@ -524,6 +524,27 @@
% \end{macrocode}
% \end{macro}
%
+% \begin{macro}{\@currpath}
+% Path to the current file if explicitly given.
+% \changes{v1.3u}{2020/11/20}{Macro added}
+% \begin{macrocode}
+%</2ekernel>
+%<*2ekernel|latexrelease>
+%<latexrelease>
+%<latexrelease>\IncludeInRelease{2020/10/01}{\@currpath}%
+%<latexrelease> {Add \@currpath}%
+\let\@currpath\@empty
+%<latexrelease>\EndIncludeInRelease
+%
+%<latexrelease>\IncludeInRelease{0000/00/00}{\@currpath}%
+%<latexrelease> {Add \@currpath}%
+%<latexrelease>\let\@currpath\@undefined
+%<latexrelease>\EndIncludeInRelease
+%</2ekernel|latexrelease>
+%<*2ekernel>
+% \end{macrocode}
+% \end{macro}
+%
% \begin{macro}{\@currname}
% Name of current package or option.
% \begin{macrocode}
@@ -562,6 +583,7 @@
% \changes{v1.3l}{2020/06/05}{Added \cs{@expl@push@filename@@}
% and \cs{@expl@push@filename@aux@@}}
% \changes{v1.3s}{2020/10/08}{Added missing 2020/02/02 \cs{IncludeInRelease}}
+% \changes{v1.3v}{2020/12/14}{Removed \cs{@expl@@@hook@curr@name@push@@n}}
% \begin{macrocode}
%</2ekernel>
%<*2ekernel|latexrelease>
@@ -578,13 +600,22 @@
% here, e.g., \cs{@expl@push@filename@@} needs cleanup and (and
% should probably not have this name either).
% \begin{macrocode}
- \@expl@@@hook@curr@name@push@@n{}%
\@expl@push@filename@@
\xdef\@currnamestack{%
{\@currname}%
{\@currext}%
{\the\catcode`\@}%
\@currnamestack}%
+% \end{macrocode}
+% Temporarily add a stack for \cs{@currpath} here. This should be
+% integrated in the main file stack eventually, but other packages
+% rely on \cs{@currnamestack} having three elements per file, so that
+% isn't a trivial change. The prefix \cs{@kernel@...} hopefully
+% discourages people from using it.
+% \begin{macrocode}
+ \xdef\@kernel@currpathstack{%
+ {\@currpath}%
+ \@kernel@currpathstack}%
\@expl@push@filename@aux@@}
%<latexrelease>\EndIncludeInRelease
% \end{macrocode}
@@ -632,6 +663,10 @@
%<latexrelease> {Add \@expl@pop@filename@@}%
\def\@popfilename{\@expl@@@hook@curr@name@pop@@
\expandafter\@p@pfilename\@currnamestack\@nil
+% \end{macrocode}
+% Same for popping:
+% \begin{macrocode}
+ \expandafter\@p@pfilepath\@kernel@currpathstack\@nil
\@expl@pop@filename@@}
%<latexrelease>\EndIncludeInRelease
%<latexrelease>
@@ -672,6 +707,36 @@
% \end{macro}
% \end{macro}
%
+%
+% \begin{macro}{\@kernel@currpathstack}
+% Path to the current file if explicitly given. The auxiliary is
+% needed here to insert a \cs{@empty} to prevent the loss of braces.
+% \changes{v1.3u}{2020/11/20}{Macro added}
+% \begin{macrocode}
+%</2ekernel>
+%<*2ekernel|latexrelease>
+%<latexrelease>
+%<latexrelease>\IncludeInRelease{2020/10/01}{\@kernel@currpathstack}%
+%<latexrelease> {Add \@kernel@currpathstack}%
+\gdef\@kernel@currpathstack{}
+\def\@p@pfilepath#1{%
+ \gdef\@currpath{#1}\@p@pfilepath@aux\@empty}
+\def\@p@pfilepath@aux#1\@nil{%
+ \xdef\@kernel@currpathstack{#1}}
+%<latexrelease>\EndIncludeInRelease
+%
+%<latexrelease>\IncludeInRelease{0000/00/00}{\@kernel@currpathstack}%
+%<latexrelease> {Add \@kernel@currpathstack}%
+%<latexrelease>\let\@kernel@currpathstack\@undefined
+%<latexrelease>\let\@p@pfilepath\@undefined
+%<latexrelease>\let\@p@pfilepath@aux\@undefined
+%<latexrelease>\EndIncludeInRelease
+%</2ekernel|latexrelease>
+%<*2ekernel>
+% \end{macrocode}
+% \end{macro}
+%
+%
% \begin{macro}{\@ptionlist}
% Returns the option list of the file.
% \begin{macrocode}
@@ -915,15 +980,42 @@
% \changes{v0.3c}{1994/03/12}
% {use \cs{@gtempa}}
% \begin{macrocode}
+%</2ekernel>
+%<latexrelease>\IncludeInRelease{2020/10/01}%
+%<latexrelease> {\ProvidesPackage}{Check name with \strcmp}%
+%<*2ekernel|latexrelease>
\def\ProvidesPackage#1{%
\xdef\@gtempa{#1}%
- \ifx\@gtempa\@currname\else
+% \end{macrocode}
+% \changes{v1.3u}{2020/11/20}
+% {Use string comparison instead of \cs{ifx}}
+% Here \cs{@currpath} is explicitly added to the file name to report
+% when a package or class is loaded using an explicit path. Loading
+% using a path in the argument is supported but not encouraged.
+% \begin{macrocode}
+ \@expandtwoargs\@expl@str@if@eq@@nnTF
+ {\@gtempa}{\@currpath\@currname}{}{%
\@latex@warning@no@line{You have requested
- \@cls@pkg\space`\@currname',\MessageBreak
+ \@cls@pkg\space`\@currpath\@currname',\MessageBreak
but the \@cls@pkg\space provides `#1'}%
- \fi
+ }%
\@ifnextchar[\@pr@videpackage{\@pr@videpackage[]}}%]
\@onlypreamble\ProvidesPackage
+%</2ekernel|latexrelease>
+%<latexrelease>\EndIncludeInRelease
+%
+%<latexrelease>\IncludeInRelease{0000/00/00}%
+%<latexrelease> {\ProvidesPackage}{Undo: check name with \strcmp}%
+%<latexrelease>\def\ProvidesPackage#1{%
+%<latexrelease> \xdef\@gtempa{#1}%
+%<latexrelease> \ifx\@gtempa\@currname\else
+%<latexrelease> \@latex@warning@no@line{You have requested
+%<latexrelease> \@cls@pkg\space`\@currname',\MessageBreak
+%<latexrelease> but the \@cls@pkg\space provides `#1'}%
+%<latexrelease> \fi
+%<latexrelease> \@ifnextchar[\@pr@videpackage{\@pr@videpackage[]}}%]
+%<latexrelease>\EndIncludeInRelease
+%<*2ekernel>
% \end{macrocode}
% \end{macro}
%
@@ -1007,9 +1099,18 @@
%
% \begin{macro}{\ProvidesClass}
% Like |\ProvidesPackage|, but for classes.
+% This needs a dummy \pkg{latexrelease} block to copy the definition
+% of \cs{ProvidesPackage} as it changes across releases.
% \begin{macrocode}
+%</2ekernel>
+%<latexrelease>\IncludeInRelease{0000/00/00}%
+%<latexrelease> {\ProvidesClass}{Track \ProvidesPackage}%
+%<*2ekernel|latexrelease>
\let\ProvidesClass\ProvidesPackage
\@onlypreamble\ProvidesClass
+%</2ekernel|latexrelease>
+%<latexrelease>\EndIncludeInRelease
+%<*2ekernel>
% \end{macrocode}
% \end{macro}
%
@@ -1075,10 +1176,18 @@
\@expl@@@filehook@set@curr@file@@nNN
{\@expl@@@filehook@resolve@file@subst@@w #3.#1\@nil}%
\reserved@a\reserved@b
+ \@expl@@@filehook@clear@replacement@flag@@
\expandafter\xdef\csname opt@\reserved@a\endcsname{%
\@ifundefined{opt@\reserved@a}\@empty
{\csname opt@\reserved@a\endcsname,}%
- \zap@space#2 \@empty}}
+ \zap@space#2 \@empty}%
+% \end{macrocode}
+% \changes{v1.3u}{2020/11/20}
+% {Copy option list to the requested package.}
+% \begin{macrocode}
+ \expandafter\let
+ \csname opt@#3.#1\expandafter\endcsname
+ \csname opt@\reserved@a\endcsname}
%</2ekernel|latexrelease>
%<latexrelease>\EndIncludeInRelease
%
@@ -1719,8 +1828,38 @@
%<latexrelease>\IncludeInRelease{2020/10/01}%
%<latexrelease> {\@onefilewithoptions}{Hooks and unused options issue}%
\def\@onefilewithoptions#1[#2][#3]#4{%
+% \end{macrocode}
+% We have to sanitise file names, so that something like
+% \begin{verbatim}
+% \usepackage{some/local/path/array}
+% \usepackage{array}
+% \end{verbatim}
+% won't load \file{array.sty} twice. It is remotely possible that
+% those are two different files, but as a matter of principles, we
+% will consider that the base file name uniquely identifies a
+% package, regardless of where it lives. This assumption already
+% holds for file hooks, for example, which address the hook to a file
+% by its base name only.
+%
+% We'll use \cs{@expl@@@filehook@set@curr@file@@nNN} to parse the
+% file name and return the \meta{path} and \meta{base+ext} in
+% separate token lists. Further ahead, most operations use
+% \cs{@currname} which doesn't have a path attached to it; only few
+% actions prepend \cs{@currpath} to \cs{@currname} (namely loading,
+% as we have to respect the given path).
+%
+% A file substituiton isn't followed just yet because at this point
+% we are parsing user input, so the file is still what the user
+% asked for, and not the file actually loaded.
+% \begin{macrocode}
+ \@expl@@@filehook@set@curr@file@@nNN{#1.#4}\reserved@a\reserved@b
+ \edef\reserved@c{\def\noexpand\reserved@c####1%
+ \detokenize\expandafter{\expanded{.#4}}%
+ \noexpand\@nil{\def\noexpand\reserved@a{####1}}}\reserved@c
+ \expandafter\reserved@c\reserved@a\@nil
\@pushfilename
- \xdef\@currname{#1}%
+ \xdef\@currname{\string@makeletter\reserved@a}%
+ \xdef\@currpath{\ifx\reserved@b\@empty\else\reserved@b/\fi}%
\global\let\@currext#4%
% \end{macrocode}
% The command \cs{ver@\meta{file}.\meta{ext}} is used to signal that
@@ -1765,9 +1904,11 @@
% \end{macrocode}
% First we take the \meta{name} and \meta{ext} given in the argument
% and check if the file exists, and issue an error otherwise asking
-% for a correction with \cs{@missingfileerror}.
+% for a correction with \cs{@missingfileerror}. For checking if the
+% file exists we use \cs{@currpath} (usually empty) before
+% \cs{@currname}.
% \begin{macrocode}
- \IfFileExists{\@currname.\@currext}{}%
+ \IfFileExists{\@currpath\@currname.\@currext}{}%
{\@missing@onefilewithoptions{#2}}%
% \end{macrocode}
% If \cs{@currname} is empty (the user replied to the ``Enter file
@@ -1784,11 +1925,12 @@
% do the bookkeeping with \cs{@filehook@file@push}
% then call \cs{set@curr@file} to set \cs{@curr@file} (and do any
% required substitution), then actually load the class/package with
-% \cs{load@onefile@withoptions}.
+% \cs{load@onefile@withoptions}. \cs{set@curr@file} also needs the
+% file path.
% \begin{macrocode}
\@disable@packageload@do{\@currname.\@currext}%
{\@expl@@@filehook@file@push@@
- \set@curr@file{\@currname.\@currext}%
+ \set@curr@file{\@currpath\@currname.\@currext}%
\@filehook@set@CurrentFile
% \end{macrocode}
% \changes{v1.3q}{2020/09/06}
@@ -1812,10 +1954,15 @@
\expandafter\@swaptwoargs\expandafter
{\expandafter{\@currpkg@reqd}}%
{% <
+% \end{macrocode}
+% \cs{@currpkg@reqd} doesn't take a path because it is used later to
+% assign \cs[no-index]{opt@...} and \cs[no-index]{ver@...}.
+% \begin{macrocode}
\edef\@currpkg@reqd{\@currname.\@currext}%
\ifx\CurrentFile\CurrentFileUsed
\else
\filename@parse\@curr@file
+ \edef\@currpath{\string@makeletter\filename@area}%
\edef\@currname{\string@makeletter\filename@base}%
\edef\@currext{\string@makeletter\filename@ext}%
\fi
@@ -1864,11 +2011,13 @@
% \end{macro}
%
% \begin{macro}{\@missing@onefilewithoptions}
-% Now the action taken when a file is not found.
+% Now the action taken when a file is not found. Path must be
+% included here as it eventually leads to a file lookup.
% \begin{macrocode}
\def\@missing@onefilewithoptions#1{%
- \@missingfileerror\@currname\@currext
- \xdef\@currname{\@missingfile@area\@missingfile@base}%
+ \@missingfileerror{\@currpath\@currname}\@currext
+ \global\let\@currpath\@missingfile@area
+ \global\let\@currname\@missingfile@base
\global\let\@currext\@missingfile@ext}
% \end{macrocode}
% \end{macro}
@@ -1887,6 +2036,13 @@
% \begin{macrocode}
\def\reserved@a{%
\@pass@ptions\@currext{#1}{\@currname}%
+% \end{macrocode}
+% \changes{v1.3u}{2020/11/20}
+% {Copy option list to the requested package.}
+% \begin{macrocode}
+ \expandafter\let
+ \csname opt@\@currpkg@reqd\expandafter\endcsname
+ \csname opt@\@currname.\@currext\endcsname
\global\expandafter
\let\csname ver@\@currname.\@currext\endcsname\@empty
% \end{macrocode}
@@ -1912,11 +2068,12 @@
\fi
% \end{macrocode}
% Now actually load the file (at this point we are certain it exists,
-% but use \cs{InputIfFileExists} so that file hooks are executed):
+% but use \cs{InputIfFileExists} so that file hooks are executed).
+% \cs{@currpath} is needed here too.
% \begin{macrocode}
- \InputIfFileExists{\@currpkg@reqd}{}%
+ \InputIfFileExists{\@currpath\@currpkg@reqd}{}%
{\@latex@error
- {The \@cls@pkg\space\@currpkg@reqd\space failed to load.}\@ehd}%
+ {The \@cls@pkg\space\@currpkg@reqd\space failed to load}\@ehd}%
%-----------------------------------------
% \end{macrocode}
% In older versions of the code |\@unprocessedoptions| would
@@ -3271,19 +3428,20 @@
% A similar error is given if global rollback date and min-date on
% a specific package conflict with each other, but that case is
% happens only once so it is inlined.
+% \changes{v1.3u}{2020/11/09}{Change help text because the package may have
+% existed then --- there is just no rollback data (gh/423).}
% \begin{macrocode}
\def\pkgcls@rollbackdate@error#1{%
\@latex@error{Suspicious rollback date given}%
- {The \@cls@pkg\space'\@currname' claims that it
- came into existence on #1 which\MessageBreak
+ {The \@cls@pkg\space'\@currname' has no rollback data
+ before #1 which\MessageBreak
is after your requested rollback date --- so
- something is wrong here.\MessageBreak
+ something may be wrong here.\MessageBreak
Continue and we use the earliest known release.}}
% \end{macrocode}
% \end{macro}
%
%
-%
% \begin{macro}{\DeclareCurrentRelease}
% This declares the date (and possible name) of the current version
% of a package or class.
diff --git a/Master/texmf-dist/source/latex/base/ltdefns.dtx b/Master/texmf-dist/source/latex/base/ltdefns.dtx
index 569c9db4df9..920c1acde6d 100644
--- a/Master/texmf-dist/source/latex/base/ltdefns.dtx
+++ b/Master/texmf-dist/source/latex/base/ltdefns.dtx
@@ -32,7 +32,7 @@
%<*driver>
% \fi
\ProvidesFile{ltdefns.dtx}
- [2020/09/25 v1.5n LaTeX Kernel (definition commands)]
+ [2020/11/25 v1.5o LaTeX Kernel (definition commands)]
% \iffalse
\documentclass{ltxdoc}
\GetFileInfo{ltdefns.dtx}
@@ -385,8 +385,19 @@
% \begin{macro}{\@carcube}
% |\@carcube T1 ... Tn\@nil| = |T1| |T2| |T3| , $n > 3$
% \changes{v1.5k}{2020/08/19}{Made \cs{long} for \cs{NewCommandCopy}}
+% \changes{v1.5o}{2020/11/25}{Added missing latexrelease entry}
% \begin{macrocode}
+%</2ekernel>
+%<latexrelease>\IncludeInRelease{2020/10/01}{\@carcube}{Make \@carcube long}%
+%<*2ekernel|latexrelease>
\long\def\@carcube#1#2#3#4\@nil{#1#2#3}
+%</2ekernel|latexrelease>
+%<latexrelease>\EndIncludeInRelease
+%
+%<latexrelease>\IncludeInRelease{0000/00/00}{\@carcube}{Undo: Make \@carcube long}%
+%<latexrelease>\def\@carcube#1#2#3#4\@nil{#1#2#3}
+%<latexrelease>\EndIncludeInRelease
+%<*2ekernel>
% \end{macrocode}
% \end{macro}
%
diff --git a/Master/texmf-dist/source/latex/base/ltexpl.dtx b/Master/texmf-dist/source/latex/base/ltexpl.dtx
index 4100da79c28..7f9019ede31 100644
--- a/Master/texmf-dist/source/latex/base/ltexpl.dtx
+++ b/Master/texmf-dist/source/latex/base/ltexpl.dtx
@@ -33,7 +33,7 @@
%<*driver>
% \fi
\ProvidesFile{ltexpl.dtx}
- [2020/09/06 v1.2f LaTeX Kernel (expl3-dependent code)]
+ [2020/12/18 v1.2h LaTeX Kernel (expl3-dependent code)]
% \iffalse
\documentclass{ltxdoc}
\GetFileInfo{ltexpl.dtx}
@@ -72,16 +72,45 @@
% {Define a local version of some \LaTeXe{} basic macros to support
% package loading}
%
+% \begin{macro}{\@kernel@after@enddocument,
+% \@kernel@after@enddocument@afterlastpage}
+% These two kernel hooks are used by the shipout code. They are
+% defined earlier here because the \pkg{lthooks} code adds material
+% to them.
+% \changes{v1.2h}{2020/12/18}
+% {Define kernel \cs{enddocument} hooks early}
+% \begin{macrocode}
+%<*2ekernel|latexrelease>
+%<latexrelease>\IncludeInRelease{2020/10/01}%
+%<latexrelease> {kernel@enddocument hooks}{Define kernel enddocument Hooks}%
+\let\@kernel@after@enddocument\@empty
+\let\@kernel@after@enddocument@afterlastpage\@empty
+%<latexrelease>\EndIncludeInRelease
+% \end{macrocode}
+%
+% \begin{macrocode}
+%<latexrelease>\IncludeInRelease{0000/00/00}%
+%<latexrelease> {kernel@enddocument hooks}{Define kernel enddocument Hooks}%
+%<latexrelease>\let\@kernel@after@enddocument\@undefined
+%<latexrelease>\let\@kernel@after@enddocument@afterlastpage\@undefined
+%<latexrelease>\EndIncludeInRelease
+%</2ekernel|latexrelease>
+% \end{macrocode}
+% \end{macro}
+%
% First define some blank commands, so that in case something goes wrong while
% loading \textsf{expl3}, we won't get strange \texttt{Undefined control
% sequence} errors.
% \begin{macrocode}
-%<*2ekernel>
+%<*2ekernel|latexrelease>
+%<latexrelease>\IncludeInRelease{2020/10/01}%
+%<latexrelease> {\@expl@sys@load@backend@@}{Roll forward support}%
\def\@expl@sys@load@backend@@{}
\def\@expl@push@filename@@{}
\def\@expl@push@filename@aux@@{}
\def\@expl@pop@filename@@{}
-%</2ekernel>
+%<latexrelease>\EndIncludeInRelease
+%</2ekernel|latexrelease>
% \end{macrocode}
%
% \changes{v1.2d}{2020/07/08}
@@ -183,9 +212,20 @@
\errmessage{LaTeX requires expl3}%
\batchmode \read -1 to \reserved@a
%</2ekernel>
+% \end{macrocode}
+% We do not support a roll forward across 2019. You need to start
+% with 2019 if you want to get to 2020 or beyond.
+% \changes{v1.2g}{2020/11/24}{Support for roll forward (gh/434)}
+% \begin{macrocode}
%<*latexrelease>
- \@latex@error{LaTeX requires expl3}\@ehd
- \@gobble
+ \@latex@warning@no@line
+ {You need a format that already contains a recent\MessageBreak
+ expl3 as part of the kernel, e.g. at least a kernel\MessageBreak
+ from 2019 to roll forward to that date!\MessageBreak
+ --- I'm giving up!\MessageBreak\MessageBreak
+ Note that manually loading the expl3 package\MessageBreak
+ from your distribution is not enough}%
+ \@@end % die
%</latexrelease>
}%
{%
@@ -222,6 +262,36 @@
%<latexrelease>\EndIncludeInRelease
% \end{macrocode}
%
+%
+% Starting with 2020-10 the kernel contains most of the
+% \texttt{xparse} interfaces loaded above. These interfaces are
+% later used to define various user command. However, if somebody
+% with an earlier installation tries to roll forward (using a
+% \texttt{latexrelease} package from a newer release) this will not
+% work as the earlier kernel doesn't contain commands such as
+% \cs{NewDocumentCommand}.
+%
+% We therefore add code into \texttt{latexrelease.sty} to load the
+% \texttt{xparse} package of the current installation instead. this
+% may not work if the installation is really old, but roll forward
+% can't do miracles.
+%
+% If the kernel is 2020-10 or later \cs{NewDocumentCommand} is
+% already known (whether or not you roll forward or back) so
+% nothing happens, but if you start from am earlier kernel the
+% \texttt{xparse} package gets loaded by \texttt{latexrelease}.
+% \changes{v1.2g}{2020/11/24}{Load xparse in latexrelease if needed (gh/434)}
+% \begin{macrocode}
+%<latexrelease>\IncludeInRelease{2020/10/01}%
+%<latexrelease> {\NewDocumentCommand}{Emergency loading xparse}%
+%<latexrelease>
+%<latexrelease>\ifdefined\NewDocumentCommand \else
+%<latexrelease> \RequirePackage{xparse}
+%<latexrelease>\fi
+%<latexrelease>
+%<latexrelease>\EndIncludeInRelease
+% \end{macrocode}
+%
% \subsection{Using expl3 code}
%
% In order to ease the implemantation of some new features in
@@ -242,9 +312,6 @@
% if that \pkg{expl3} command is needed in places that are others
% coded in \LaTeXe{} conventions.
%
-% \begin{macrocode}
-\ExplSyntaxOn
-% \end{macrocode}
%
% In this file, each release of LaTeX adds an \cs{IncludeInRelease}
% block, in which the macros copied for that release were defined.
@@ -259,8 +326,16 @@
% redefinitions.
%
% \begin{macrocode}
-%<latexrelease>\IncludeInRelease{2020/10/01}{expl3~2020-10-01}%
-%<latexrelease> {expl3~macros~added~for~the~2020-10-01~release}%
+%<latexrelease>\IncludeInRelease{2020/10/01}{\@expl@cs@to@str@@N}%
+%<latexrelease> {expl3 macros added for the 2020-10-01 release}%
+% \end{macrocode}
+%
+% The expl3 activation needs to be inside the release guards as
+% otherwise rolling forward is broken in old kernels that do not
+% have expl3 loaded.
+% \changes{v1.2g}{2020/11/24}{Support for roll forward (gh/434)}
+% \begin{macrocode}
+\ExplSyntaxOn
% \end{macrocode}
%
% \changes{v1.2e}{2020/08/19}
@@ -290,21 +365,27 @@
% \end{macrocode}
%
% \begin{macrocode}
+\ExplSyntaxOff
+% \end{macrocode}
+%
+%
+% Here we can't assume that expl3 is available. It will be if we
+% roll back but if this code is executed rolling forward it needs
+% to be pure 2e.
+% \changes{v1.2g}{2020/11/24}{Support for roll forward (gh/434)}
+% \begin{macrocode}
%<latexrelease>\EndIncludeInRelease
-%<latexrelease>\IncludeInRelease{0000/00/00}{expl3~2020-10-01}%
-%<latexrelease> {expl3~macros~added~for~the~2020-10-01~release}%
-%<latexrelease>\cs_undefine:N \@expl@cs@to@str@@N
-%<latexrelease>\cs_undefine:N \@expl@str@if@eq@@nnTF
-%<latexrelease>\cs_undefine:N \@expl@cs@prefix@spec@@N
-%<latexrelease>\cs_undefine:N \@expl@cs@argument@spec@@N
-%<latexrelease>\cs_undefine:N \@expl@cs@replacement@spec@@N
-%<latexrelease>\cs_undefine:N \@expl@str@map@function@@NN
+%<latexrelease>\IncludeInRelease{0000/00/00}{\@expl@cs@to@str@@N}%
+%<latexrelease> {expl3 macros added for the 2020-10-01 release}%
+%<latexrelease>\let \@expl@cs@to@str@@N \@undefined
+%<latexrelease>\let \@expl@str@if@eq@@nnTF \@undefined
+%<latexrelease>\let \@expl@cs@prefix@spec@@N \@undefined
+%<latexrelease>\let \@expl@cs@argument@spec@@N \@undefined
+%<latexrelease>\let \@expl@cs@replacement@spec@@N \@undefined
+%<latexrelease>\let \@expl@str@map@function@@NN \@undefined
%<latexrelease>\EndIncludeInRelease
%</2ekernel|latexrelease>
% \end{macrocode}
%
-% \begin{macrocode}
-\ExplSyntaxOff
-% \end{macrocode}
%
% \Finale
diff --git a/Master/texmf-dist/source/latex/base/ltfilehook.dtx b/Master/texmf-dist/source/latex/base/ltfilehook.dtx
index ecb499f3475..c7ed13f041a 100644
--- a/Master/texmf-dist/source/latex/base/ltfilehook.dtx
+++ b/Master/texmf-dist/source/latex/base/ltfilehook.dtx
@@ -31,8 +31,8 @@
%%% From File: ltfilehook.dtx
%
% \begin{macrocode}
-\providecommand\ltfilehookversion{v1.0c}
-\providecommand\ltfilehookdate{2020/10/18}
+\providecommand\ltfilehookversion{v1.0d}
+\providecommand\ltfilehookdate{2020/11/24}
% \end{macrocode}
%
%<*driver>
@@ -615,6 +615,62 @@
% \begin{macrocode}
%</2ekernel|latexrelease>
%<latexrelease>\EndIncludeInRelease
+% \end{macrocode}
+%
+% When rolling forward the following expl3 functions may not be defined.
+% If we roll back the code does nothing.
+% \changes{v1.0d}{2020/11/24}{Support for roll forward (gh/434)}
+% \begin{macrocode}
+%<latexrelease>\IncludeInRelease{2020/10/01}%
+%<latexrelease> {\file_parse_full_name_apply:nN}{Roll forward help}%
+%<latexrelease>
+%<latexrelease>\ExplSyntaxOn
+%<latexrelease>\cs_if_exist:NF\file_parse_full_name_apply:nN
+%<latexrelease>{
+%<latexrelease>\cs_new:Npn \file_parse_full_name_apply:nN #1
+%<latexrelease> {
+%<latexrelease> \exp_args:Ne \__file_parse_full_name_auxi:nN
+%<latexrelease> { \__kernel_file_name_sanitize:n {#1} }
+%<latexrelease> }
+%<latexrelease>\cs_new:Npn \__file_parse_full_name_auxi:nN #1
+%<latexrelease> {
+%<latexrelease> \__file_parse_full_name_area:nw { } #1
+%<latexrelease> / \s__file_stop
+%<latexrelease> }
+%<latexrelease>\cs_new:Npn \__file_parse_full_name_area:nw #1 #2 / #3 \s__file_stop
+%<latexrelease> {
+%<latexrelease> \tl_if_empty:nTF {#3}
+%<latexrelease> { \__file_parse_full_name_base:nw { } #2 . \s__file_stop {#1} }
+%<latexrelease> { \__file_parse_full_name_area:nw { #1 / #2 } #3 \s__file_stop }
+%<latexrelease> }
+%<latexrelease>\cs_new:Npn \__file_parse_full_name_base:nw #1 #2 . #3 \s__file_stop
+%<latexrelease> {
+%<latexrelease> \tl_if_empty:nTF {#3}
+%<latexrelease> {
+%<latexrelease> \tl_if_empty:nTF {#1}
+%<latexrelease> {
+%<latexrelease> \tl_if_empty:nTF {#2}
+%<latexrelease> { \__file_parse_full_name_tidy:nnnN { } { } }
+%<latexrelease> { \__file_parse_full_name_tidy:nnnN { .#2 } { } }
+%<latexrelease> }
+%<latexrelease> { \__file_parse_full_name_tidy:nnnN {#1} { .#2 } }
+%<latexrelease> }
+%<latexrelease> { \__file_parse_full_name_base:nw { #1 . #2 } #3 \s__file_stop }
+%<latexrelease> }
+%<latexrelease>\cs_new:Npn \__file_parse_full_name_tidy:nnnN #1 #2 #3 #4
+%<latexrelease> {
+%<latexrelease> \exp_args:Nee #4
+%<latexrelease> {
+%<latexrelease> \str_if_eq:nnF {#3} { / } { \use_none:n }
+%<latexrelease> #3 \prg_do_nothing:
+%<latexrelease> }
+%<latexrelease> { \use_none:n #1 \prg_do_nothing: }
+%<latexrelease> {#2}
+%<latexrelease> }
+%<latexrelease>}
+%<latexrelease>\ExplSyntaxOff
+%<latexrelease>
+%<latexrelease>\EndIncludeInRelease
%<*2ekernel>
% \end{macrocode}
%
@@ -643,6 +699,8 @@
% kernel we do this only now and not in \texttt{ltfiles}.
%
% \begin{macro}{\InputIfFileExists}
+% \begin{macro}{\@input@file@exists@with@hooks}
+% \begin{macro}{\unqu@tefilef@und}
% \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
@@ -665,7 +723,7 @@
% If the file exists then \cs{CurrentFile} 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
+% preserve the name and then restore it for the
% \texttt{file/after/...} hook.
%
% The hook always refers to the file requested by the user. The hook
@@ -683,33 +741,68 @@
% refer to the file by their name only. The path to the file is
% returned in \cs{CurrentFilePath}.
% \begin{macrocode}
- \edef\reserved@a{\@filef@und
+ \edef\reserved@a{%
\@expl@@@filehook@file@pop@assign@@nnnn
{\CurrentFilePathUsed}%
{\CurrentFileUsed}%
{\CurrentFilePath}%
- {\CurrentFile}}%
+ {\CurrentFile}%
+% \end{macrocode}
+%
+% We pre-expand \cs{@filef@und} so that in case another file is
+% loaded in the true branch of \cs{InputIfFileExists}, these don't
+% change their value meanwhile. This isn't a worry with
+% \cs[no-index]{CurrentFile...} because they are kept in a stack.
+%
+% \changes{v1.0d}{2020/11/20}
+% {Move loading to \cs{@input@file@exists@with@hooks} and expand
+% \cs{@filef@und} to avoid getting the wrong file name in the case of
+% a substitution.}
+% \begin{macrocode}
+ \noexpand\@input@file@exists@with@hooks{\@filef@und}}%
\expandafter\@swaptwoargs\expandafter
{\reserved@a}%
- {%
- #2%
- \@addtofilelist{#1}%
- \UseHook{file/before}%
+ {#2}%
+ \@expl@@@filehook@file@pop@@
+ }%
+}
+% \end{macrocode}
+%
+% Before adding to the file list we need to make all (letter) characters
+% catcode~11, because several packages use constructions like
+% \begin{verbatim}
+% \filename@parse{<filename>}
+% \ifx\filename@ext\@clsextension
+% ...
+% \fi
+% \end{verbatim}
+% and that doesn't work if \cs{filename@ext} is \cs{detokenize}d.
+% Making \cs{@clsextension} a string doesn't help much because some
+% packages define their own \cs[no-index]{<prefix>@someextension} with
+% normal catcodes. This is not entirely correct because packages loaded
+% (somehow) with catcode~12 alphabetic tokens (say, as the result of
+% a \cs{string} or \cs{detokenize} command, or from a \TeX{} string like
+% \cs{jobname}) will have these character tokens incorrectly turned into
+% letter tokens. This however is rare, so we'll go for the all-letters
+% approach (grepping the packages in \TeX{} Live didn't bring up any
+% obvious candidate for breaking with this catcode change).
+% \begin{macrocode}
+\def\@input@file@exists@with@hooks#1{%
+ \edef\reserved@a{\unqu@tefilef@und#1\@nil}%
+ \@addtofilelist{\string@makeletter\reserved@a}%
+ \UseHook{file/before}%
% \end{macrocode}
% The current file name is available in \cs{CurrentFile} so we use
% that in the specific hook.
% \begin{macrocode}
- \UseHook{file/before/\CurrentFile}%
- \@@input
- }%
+ \UseHook{file/before/\CurrentFile}%
+ \@@input #1% <- trailing space comes from \@filef@und
% \end{macrocode}
% And it is restored here so we can use it once more.
% \begin{macrocode}
- \UseHook{file/after/\CurrentFile}%
- \UseHook{file/after}%
- \@expl@@@filehook@file@pop@@
- }%
-}
+ \UseHook{file/after/\CurrentFile}%
+ \UseHook{file/after}}
+\def\unqu@tefilef@und"#1" \@nil{#1}
%<latexrelease>\EndIncludeInRelease
%</2ekernel|latexrelease>
% \end{macrocode}
@@ -737,6 +830,8 @@
%<latexrelease> {%
%<latexrelease> \expandafter\@swaptwoargs\expandafter
%<latexrelease> {\@filef@und}{#2\@addtofilelist{#1}\@@input}}}
+%<latexrelease>\let\@input@file@exists@with@hooks\@undefined
+%<latexrelease>\let\unqu@tefilef@und\@undefined
%<latexrelease>\EndIncludeInRelease
% \end{macrocode}
%
@@ -746,10 +841,14 @@
%<latexrelease>\long\def \InputIfFileExists#1#2{%
%<latexrelease> \IfFileExists{#1}%
%<latexrelease> {#2\@addtofilelist{#1}\@@input \@filef@und}}
+%<latexrelease>\let\@input@file@exists@with@hooks\@undefined
+%<latexrelease>\let\unqu@tefilef@und\@undefined
%<latexrelease>\EndIncludeInRelease
%<*2ekernel>
% \end{macrocode}
% \end{macro}
+% \end{macro}
+% \end{macro}
%
%
%
@@ -772,8 +871,8 @@
%
%
% \begin{macro}{\@@_subst_add:nn,\@@_subst_remove:n,
-% \@@_subst_file_normalize:n,\@@_subst_empty_name_chk:NN}
-% \cs{@@_substitution_lthooadd:nn} declares a file substitution by
+% \@@_subst_file_normalize:Nn,\@@_subst_empty_name_chk:NN}
+% \cs{@@_subst_add:nn} declares a file substitution by
% doing a (global) definition of the form
% |\def|\cs{@file-subst@\meta{file}}|{|\meta{replacement}|}|.
% The file names are properly sanitised, and normalized with the same
@@ -787,8 +886,12 @@
\group_begin:
\cs_set:cpx { } { \exp_not:o { \cs:w\cs_end: } }
\int_set:Nn \tex_escapechar:D { -1 }
- \cs_gset:cpx { @file-subst@ \@@_subst_file_normalize:n {#1} }
- { \@@_subst_file_normalize:n {#2} }
+ \cs_gset:cpx
+ {
+ @file-subst@
+ \@@_subst_file_normalize:Nn \use_ii_iii:nnn {#1}
+ }
+ { \@@_subst_file_normalize:Nn \@@_file_name_compose:nnn {#2} }
\group_end:
}
\cs_new_protected:Npn \@@_subst_remove:n #1
@@ -796,14 +899,18 @@
\group_begin:
\cs_set:cpx { } { \exp_not:o { \cs:w\cs_end: } }
\int_set:Nn \tex_escapechar:D { -1 }
- \cs_undefine:c { @file-subst@ \@@_subst_file_normalize:n {#1} }
+ \cs_undefine:c
+ {
+ @file-subst@
+ \@@_subst_file_normalize:Nn \use_ii_iii:nnn {#1}
+ }
\group_end:
}
-\cs_new:Npn \@@_subst_file_normalize:n #1
+\cs_new:Npn \@@_subst_file_normalize:Nn #1 #2
{
\exp_after:wN \@@_subst_empty_name_chk:NN
\cs:w \exp_after:wN \cs_end:
- \cs:w \@@_file_parse_full_name:nN {#1} \use_ii_iii:nnn \cs_end:
+ \cs:w \@@_file_parse_full_name:nN {#2} #1 \cs_end:
}
\cs_new:Npn \@@_subst_empty_name_chk:NN #1 #2
{ \if_meaning:w #1 #2 .tex \else: \token_to_str:N #2 \fi: }
@@ -929,6 +1036,7 @@
\if@tempswa \@expl@@@filehook@drop@extension@@N\@curr@file@reqd \fi}%
{\if@tempswa \@expl@@@filehook@drop@extension@@N\@curr@file \fi
\global\let\@curr@file@reqd\@curr@file}%
+ \@expl@@@filehook@clear@replacement@flag@@
\endgroup}
%</2ekernel|latexrelease>
%<latexrelease>\EndIncludeInRelease
@@ -1079,18 +1187,25 @@
%
% \begin{macro}{flag @@_file_replaced}
% \begin{macro}{\@@_if_file_replaced:TF}
+% \begin{macro}{\@@_clear_replacement_flag:}
% Since the file replacement is done expandably in a \cs{csname}, use
% a flag to remember if a substitution happened. We use this in
% \cs{set@curr@file} to short-circuit some of it in case no
% substitution happened (by far the most common case, so it's worth
-% optimising).
+% optimising). The flag raised during the file substitution algorithm
+% must be explicitly cleared after the \cs{@@_if_file_replaced:TF}
+% conditional is no longer needed, otherwise further uses of
+% \cs{@@_if_file_replaced:TF} will wrongly return true.
% \begin{macrocode}
\flag_new:n { @@_file_replaced }
\cs_new:Npn \@@_if_file_replaced:TF #1 #2
- { \flag_if_raised:nTF { @@_file_replaced } {#1} {#2} }
+ { \flag_if_raised:nTF { @@_file_replaced } {#1} {#2} }
+\cs_new_protected:Npn \@@_clear_replacement_flag:
+ { \flag_clear:n { @@_file_replaced } }
% \end{macrocode}
% \end{macro}
% \end{macro}
+% \end{macro}
%
% \begin{macro}{\@@_file_subst_begin:nnn}
% First off, start by checking if the current file ($\meta{name} +
@@ -1343,7 +1458,12 @@
\cs_new_eq:NN \@expl@@@filehook@if@file@replaced@@TF
\__filehook_if_file_replaced:TF
% \end{macrocode}
-%
+%
+% \begin{macrocode}
+\cs_new_eq:NN \@expl@@@filehook@clear@replacement@flag@@
+ \__filehook_clear_replacement_flag:
+% \end{macrocode}
+%
% \begin{macrocode}
\cs_new_eq:NN \@expl@@@filehook@drop@extension@@N
\__filehook_drop_extension:N
diff --git a/Master/texmf-dist/source/latex/base/ltfssaxes.dtx b/Master/texmf-dist/source/latex/base/ltfssaxes.dtx
index d8e4286b786..a66a26cd39c 100644
--- a/Master/texmf-dist/source/latex/base/ltfssaxes.dtx
+++ b/Master/texmf-dist/source/latex/base/ltfssaxes.dtx
@@ -836,7 +836,7 @@
% condensed series, etc.). We do this in all branches above because a user
% might have written
%\begin{verbatim}
-\DeclareFontSeriesChangeRule {m}{sc}{msc}{mc}
+% \DeclareFontSeriesChangeRule {m}{sc}{msc}{mc}
%\end{verbatim}
% instead of using \texttt{sc} and \texttt{c} as needed in the
% \texttt{.fd} file.
diff --git a/Master/texmf-dist/source/latex/base/ltfssbas.dtx b/Master/texmf-dist/source/latex/base/ltfssbas.dtx
index 4a6afca3ace..30f500b6e4e 100644
--- a/Master/texmf-dist/source/latex/base/ltfssbas.dtx
+++ b/Master/texmf-dist/source/latex/base/ltfssbas.dtx
@@ -35,7 +35,7 @@
%
%
\ProvidesFile{ltfssbas.dtx}
- [2020/02/27 v3.2g LaTeX Kernel (NFSS Basic Macros)]
+ [2020/12/10 v3.2h LaTeX Kernel (NFSS Basic Macros)]
% \iffalse
\documentclass{ltxdoc}
\begin{document}
@@ -891,12 +891,31 @@
% series and shape which is not desired if we intend to use an
% explicit font shape!
% \changes{v3.2e}{2019/12/17}{Don't call \cs{fontseries} or \cs{fontshape}}
+% \changes{v3.2h}{2020/12/10}{Drop ``m'' if the series value is a member
+% of a fixed list and issue warning if doing it (gh/453)}
% \begin{macrocode}
+%</2ekernel>
+%<*2ekernel|latexrelease>
+%<latexrelease>\IncludeInRelease{2020/02/02}%
+%<latexrelease> {\usefont}{Drop m in usefont}%
\DeclareRobustCommand\usefont[4]{\fontencoding{#1}%
\edef\f@family{#2}%
- \edef\f@series{#3}%
+ \set@target@series{#3}%
\edef\f@shape{#4}\selectfont
\ignorespaces}
+%</2ekernel|latexrelease>
+%<latexrelease>\EndIncludeInRelease
+%<latexrelease>\IncludeInRelease{0000/00/00}%
+%<latexrelease> {\usefont}{Drop m in usefont}%
+%<latexrelease>
+%<latexrelease>\DeclareRobustCommand\usefont[4]{\fontencoding{#1}%
+%<latexrelease> \edef\f@family{#2}%
+%<latexrelease> \edef\f@series{#3}%
+%<latexrelease> \edef\f@shape{#4}\selectfont
+%<latexrelease> \ignorespaces}
+%<latexrelease>
+%<latexrelease>\EndIncludeInRelease
+%<*2ekernel>
% \end{macrocode}
% \end{macro}
%
diff --git a/Master/texmf-dist/source/latex/base/lthooks.dtx b/Master/texmf-dist/source/latex/base/lthooks.dtx
index e4ff7dd2ed4..cc79892ca77 100644
--- a/Master/texmf-dist/source/latex/base/lthooks.dtx
+++ b/Master/texmf-dist/source/latex/base/lthooks.dtx
@@ -31,8 +31,8 @@
%%% From File: lthooks.dtx
%
% \begin{macrocode}
-\def\lthooksversion{v1.0e}
-\def\lthooksdate{2020/10/23}
+\def\lthooksversion{v1.0g}
+\def\lthooksdate{2020/12/18}
% \end{macrocode}
%
%<*driver>
@@ -222,11 +222,13 @@
% \begin{syntax}
% \cs{AddToHook} \Arg{hook}\oarg{label}\Arg{code}
% \end{syntax}
-% 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~(see section~\ref{sec:default-label}).
+% Adds \meta{code} to the \meta{hook} labeled by \meta{label}.
+% When the optional argument \meta{label} is not provided, the
+% \meta{default label} is used (see section~\ref{sec:default-label}).
+% If \cs{AddToHook} is used in a package/class, the
+% \meta{default label} is the package/class name, otherwise it is
+% \hook{top-level} (the \hook{top-level} label is treated
+% differently: see section~\ref{sec:top-level}).
%
% 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).
@@ -234,10 +236,10 @@
% \meta{label}, first apply \cs{RemoveFromHook}.
%
% The hook doesn't have to exist for code to be added to
-% it. However, if it is not declared later then obviously the
+% it. However, if it is not declared, then obviously the
% 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
+% enables packages to add to hooks from other packages without
% worrying whether they are actually used in the current document.
% See section~\ref{sec:querying}.
%
@@ -251,10 +253,8 @@
% \cs{RemoveFromHook} \Arg{hook}\oarg{label}
% \end{syntax}
% Removes any code labeled by \meta{label} from the \meta{hook}.
-% 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.
+% When the optional argument \meta{label} is not provided, the
+% \meta{default label} is used (see section~\ref{sec:default-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
@@ -273,7 +273,7 @@
% \medskip
%
% In contrast to the \texttt{voids} relationship between two labels
-% in a \cs{DeclareHookrule} this is a destructive operation as the
+% 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.
@@ -367,7 +367,8 @@
% token, a low-level \TeX{} error is raised (namely, the \meta{hook} is
% expanded using \TeX's \cs{csname}\ldots\cs{endcsname}, as such,
% Unicode characters are allowed in \meta{hook} and \meta{label}
-% arguments). The arguments of \cs{UseHook} and \cs{UseOneTimeHook} are
+% arguments). The arguments of \cs{UseHook}, \cs{UseOneTimeHook},
+% \cs{IfHookEmptyTF}, and \cs{IfHookExistsTF} are
% processed much in the same way except that spaces are not trimmed
% around the argument, for better performance.
%
@@ -377,10 +378,10 @@
% 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 in the name of a \meta{hook} and in a \meta{label}.
-% If \meta{hook} name or \meta{label} consist just of a single dot
+% If the \meta{hook} name or the \meta{label} consist just of a single dot
% (|.|), or starts with a dot followed by a slash (|./|) then the dot
% denotes the \meta{default label} (usually the current package or class
-% name---see~\cs{DeclareDefaultHookLabel}).
+% name---see~\cs{SetDefaultHookLabel}).
% A \enquote{|.|} or \enquote{|./|} anywhere else in a \meta{hook} or in
% \meta{label} is treated literally and is not replaced.
%
@@ -403,15 +404,15 @@
% \AddToHook {file/after/foo.tex}{code} % unchanged
% \end{verbatim}
%
-% 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}.
+% The \meta{default label} is automatically set equal to the name of the
+% current package or class at the time the package is loaded. If 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}. This may have
+% exceptions---see \cs{PushDefaultHookLabel}.
%
% This syntax is available in all \meta{label} arguments and most
-% \meta{hook}, both in the \LaTeXe{} interface, and the \LaTeX3
+% \meta{hook} arguments, both in the \LaTeXe{} interface, and the \LaTeX3
% interface described in section~\ref{sec:l3hook-interface}.
%
% Note, however, that the replacement of |.| by the \meta{default label}
@@ -430,29 +431,104 @@
% 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}:
+% \cs{SetDefaultHookLabel} or
+% \cs{PushDefaultHookLabel}..\cs{PopDefaultHookLabel}.
%
-% \begin{function}{\DeclareDefaultHookLabel}
+% \begin{function}{\PushDefaultHookLabel,\PopDefaultHookLabel}
% \begin{syntax}
-% \cs{DeclareDefaultHookLabel} \Arg{default label}
+% \cs{PushDefaultHookLabel} \Arg{default label}
+% \quad \meta{code}
+% \cs{PopDefaultHookLabel}
% \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.
+% \cs{PushDefaultHookLabel} sets the current \meta{default label} to
+% be used in \meta{label} arguments, or when replacing a leading
+% ``|.|'' (see above). \cs{PopDefaultHookLabel} reverts the
+% \meta{default label} to its previous value.
+%
+% Inside a package or class, the \meta{default label} is equal to the
+% package or class name, unless explicitly changed. Everywhere else,
+% the \meta{default label} is |top-level| (see
+% section~\ref{sec:top-level}) unless explicitly changed.
+%
+% The effect of \cs{PushDefaultHookLabel} holds until the next
+% \cs{PopDefaultHookLabel}. \cs{usepackage} (and \cs{RequirePackage}
+% and \cs{documentclass}) internally use
+% \begin{quote}
+% \cs{PushDefaultHookLabel}\Arg{package name} \\
+% \null \quad \meta{package code} \\
+% \cs{PopDefaultHookLabel}
+% \end{quote}
+% to set the \meta{default label} for the package or class file.
+% Inside the \meta{package code} the \meta{default label} can also be
+% changed with \cs{SetDefaultHookLabel}. \cs{input} and other
+% file input-related commands from the \LaTeX{} kernel do not use
+% \cs{PushDefaultHookLabel}, so code within files loaded by these
+% commands does \emph{not} get a dedicated \meta{label}! (that is, the
+% \meta{default label} is the current active one when the file was
+% loaded.)
+%
+% Packages that provide their own package-like interfaces
+% (Ti\textit{k}Z's \cs{usetikzlibrary}, for example) can use
+% \cs{PushDefaultHookLabel} and \cs{PopDefaultHookLabel} to set
+% dedicated labels and emulate \cs{usepackage}-like hook behaviour
+% within those contexts.
+%
+% The |top-level| label is treated differently, and is reserved to the
+% user document, so it is not allowed to change the
+% \meta{default label} to |top-level|.
+% \end{function}
+%
+% \begin{function}{\SetDefaultHookLabel}
+% \begin{syntax}
+% \cs{SetDefaultHookLabel} \Arg{default label}
+% \end{syntax}
+% Similarly to \cs{PushDefaultHookLabel},
+% sets the current \meta{default label} to
+% be used in \meta{label} arguments, or when replacing a leading
+% ``|.|''. The effect holds until the label is changed again or until
+% the next \cs{PopDefaultHookLabel}. The difference between
+% \cs{PushDefaultHookLabel} and \cs{SetDefaultHookLabel} is that the
+% latter does not save the current \meta{default label}.
+%
+% This command is useful when a large package is composed of several
+% smaller packages, but all should have the same \meta{label}, so
+% \cs{SetDefaultHookLabel} can be used at the beginning of each
+% package file to set the correct label.
+%
+% \cs{SetDefaultHookLabel} is not allowed in the main document, where
+% the \meta{default label} is |top-level| and there is no
+% \cs{PopDefaultHookLabel} to end its effect.
+% It is also not allowed to change the \meta{default label} to
+% |top-level|.
% \end{function}
%
+% \subsubsection{The \texttt{top-level} label}
+% \label{sec:top-level}
+%
+% The |top-level| label, assigned to code added from the main document,
+% is different from other labels. Code added to hooks (usually
+% \cs{AtBeginDocument}) in the preamble is almost always to change
+% something defined by a package, so it should go at the very end of the
+% hook.
+%
+% Therefore, code added in the |top-level| is always executed at the end
+% of the hook, regardless of where it was declared. If the hook is
+% reversed (see \cs{NewReversedHook}), the |top-level| chunk is executed
+% at the very beginning instead.
+%
+% Rules regarding |top-level| have no effect: if a user wants to have a
+% specific set of rules for a code chunk, they should use a different
+% label to said code chunk, and provide a rule for that label instead.
+%
+% The |top-level| label is exclusive for the user, so trying to add code
+% with that label from a package results in an error.
%
% \subsubsection{Defining relations between hook code}
%
% The default assumption is that code added to hooks by different
-% packages is independent and the order in which it is executed is
-% irrelevant. While this is true in many case it is obviously false
-% in many others.
+% packages are independent and the order in which they are executed is
+% irrelevant. While this is true in many cases it is obviously false
+% in others.
%
% Before the hook management system was introduced
% packages had to take elaborate precaution to determine of some other
@@ -589,7 +665,8 @@
% its permanent code pool, or to its ``next'' token list. The hook
% doesn't need to be declared to have code added to its code pool.
% A hook is said to exist when it was declared with \cs{NewHook} or
-% some variant thereof.
+% some variant thereof. Generic \hook{file} and \hook{env} hooks are
+% automatically declared when code is added to them.
%
% \begin{function}[EXP]{\IfHookEmptyTF}
% \begin{syntax}
@@ -650,6 +727,7 @@
% \item
% any code executed on the next invocation only.
% \end{itemize}
+% \end{function}
%
% \cs{LogHook} prints the information to the |.log| file, and
% \cs{ShowHook} prints them to the terminal/command window and starts
@@ -660,6 +738,7 @@
%
%^^A % Code for the listing below:
%^^A \NewHook{example-hook}
+%^^A \AddToHook{example-hook}{[code from 'top-level']}
%^^A \AddToHook{example-hook}[foo]{[code from package 'foo']}
%^^A \AddToHook{example-hook}[bar]{[from package 'bar']}
%^^A \AddToHook{example-hook}[baz]{[package 'baz' is here]}
@@ -680,13 +759,15 @@
% > foo -> [code from package 'foo']
% > bar -> [from package 'bar']
% > baz -> [package 'baz' is here]
+% > Document-level (top-level) code (executed last):
+% > -> [code from 'top-level']
% > Extra code for next invocation:
% > -> [one-time code]
% > Rules:
% > foo|baz with relation >
% > baz|bar with default relation <
% > Execution order (after applying rules):
-% > bar, baz, foo.
+% > baz, foo, bar.
% \end{verbatim}
%
% In the listing above, lines~3 to~5 show the three code chunks added
@@ -695,7 +776,18 @@
% \quad \meta{label}\verb| -> |\meta{code}
% \end{quote}
%
-% Line~7 shows the code chunk for the next execution of the hook in
+% Line~7 shows the code chunk added by the user in the main document
+% (labeled |top-level|) in the format
+% \begin{quote}
+% \quad\verb|Document-level (top-level) code (executed |%^^A
+% \meta{first\texttt{\string|}last}\verb|):|\\
+% \quad\verb| -> |\meta{\texttt{top-level} code}
+% \end{quote}
+% This code will be either the first or last code executed by the hook
+% (|last| if the hook is normal, |first| if it is reversed). This
+% chunk is not affected by rules and does not take part in sorting.
+%
+% Line~9 shows the code chunk for the next execution of the hook in
% the format
% \begin{quote}
% \quad \verb|-> |\meta{next-code}
@@ -705,7 +797,7 @@
% earlier, which can only be removed from that hook by doing
% \verb|\RemoveFromHook{|\meta{label}|}[example-hook]|.
%
-% Lines~9 and~10 show the rules declared that affect this hook in the
+% Lines~11 and~12 show the rules declared that affect this hook in the
% format
% \begin{quote}
% \quad \meta{label-1}\verb+|+\meta{label-2}| with |%^^A
@@ -717,9 +809,8 @@
% to \meta{label-1} and \meta{label-2} in \emph{all} hooks, (unless
% overrided by a non-default relation).
%
-% Finally, line~12 lists the labels in the hook after sorting;
+% Finally, line~14 lists the labels in the hook after sorting;
% that is, in the order they will be executed when the hook is used.
-% \end{function}
%
%
% \subsubsection{Debugging hook code}
@@ -749,8 +840,9 @@
% \begin{function}
% {\hook_new:n,\hook_new_reversed:n,\hook_new_pair:nn}
% \begin{syntax}
-% \cs{hook_new:n}\Arg{hook}
-% \cs{hook_new_pair:nn}\Arg{hook-1}\Arg{hook-2}
+% \cs{hook_new:n} \Arg{hook}
+% \cs{hook_new_reversed:n} \Arg{hook}
+% \cs{hook_new_pair:nn} \Arg{hook-1} \Arg{hook-2}
% \end{syntax}
% Creates a new \meta{hook} with normal or reverse ordering of code
% chunks. \cs{hook_new_pair:nn} creates a pair of such hooks with
@@ -782,7 +874,6 @@
% Changes the \Arg{hook} status so that from now on any addition to
% the hook code is executed immediately. Then execute any
% \Arg{hook} code already set up.
-% \fmi{better L3 name?}
%
% The \meta{hook} \emph{cannot} be specified using the dot-syntax.
% A leading |.| is treated literally.
@@ -954,17 +1045,19 @@
% \texttt{packageB}, \texttt{packageC} which you can verify with
% \cs{ShowHook}\texttt{\{myhook\}}:
%\begin{verbatim}
-% The hook 'myhook':
-% Code chunks:
-% packageA -> \typeout {A}
-% packageB -> \typeout {B}
-% packageC -> \typeout {C}
-% Extra code next invocation:
-% ---
-% Rules:
-% ---
-% Execution order:
-% packageA, packageB, packageC
+% -> The hook 'myhook':
+% > Code chunks:
+% > packageA -> \typeout {A}
+% > packageB -> \typeout {B}
+% > packageC -> \typeout {C}
+% > Document-level (top-level) code (executed last):
+% > ---
+% > Extra code for next invocation:
+% > ---
+% > Rules:
+% > ---
+% > Execution order:
+% > packageA, packageB, packageC.
%\end{verbatim}
% The reason is that the code chunks are internally saved in a property list
% and the initial order of such a property list is the order in
@@ -988,17 +1081,19 @@
%\end{verbatim}
% instead of the previous lines we get
%\begin{verbatim}
-% The hook 'myhook':
-% Code chunks:
-% packageA -> \typeout {A}
-% packageB -> \typeout {B}
-% packageC -> \typeout {C}
-% Extra code next invocation:
-% ---
-% Rules:
-% packageA|packageB with relation before
-% Execution order (after applying rules):
-% packageA, packageC, packageB
+% -> The hook 'myhook':
+% > Code chunks:
+% > packageA -> \typeout {A}
+% > packageB -> \typeout {B}
+% > packageC -> \typeout {C}
+% > Document-level (top-level) code (executed last):
+% > ---
+% > Extra code for next invocation:
+% > ---
+% > Rules:
+% > packageB|packageA with relation >
+% > Execution order (after applying rules):
+% > packageA, packageC, packageB.
%\end{verbatim}
% As you can see the code chunks are still in the same order, but
% in the execution order for the labels \texttt{packageB} and
@@ -1010,7 +1105,7 @@
% doesn't run at all as there is nothing to resolve).
% Incidentally, if we had instead specified the redundant rule
%\begin{verbatim}
-% \DeclareHookRule{myhook}{packageB}{before}{label-3}
+% \DeclareHookRule{myhook}{packageB}{before}{packageC}
%\end{verbatim}
% the execution order would not have changed.
%
@@ -1039,17 +1134,17 @@
% \AddToHook{env/quote/after} [package-1]{\end{itshape}}
%\end{verbatim}
% As a result, all quotes will be in italics.
-% Now suppose further that the user wants the quotes also in blue
-% and therefore adds:
+% Now suppose further that another |package-too| makes the quotes
+% also in blue and therefore adds:
%\begin{verbatim}
% \usepackage{color}
-% \AddToHook{env/quote/before}{\begin{color}{blue}}
-% \AddToHook{env/quote/after} {\end{color}}
+% \AddToHook{env/quote/before}[package-too]{\begin{color}{blue}}
+% \AddToHook{env/quote/after} [package-too]{\end{color}}
%\end{verbatim}
% Now if the \hook{env/quote/after} hook would be a normal hook we
% would get the same execution order in both hooks, namely:
%\begin{verbatim}
-% package-1, top-level
+% package-1, package-too
%\end{verbatim}
% (or vice versa) and as a result, would get:
%\begin{verbatim}
@@ -1063,16 +1158,18 @@
% the correct sequence and \cs{ShowHook} would give us the
% following output:
%\begin{verbatim}
-% The hook 'env/quote/after':
-% Code chunks:
-% package-1 -> \end {itshape}
-% top-level -> \end {color}
-% Extra code next invocation:
-% ---
-% Rules:
-% ---
-% Execution order (after reversal):
-% top-level, package-1
+% -> The hook 'env/quote/after':
+% > Code chunks:
+% > package-1 -> \end {itshape}
+% > package-too -> \end {color}
+% > Document-level (top-level) code (executed first):
+% > ---
+% > Extra code for next invocation:
+% > ---
+% > Rules:
+% > ---
+% > Execution order (after reversal):
+% > package-too, package-1.
%\end{verbatim}
%
% The reversal of the execution order happens before applying any
@@ -1206,13 +1303,15 @@
% \hook{begindocument}
% (which is executed inside \verb=\begin{document}=).
% However, all code added this way is labeled with the label
-% \hook{top-level} if done outside of a package or class or with the
-% package/class name if called inside such a file.
+% \hook{top-level} (see section~\ref{sec:top-level})
+% if done outside of a package or class or with the
+% package/class name if called inside such a file
+% (see section~\ref{sec:default-label}).
%
% This way one can add further code to the hook using
% \cs{AddToHook} or \cs{AtBeginDocument} using a different label
% and explicitly order the code chunks as necessary, e.g., run some
-% code before or after the \hook{top-level} code. When using the
+% code before or after another package's code. When using the
% optional argument the call is equivalent to running
% \cs{AddToHook} \texttt{\{begindocument\}} \oarg{label}
% \Arg{code}.
@@ -1251,7 +1350,7 @@
% 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
+% \cs{AtBeginDocument}. 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
@@ -1333,8 +1432,8 @@
% \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.
+% using the \meta{label}. If \meta{label} is not given, the
+% \meta{default label} is used (see section~\ref{sec:default-label}).
% \end{function}
%
% \begin{function}{\AtBeginEnvironment}
@@ -1774,6 +1873,37 @@
% \end{macrocode}
% \end{macro}
%
+% \begin{macro}{\@@_tl_set:Nn,\@@_tl_set:cn,\@@_tl_set:cx}
+% \begin{macro}{\@@_tl_gset:Nn,\@@_tl_gset:cn,\@@_tl_gset:co,\@@_tl_gset:cx}
+% \begin{macro}{\@@_tl_gput_right:Nn,\@@_tl_gput_right:No,\@@_tl_gput_right:cn}
+% \begin{macro}{\@@_tl_gput_left:Nn,\@@_tl_gput_left:No}
+% \begin{macro}{\@@_tl_gclear:N,\@@_tl_gclear:c}
+% \begin{macro}{\@@_tl_gset_eq:NN}
+% Private copies of a few \pkg{expl3} functions. \pkg{l3debug} will
+% only add debugging to the public names, not to these copies, so we
+% don't have to use \cs{debug_suspend:} and \cs{debug_resume:}
+% everywhere.
+% \begin{macrocode}
+\cs_new_eq:NN \@@_tl_set:Nn \tl_set:Nn
+\cs_generate_variant:Nn \@@_tl_set:Nn { cn, cx }
+\cs_new_eq:NN \@@_tl_gset:Nn \tl_gset:Nn
+\cs_generate_variant:Nn \@@_tl_gset:Nn { cn, co, cx }
+\cs_new_eq:NN \@@_tl_gput_right:Nn \tl_gput_right:Nn
+\cs_generate_variant:Nn \@@_tl_gput_right:Nn { No, cn }
+\cs_new_eq:NN \@@_tl_gput_left:Nn \tl_gput_left:Nn
+\cs_generate_variant:Nn \@@_tl_gput_left:Nn { No }
+\cs_new_protected:Npn \@@_tl_gclear:N #1
+ { \@@_tl_gset_eq:NN #1 \c_empty_tl }
+\cs_generate_variant:Nn \@@_tl_gclear:N { c }
+\cs_new_eq:NN \@@_tl_gset_eq:NN \tl_gset_eq:NN
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
%
% \subsection{Providing new hooks}
%
@@ -1808,6 +1938,13 @@
% $\meta{reversed}1$ is $+1$ for normal hooks and $-1$ for reversed
% ones.
%
+% \item[\cs{@@_toplevel~\meta{name}}] This token list stores the code
+% inserted in the hook from the user's document, in the |top-level|
+% label. This label is special, and doesn't participate in sorting.
+% Instead, all code is appended to it and executed after (or before,
+% if the hook is reversed) the normal
+% hook code, but before the |next| code chunk.
+%
% \item[\cs{@@_next~\meta{name}}] 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
@@ -1890,15 +2027,16 @@
% \begin{macro}{\@@_declare:n}
% This function declares the basic data structures for a hook without
% actually declaring the hook itself. This is needed to allow adding
-% to undeclared hooks. Here it is unnecessary to check whether both
-% variables exist, since both are declared at the same time (either
-% both exist, or neither).
+% to undeclared hooks. Here it is unnecessary to check whether all
+% variables exist, since all three are declared at the same time
+% (either all of them exist, or none).
% \begin{macrocode}
\cs_new_protected:Npn \@@_declare:n #1
{
\@@_if_exist:nF {#1}
{
\prop_new:c { g_@@_#1_code_prop }
+ \tl_new:c { @@_toplevel~#1 }
\tl_new:c { @@_next~#1 }
}
}
@@ -1951,13 +2089,6 @@
\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
-% 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:
-% \end{macrocode}
% If the macro doesn't exist (which is the usual case) then nothing
% needs to be done.
% \begin{macrocode}
@@ -1975,10 +2106,9 @@
% 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_gclear:c { @#1hook }
+ \@@_tl_gclear:c { @#1hook }
}
}
- \debug_resume:
}
% \end{macrocode}
% \end{macro}
@@ -1990,79 +2120,76 @@
% \begin{macro}[EXP]{\@@_parse_label_default:n}
% 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.
-%
-% The default |top-level| is hard-coded here. It once was an
-% argument, but it's no longer needed. \pho{can't remember why}
+% replace by \cs{@@_currname_or_default:}.
% \begin{macrocode}
\cs_new:Npn \@@_parse_label_default:n #1
{
\tl_if_novalue:nTF {#1}
- { \@@_currname_or_default:n { top-level } }
- {
- \tl_trim_spaces_apply:nN {#1}
- \@@_parse_dot_label:nn { top-level }
- }
+ { \@@_currname_or_default: }
+ { \tl_trim_spaces_apply:nN {#1} \@@_parse_dot_label:n }
}
% \end{macrocode}
% \end{macro}
%
-% \begin{macro}[EXP]{\@@_parse_dot_label:nn}
+% \begin{macro}[EXP]{\@@_parse_dot_label:n}
% \begin{macro}[EXP]{
-% \@@_parse_dot_label:nw,
+% \@@_parse_dot_label:w,
% \@@_parse_dot_label_cleanup:w,
-% \@@_parse_dot_label_aux:nw
+% \@@_parse_dot_label_aux:w
% }
% 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
+% \verb|.| is replaced with \cs{@@_currname_or_default:}. Otherwise
% the label is returned unchanged.
% \begin{macrocode}
-\cs_new:Npn \@@_parse_dot_label:nn #1 #2
+\cs_new:Npn \@@_parse_dot_label:n #1
{
\tl_if_empty:nTF {#1}
{
- \msg_expandable_error:nnn { hooks } { empty-label } {#2}
- #2
+ \msg_expandable_error:nn { hooks } { empty-label }
+ \@@_currname_or_default:
}
{
\str_if_eq:nnTF {#1} { . }
- { \@@_currname_or_default:n {#2} }
- { \@@_parse_dot_label:nw {#2} #1 ./ \s_@@_mark }
+ { \@@_currname_or_default: }
+ { \@@_parse_dot_label:w #1 ./ \s_@@_mark }
}
}
-\cs_new:Npn \@@_parse_dot_label:nw #1 #2 ./ #3 \s_@@_mark
+\cs_new:Npn \@@_parse_dot_label:w #1 ./ #2 \s_@@_mark
{
- \tl_if_empty:nTF {#2}
- { \@@_parse_dot_label_aux:nw {#1} #3 \s_@@_mark }
+ \tl_if_empty:nTF {#1}
+ { \@@_parse_dot_label_aux:w #2 \s_@@_mark }
{
- \tl_if_empty:nTF {#3}
- { \@@_make_name:n {#2} }
- { \@@_parse_dot_label_cleanup:w #2 ./ #3 \s_@@_mark }
+ \tl_if_empty:nTF {#2}
+ { \@@_make_name:n {#1} }
+ { \@@_parse_dot_label_cleanup:w #1 ./ #2 \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} / \@@_make_name:n {#2} }
+\cs_new:Npn \@@_parse_dot_label_aux:w #1 ./ \s_@@_mark
+ { \@@_currname_or_default: / \@@_make_name:n {#1} }
% \end{macrocode}
% \end{macro}
% \end{macro}
%
-% \begin{macro}[EXP]{\@@_currname_or_default:n}
+% \begin{macro}[EXP]{\@@_currname_or_default:}
% 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}).
+% \cs{@currname}. If neither is set, raises an error and uses the
+% fallback value \verb|label-missing|.
% \begin{macrocode}
-\cs_new:Npn \@@_currname_or_default:n #1
+\cs_new:Npn \@@_currname_or_default:
{
\tl_if_empty:NTF \g_@@_hook_curr_name_tl
{
\tl_if_empty:NTF \@currname
- { \@@_make_name:n {#1} }
+ {
+ \msg_expandable_error:nnn { hooks } { should-not-happen }
+ { Empty~default~label. }
+ \@@_make_name:n { label-missing }
+ }
{ \@currname }
}
{ \g_@@_hook_curr_name_tl }
@@ -2213,14 +2340,33 @@
% \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=.
+% otherwise just put \verb=#3=. If the current label is |top-level|,
+% the code is added to a dedicated token list
+% \cs[no-index]{@@_toplevel~\meta{hook}} that goes at the end of the
+% hook (or at the beginning, for a reversed hook), just before
+% \cs[no-index]{@@_next~\meta{hook}}.
+% \begin{macrocode}
+ \str_if_eq:nnTF {#2} { top-level }
+ {
+ \str_if_eq:eeTF { top-level } { \@@_currname_or_default: }
+ {
+% \end{macrocode}
+% If the hook's basic structure does not exist, we need to declare it
+% with \cs{@@_declare:n}.
% \begin{macrocode}
- \prop_get:cnNTF { g_@@_#1_code_prop } {#2} \l_@@_return_tl
+ \@@_declare:n {#1}
+ \@@_tl_gput_right:cn { @@_toplevel~#1 } {#3}
+ }
+ { \msg_error:nnn { hooks } { misused-top-level } {#1} }
+ }
{
- \prop_gput:cno { g_@@_#1_code_prop } {#2}
- { \l_@@_return_tl #3 }
+ \prop_get:cnNTF { g_@@_#1_code_prop } {#2} \l_@@_return_tl
+ {
+ \prop_gput:cno { g_@@_#1_code_prop } {#2}
+ { \l_@@_return_tl #3 }
+ }
+ { \prop_gput:cnn { g_@@_#1_code_prop } {#2} {#3} }
}
- { \prop_gput:cnn { g_@@_#1_code_prop } {#2} {#3} }
}
% \end{macrocode}
% \end{macro}
@@ -2434,24 +2580,48 @@
% hook before its defined (see section~\ref{sec:querying}).
% \begin{macrocode}
\@@_if_exist:nTF {#1}
+ {
% \end{macrocode}
% Then remove the chunk and run \cs{@@_update_hook_code:n} so
% that the execution token list reflects the change if we are after
% \verb=\begin{document}=.
+%
+% If all code is to be removed, clear the code pool
+% \cs[no-index]{g_@@_\meta{hook}_code_prop}, the top-level code
+% \cs[no-index]{@@_toplevel~\meta{hook}}, and the next-execution code
+% \cs[no-index]{@@_next~\meta{hook}}.
% \begin{macrocode}
- {
\str_if_eq:nnTF {#2} {*}
- { \prop_gclear:c { g_@@_#1_code_prop } }
{
+ \prop_gclear:c { g_@@_#1_code_prop }
+ \@@_tl_gclear:c { @@_toplevel~#1 }
+ \@@_tl_gclear:c { @@_next~#1 }
+ }
+ {
+% \end{macrocode}
+% If the label is |top-level| then clear the token list, as all code
+% there is under the same label. Marked removal is not implemented
+% for |top-level| because it is hard to reliably know that no code
+% was added to \cs[no-index]{@@_toplevel~\meta{hook}} (granted that
+% an empty code could be interpreted as that, but then it differs in
+% behaviour from other labels, in which an empty chunk is still valid
+% for removal). Besides, it doesn't make much (if any) sense for
+% packages to remove |top-level| code. So here the chunk is just
+% cleared unconditionally.
+% \begin{macrocode}
+ \str_if_eq:nnTF {#2} { top-level }
+ { \@@_tl_gclear:c { @@_toplevel~#1 } }
+ {
% \end{macrocode}
-% Check if the label being removed exists in the code pool. If it does,
-% just call \cs{@@_gremove_code_do:nn} to do the removal, otherwise mark it
-% to be removed.
+% Otherwise check if the label being removed exists in the code pool.
+% If it does, 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
- { \@@_gremove_code_do:nn }
- { \@@_mark_removal:nn }
- {#1} {#2}
+ \prop_get:cnNTF { g_@@_#1_code_prop } {#2} \l_@@_return_tl
+ { \@@_gremove_code_do:nn }
+ { \@@_mark_removal:nn }
+ {#1} {#2}
+ }
}
% \end{macrocode}
% Finally update the code, if the hook exists.
@@ -2470,6 +2640,7 @@
% \end{macrocode}
%
% \begin{macro}{\@@_gremove_code_do:nn}
+% Remove code for a given label.
% \begin{macrocode}
\cs_new_protected:Npn \@@_gremove_code_do:nn #1 #2
{ \prop_gremove:cn { g_@@_#1_code_prop } {#2} }
@@ -2605,7 +2776,6 @@
% Then we call the function to handle the given rule. Throw an error if the
% rule is invalid.
% \begin{macrocode}
- \debug_suspend:
\cs_if_exist_use:cTF { @@_rule_#3_gset:nnn }
{
{#1} {#2} {#4}
@@ -2613,7 +2783,6 @@
}
{ \msg_error:nnnnnn { hooks } { unknown-rule }
{#1} {#2} {#3} {#4} }
- \debug_resume:
}
% \end{macrocode}
% \end{macro}
@@ -2639,7 +2808,7 @@
% \begin{macrocode}
\cs_new_protected:Npn \@@_rule_before_gset:nnn #1#2#3
{
- \tl_gset:cx { g_@@_#1_rule_ \@@_label_pair:nn {#2} {#3} _tl }
+ \@@_tl_gset:cx { g_@@_#1_rule_ \@@_label_pair:nn {#2} {#3} _tl }
{ \@@_label_ordered:nnTF {#2} {#3} { < } { > } }
}
\cs_new_eq:cN { @@_rule_<_gset:nnn } \@@_rule_before_gset:nnn
@@ -2648,7 +2817,7 @@
% \begin{macrocode}
\cs_new_protected:Npn \@@_rule_after_gset:nnn #1#2#3
{
- \tl_gset:cx { g_@@_#1_rule_ \@@_label_pair:nn {#3} {#2} _tl }
+ \@@_tl_gset:cx { g_@@_#1_rule_ \@@_label_pair:nn {#3} {#2} _tl }
{ \@@_label_ordered:nnTF {#3} {#2} { < } { > } }
}
\cs_new_eq:cN { @@_rule_>_gset:nnn } \@@_rule_after_gset:nnn
@@ -2661,7 +2830,7 @@
% \begin{macrocode}
\cs_new_protected:Npn \@@_rule_voids_gset:nnn #1#2#3
{
- \tl_gset:cx { g_@@_#1_rule_ \@@_label_pair:nn {#2} {#3} _tl }
+ \@@_tl_gset:cx { g_@@_#1_rule_ \@@_label_pair:nn {#2} {#3} _tl }
{ \@@_label_ordered:nnTF {#2} {#3} { -> } { <- } }
}
% \end{macrocode}
@@ -2675,9 +2844,9 @@
% together in hook |#1|.
% \begin{macrocode}
\cs_new_protected:cpn { @@_rule_incompatible-error_gset:nnn } #1#2#3
- { \tl_gset:cn { g_@@_#1_rule_ \@@_label_pair:nn {#2} {#3} _tl } { xE } }
+ { \@@_tl_gset:cn { g_@@_#1_rule_ \@@_label_pair:nn {#2} {#3} _tl } { xE } }
\cs_new_protected:cpn { @@_rule_incompatible-warning_gset:nnn } #1#2#3
- { \tl_gset:cn { g_@@_#1_rule_ \@@_label_pair:nn {#2} {#3} _tl } { xW } }
+ { \@@_tl_gset:cn { g_@@_#1_rule_ \@@_label_pair:nn {#2} {#3} _tl } { xW } }
% \end{macrocode}
% \end{macro}
%
@@ -2722,7 +2891,7 @@
% \end{macro}
%
% \begin{macro}[EXP]{\@@_if_label_case:nnnnn}
-% To avoid doing the string comparison twice in \cs{@@_initialize_single:NNNn}
+% To avoid doing the string comparison twice in \cs{@@_initialize_single:NNn}
% (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
@@ -2800,7 +2969,6 @@
% \begin{macrocode}
\cs_new_protected:Npn \@@_initialize_hook_code:n #1
{
- \debug_suspend:
\@@_debug:n{ \iow_term:x{^^JUpdate~ code~ for~ hook~
'#1' \on@line :^^J} }
% \end{macrocode}
@@ -2815,17 +2983,22 @@
% 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{@@~\meta{hook}} to hold the next
-% code. If there are code chunks we call
-% \cs{@@_initialize_single:NNNn} and pass to it ready made csnames
+% case just update \cs{@@~\meta{hook}} to hold the |top-level| and
+% |next| code chunks. If there are code chunks we call
+% \cs{@@_initialize_single:NNn} 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}
\hook_if_exist:nT {#1}
{
\prop_if_empty:cTF {g_@@_#1_code_prop}
- { \tl_gset:co { @@~#1 }
- { \cs:w @@_next~#1 \cs_end: } }
+ {
+ \@@_tl_gset:co { @@~#1 }
+ {
+ \cs:w @@_toplevel~#1 \exp_after:wN \cs_end:
+ \cs:w @@_next~#1 \cs_end:
+ }
+ }
{
% \end{macrocode}
% By default the algorithm sorts the code chunks and then saves the
@@ -2836,9 +3009,9 @@
% in preparation is to change two definitions used later on.
% \begin{macrocode}
\@@_if_reversed:nTF {#1}
- { \cs_set_eq:NN \@@_tl_gput:NV \tl_gput_left:NV
+ { \cs_set_eq:NN \@@_tl_gput:Nn \@@_tl_gput_left:Nn
\cs_set_eq:NN \@@_clist_gput:NV \clist_gput_left:NV }
- { \cs_set_eq:NN \@@_tl_gput:NV \tl_gput_right:NV
+ { \cs_set_eq:NN \@@_tl_gput:Nn \@@_tl_gput_right:Nn
\cs_set_eq:NN \@@_clist_gput:NV \clist_gput_right:NV }
% \end{macrocode}
%
@@ -2848,9 +3021,8 @@
% save the old code property list so that it can be restored later.
% \begin{macrocode}
\prop_set_eq:Nc \l_@@_work_prop { g_@@_#1_code_prop }
- \@@_initialize_single:cccn
- { @@~#1 } { @@_next~#1 }
- { g_@@_#1_labels_clist } {#1}
+ \@@_initialize_single:ccn
+ { @@~#1 } { 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
@@ -2862,7 +3034,6 @@
\g_@@_used_prop {#1}{} }
}
}
- \debug_resume:
}
% \end{macrocode}
% \end{macro}
@@ -2918,12 +3089,13 @@
% \end{macro}
%
%
-% \begin{macro}{\@@_initialize_single:NNNn,\@@_initialize_single:cccn}
+% \begin{macro}{\@@_initialize_single:NNn,\@@_initialize_single:ccn}
%
-% \cs{@@_initialize_single:NNNn} implements the sorting of the code
+% \cs{@@_initialize_single:NNn} 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},
+% execution (\verb=#4=). The arguments are \meta{hook-code-plist},
+% \meta{hook-code-tl}, \meta{hook-top-level-code-tl},
+% \meta{hook-next-code-tl},
% \meta{hook-ordered-labels-clist} and \meta{hook-name} (the latter
% is only used for debugging---the \meta{hook-rule-plist} is accessed
% using the \meta{hook-name}).
@@ -2935,8 +3107,12 @@
% far as possible. The result is a restriction I do not test for at
% the moment: a label can't be equal to the number 0! \fmi{Needs
% checking for, just in case}
+%
+% ^^A #1 <- \@@~#1
+% ^^A #2 <- \g_@@_#1_labels_clist
+% ^^A #3 <- #1
% \begin{macrocode}
-\cs_new_protected:Npn \@@_initialize_single:NNNn #1#2#3#4
+\cs_new_protected:Npn \@@_initialize_single:NNn #1#2#3
{
% \end{macrocode}
% Step T1: Initialize the data structure \ldots
@@ -2947,7 +3123,7 @@
%
% Store the name of the hook:
% \begin{macrocode}
- \tl_set:Nn \l_@@_cur_hook_tl {#4}
+ \tl_set:Nn \l_@@_cur_hook_tl {#3}
% \end{macrocode}
%
% We loop over the property list holding the code and record all
@@ -2961,7 +3137,7 @@
{
\int_incr:N \l_@@_labels_int
\seq_put_right:Nn \l_@@_labels_seq {##1}
- \tl_set:cn { \@@_tl_csname:n {##1} }{0}
+ \@@_tl_set:cn { \@@_tl_csname:n {##1} } { 0 }
\seq_clear_new:c { \@@_seq_csname:n {##1} }
}
% \end{macrocode}
@@ -2987,7 +3163,7 @@
{ \prop_map_break: }
{ \@@_apply_label_pair:nnn {##1} {####1} }
{ \@@_apply_label_pair:nnn {####1} {##1} }
- {#4}
+ {#3}
}
}
% \end{macrocode}
@@ -3014,8 +3190,8 @@
% \end{macrocode}
%
% \begin{macrocode}
- \tl_gclear:N #1
- \clist_gclear:N #3
+ \@@_tl_gclear:N #1
+ \clist_gclear:N #2
% \end{macrocode}
%
% The whole loop combines steps T5--T7:
@@ -3027,11 +3203,11 @@
% \begin{macrocode}
\int_decr:N \l_@@_labels_int
\prop_get:NVN \l_@@_work_prop \l_@@_front_tl \l_@@_return_tl
- \@@_tl_gput:NV #1 \l_@@_return_tl
+ \exp_args:NNV \@@_tl_gput:Nn #1 \l_@@_return_tl
% \end{macrocode}
%
% \begin{macrocode}
- \@@_clist_gput:NV #3 \l_@@_front_tl
+ \@@_clist_gput:NV #2 \l_@@_front_tl
\@@_debug:n{ \iow_term:x{Handled~ code~ for~ \l_@@_front_tl} }
% \end{macrocode}
%
@@ -3078,27 +3254,31 @@
}
% \end{macrocode}
% 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=#2= but is normally empty.
-% \begin{macrocode}
- \tl_gput_right:Nn #1 {#2}
+% with adding extra code for the |top-level| (\verb=#2=) and for one
+% time execution (\verb=#3=). These should normally be empty. The
+% |top-level| code is added with \cs{@@_tl_gput:Nn} as that might
+% change for a reversed hook (then |top-level| is the very first code
+% chunk added). The |next| code is always added last.
+% \begin{macrocode}
+ \exp_args:NNo \@@_tl_gput:Nn #1 { \cs:w @@_toplevel~#3 \cs_end: }
+ \@@_tl_gput_right:No #1 { \cs:w @@_next~#3 \cs_end: }
}
% \end{macrocode}
-%
+%
% \begin{macrocode}
-\cs_generate_variant:Nn \@@_initialize_single:NNNn {ccc}
+\cs_generate_variant:Nn \@@_initialize_single:NNn { cc }
% \end{macrocode}
% \end{macro}
%
%
%
-% \begin{macro}{\@@_tl_gput:NV,\@@_clist_gput:NV}
+% \begin{macro}{\@@_tl_gput:Nn,\@@_clist_gput:NV}
% These append either on the right (normal hook) or on the left
% (reversed hook). This is setup up in
% \cs{@@_initialize_hook_code:n}, elsewhere their behavior is undefined.
% \begin{macrocode}
-\cs_new:Npn \@@_tl_gput:NV {\ERROR}
-\cs_new:Npn \@@_clist_gput:NV {\ERROR}
+\cs_new:Npn \@@_tl_gput:Nn { \ERROR }
+\cs_new:Npn \@@_clist_gput:NV { \ERROR }
% \end{macrocode}
% \end{macro}
%
@@ -3347,7 +3527,8 @@
% \begin{macrocode}
\hook_if_exist:nF {#1}
{ \@@_log_line:x { is~not~declared! } }
- \@@_if_exist:nTF {#1}
+ \hook_if_empty:nTF {#1}
+ { #2 { The~hook~is~empty } }
{
\@@_log_line:x { Code~chunks: }
\prop_if_empty:cTF { g_@@_#1_code_prop }
@@ -3357,9 +3538,25 @@
{ \@@_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 { Extra~code~for~next~invocation:}
+ \@@_log_line:x
+ {
+ Document-level~(top-level)~code
+ \hook_if_exist: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 }
@@ -3427,7 +3624,6 @@
}
}
}
- { #2 { The~hook~is~empty. } }
}
% \end{macrocode}
%
@@ -3478,7 +3674,7 @@
% \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} {#3}
{ \@@_list_if_rule_exists:nnnF {#1} {#2} { ?? } { } }
}
\cs_new_protected:Npn \@@_list_if_rule_exists:nnnF #1#2#3
@@ -3486,7 +3682,9 @@
\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}
+ \exp_after:wN \use_none:nn
\fi:
+ \use:n
}
% \end{macrocode}
% \end{macro}
@@ -3528,12 +3726,10 @@
{ \@@_normalize_hook_args:Nn \@@_gput_next_code:nn {#1} }
\cs_new_protected:Npn \@@_gput_next_code:nn #1 #2
{
- \debug_suspend:
\@@_declare:n {#1}
\hook_if_exist:nTF {#1}
{ \@@_gput_next_do:nn {#1} {#2} }
{ \@@_try_declaring_generic_next_hook:nn {#1} {#2} }
- \debug_resume:
}
\cs_new_protected:Npn \@@_gput_next_do:nn #1
{
@@ -3556,8 +3752,8 @@
\tl_if_empty:cT { @@~#2 }
{ \@@_update_hook_code:n {#2} }
\tl_if_empty:NT #1
- { \tl_gset:Nn #1 { \@@_clear_next:n {#2} } }
- \tl_gput_right:Nn #1
+ { \@@_tl_gset:Nn #1 { \@@_clear_next:n {#2} } }
+ \@@_tl_gput_right:Nn #1
}
\cs_new_protected:Npn \@@_clear_next:n #1
{ \cs_gset_eq:cN { @@_next~#1 } \c_empty_tl }
@@ -3565,7 +3761,6 @@
% \end{macro}
% \end{macro}
%
-%
% \subsection{Using the hook}
%
% \begin{macro}{\hook_use:n}
@@ -3720,8 +3915,9 @@
%
% \begin{macro}[pTF]{\hook_if_empty:n}
% 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
+% A \meta{hook} being empty means that all three of its
+% \cs[no-index]{g_@@_\meta{hook}_code_prop}, its
+% \cs[no-index]{@@_toplevel~\meta{hook}} and its
% \cs[no-index]{@@_next~\meta{hook}} are empty.
% \begin{macrocode}
\prg_new_conditional:Npnn \hook_if_empty:n #1 { p , T , F , TF }
@@ -3730,7 +3926,11 @@
{
\bool_lazy_and:nnTF
{ \prop_if_empty_p:c { g_@@_#1_code_prop } }
- { \tl_if_empty_p:c { @@_next~#1 } }
+ {
+ \bool_lazy_and_p:nn
+ { \tl_if_empty_p:c { @@_toplevel~#1 } }
+ { \tl_if_empty_p:c { @@_next~#1 } }
+ }
{ \prg_return_true: }
{ \prg_return_false: }
}
@@ -3812,9 +4012,20 @@
%
% \begin{macrocode}
\msg_new:nnn { hooks } { empty-label }
- { Empty~code~label~\msg_line_context:.~Using~`#1'~instead. }
+ {
+ Empty~code~label~\msg_line_context:.~
+ Using~`\@@_currname_or_default:'~instead.
+ }
% \end{macrocode}
-%
+%
+% \begin{macrocode}
+\msg_new:nnn { hooks } { no-default-label }
+ {
+ Missing~(empty)~default~label~\msg_line_context:. \\
+ This~command~was~ignored.
+ }
+% \end{macrocode}
+%
% \begin{macrocode}
\msg_new:nnnn { hooks } { unknown-rule }
{ Unknown~ relationship~ `#3'~
@@ -3834,6 +4045,51 @@
% \end{macrocode}
%
% \begin{macrocode}
+\msg_new:nnnn { hooks } { misused-top-level }
+ {
+ Illegal~\iow_char:N \\AddToHook{#1}[top-level]{...}.\\
+ 'top-level'~is~reserved~for~the~user's~document.
+ }
+ {
+ The~'top-level'~label~is~meant~for~user~code~only,~and~should~only~
+ be~used~(sparingly)~in~the~main~document.~Use~the~default~label~
+ '\@@_currname_or_default:'~for~this~\@cls@pkg,~or~another~
+ suitable~label.
+ }
+% \end{macrocode}
+%
+% \begin{macrocode}
+\msg_new:nnn { hooks } { set-top-level }
+ {
+ You~cannot~change~the~default~label~#1~`top-level'.~Illegal \\
+ \use:nn { ~ } { ~ } \iow_char:N \\#2{#3} \\
+ \msg_line_context:.
+ }
+% \end{macrocode}
+%
+% \begin{macrocode}
+\msg_new:nnn { hooks } { ddhl-deprecated }
+ {
+ \iow_char:N \\DeclareDefaultHookLabel~is~deprecated.\\
+ Use~\iow_char:N \\SetDefaultHookLabel~instead.\\ \\
+ The~deprecated~name~will~be~removed~in~the~next~release.
+ }
+% \end{macrocode}
+%
+% \begin{macrocode}
+\msg_new:nnn { hooks } { extra-pop-label }
+ {
+ Extra~\iow_char:N \\PopDefaultHookLabel. \\
+ This~command~will~be~ignored.
+ }
+\msg_new:nnn { hooks } { missing-pop-label }
+ {
+ Missing~\iow_char:N \\PopDefaultHookLabel. \\
+ The~label~`#1'~was~pushed~but~never~popped.~Something~is~wrong.
+ }
+% \end{macrocode}
+%
+% \begin{macrocode}
\msg_new:nnn { hooks } { should-not-happen }
{
ERROR!~This~should~not~happen.~#1 \\
@@ -3879,39 +4135,77 @@
% \end{macrocode}
% \end{macro}
%
+% \begin{macro}{\SetDefaultHookLabel}
+% \begin{macro}{\PushDefaultHookLabel}
+% \begin{macro}{\PopDefaultHookLabel}
% \begin{macro}{\DeclareDefaultHookLabel}
-% \begin{macro}{\@@_curr_name_push:n,\@@_curr_name_pop:}
+% \begin{macro}{\@@_curr_name_push:n,\@@_curr_name_push_aux:n}
+% \begin{macro}{\@@_curr_name_pop:}
+% \begin{macro}{\@@_end_document_label_check:}
% 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).
+% \cs{SetDefaultHookLabel} to change the default label (in which
+% case \cs{@currname} is used).
%
-% 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. 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.
+% To pull that one 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| (this stack should never go
+% empty). If we're building the format, set the default label to be
+% |top-level|:
% \begin{macrocode}
-\seq_gpush:Nn \g_@@_name_stack_seq { }
+\tl_gset:Nn \g_@@_hook_curr_name_tl { top-level }
% \end{macrocode}
%
+% Then, in case we're in \pkg{latexrelease} we push something on
+% the stack to support roll forward. But in some rare cases,
+% \pkg{latexrelease} may be loaded inside another package (notably
+% \pkg{platexrelease}), so we'll first push the |top-level| entry:
+% \begin{macrocode}
+%<latexrelease>\seq_gput_right:Nn \g_@@_name_stack_seq { top-level }
+% \end{macrocode}
+% then we dissect the \cs{@currnamestack}, adding \cs{@currname} to
+% the stack:
+% \changes{v1.0f}{2020/11/24}{Support for roll forward (gh/434)}
+% \begin{macrocode}
+%<latexrelease>\cs_set_protected:Npn \@@_tmp:w #1 #2 #3
+%<latexrelease> {
+%<latexrelease> \quark_if_recursion_tail_stop:n {#1}
+%<latexrelease> \seq_gput_right:Nn \g_@@_name_stack_seq {#1}
+%<latexrelease> \@@_tmp:w
+%<latexrelease> }
+%<latexrelease>\exp_after:wN \@@_tmp:w \@currnamestack
+%<latexrelease> \q_recursion_tail \q_recursion_tail
+%<latexrelease> \q_recursion_tail \q_recursion_stop
+% \end{macrocode}
+% and finalle set the default label to be the \cs{@currname}:
+% \begin{macrocode}
+%<latexrelease>\tl_gset:Nx \g_@@_hook_curr_name_tl { \@currname }
+% \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:
+% \cs{@@_curr_name_push:n} pushes the current default label to the
+% stack, and sets the new default label in one go:
% \begin{macrocode}
\cs_new_protected:Npn \@@_curr_name_push:n #1
+ { \exp_args:Nx \@@_curr_name_push_aux:n { \@@_make_name:n {#1} } }
+\cs_new_protected:Npn \@@_curr_name_push_aux:n #1
{
- \seq_gpush:Nn \g_@@_name_stack_seq {#1}
- \tl_gset:Nn \g_@@_hook_curr_name_tl {#1}
+ \tl_if_blank:nTF {#1}
+ { \msg_error:nn { hooks } { no-default-label } }
+ {
+ \str_if_eq:nnTF {#1} { top-level }
+ {
+ \msg_error:nnnnn { hooks } { set-top-level }
+ { to } { PushDefaultHookLabel } {#1}
+ }
+ {
+ \seq_gpush:NV \g_@@_name_stack_seq \g_@@_hook_curr_name_tl
+ \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}
@@ -3919,12 +4213,27 @@
% \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
+ \seq_gpop:NNTF \g_@@_name_stack_seq \l_@@_return_tl
{ \tl_gset_eq:NN \g_@@_hook_curr_name_tl \l_@@_return_tl }
+ { \msg_error:nn { hooks } { extra-pop-label } }
+ }
+% \end{macrocode}
+%
+% At the end of the document we want to check if there was no
+% \cs{@@_curr_name_push:} without a matching \cs{@@_curr_name_pop:}
+% (not a critical error, but it might indicate that something else is
+% not quite right):
+% \begin{macrocode}
+\tl_gput_right:Nn \@kernel@after@enddocument@afterlastpage
+ { \@@_end_document_label_check: }
+\cs_new_protected:Npn \@@_end_document_label_check:
+ {
+ \seq_gpop:NNT \g_@@_name_stack_seq \l_@@_return_tl
{
- \msg_error:nnn { hooks } { should-not-happen }
- { Tried~to~pop~from~an~empty~default~label~stack. }
+ \msg_error:nnx { hooks } { missing-pop-label }
+ { \g_@@_hook_curr_name_tl }
+ \tl_gset_eq:NN \g_@@_hook_curr_name_tl \l_@@_return_tl
+ \@@_end_document_label_check:
}
}
% \end{macrocode}
@@ -3935,14 +4244,69 @@
% 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 \SetDefaultHookLabel { m }
+ {
+ \seq_if_empty:NTF \g_@@_name_stack_seq
+ {
+ \msg_error:nnnnn { hooks } { set-top-level }
+ { for } { SetDefaultHookLabel } {#1}
+ }
+ { \exp_args:Nx \@@_set_default_label:n { \@@_make_name:n {#1} } }
+ }
+\cs_new_protected:Npn \@@_set_default_label:n #1
+ {
+ \str_if_eq:nnTF {#1} { top-level }
+ {
+ \msg_error:nnnnn { hooks } { set-top-level }
+ { to } { SetDefaultHookLabel } {#1}
+ }
+ { \tl_gset:Nn \g_@@_hook_curr_name_tl {#1} }
+ }
\NewDocumentCommand \DeclareDefaultHookLabel { m }
{
- \seq_gpop:NN \g_@@_name_stack_seq \l_@@_return_tl
- \@@_curr_name_push:n {#1}
+ \msg_error:nn { hooks } { ddhl-deprecated }
+ \SetDefaultHookLabel {#1}
+ }
+% \end{macrocode}
+%
+% The label is only automatically updated with \cs{@onefilewithoptions}
+% (\cs{usepackage} and \cs{documentclass}), but some packages, like
+% Ti\emph{k}Z, define package-like interfaces, like
+% \cs{usetikzlibrary} that are wrappers around \cs{input}, so they
+% inherit the default label currently in force (usually |top-level|,
+% but it may change if loaded in another package). To provide a
+% package-like behaviour also for hooks in these files, we provide
+% high-level access to the default label stack.
+% \begin{macrocode}
+\NewDocumentCommand \PushDefaultHookLabel { m }
+ { \@@_curr_name_push:n {#1} }
+\NewDocumentCommand \PopDefaultHookLabel { }
+ { \@@_curr_name_pop: }
+% \end{macrocode}
+%
+% The current label stack holds the labels for all files but the
+% current one (more or less like \cs{@currnamestack}), and the current
+% label token list, \cs{g_@@_hook_curr_name_tl}, holds the label for
+% the current file. However \cs{@pushfilename} happens before
+% \cs{@currname} is set, so we need to look ahead to get the
+% \cs{@currname} for the label. \pkg{expl3} also requires the current
+% file in \cs{@pushfilename}, so here we abuse
+% \cs{@expl@push@filename@aux@@@@} to do \cs{@@_curr_name_push:n}.
+% \begin{macrocode}
+\cs_gset_protected:Npn \@expl@push@filename@aux@@@@ #1#2#3
+ {
+ \@@_curr_name_push:n {#3}
+ \str_gset:Nx \g_file_curr_name_str {#3}
+ #1 #2 {#3}
}
% \end{macrocode}
% \end{macro}
% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
%
%
%
@@ -4029,20 +4393,14 @@
% \end{macrocode}
%
% \begin{macro}{\@expl@@@initialize@all@@,
-% \@expl@@@hook@curr@name@push@@n,
% \@expl@@@hook@curr@name@pop@@}
-%
+%
% \begin{macrocode}
\cs_new_eq:NN \@expl@@@initialize@all@@
\__hook_initialize_all:
% \end{macrocode}
%
% \begin{macrocode}
-\cs_new_eq:NN \@expl@@@hook@curr@name@push@@n
- \__hook_curr_name_push:n
-% \end{macrocode}
-%
-% \begin{macrocode}
\cs_new_eq:NN \@expl@@@hook@curr@name@pop@@
\__hook_curr_name_pop:
% \end{macrocode}
diff --git a/Master/texmf-dist/source/latex/base/ltmath.dtx b/Master/texmf-dist/source/latex/base/ltmath.dtx
index 36b8bb7ec46..770367c8a30 100644
--- a/Master/texmf-dist/source/latex/base/ltmath.dtx
+++ b/Master/texmf-dist/source/latex/base/ltmath.dtx
@@ -38,7 +38,7 @@
%<*driver>
% \fi
\ProvidesFile{ltmath.dtx}
- [2020/07/27 v1.2g LaTeX Kernel (Math Setup)]
+ [2020/11/09 v1.2h LaTeX Kernel (Math Setup)]
% \iffalse
%</driver>
%
@@ -593,6 +593,13 @@
%<latexrelease>\def\;{\mskip\thickmuskip}
%<latexrelease>\def\!{\mskip-\thinmuskip}
%<latexrelease>
+% \end{macrocode}
+% \changes{v1.2h}{2020/11/09}{\cs{negmedspace} and \cs{negthickspace}
+% have been only in amsmath, so we need to undefine for rollback (gh/423)}
+% \begin{macrocode}
+%<latexrelease>\let\negmedspace\@undefined
+%<latexrelease>\let\negthickspace\@undefined
+%<latexrelease>
%<latexrelease>\EndIncludeInRelease
%<*2ekernel>
% \end{macrocode}
diff --git a/Master/texmf-dist/source/latex/base/ltmiscen.dtx b/Master/texmf-dist/source/latex/base/ltmiscen.dtx
index 9acbcccd683..cf7f3c836be 100644
--- a/Master/texmf-dist/source/latex/base/ltmiscen.dtx
+++ b/Master/texmf-dist/source/latex/base/ltmiscen.dtx
@@ -32,7 +32,7 @@
%<*driver>
% \fi
\ProvidesFile{ltmiscen.dtx}
- [2020/10/23 v1.1w LaTeX Kernel (Misc. Environments)]
+ [2020/12/18 v1.1x LaTeX Kernel (Misc. Environments)]
% \iffalse
\documentclass{ltxdoc}
\GetFileInfo{ltmiscen.dtx}
@@ -277,17 +277,6 @@
% \end{macro}
% \end{environment}
%
-%
-% \begin{macro}{\@kernel@after@enddocument,
-% \@kernel@after@enddocument@afterlastpage}
-%
-% 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}
@@ -395,8 +384,6 @@
%<latexrelease> \endgroup
%<latexrelease> \deadcycles\z@\@@end}
%<latexrelease>
-%<latexrelease>\let\@kernel@after@enddocument\@undefined
-%<latexrelease>\let\@kernel@after@enddocument@afterlastpage\@undefined
%<latexrelease>\let\@enddocument@kernel@warnings\@undefined
%<latexrelease>
%<latexrelease>\EndIncludeInRelease
diff --git a/Master/texmf-dist/source/latex/base/ltshipout.dtx b/Master/texmf-dist/source/latex/base/ltshipout.dtx
index 8f0422c887b..e226f753f35 100644
--- a/Master/texmf-dist/source/latex/base/ltshipout.dtx
+++ b/Master/texmf-dist/source/latex/base/ltshipout.dtx
@@ -31,8 +31,8 @@
%%% From File: ltshipout.dtx
%
% \begin{macrocode}
-\providecommand\ltshipoutversion{v1.0c}
-\providecommand\ltshipoutdate{2020/09/27}
+\providecommand\ltshipoutversion{v1.0d}
+\providecommand\ltshipoutdate{2020/11/24}
% \end{macrocode}
%
%<*driver>
@@ -1376,9 +1376,11 @@
%
%
% \begin{macro}{\AtBeginDvi}
-%
+% If we roll forward from an earlier kernel \cs{AtBeginDvi} is
+% defined so we better not use \cs{cs_new_protected:Npn} here.
+% \changes{v1.0d}{2020/11/24}{Support for roll forward (gh/434)}
% \begin{macrocode}
-\cs_new_protected:Npn \AtBeginDvi {\@@_add_firstpage_material:Nn \AtBeginDvi}
+\cs_set_protected:Npn \AtBeginDvi {\@@_add_firstpage_material:Nn \AtBeginDvi}
% \end{macrocode}
% \end{macro}
%
@@ -1448,7 +1450,17 @@
% \begin{macrocode}
%<latexrelease>\IncludeInRelease{0000/00/00}%
%<latexrelease> {\shipout}{The hook management (shipout)}%
-%<latexrelease>\expandafter\let\expandafter\shipout\csname tex_shipout:D\endcsname
+%<latexrelease>
+% \end{macrocode}
+% If we roll forward then \cs{tex\_shipout:D} may not be defined in
+% which case \cs{shipout} does have it original definition and so
+% we must not \cs{let} it to something else which is \cs{relax}!
+% \changes{v1.0d}{2020/11/24}{Support for roll forward (gh/434)}
+% \begin{macrocode}
+%<latexrelease>\ifcsname tex_shipout:D\endcsname
+%<latexrelease>\expandafter\let\expandafter\shipout
+%<latexrelease> \csname tex_shipout:D\endcsname
+%<latexrelease>\fi
%<latexrelease>
%<latexrelease>\let \ShipoutBox\@undefined
%<latexrelease>\let \ReadonlyShipoutCounter \@undefined
diff --git a/Master/texmf-dist/source/latex/base/ltvers.dtx b/Master/texmf-dist/source/latex/base/ltvers.dtx
index dd69d5a6e35..c2ec2ffde33 100644
--- a/Master/texmf-dist/source/latex/base/ltvers.dtx
+++ b/Master/texmf-dist/source/latex/base/ltvers.dtx
@@ -115,7 +115,7 @@
{2020-10-01}
%</2ekernel|latexrelease>
%<*2ekernel>
-\def\patch@level{2}
+\def\patch@level{3}
% \end{macrocode}
%
% \begin{macro}{\development@branch@name}