From e80240b5e5bfb83d84a9e6d81e31b0bfb82d637c Mon Sep 17 00:00:00 2001 From: Karl Berry Date: Fri, 12 Nov 2021 23:08:46 +0000 Subject: 2e (12nov21) git-svn-id: svn://tug.org/texlive/trunk@61041 c570f23f-e606-0410-a88d-b1316a301751 --- Master/texmf-dist/source/latex/base/classes.dtx | 28 +- Master/texmf-dist/source/latex/base/doc.dtx | 11 +- Master/texmf-dist/source/latex/base/ltboxes.dtx | 25 +- Master/texmf-dist/source/latex/base/ltclass.dtx | 159 +- Master/texmf-dist/source/latex/base/ltcmd.dtx | 1015 +++++++++-- Master/texmf-dist/source/latex/base/ltcmdhooks.dtx | 456 ++++- Master/texmf-dist/source/latex/base/ltcounts.dtx | 132 +- Master/texmf-dist/source/latex/base/ltdefns.dtx | 4 +- Master/texmf-dist/source/latex/base/lterror.dtx | 111 +- Master/texmf-dist/source/latex/base/ltexpl.dtx | 2 +- Master/texmf-dist/source/latex/base/ltfilehook.dtx | 164 +- Master/texmf-dist/source/latex/base/ltfiles.dtx | 38 +- Master/texmf-dist/source/latex/base/ltfinal.dtx | 41 +- Master/texmf-dist/source/latex/base/ltfloat.dtx | 27 +- Master/texmf-dist/source/latex/base/ltfntcmd.dtx | 5 +- Master/texmf-dist/source/latex/base/ltfssbas.dtx | 5 +- Master/texmf-dist/source/latex/base/ltfssdcl.dtx | 255 ++- Master/texmf-dist/source/latex/base/ltfssini.dtx | 383 +++- Master/texmf-dist/source/latex/base/ltfsstrc.dtx | 2 +- Master/texmf-dist/source/latex/base/lthooks.dtx | 1915 ++++++++++++-------- Master/texmf-dist/source/latex/base/ltluatex.dtx | 6 +- Master/texmf-dist/source/latex/base/ltmath.dtx | 8 +- Master/texmf-dist/source/latex/base/ltmiscen.dtx | 5 +- Master/texmf-dist/source/latex/base/ltoutenc.dtx | 15 +- Master/texmf-dist/source/latex/base/ltoutput.dtx | 78 +- Master/texmf-dist/source/latex/base/ltpara.dtx | 253 ++- Master/texmf-dist/source/latex/base/ltplain.dtx | 20 +- Master/texmf-dist/source/latex/base/ltsect.dtx | 42 +- Master/texmf-dist/source/latex/base/ltshipout.dtx | 18 +- Master/texmf-dist/source/latex/base/ltvers.dtx | 16 +- Master/texmf-dist/source/latex/base/makeindx.dtx | 4 +- Master/texmf-dist/source/latex/base/preload.dtx | 4 +- Master/texmf-dist/source/latex/base/slides.dtx | 8 +- Master/texmf-dist/source/latex/base/tulm.fdd | 9 +- Master/texmf-dist/source/latex/base/utf8ienc.dtx | 36 +- 35 files changed, 3913 insertions(+), 1387 deletions(-) (limited to 'Master/texmf-dist/source/latex/base') diff --git a/Master/texmf-dist/source/latex/base/classes.dtx b/Master/texmf-dist/source/latex/base/classes.dtx index ffe04c620fa..a13053b871a 100644 --- a/Master/texmf-dist/source/latex/base/classes.dtx +++ b/Master/texmf-dist/source/latex/base/classes.dtx @@ -53,7 +53,7 @@ %<*driver> \ProvidesFile{classes.drv} % - [2021/02/12 v1.4n + [2021/10/04 v1.4n % Standard LaTeX document class] %<10pt|11pt|12pt> Standard LaTeX file (size option)] % \end{macrocode} @@ -221,9 +221,9 @@ % file has version number \fileversion, last revised \filedate.}} % % \author{% -% Copyright (C) 1992 by Leslie Lamport and -% Copyright (C) 1994-2020 by Frank Mittelbach and Johannes Braams and -% LaTeX Project Team +% Copyright (C) 1992 by Leslie Lamport \and +% Copyright (C) 1994-2021 by Frank Mittelbach, \and Johannes Braams and +% the \LaTeX\ Project Team % } % \date{\filedate} % \MaintainedByLaTeXTeam{latex} @@ -1622,7 +1622,7 @@ % \label{sec:classes:pagestyle} % % The pagestyles \pstyle{empty} and \pstyle{plain} are defined in -% \file{latex.dtx}. +% the \LaTeX{} format. % % \begin{macro}{\ps@headings} % The definition of the page style \pstyle{headings} has to be @@ -1771,7 +1771,7 @@ % \begin{macro}{\title} % \begin{macro}{\author} % \begin{macro}{\date} -% These three macros are provided by \file{latex.dtx} to provide +% These three macros are provided by the \LaTeX{} format to provide % information about the title, author(s) and date of the document. % The information is stored away in internal control sequences. % It is the task of the |\maketitle| command to use the @@ -2056,7 +2056,7 @@ % Default initializations of |\...mark| commands. These commands % are used in the definition of the page styles (see % section~\ref{sec:classes:pagestyle}) Most of them are already defined by -% \file{latex.dtx}, so they are only shown here. +% the \LaTeX{} format, so they are only shown here. % % \begin{macrocode} %\newcommand*\chaptermark[1]{} @@ -2891,7 +2891,7 @@ % \begin{macro}{\theenumii} % \begin{macro}{\theenumiii} % \begin{macro}{\theenumiv} -% The counters are already defined in \file{latex.dtx}, but their +% The counters are already defined in the \LaTeX{} format, but their % representation is changed here. % % \begin{macrocode} @@ -2990,7 +2990,7 @@ % % \begin{environment}{description} % The description environment is defined here -- while the itemize -% and enumerate environments are defined in \file{latex.dtx}. +% and enumerate environments are defined in the \LaTeX{} format. % % \begin{macrocode} \newenvironment{description} @@ -3123,7 +3123,7 @@ % \subsubsection{Theorem} % % This document class does not define it's own theorem environments, -% the defaults, supplied by \file{latex.dtx} are available. +% the defaults, supplied by the \LaTeX{} format are available. % % \subsubsection{Titlepage} % @@ -3365,7 +3365,7 @@ % % \subsection{Floating objects} % -% The file \file{latex.dtx} only defines a number of tools with +% The \LaTeX{} format only defines a number of tools with % which floating objects can be defined. This is done in the % document class. It needs to define the following macros for each % floating object of type \texttt{TYPE} (e.g., \texttt{TYPE} = @@ -3402,7 +3402,7 @@ % % The actual environment that implements a floating object such as % a figure is defined using the macros |\@float| and |\end@float|, -% which are defined in \file{latex.dtx}. +% which are defined in the \LaTeX{} format. % % An environment that implements a single-column floating object is % started with |\@float{|\texttt{TYPE}|}[|\meta{placement}|]| of type @@ -4194,7 +4194,7 @@ % % \begin{macro}{\@biblabel} % The label for a |\bibitem[...]| command is produced by this -% macro. The default from \file{latex.dtx} is used. +% macro. The default from the \LaTeX{} format is used. % \begin{macrocode} % \renewcommand*{\@biblabel}[1]{[#1]\hfill} % \end{macrocode} @@ -4202,7 +4202,7 @@ % % \begin{macro}{\@cite} % The output of the |\cite| command is produced by this macro. The -% default from \file{latex.dtx} is used. +% default from the \LaTeX{} format is used. % \begin{macrocode} % \renewcommand*{\@cite}[1]{[#1]} % \end{macrocode} diff --git a/Master/texmf-dist/source/latex/base/doc.dtx b/Master/texmf-dist/source/latex/base/doc.dtx index fb3412f21f4..41bc0733155 100644 --- a/Master/texmf-dist/source/latex/base/doc.dtx +++ b/Master/texmf-dist/source/latex/base/doc.dtx @@ -35,7 +35,7 @@ %<+package|shortvrb>\NeedsTeXFormat{LaTeX2e}[1994/12/01] %<+package> \ProvidesPackage{doc} %<+shortvrb>\ProvidesPackage{shortvrb} -%<+package|shortvrb> [2021/05/28 v2.1n +%<+package|shortvrb> [2021/10/04 v2.1n %<+package|shortvrb> Standard LaTeX documentation package (FMi)] %\catcode`\<=12 % @@ -885,7 +885,7 @@ % We provide macros for logos such as \Web, \AmSTeX, \BibTeX, % \SliTeX{} and \PlainTeX. Just type |\Web|, |\AmSTeX|, % |\BibTeX|, |\SliTeX| or |\PlainTeX|, respectively. -% \LaTeX{} and \TeX{} are already defined in \texttt{latex.tex}. +% \LaTeX{} and \TeX{} are already defined in the \LaTeX{} format. % % \DescribeMacro\meta % Another useful macro is |\meta| which has one argument and @@ -938,7 +938,8 @@ % argument and produces a verbatim listing of the file, indexing every % command as it goes along. This might be handy, if you want to learn % something about macros without enough documentation. I used this -% feature to cross-reference \texttt{latex.tex} getting a verbatim +% feature to cross-reference \texttt{latex.tex} (these days +% called \texttt{latex.ltx}) getting a verbatim % copy with about 15 pages index.\footnote{It took quite a long time % and the resulting \texttt{.idx} file was longer than the % \texttt{.dvi} file. Actually too long to be handled by the @@ -2031,7 +2032,7 @@ % \begin{macro}{\@verbatim} % Additionally we redefine the |\@verbatim| macro so that it % suppresses |%| characters at the beginning of the line. The -% first lines are copied literally from \texttt{latex.tex}. +% first lines are copied literally from the \LaTeX{} format. % \changes{v1.7i}{1992/07/12}{Added \cs{@@par} to clear possible % \cs{parshape}.} % \begin{macrocode} @@ -2055,7 +2056,7 @@ % \begin{macrocode} \check@percent}% % \end{macrocode} -% The rest is again copied literally from \texttt{latex.tex} (less +% The rest is again copied literally from the \LaTeX{} format (less % "\tt"). % \changes{v1.7a}{1992/02/26}{Removed redundant \cs{tt}.} % \changes{v1.8b}{1993/09/21}{Changed to conform to new LaTeX verbatim, diff --git a/Master/texmf-dist/source/latex/base/ltboxes.dtx b/Master/texmf-dist/source/latex/base/ltboxes.dtx index 8499d3ab8b9..92d9228a8af 100644 --- a/Master/texmf-dist/source/latex/base/ltboxes.dtx +++ b/Master/texmf-dist/source/latex/base/ltboxes.dtx @@ -33,7 +33,7 @@ %<*driver> % \fi \ProvidesFile{ltboxes.dtx} - [2021/02/10 v1.4b LaTeX Kernel (Box Commands)] + [2021/10/14 v1.4c LaTeX Kernel (Box Commands)] % \iffalse \documentclass{ltxdoc} \GetFileInfo{ltboxes.dtx} @@ -1137,10 +1137,12 @@ % {Color groups restored here.} % \changes{v1.4b}{2021/02/10} % {Explicitly run \cs{par} in support for paragraph tagging} +% \changes{v1.4c}{2021/10/14} +% {Explicitly set \cs{@currentcounter} (gh/687)} % \begin{macrocode} % %<*2ekernel|latexrelease> -%\IncludeInRelease{2021/06/01}% +%\IncludeInRelease{2021/11/15}% % {\@mpfootnotetext}{footnotetext tagging}% \long\def\@mpfootnotetext#1{% \global\setbox\@mpfootins\vbox{% @@ -1148,6 +1150,7 @@ \reset@font\footnotesize \hsize\columnwidth \@parboxrestore + \def\@currentcounter{mpfootnote}% \protected@edef\@currentlabel {\csname p@mpfootnote\endcsname\@thefnmark}% \color@begingroup @@ -1158,6 +1161,24 @@ % %\EndIncludeInRelease % \end{macrocode} +% \begin{macrocode} +%\IncludeInRelease{2021/06/01}% +% {\@mpfootnotetext}{footnotetext tagging}% +%\long\def\@mpfootnotetext#1{% +% \global\setbox\@mpfootins\vbox{% +% \unvbox\@mpfootins +% \reset@font\footnotesize +% \hsize\columnwidth +% \@parboxrestore +% \protected@edef\@currentlabel +% {\csname p@mpfootnote\endcsname\@thefnmark}% +% \color@begingroup +% \@makefntext{% +% \rule\z@\footnotesep\ignorespaces#1\@finalstrut\strutbox}% +% \par +% \color@endgroup}} +%\EndIncludeInRelease +% \end{macrocode} % % \begin{macrocode} %\IncludeInRelease{0000/00/00}% diff --git a/Master/texmf-dist/source/latex/base/ltclass.dtx b/Master/texmf-dist/source/latex/base/ltclass.dtx index 2ab3081bf74..06e0f437af1 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} - [2021/06/06 v1.4c LaTeX Kernel (Class & Package Interface)] + [2021/08/25 v1.4f LaTeX Kernel (Class & Package Interface)] % \iffalse \documentclass{ltxdoc} \GetFileInfo{ltclass.dtx} @@ -68,6 +68,7 @@ % \changes{v1.0z}{1998/03/21}{Added to documentation of filecontents} % \changes{v1.1c}{1998/08/17}{(RmS) Minor documentation fixes.} % \changes{v1.3o}{2020/08/21}{Integration of new hook management interface} +% \changes{v1.4f}{2021/08/25}{Standardise generic hook names (gh/648)} % % % \section{Introduction} @@ -311,27 +312,49 @@ % default option handler, which is not used for |landscape| as that % option is explicitly declared. % +% \DescribeMacro\IfPackageLoadedTF +% \DescribeMacro\IfClassLoadedTF % \DescribeMacro\@ifpackageloaded -% To find out if a package has already been loaded, use\\ % \DescribeMacro\@ifclassloaded -% |\@ifpackageloaded{|\meta{package}|}{|\meta{true}|}{|\meta{false}|}|. -% +% To find out if a package has already been loaded, use +% \begin{quote} +% |\IfPackageLoadedTF{|\meta{package}|}{|\meta{true}|}{|\meta{false}|}|\\ +% \end{quote} +% or the old name \cs{@ifpackageloaded}. +% +% \DescribeMacro\IfPackageAtLeastTF +% \DescribeMacro\IfClassAtLeastTF % \DescribeMacro\@ifpackagelater +% \DescribeMacro\@ifclasslater % \changes{v1.1i}{2013/07/07}{Correctly describe how the date in % \cs{@ifpackagelater} is used} % To find out if a package has already been loaded with a version % equal to or more -% recent than \meta{version}, use\\ -% \DescribeMacro\@ifclasslater -% |\@ifpackagelater{|\meta{package}|}{|\meta{version}|}{|^^A -% \meta{true}|}{|\meta{false}|}|. -% +% recent than \meta{date}, use +% \begin{quote} +% |\IfPackageAtLeastTF{|\meta{package}|}{|\meta{date}|}{|^^A +% \meta{true}|}{|\meta{false}|}| +% \end{quote} +% or the old name \cs{@ifpackagelater}. + +% \DescribeMacro\IfFormatAtLeastTF +% To test the format date use +% \begin{quote} +% |\IfFormatAtLeastTF{|\meta{date}|}{|^^A +% \meta{true}|}{|\meta{false}|}| +% \end{quote} +% +% \DescribeMacro\IfPackageLoadedWithOptionsTF +% \DescribeMacro\IfClassLoadedWithOptionsTF % \DescribeMacro\@ifpackagewith +% \DescribeMacro\@ifclasswith % To find out if a package has already been loaded with at least the % options \meta{options}, use -% \DescribeMacro\@ifclasswith -% |\@ifpackagewith{|\meta{package}|}{|\meta{options}|}{|^^A -% \meta{true}|}{|\meta{false}|}|. +% \begin{quote} +% |\IfPackageLoadedWithOptionsTF{|\meta{package}|}{|\meta{options}|}{|^^A +% \meta{true}|}{|\meta{false}|}| +% \end{quote} +% or the old name \cs{@ifpackagewith}. % % There exists one package that can't be tested with the above % commands: the \texttt{fontenc} package pretends that it was never @@ -499,9 +522,10 @@ % \begin{macro}{\@classoptionslist} % List of options of the main class. % \changes{v1.0u}{1996/07/26}{made only preamble} +% \changes{v1.4e}{2021/07/19}{Drop \cs{@onlypreamble}} % \begin{macrocode} \let\@classoptionslist\relax -\@onlypreamble\@classoptionslist +%\@onlypreamble\@classoptionslist % \end{macrocode} % \end{macro} % @@ -517,9 +541,10 @@ % \changes{v1.0u}{1996/07/26}{made only preamble} % List of options of the main class that haven't been declared or % loaded as class option files. +% \changes{v1.4e}{2021/07/19}{Drop \cs{@onlypreamble}} % \begin{macrocode} \let\@unusedoptionlist\@empty -\@onlypreamble\@unusedoptionlist +%\@onlypreamble\@unusedoptionlist % \end{macrocode} % \end{macro} % @@ -571,11 +596,10 @@ % \begin{macro}{\@clsextension} % \begin{macro}{\@pkgextension} % The two possible values of |\@currext|. +% \changes{v1.4e}{2021/07/19}{Drop \cs{@onlypreamble}} % \begin{macrocode} \def\@clsextension{cls} \def\@pkgextension{sty} -\@onlypreamble\@clsextension -\@onlypreamble\@pkgextension % \end{macrocode} % \end{macro} % \end{macro} @@ -811,10 +835,11 @@ % % \begin{macro}{\@ptionlist} % Returns the option list of the file. +% \changes{v1.4e}{2021/07/19}{Drop \cs{@onlypreamble}} % \begin{macrocode} \def\@ptionlist#1{% \@ifundefined{opt@#1}\@empty{\csname opt@#1\endcsname}} -\@onlypreamble\@ptionlist +%\@onlypreamble\@ptionlist % \end{macrocode} % \end{macro} % @@ -824,11 +849,10 @@ % Checks to see whether a file has been loaded. % \changes{v0.2t}{1994/01/18} % {Fix typo \cs{@pkgetension}} +% \changes{v1.4e}{2021/07/19}{Drop \cs{@onlypreamble}} % \begin{macrocode} \def\@ifpackageloaded{\@ifl@aded\@pkgextension} \def\@ifclassloaded{\@ifl@aded\@clsextension} -\@onlypreamble\@ifpackageloaded -\@onlypreamble\@ifclassloaded % \end{macrocode} % % \begin{macrocode} @@ -838,11 +862,12 @@ \else \expandafter\@firstoftwo \fi} -\@onlypreamble\@ifl@aded % \end{macrocode} % \end{macro} % \end{macro} % +% +% % \begin{macro}{\@ifpackagelater} % \begin{macro}{\@ifclasslater} % |\@ifpackagelater{|\meta{name}|}{YYYY/MM/DD}{|\meta{true @@ -852,17 +877,17 @@ % A better name for it would therefore been % |\@ifpackagelaterorequal| but it is in use for more than 30 % years, so \ldots +% \changes{v1.4e}{2021/07/19}{Drop \cs{@onlypreamble}} % \begin{macrocode} \def\@ifpackagelater{\@ifl@ter\@pkgextension} \def\@ifclasslater{\@ifl@ter\@clsextension} -\@onlypreamble\@ifpackagelater -\@onlypreamble\@ifclasslater % \end{macrocode} % \end{macro} % \end{macro} % % % +% % \begin{macro}{\IfPackageAtLeastTF} % \begin{macro}{\IfClassAtLeastTF} % \begin{macro}{\IfFormatAtLeastTF} @@ -870,6 +895,7 @@ % code}|}{|\meta{false code}|}| % Test if the format is later or equal to the given date. % \changes{v1.3k}{2020/04/07}{Macro added; also in rollback (gh/168)} +% \changes{v1.4e}{2021/07/19}{Drop \cs{@onlypreamble}} % \begin{macrocode} % %<*2ekernel|latexrelease> @@ -878,9 +904,6 @@ \def\IfFormatAtLeastTF{\@ifl@t@r\fmtversion} \let\IfPackageAtLeastTF\@ifpackagelater \let\IfClassAtLeastTF\@ifclasslater -\@onlypreamble\IfFormatAtLeastTF -\@onlypreamble\IfPackageAtLeastTF -\@onlypreamble\IfClassAtLeastTF % \end{macrocode} % For rollback pretend it was available since the beginning of dawn. % \begin{macrocode} @@ -899,11 +922,11 @@ % \end{macro} % % \begin{macro}{\@ifl@ter} +% \changes{v1.4e}{2021/07/19}{Drop \cs{@onlypreamble}} % \begin{macrocode} \def\@ifl@ter#1#2{% \expandafter\@ifl@t@r \csname ver@#2.#1\endcsname} -\@onlypreamble\@ifl@ter % % \end{macrocode} % @@ -942,9 +965,6 @@ %<*2ekernel> % \end{macrocode} % -% \begin{macrocode} -\@onlypreamble\@ifl@t@r -% \end{macrocode} % \end{macro} % % \changes{v1.1j}{2016/06/20} @@ -974,17 +994,15 @@ % |\@ifpackagewith{|\meta{name}|}{|\meta{option-list}|}| % Checks that \meta{option-list} is a subset of the options % \textbf{with} which \meta{name} was loaded. +% \changes{v1.4e}{2021/07/19}{Drop \cs{@onlypreamble}} % \begin{macrocode} \def\@ifpackagewith{\@if@ptions\@pkgextension} \def\@ifclasswith{\@if@ptions\@clsextension} -\@onlypreamble\@ifpackagewith -\@onlypreamble\@ifclasswith % \end{macrocode} % % \begin{macrocode} \def\@if@ptions#1#2{% \@expandtwoargs\@if@pti@ns{\@ptionlist{#2.#1}}} -\@onlypreamble\@if@ptions % \end{macrocode} % % Probably shouldn't use |\CurrentOption| here\ldots (changed to @@ -993,6 +1011,7 @@ % {Add extra ,s so `two' is not matched with `twocolumn'} % \changes{v1.1i}{2011/08/19} % {Re-jig definition after more stringent \cs{in@} test.} +% \changes{v1.4e}{2021/07/19}{Drop \cs{@onlypreamble}} % \begin{macrocode} % %\IncludeInRelease{2017/01/01}% @@ -1038,12 +1057,45 @@ %<*2ekernel> % \end{macrocode} % -% \begin{macrocode} -\@onlypreamble\@if@pti@ns -% \end{macrocode} % \end{macro} % \end{macro} % +% +% +% +% \begin{macro}{\IfPackageLoadedTF,\IfPackageLoadedWithOptionsTF, +% \IfClassLoadedTF,\IfClassLoadedWithOptionsTF} +% More public names for the commands already available for a long time. +% \begin{macrocode} +% +%<*2ekernel|latexrelease> +%\IncludeInRelease{2021/11/15}% +% {\IfPackageLoadedtTF}{Test package loading}% +\let \IfPackageLoadedTF \@ifpackageloaded +\let \IfClassLoadedTF \@ifclassloaded +\let \IfPackageLoadedWithOptionsTF \@ifpackagewith +\let \IfClassLoadedWithOptionsTF \@ifclasswith +% \end{macrocode} +% For rollback pretend it was available since the beginning of dawn. +% \begin{macrocode} +% +%\EndIncludeInRelease +%\IncludeInRelease{0000/00/00}% +% {\IfPackageLoadedtTF}{Test package loading}% +% +%\let \IfPackageLoadedTF \@ifpackageloaded +%\let \IfClassLoadedTF \@ifclassloaded +%\let \IfPackageLoadedWithOptionsTF \@ifpackagewith +%\let \IfClassLoadedWithOptionsTF \@ifclasswith +% +%\EndIncludeInRelease +%<*2ekernel> +% \end{macrocode} +% \end{macro} +% +% +% +% % \begin{macro}{\ProvidesPackage} % Checks that the current filename is correct, and defines % |\ver@filename|. @@ -1979,8 +2031,9 @@ \ifx\@nnil##1\@nnil\else % \end{macrocode} % +% \changes{v1.4d}{2021/07/12}{add \cs{unexpanded}} % \begin{macrocode} - \noexpand\@onefilewithoptions##1[{#2}][{#4}]% + \noexpand\@onefilewithoptions##1[{\unexpanded{#2}}][{#4}]% \noexpand\@pkgextension \fi \expandafter\reserved@b @@ -2289,7 +2342,7 @@ % \changes{v1.3u}{2020/11/20} % {Copy option list to the requested package.} % \changes{v1.4c}{2021/06/06} -% {Copy raw raw options for gh/580} +% {Copy raw options for gh/580} % \begin{macrocode} \expandafter\let \csname opt@\@currpkg@reqd\expandafter\endcsname @@ -2309,15 +2362,17 @@ % package otherwise, if it is \cs{@clsextension}, a class, so % depending on that we execute different hooks. If the extension is % neither, then it is another type of file without special hooks. +% \changes{v1.4e}{2021/07/23}{Make class/name/before a one-time hook} +% \changes{v1.4e}{2021/07/23}{Make package/name/before a one-time hook} % \begin{macrocode} %----------------------------------------- \ifx\@currext\@pkgextension \UseHook{package/before}% - \UseHook{package/before/\@currname}% + \UseOneTimeHook{package/\@currname/before}% \else \ifx\@currext\@clsextension \UseHook{class/before}% - \UseHook{class/before/\@currname}% + \UseOneTimeHook{class/\@currname/before}% \fi \fi % \end{macrocode} @@ -2376,27 +2431,35 @@ % \end{macrocode} % And same procedure, James, when we are finished loading, except % that the hook order is now reversed. +% \changes{v1.4e}{2021/07/23}{Make class/name/after a one-time hook} +% \changes{v1.4e}{2021/07/23}{Make package/name/after a one-time hook} % \begin{macrocode} %----------------------------------------- \ifx\@currext\@pkgextension - \UseHook{package/after/\@currname}% + \UseOneTimeHook{package/\@currname/after}% \UseHook{package/after}% \else \ifx\@currext\@clsextension - \UseHook{class/after/\@currname}% + \UseOneTimeHook{class/\@currname/after}% \UseHook{class/after}% \fi \fi}% %----------------------------------------- \@ifl@aded\@currext\@currname{}{\reserved@a}} % \end{macrocode} -% \end{macro} -% +% +% \changes{v1.4f}{2021/08/25}{Declare non-generic package and class hooks} +% Now declare the non-generic package and class hooks used above: % \begin{macrocode} -% +\NewHook{package/before} +\NewHook{class/before} +\NewReversedHook{package/after} +\NewReversedHook{class/after} % \end{macrocode} -% +% \end{macro} +% % \begin{macrocode} +% %\EndIncludeInRelease %\IncludeInRelease{0000/00/00}% % {\@onefilewithoptions}{Hooks and unused options issue}% @@ -2771,11 +2834,12 @@ % \end{macrocode} % % Lua\TeX\ has more writes (and 18 is safe here). +% \changes{v1.4b}{2021/06/09}{Use \cs{@latex@note@no@line} to display the information} % \begin{macrocode} \chardef\reserved@c\ifx\directlua\@undefined 15 \else 127 \fi% \openin\@inputcheck\q@curr@file \space % \ifeof\@inputcheck% - \@latex@warning@no@line% + \@latex@note@no@line% {Writing file `\@currdir\@curr@file'}% % \end{macrocode} % @@ -2789,9 +2853,10 @@ % % \changes{v1.0y}{1997/10/10} % {Use \cs{@gobbletwo}} +% \changes{v1.4b}{2021/06/09}{Use \cs{@latex@note@no@line} to display the information} % \begin{macrocode} \if@filesw% - \@latex@warning@no@line% + \@latex@note@no@line% {File `\@curr@file' already \filec@ntents@where.\MessageBreak% Not generating it from this source}% \let\write\@gobbletwo% diff --git a/Master/texmf-dist/source/latex/base/ltcmd.dtx b/Master/texmf-dist/source/latex/base/ltcmd.dtx index 806161d5386..04be2abfbfd 100644 --- a/Master/texmf-dist/source/latex/base/ltcmd.dtx +++ b/Master/texmf-dist/source/latex/base/ltcmd.dtx @@ -34,8 +34,8 @@ %%% From File: ltcmd.dtx % % \begin{macrocode} -\def\ltcmdversion{v1.0e} -\def\ltcmddate{2021-05-24} +\def\ltcmdversion{v1.0h} +\def\ltcmddate{2021-08-30} % \end{macrocode} % %<*driver> @@ -343,8 +343,7 @@ % % \begin{macro}{\@@_declare_cmd:Nnn, \@@_declare_expandable_cmd:Nnn} % \begin{macro}{\@@_declare_cmd_aux:Nnn} -% \begin{macro} -% {\@@_declare_cmd_internal:Nnnn, \@@_declare_cmd_internal:cnxn} +% \begin{macro}{\@@_declare_cmd_internal:Nnnn} % The main functions for creating commands set the appropriate flag then % use the same internal code to do the definition. % \begin{macrocode} @@ -366,7 +365,7 @@ { \cs_if_exist:NTF #1 { - \msg_info:nnxx { cmd } { redefine-command } + \msg_info:nnxx { cmd } { redefine } { \token_to_str:N #1 } { \tl_to_str:n {#2} } } { @@ -400,7 +399,6 @@ #4 \@@_break_point:n {#2} } -\cs_generate_variant:Nn \@@_declare_cmd_internal:Nnnn { cnx } % \end{macrocode} % \end{macro} % \end{macro} @@ -536,11 +534,11 @@ { \tl_trim_spaces:o { \l_@@_environment_str } } \cs_if_exist:cTF { \l_@@_environment_str } { - \msg_info:nnxx { cmd } { redefine-environment } + \msg_info:nnxx { cmd } { redefine-env } { \l_@@_environment_str } { \tl_to_str:n {#2} } } { - \msg_info:nnxx { cmd } { define-environment } + \msg_info:nnxx { cmd } { define-env } { \l_@@_environment_str } { \tl_to_str:n {#2} } } \bool_set_false:N \l_@@_expandable_bool @@ -565,15 +563,8 @@ % \begin{macrocode} \cs_new_protected:Npn \@@_declare_env_internal:nnnn #1#2#3#4 { - \@@_declare_cmd_internal:cnxn { environment~ #1 } {#2} - { - \cs_set_nopar:Npx \exp_not:c { environment~ #1 ~end~aux } - { - \exp_not:N \exp_not:N \exp_not:c { environment~ #1~end~aux~ } - \exp_not:n { \exp_not:o \l_@@_args_tl } - } - \exp_not:n {#3} - } + \exp_args:Nc \@@_declare_cmd_internal:Nnnn { environment~ #1 } {#2} + {#3} { \cs_set_nopar:cpx { environment~ #1 ~end } { \exp_not:c { environment~ #1 ~end~aux } } @@ -584,6 +575,14 @@ \cs_set_eq:cc { end #1 } { environment~ #1 ~end } } } +\cs_new_protected:Npn \@@_set_environment_end:n #1 + { + \cs_set_nopar:cpx { environment~ #1 ~end~aux } + { + \exp_not:c { environment~ #1 ~end~aux~ } + \exp_not:o \l_@@_args_tl + } + } % \end{macrocode} % \end{macro} % \end{macro} @@ -639,7 +638,10 @@ \tl_set:Nn \l_@@_fn_code_tl {#2} \tl_set:Nn \l_@@_defaults_tl {#5} \tl_set:Nn \l_@@_process_all_tl {#6} - #4 \@@_run_code: + #4 + \bool_if:NT \l_@@_environment_bool + { \exp_args:No \@@_set_environment_end:n \l_@@_environment_str } + \@@_run_code: } \cs_generate_variant:Nn \@@_start_aux:NNnnnn { cc } % \end{macrocode} @@ -693,7 +695,7 @@ } \cs_new_protected:Npn \@@_defaults_error:w \q_recursion_stop { - \msg_error:nnx { cmd } { loop-in-defaults } + \msg_error:nnx { cmd } { default-loop } { \@@_environment_or_command: } } % \end{macrocode} @@ -821,7 +823,7 @@ \@@_end_expandable_defaults:nnnNNn {#1} { } {#1} #2#3 { } { } { } { } { } { } { } { } { } { } { - \msg_expandable_error:nnf { cmd } { loop-in-defaults } + \msg_expandable_error:nnf { cmd } { default-loop } { \exp_args:Nf \tl_trim_spaces:n { \token_to_str:N #4 } } \use_iv:nnnn } @@ -919,7 +921,7 @@ \q_recursion_tail \q_recursion_tail \q_recursion_tail \q_recursion_stop \int_compare:nNnT \l_@@_current_arg_int > 9 { - \msg_error:nnxx { cmd } { too-many-arguments } + \msg_error:nnxx { cmd } { too-many-args } { \@@_environment_or_command: } { \tl_to_str:n {#1} } \@@_bad_def:wn } @@ -951,7 +953,7 @@ { \str_if_eq_p:nn {#1} { u } } } { - \msg_error:nnxx { cmd } { xparse-argument-type } + \msg_error:nnxx { cmd } { xparse-arg-type } { \@@_environment_or_command: } { \tl_to_str:n {#1} } } { @@ -1241,7 +1243,7 @@ { \use_none:n } } { - \msg_error:nnxxx { cmd } { forbidden-implicit-group-token } + \msg_error:nnxxx { cmd } { forbidden-group-token } { \@@_environment_or_command: } { \tl_to_str:n {#1} } { \token_if_eq_meaning:NNTF #1 \c_group_begin_token @@ -1261,7 +1263,7 @@ { \bool_if:NT \l_@@_expandable_bool { - \msg_error:nnxx { cmd } { invalid-expandable-argument-type } + \msg_error:nnxx { cmd } { invalid-expandable-arg } { \iow_char:N \\ \l_@@_function_tl } { \tl_to_str:n {#1} } \@@_bad_def:wn } @@ -1334,7 +1336,7 @@ { \bool_if:NT \l_@@_expandable_bool { - \msg_error:nnx { cmd } { inconsistent-long } + \msg_error:nnx { cmd } { long-short-mix } { \iow_char:N \\ \l_@@_function_tl } \@@_bad_def:wn } @@ -1356,7 +1358,7 @@ { \bool_if:NT \l_@@_some_obey_spaces_bool { - \msg_error:nnxx { cmd } { non-trailing-obey-spaces } + \msg_error:nnxx { cmd } { invalid-bang } { \@@_environment_or_command: } { \tl_to_str:n {#1} } \@@_bad_def:wn } @@ -1505,12 +1507,21 @@ % % \begin{macro}{\@@_add_type_E:w} % The \texttt{E}-type argument needs a special handling of default -% values. +% values. Since each embellishment is a separate argument, it +% also needs to replicate the argument processors for each embellishment +% argument so that the numbers of arguments and processors remain in sync. +% \changes{v1.0g}{2021/08/07} +% {Replicate argument processors for all embellishments (gh/639)} % \begin{macrocode} \cs_new_protected:Npn \@@_add_type_E:w #1#2 { \@@_flush_m_args: \@@_add_default_E:nn {#1} {#2} + \use:x + { + \@@_replicate_processor:nn { \tl_count:n {#1} } + { \exp_not:o \l_@@_process_one_tl } + } \@@_add_grabber:N E \tl_put_right:Nn \l_@@_signature_tl { {#1} } \@@_prepare_signature:N @@ -1518,6 +1529,48 @@ % \end{macrocode} % \end{macro} % +% \begin{macro}{\@@_replicate_processor:nn} +% In the command's argument processor signature (the final argument of +% \cs{@@_start:nNNnnn}) there is one braced item for each formal +% argument (up to nine), and in each of these items there is one +% braced item for each processor (as many as there were processors +% declared for a given argument). Something like this: +% \begin{quote} +% \ttfamily \obeylines +% \{ \% argument processors +% \ \ \{ \% argument 1 +% \ \ \ \ \{ processor 1 \} \{ processor 2 \} \ldots\ \{ processor n \} +% \ \ \} \% end argument 1 +% \ \ \{ \ldots\ \} \% argument 2 +% \ \ \ \ \ \vdots +% \ \ \{ \ldots\ \} \% argument n +% \} \% end argument processors +% \end{quote} +% +% The function \cs{@@_add_grabber:N} adds one single grabber for an +% argument, and adds the braced item for that one argument. However, +% in an |E|-type argument each embellishment requires its own formal +% argument, so we need to break out of one layer of braces in +% \cs{l_@@_process_one_tl}, add copies of the processor as necessary, +% and then return the removed brace. The function below does just +% that: it defines \cs{l_@@_process_one_tl} starting with a |}|$_2$ +% and ending with a |{|$_1$, so that it adds as many processors as +% needed when |x|-expanded. +% \begin{macrocode} +\cs_new_protected:Npn \@@_replicate_processor:nn #1 #2 + { + \int_compare:nNnF {#1} > { 1 } { \use_none:nnn } + \tl_set:Nx \l_@@_process_one_tl + { + \exp_not:n { \exp_not:n {#2} \if_false: { \fi: } } + \prg_replicate:nn { #1 - 2 } + { \exp_not:n { \exp_not:n { {#2} } } } + \exp_not:n { { \if_false: } \fi: \exp_not:n {#2} } + } + } +% \end{macrocode} +% \end{macro} +% % \begin{macro}{\@@_add_type_m:w} % The \texttt{m} type is special as short arguments which are not % post-processed are simply counted at this stage. Thus there is a check @@ -1608,6 +1661,8 @@ % \cs{l_@@_obey_spaces_bool} boolean can only be \texttt{true} for % trailing optional arguments. In that case spaces will not be % ignored when looking for that optional argument. +% \changes{v1.0g}{2021/08/07} +% {Replicate argument processors for all embellishments (gh/639)} % \begin{macrocode} \cs_new_protected:Npn \@@_add_grabber:N #1 { @@ -1624,7 +1679,12 @@ \bool_set_false:N \l_@@_long_bool \bool_set_false:N \l_@@_obey_spaces_bool \tl_put_right:Nx \l_@@_process_all_tl - { { \exp_not:o \l_@@_process_one_tl } } + { + { + \if_charcode:w E #1 \use_i:nn \fi: + \exp_not:o \l_@@_process_one_tl + } + } \tl_clear:N \l_@@_process_one_tl } % \end{macrocode} @@ -1676,8 +1736,7 @@ % We have already checked that short arguments are before long % arguments, so \cs{l_@@_long_bool} only changes from \texttt{false} % to \texttt{true} once (and there is no need to reset it after each -% argument). Also knock back the argument count because |+| is not an -% argument. Continue the loop. +% argument). Continue the loop. % \begin{macrocode} \cs_new_protected:cpn { @@_add_expandable_type_+:w } { @@ -1875,6 +1934,657 @@ % \end{macro} % \end{macro} % +% \subsubsection{Copying a command and its internal structure} +% +% \begin{macrocode} +%\IncludeInRelease{2021/11/15}{\@@_copy:NN}% +% {Support~\NewCommandCopy~in~ltcmd} +% \end{macrocode} +% +% \changes{v1.0h}{2021/08/30}{Added support for \cs{NewCommandCopy}} +% Since the 2020-10-01 \LaTeXe{} release, support for copying, and +% showing the definition of, robust commands has been available, but the +% specifics of each command are implemented separately. Here we'll add +% support for copying and showing \pkg{ltcmd} definitions. +% +% To fully support copying, we need two commands: a conditional to test +% if a command is in fact a \pkg{ltcmd} command, and another command to +% actually copy the command. The conditional is defined later as +% \cs{__kernel_cmd_if_xparse:NTF}, so now to the copying: +% +% \begin{macro}{\@@_copy:NN} +% \begin{macro}{\@@_set_eq_if_exist:NN,\@@_set_eq_if_exist:cc} +% This macro just branches to the proper copying command by using +% \cs{@@_cmd_type_cases:NnnnnF}. The copying command takes the names +% of the commands to be copied to and from, and the actual commands +% as its four arguments. +% \begin{macrocode} +\cs_new_protected:Npn \@@_copy:NN #1 #2 + { + \use:x + { + \int_set:Nn \tex_escapechar:D { 92 } + \exp_not:N \@@_cmd_type_cases:NnnnnF \exp_not:N #2 + { \@@_copy_command:nnNN } + { \@@_copy_expandable:nnNN } + { \@@_copy_environment:nnNN } + { \@@_copy_environment_end:nnNN } + { \@@_cant_copy:nwn { non-ltcmd } } + { \cs_to_str:N #1 } { \cs_to_str:N #2 } + \exp_not:N #1 \exp_not:N #2 + \exp_not:N \@@_break_point:n { \cs_to_str:N #2 } + \int_set:Nn \tex_escapechar:D { \int_use:N \tex_escapechar:D } + } + } +\cs_new_protected:Npn \@@_set_eq_if_exist:NN #1 #2 + { \cs_if_exist:NTF #2 { \cs_set_eq:NN } { \use_none:nn } #1 #2 } +\cs_generate_variant:Nn \@@_set_eq_if_exist:NN { cc } +% \end{macrocode} +% +% \begin{macro}{\@@_cant_copy:nwn} +% An utility macro similar to \cs{@@_bad_def:wn} to abort a command +% copy. Contrary to \cs{@@_bad_def:wn} though, when this happens the +% issue is most likely internal, because the command was already +% (supposedly) correcly defined so it should be copyable. Hopefully +% this macro will never be used ever, but if it does, apologise and +% give the reason for the failure so the user can report. +% \begin{macrocode} +\cs_new_protected:Npn \@@_cant_copy:nwn #1 #2 \@@_break_point:n #3 + { \msg_error:nnnn { cmd } { copy-bug } {#1} {#3} } +\msg_new:nnn { cmd } { copy-bug } + { + Error~while~copying~command~\iow_char:N\\#2:\\ + \str_case:nn {#1} + { + { non-ltcmd } { Command~is~not~a~valid~ltcmd~command. } + { unknown-type } { Found~an~unknown~argument~type. } + { invalid-end } + { Target~command~is~not~named~\iow_char:N \\end. } + } + } +% \end{macrocode} +% \end{macro} +% +% And, of course, add \cs{__kernel_cmd_if_xparse:NTF} and +% \cs{@@_copy:NN} to \cs{@declarecommandcopylisthook}: +% \begin{macrocode} +\tl_gput_right:Nn \@declarecommandcopylisthook + { { \__kernel_cmd_if_xparse:NTF \@@_copy:NN } } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\@@_copy_command:nnNN,\@@_copy_command:NnNNnnnn} +% A normal (non-expandable) command has a pretty straightforward +% structure. Its definition is stored in +% \cs{\meta{cmd}\textvisiblespace code}, its defaults (if any) are +% stored in \cs{\meta{cmd}\textvisiblespace defaults}, and its +% top-level definition contains its signature, which can just be +% copied over. \cs{@@_copy_command:nnNN} copies the command code and +% defaults, and then defines the top-level command using the auxiliary +% \cs{@@_copy_command:NnNNnnnn}. This macro takes the signature of +% the command being copied from its top-level definition, and replaces +% the named bits with the new name. +% \begin{macrocode} +\cs_new_protected:Npn \@@_copy_command:nnNN #1 #2 #3 #4 + { + \cs_set_eq:cc { #1 ~ code } { #2 ~ code } + \@@_set_eq_if_exist:cc { #1 ~ defaults } { #2 ~ defaults } + \cs_set_protected_nopar:Npx #3 + { \exp_after:wN \@@_copy_command:NnNNnnnn #4 {#1} } + } +\cs_new:Npn \@@_copy_command:NnNNnnnn #1 #2 #3 #4 #5 #6 #7 #8 + { + #1 \exp_not:n { {#2} } + \exp_not:c { #8 ~ } \exp_not:c { #8 ~ code } + \exp_not:n { {#5} {#6} {#7} } + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\@@_copy_expandable:nnNN,\@@_copy_expandable:NnNNNNnnn} +% An expandable command is slightly more complicated. Besides the +% \cs{\meta{cmd}\textvisiblespace code}, and +% \cs{\meta{cmd}\textvisiblespace defaults}, it also has an auxiliary +% \cs{\meta{cmd}\textvisiblespace} for grabbing delimited arguments, +% and possibly another auxiliary +% \cs{\meta{cmd}\textvisiblespace\textvisiblespace}, if the command +% has both long and short arguments. Then, its signature also has +% several specific bits that are unique to that command; this is in contrast to +% non-expandable commands, which use a common set of parsing functions. +% +% We start by copying the basics, then call +% \cs{@@_copy_expandable_signature:NnNNNNnnn} to parse the signature +% of the command and build up the modified copy in a temporary token list, +% then we call \cs{@@_copy_expandable:NnNNNNnnn} that will copy the +% top-level definition of the command, with the proper internal +% renames. +% \begin{macrocode} +\cs_new_protected:Npn \@@_copy_expandable:nnNN #1 #2 #3 #4 + { + \cs_set_eq:cc { #1 ~ code } { #2 ~ code } + \@@_set_eq_if_exist:cc { #1 ~ } { #2 ~ } + \@@_set_eq_if_exist:cc { #1 ~ \c_space_tl } { #2 ~ \c_space_tl } + \@@_set_eq_if_exist:cc { #1 ~ defaults } { #2 ~ defaults } + \exp_after:wN \@@_copy_expandable_signature:NnNNNNnnn #4 {#1} {#2} + \cs_set_nopar:Npx #3 + { \exp_after:wN \@@_copy_expandable:NnNNNNnnn #4 {#1} {#2} } + } +\cs_new:Npn \@@_copy_expandable:NnNNNNnnn #1 #2 #3 #4 #5 #6 #7 #8 #9 + { + \exp_not:N #1 \exp_not:n { {#2} } + \exp_not:c { #8 ~ } + \exp_not:c + { + #8 ~ + \str_if_eq:eeT + { \exp_not:c { #9 ~ \c_space_tl } } { \exp_not:N #4 } + { \c_space_tl } + } + \exp_not:c { #8 ~ code } + \str_if_eq:eeTF { \exp_not:N #6 } { ? } + { ? } + { \exp_not:c { #8 ~ defaults } } + { \exp_not:V \l_@@_tmpa_tl } + } +% \end{macrocode} +% +% \begin{macro}{ +% \@@_copy_expandable_signature:NnNNNNnnn, +% \@@_copy_expandable:nnN, +% \@@_copy_parse_grabber:w, +% } +% A signature for an expandable command contains as many +% \cs{expandable_grab_\meta{type}:w} as there are arguments, and what +% follows this macro depends on the \meta{type}. We'll start a loop +% through the signature, and at each argument grabber, we'll step the +% argument count, and look for the \meta{type} with +% \cs{@@_copy_parse_grabber:w} so that we know which +% \cs{@@_copy_grabber_\meta{type}:w} to call next. +% \begin{macrocode} +\cs_new_protected:Npn \@@_copy_expandable_signature:NnNNNNnnn + #1 #2 #3 #4 #5 #6 #7 #8 #9 + { + \int_zero:N \l_@@_current_arg_int + \tl_clear:N \l_@@_tmpa_tl + \@@_copy_expandable:nnN {#8} {#9} #7 + \q_recursion_tail \q_recursion_stop + } +\cs_new_protected:Npn \@@_copy_expandable:nnN #1 #2 #3 + { + \quark_if_recursion_tail_stop:n {#3} + \int_incr:N \l_@@_current_arg_int + \exp_after:wN \@@_copy_parse_grabber:w \token_to_str:N #3 {#1} {#2} + } +\use:x + { + \cs_new_protected:Npn \exp_not:N \@@_copy_parse_grabber:w ##1 + \tl_to_str:n { expandable_grab_ } ##2 \tl_to_str:n { :w } + { + \tl_put_right:Nx \exp_not:N \l_@@_tmpa_tl + { \exp_not:N \exp_not:c { @@_expandable_grab_##2:w } } + \exp_not:N \cs_if_exist_use:cF { @@_copy_grabber_##2:w } + { \@@_cant_copy:nwn { unknown-type } } + } + } +% \end{macrocode} +% +% \begin{macro}{ +% \@@_copy_grabber_D:w,\@@_copy_grabber_D_alt:w, +% \@@_copy_grabber_R:w,\@@_copy_grabber_R_alt:w, +% \@@_copy_grabber_E:w,\@@_copy_grabber_E_long:w, +% \@@_copy_grabber_t:w, +% \@@_copy_grabber_m:w,\@@_copy_grabber_m_long:w, +% } +% The most complicated is the |D|elimited argument: each argument has +% a dedicated grabbing function named after the command that has to be +% copied over (of the form +% \cs{\meta{cmd}\textvisiblespace(arg\textvisiblespace\meta{num})}). +% \begin{macrocode} +\cs_new_protected:Npn \@@_copy_grabber_D:w #1 #2 #3 #4 #5 + { + \tl_put_right:Nx \l_@@_tmpa_tl + { + \exp_not:c { #1 ~ (arg ~ \int_use:N \l_@@_current_arg_int ) } + \exp_not:n { #4 #5 } + } + \cs_set_eq:cc + { #1 ~ (arg ~ \int_use:N \l_@@_current_arg_int ) } + { #2 ~ (arg ~ \int_use:N \l_@@_current_arg_int ) } + \@@_copy_expandable:nnN {#1} {#2} + } +% \end{macrocode} +% +% |D_alt| is just a special case of |D| that uses a single delimiter +% (used when both delimiters of the argument are identical): +% \begin{macrocode} +\cs_new_protected:Npn \@@_copy_grabber_D_alt:w #1 #2 #3 #4 + { \@@_copy_grabber_D:w {#1} {#2} {#3} {#4} { } } +% \end{macrocode} +% +% As far as copying is concerned, |R| is identical to |D|: +% \begin{macrocode} +\cs_new_eq:NN \@@_copy_grabber_R:w \@@_copy_grabber_D:w +\cs_new_eq:NN \@@_copy_grabber_R_alt:w \@@_copy_grabber_D_alt:w +% \end{macrocode} +% +% |E| is straightforward: we just copy the embellishments over, and +% increase the current argument number \cs{l_@@_current_arg_int} by +% the number of embellishments (minus one because there is a +% \cs{int_incr:N} down the line). +% \begin{macrocode} +\cs_new_protected:Npn \@@_copy_grabber_E:w #1 #2 #3 #4 + { + \tl_put_right:Nn \l_@@_tmpa_tl { {#3} {#4} } + \int_add:Nn \l_@@_current_arg_int { \tl_count:n {#4} - 1 } + \@@_copy_expandable:nnN {#1} {#2} + } +\cs_new_eq:NN \@@_copy_grabber_E_long:w \@@_copy_grabber_E:w +% \end{macrocode} +% +% |t| just needs copying the token to be tested for: +% \begin{macrocode} +\cs_new_protected:Npn \@@_copy_grabber_t:w #1 #2 #3 #4 + { + \tl_put_right:Nn \l_@@_tmpa_tl { #3 #4 } + \@@_copy_expandable:nnN {#1} {#2} + } +% \end{macrocode} +% +% And last but not least, |m| is the simplest; the grabber is just +% \cs{@@_expandable_grab_m:w}, which is already added to the new +% command so here we just resume the loop: +% \begin{macrocode} +\cs_new_protected:Npn \@@_copy_grabber_m:w { \@@_copy_expandable:nnN } +\cs_new_eq:NN \@@_copy_grabber_m_long:w \@@_copy_grabber_m:w +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\@@_copy_environment:nnNN} +% \begin{macro}{\@@_copy_environment:Nnnnnnn} +% Copying an environment's \cs{begin} part is pretty much like copying +% a command, except it has a longer name, and at the end we have to +% copy \cs[no-index]{environment~\meta{name}} into +% \cs[no-index]{\meta{name}}. +% \begin{macrocode} +\cs_new_protected:Npn \@@_copy_environment:nnNN #1 #2 #3 #4 + { + \cs_set_eq:cc { environment~ #1 ~ code } { environment~ #2 ~ code } + \@@_set_eq_if_exist:cc + { environment~ #1 ~ defaults } { environment~ #2 ~ defaults } + \cs_set_protected_nopar:cpx { environment~ #1 } + { \exp_after:wN \@@_copy_environment:Nnnnnnn #4 {#1} } + \cs_set_eq:cc {#1} { environment~ #1 } + } +\cs_new:Npn \@@_copy_environment:Nnnnnnn #1 #2 #3 #4 #5 #6 #7 + { #1 \exp_not:n { {#2} } {#7} \exp_not:n { {#4} {#5} {#6} } } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\@@_copy_environment_end:nnNN} +% \begin{macro}{\@@_copy_environment_end_aux:nnNN} +% Copying an environment's \cs{end} part is a bit trickier. We first +% have to make sure that both parts are named +% \cs[no-index]{end\meta{name}} (that's actually not a hard +% requirement, but an environment \cs{end} command makes no sense +% without the |end| in its name), and strip the leading |end| from the +% strings. After that, copying is straightforward. +% \begin{macrocode} +\cs_new_protected:Npn \@@_copy_environment_end:nnNN #1 #2 + { + \@@_check_end:Nn \l_@@_tmpa_tl {#1} + \@@_check_end:Nn \l_@@_tmpb_tl {#2} + \exp_args:Noo \@@_copy_environment_end_aux:nnNN + { \l_@@_tmpa_tl } { \l_@@_tmpb_tl } + } +\cs_new_protected:Npn \@@_copy_environment_end_aux:nnNN #1 #2 #3 #4 + { + \cs_set_nopar:cpx { environment~ #1 ~end } + { \exp_not:c { environment~ #1 ~end~aux } } + \cs_set_eq:cc + { environment~ #1 ~end~aux~ } { environment~ #2 ~end~aux~ } + \cs_set_eq:cc { end #1 } { environment~ #1 ~end } + } +% \end{macrocode} +% +% \begin{macro}{\@@_check_end:Nn,\@@_check_end:n,\@@_check_end:w} +% To check whether an \cs{end} command is valid, we look for the +% string |end| at the beginning of the command name, and if not found, +% raise an error: +% \begin{macrocode} +\cs_new_protected:Npn \@@_check_end:Nn #1 #2 + { + \tl_set:Nx #1 { \@@_check_end:n {#2} } + \token_if_eq_meaning:NNT #1 \q_nil + { \@@_cant_copy:nwn { invalid-end } } + } +\cs_set_protected:Npn \@@_tmp:w #1 + { + \cs_new:Npn \@@_check_end:n ##1 + { + \exp_after:wN \@@_check_end:w \tl_to_str:n {##1} + #1 \q_mark #1 \q_stop + } + \cs_new:Npn \@@_check_end:w ##1 #1 ##2 #1 ##3 \q_stop + { \if_meaning:w ##2 \q_mark \exp_not:N \q_nil \else: ##2 \fi: } + } +\exp_args:No \@@_tmp:w { \tl_to_str:n { end } } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% Not much to do regarding \pkg{latexrelease}: we could remove the +% entries from \cs{@declarecommandcopylisthook}, but it doesn't seem +% worth it. +% \begin{macrocode} +%\EndIncludeInRelease +%\IncludeInRelease{2020/10/01}{\@@_copy:NN}% +% {Support~\NewCommandCopy~in~ltcmd} +%\EndIncludeInRelease +% \end{macrocode} +% +% \subsubsection{Showing the definition of a command} +% +% \begin{macrocode} +%\IncludeInRelease{2021/11/15}{\@@_show:N}% +% {Support~\ShowCommand~in~ltcmd} +% \end{macrocode} +% +% \changes{v1.0h}{2021/08/30}{Added support for \cs{ShowCommand}} +% To show the definition of a command we need more or less the same +% building blocks as for copying, except that instead of making a copy, +% we'll just print stuff to the terminal. +% +% \begin{macro}{\@@_show:N} +% This macro just branches to the proper showing command by using +% \cs{@@_cmd_type_cases:NnnnnF}. The showing command takes the command +% to be shown as argument. +% \begin{macrocode} +\cs_new_protected:Npn \@@_show:N #1 + { + \use:x + { + \int_set:Nn \tex_escapechar:D { 92 } + \exp_not:N \@@_cmd_type_cases:NnnnnF \exp_not:N #1 + { \@@_show_command:N } + { \@@_show_expandable:N } + { \@@_show_environment:N } + { \@@_show_environment_end:N } + { \@@_cant_copy:nwn { non-ltcmd } } + \exp_not:N #1 + \exp_not:N \@@_break_point:n { \cs_to_str:N #1 } + \int_set:Nn \tex_escapechar:D { \int_use:N \tex_escapechar:D } + } + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{ +% \@@_show_command:N, +% \@@_show_command:NnNNwN, +% \@@_show_expandable:N, +% \@@_show_expandable:NnNNNNnN, +% \@@_show_command_aux:nNNn, +% \@@_show_environment:N, +% } +% These commands just expand the command once to reveal its innards, +% then pass the type of command, the control sequence, the signature, +% and the code macro to \cs{@@_show_command_aux:nNNn}. +% \begin{macrocode} +\cs_new_protected:Npn \@@_show_command:N #1 + { \exp_after:wN \@@_show_command:NnNNwN #1 \q_@@ #1 } +\cs_new_protected:Npn \@@_show_command:NnNNwN #1 #2 #3 #4 #5 \q_@@ #6 + { \@@_show_command_aux:nNNn { document~command } #6 #4 {#2} } +\cs_new_protected:Npn \@@_show_expandable:N #1 + { \exp_after:wN \@@_show_expandable:NnNNNNnN #1 #1 } +\cs_new_protected:Npn \@@_show_expandable:NnNNNNnN #1 #2 #3 #4 #5 #6 #7 #8 + { \@@_show_command_aux:nNNn { expandable~document~command } #8 #5 {#2} } +% \end{macrocode} +% +% Now just print everything in the required format. The auxiliary +% \cs{@@_split_signature:n} stores a ready-to-print token list in +% \cs{l_@@_tmpa_tl}, so we ust use that here: +% \begin{macrocode} +\cs_new_protected:Npn \@@_show_command_aux:nNNn #1 #2 #3 #4 + { + \@@_split_signature:n {#4} + \iow_term:x + { + > ~ \token_to_str:N #2 = #1: \iow_newline: + \tl_use:N \l_@@_tmpa_tl + -> \cs_replacement_spec:N #3 . + } + } +% \end{macrocode} +% +% We can reuse most of the above to show an environment, except that +% we need to ensure that the proper \cs[no-index]{environment~\ldots} +% are passed to \cs{@@_show_command_aux:nNNn}. Additionally, when +% |\ShowCommand\foo| is used (if |foo| is an environment), we show +% |\endfoo| as well, and when |\ShowCommand\endfoo| is used, change +% that to |\ShowCommand\foo| and do the same. +% \begin{macrocode} +\cs_new_protected:Npn \@@_show_environment:N #1 + { + \exp_after:wN \@@_show_environment:Nnnw #1 \q_@@ + \iow_term:x + { + > ~ \token_to_str:N \end { \cs_to_str:N #1 } : \iow_newline: + -> \exp_args:Nc \cs_replacement_spec:N + { environment~ \cs_to_str:N #1 ~end~aux~ } . + } + } +\cs_new_protected:Npn \@@_show_environment:Nnnw #1 #2 #3 #4 \q_@@ + { + \use:x + { + \@@_show_command_aux:nNNn { document~environment } + { \exp_not:N \begin {#3} } + \exp_not:c { environment~ #3 ~ code } + {#2} + } + } +\cs_new_protected:Npn \@@_show_environment_end:N #1 + { + \exp_args:NNx \@@_check_end:Nn \l_@@_tmpa_tl { \cs_to_str:N #1 } + \exp_args:Nc \@@_show_environment:N { \l_@@_tmpa_tl } + } +% \end{macrocode} +% +% And, of course, add \cs{__kernel_cmd_if_xparse:NTF} and +% \cs{@@_show:N} to \cs{@showcommandlisthook}: +% \begin{macrocode} +\tl_gput_right:Nn \@showcommandlisthook + { { \__kernel_cmd_if_xparse:NTF \@@_show:N } } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\@@_split_signature:n} +% Now we'll try a least-effort adventure into splitting the symbolic +% user-provided signature for a command into individual parameters for +% pretty-printing. A counter is used to keep track of the current +% argument number, and two token lists are used: \cs{l_@@_tmpa_tl} +% holds the final token list to be printed, and \cs{l_@@_tmpb_tl} +% holds just the current item, so that we can make changes to an +% individual item without having to dissect the whole thing (this is +% used for |e|- and |E|-types). +% \begin{macrocode} +\cs_new_protected:Npn \@@_split_signature:n #1 + { + \int_set:Nn \l_@@_current_arg_int { 1 } + \tl_clear:N \l_@@_tmpa_tl + \tl_clear:N \l_@@_tmpb_tl + \@@_split_signature_loop:Nw #1 \q_recursion_tail \q_recursion_stop + } +% \end{macrocode} +% +% \begin{macro}{\@@_split_signature_loop:Nw} +% This is the main chunk of the loop: it starts an item with +% \cs{@@_split_start_item:} +% (this adds indentation and the argument number to +% \cs{l_@@_tmpb_tl}), then checks if a special token list +% \cs[no-index]{c_@@_show_type_\meta{type}_tl} exists. If it doesn't, +% the current argument is a ``simple'' type which needs no extra +% processing. Otherwise, call a specific function depending on the +% value of said token list. +% \begin{macrocode} +\cs_new_protected:Npn \@@_split_signature_loop:Nw #1 + { + \quark_if_recursion_tail_stop:N #1 + \tl_if_empty:NT \l_@@_tmpb_tl { \@@_split_start_item: } + \tl_if_exist:cTF { c_@@_show_type_#1_tl } + { + \use:c + { + @@_show_ + \if_case:w \tl_use:c { c_@@_show_type_#1_tl } \exp_stop_f: + delim \or: delims \or: delims_opt \or: opt \or: + e \or: E \or: prefix \or: processor \fi: :Nw + } #1 + } + { \@@_split_end_item:n {#1} \@@_split_signature_loop:Nw } + } +% \end{macrocode} +% +% \begin{macro}{ +% \c_@@_show_type_t_tl, +% \c_@@_show_type_r_tl,\c_@@_show_type_d_tl, +% \c_@@_show_type_R_tl,\c_@@_show_type_D_tl, +% \c_@@_show_type_O_tl, +% \c_@@_show_type_e_tl, +% \c_@@_show_type_E_tl, +% \c_@@_show_type_+_tl,\c_@@_show_type_!_tl, +% \c_@@_show_type_>_tl, +% } +% The token lists \cs[no-index]{c_@@_show_type_\meta{type}_tl} exist +% for nontrivial (for printing) \meta{types} that require special +% parsing (like delimiters or optional arguments). Values from~0 to~7 +% are assigned to each type: +% \begin{enumerate} +% \item a single delimiter token; +% \item two delimiter tokens; +% \item two delimiter tokens plus a default value; +% \item a default value; +% \item a list of embellishments (exclusive for |e|-type); +% \item embellishments plus defaults (exclusive for |E|-type); +% \item simple prefixes; +% \item prefixes with arguments (argument processors); +% \end{enumerate} +% \begin{macrocode} +\cs_set_protected:Npn \@@_tmp:w #1 #2 + { + \quark_if_nil:nF {#1} + { \tl_const:cn { c_@@_show_type_#1_tl } {#2} \@@_tmp:w } + } +\@@_tmp:w t0 r1 d1 R2 D2 O3 e4 E5 +6 !6 >7 \q_nil \q_nil +% \end{macrocode} +% +% \begin{macro}{ +% \@@_show_delim:Nw,\@@_show_delims:Nw, +% \@@_show_delims_opt:Nw,\@@_show_opt:Nw, +% \@@_show_e:Nw,\@@_show_E:Nw, +% \@@_show_prefix:Nw,\@@_show_processor:Nw, +% } +% Now, based on each type we know how to act. In most cases it is +% just a matter of feeding in the grabbed arguments and resuming the +% loop. The embellishments require a bit more attention: the +% |e|-type loops through the list of embellishments and adds each to +% the token list as a separate argument. The |E|-type does more or +% less the same, but uses \cs{@@_tl_mapthread_function:nnN} to map +% over two lists simultaneously, adding each token and default to the +% token list for printing. +% \begin{macrocode} +\cs_new_protected:Npn \@@_show_delim:Nw #1 #2 + { \@@_split_end_item:n { #1 #2 } \@@_split_signature_loop:Nw } +\cs_new_protected:Npn \@@_show_delims:Nw #1 #2 #3 + { \@@_split_end_item:n { #1 #2 #3 } \@@_split_signature_loop:Nw } +\cs_new_protected:Npn \@@_show_delims_opt:Nw #1 #2 #3 #4 + { \@@_split_end_item:n { #1 #2 #3 {#4} } \@@_split_signature_loop:Nw } +\cs_new_protected:Npn \@@_show_opt:Nw #1 #2 + { \@@_split_end_item:n { #1 {#2} } \@@_split_signature_loop:Nw } +\cs_new_protected:Npn \@@_show_e:Nw #1 #2 + { + \tl_map_inline:nn {#2} + { + \@@_split_start_item: + \@@_split_end_item:n { #1 ##1 } + } + \@@_split_signature_loop:Nw + } +\cs_set_protected:Npn \@@_tmp:w #1 + { + \cs_new_protected:Npn \@@_show_E:Nw ##1 ##2 ##3 + { + \cs_set_protected:Npn \@@_tmp:w ####1 ####2 + { + \@@_split_start_item: + \@@_split_end_item:n { ##1 ####1 {####2} } + } + \@@_tl_mapthread_function:nnN {##2} + { ##3 {#1} {#1} {#1} {#1} {#1} {#1} {#1} {#1} {#1} } \@@_tmp:w + \@@_split_signature_loop:Nw + } + } +\exp_args:NV \@@_tmp:w \c_novalue_tl +% \end{macrocode} +% +% Minor wrinkle with the prefixes: they use \cs{@@_split_add_item:n} +% instead of \cs{@@_split_end_item:n} (|add| \emph{vs.} |end|) because +% they are followed by an argument, so they can't end the item. +% \begin{macrocode} +\cs_new_protected:Npn \@@_show_prefix:Nw #1 + { \@@_split_add_item:n {#1} \@@_split_signature_loop:Nw } +\cs_new_protected:Npn \@@_show_processor:Nw #1 #2 + { \@@_split_add_item:n { #1 {#2} } \@@_split_signature_loop:Nw } +% \end{macrocode} +% +% \begin{macro}{ +% \@@_split_start_item:, +% \@@_split_add_item:n, +% \@@_split_end_item:n, +% } +% And now the auxiliaries that store the strings to be printed. +% \cs{@@_split_start_item:} starts an item from scratch, +% \cs{@@_split_add_item:n} adds tokens to an item without adding a +% newline, and \cs{@@_split_end_item:n} adds tokens, terminates the +% item with a newline, and steps the argument count. +% \begin{macrocode} +\cs_new_protected:Npn \@@_split_start_item: + { + \tl_set:Nx \l_@@_tmpb_tl + { ~ \c_space_tl \c_hash_str \int_use:N \l_@@_current_arg_int : } + } +\cs_new_protected:Npn \@@_split_add_item:n #1 + { \tl_put_right:Nx \l_@@_tmpb_tl { \tl_to_str:n {#1} } } +\cs_new_protected:Npn \@@_split_end_item:n #1 + { + \tl_put_right:Nx \l_@@_tmpa_tl + { \l_@@_tmpb_tl \tl_to_str:n {#1} \iow_newline: } + \tl_clear:N \l_@@_tmpb_tl + \int_incr:N \l_@@_current_arg_int + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% Not much to do regarding \pkg{latexrelease}: we could remove the +% entries from \cs{@showcommandlisthook}, but it doesn't seem +% worth it. +% \begin{macrocode} +%\EndIncludeInRelease +% +%\IncludeInRelease{2020/10/01}{\@@_show:N}% +% {Support~\ShowCommand~in~ltcmd} +%\EndIncludeInRelease +% \end{macrocode} +% % \subsection{Grabbing arguments} % % All of the grabbers follow the same basic pattern. The initial @@ -2023,6 +2733,7 @@ % \end{macro} % \end{macro} % \end{macro} +% % \begin{macro}{\@@_grab_D_nested:NNnN} % \begin{macro}{\@@_grab_D_nested:w} % \begin{macro}{\l_@@_nesting_a_tl} @@ -2587,7 +3298,7 @@ \exp_after:wN \exp_after:wN \exp_after:wN \peek_meaning_remove:NTF \char_generate:nn { \tex_endlinechar:D } { 6 } { - \msg_error:nnxxx { cmd } { verbatim-newline } + \msg_error:nnxxx { cmd } { verbatim-nl } { \@@_environment_or_command: } { \tl_to_str:N \l_@@_v_arg_tl } { \tl_to_str:n {#1} } @@ -3115,7 +3826,7 @@ \ProcessedArgument \q_stop } - \msg_error:nnxxx { cmd } { split-excess-tokens } + \msg_error:nnxxx { cmd } { arg-split } { \tl_to_str:n {#3} } { \int_eval:n { #2 + 1 } } { \tl_to_str:n {#4} } } @@ -3375,8 +4086,11 @@ % \end{macro} % % \begin{macro}{\__kernel_cmd_if_xparse:NTF} +% \begin{macro}{\@@_cmd_type_cases:Nnnnn} % \changes{v1.0d}{2021/04/19}{Renamed \cs{__cmd_cmd_if_xparse:NTF} to % \cs{__kernel_cmd_if_xparse:NTF} for cross-module usage} +% \changes{v1.0d}{2021/07/30}{Added \cs{@@_cmd_type_cases:Nnnnn} for +% \cs{NewCommandCopy} and \cs{ShowCommand} support} % \begin{macro}{\@@_cmd_if_xparse_aux:N} % % To determine whether the command is an \pkg{xparse} command check @@ -3384,31 +4098,50 @@ % that its |replacement_spec| starts with either % \cs{@@_start:nNNnnn} (non-expandable command) or % \cs{@@_start_expandable:nNNNNn} (expandable command) or -% \cs{@@_start_env:nnnnn} (environment). +% \cs{@@_start_env:nnnnn} (environment) or +% \cs[no-index]{environment~\#1~end~aux} (environment end). % % This conditional is needed in several kernel modules and is % therefore has a kernel-internal name. % \begin{macrocode} -\cs_new_protected:Npn \__kernel_cmd_if_xparse:NTF #1 +\cs_new_protected:Npn \@@_cmd_type_cases:NnnnnF #1 #2 #3 #4 #5 #6 { - \exp_args:Nf \str_case_e:nnTF + \exp_args:Ne \str_case_e:nnF { \exp_args:Nf \tl_if_empty:nT { \cs_argument_spec:N #1 } { - \exp_last_unbraced:Nf \@@_cmd_if_xparse_aux:w - { \cs_replacement_spec:N #1 } ~ \q_stop + \token_if_macro:NT #1 + { + \exp_after:wN \exp_after:wN + \exp_after:wN \token_to_str:N + \exp_after:wN \use_i_delimit_by_q_stop:nw + #1 \scan_stop: \q_stop + } } } { - { \token_to_str:N \@@_start:nNNnnn } { } - { \token_to_str:N \@@_start_expandable:nNNNNn } { } - { \token_to_str:N \@@_start_env:nnnnn } { } + { \token_to_str:N \@@_start:nNNnnn } {#2} + { \token_to_str:N \@@_start_expandable:nNNNNn } {#3} + { \token_to_str:N \@@_start_env:nnnnn } {#4} + { + \exp_after:wN \token_to_str:N + \cs:w environment~ + \exp_last_unbraced:Ne \use_none:nnn + { \cs_to_str:N #1 } ~end~aux \cs_end: + } {#5} } + {#6} + } +\cs_new_protected:Npn \__kernel_cmd_if_xparse:NTF #1 + { + \@@_cmd_type_cases:NnnnnF #1 + { } { } { } { } { \use_iii:nnn } + \use_i:nn } -\cs_new:Npn \@@_cmd_if_xparse_aux:w #1 ~ #2 \q_stop {#1} % \end{macrocode} % \end{macro} % \end{macro} +% \end{macro} % % \begin{macro}{\@@_peek_nonspace:NTF, \@@_peek_nonspace_remove:NTF, \@@_peek_nonspace_aux:nNNTF} % Collect spaces in a loop, and put the collected spaces back in the @@ -3434,7 +4167,7 @@ % token is a control sequence, also check that the \meta{csname} is % the same as the control sequence peeked at. This extra verification % is necessary when the command is delimited by control sequence tokens -% (as opposed to character tokens), and we want the the exact same +% (as opposed to character tokens), and we want the exact same % control sequence to match. % \begin{macrocode} \cs_new_protected:Npn \@@_peek_meaning:NTF @@ -3504,94 +4237,98 @@ % \end{macro} % % Some messages intended as errors when defining commands/environments. +% \changes{v1.0f}{2021/06/04}{Normalize various error messages} % \begin{macrocode} \msg_new:nnnn { cmd } { arg-after-body } - { In~the~definition~of~#1,~b~(body)~argument~must~be~last. } + { Argument~type~'b'~must~be~last~in~#1. } { - The~'body'~argument~type~is~followed~by~'#2'~in~the~argument~ - specification~of~the~#1.~This~is~not~allowed. + The~'b'~argument~type~must~come~last~but~it~is~followed~ + by~'#2'~in~the~argument~specification.~This~is~not~allowed. \c_@@_ignore_def_tl } \msg_new:nnnn { cmd } { bad-arg-spec } { Bad~argument~specification~'#2'~for~#1. } { - The~argument~specification~provided~was~not~valid:~ - one~or~more~mandatory~pieces~of~information~were~missing. + The~argument~specification~provided~is~not~valid:~ + one~or~more~mandatory~parts~are~missing. \c_@@_ignore_def_tl } -\msg_new:nnnn { cmd } { command-already-defined } - { Command~'#1'~already~defined! } +\msg_new:nnnn { cmd } { already-defined } + { Command~'#1'~already~defined. } { You~have~used~#2~ with~a~command~that~already~has~a~definition. \\ \\ The~existing~definition~of~'#1'~will~not~be~altered. } -\msg_new:nnnn { cmd } { command-not-yet-defined } - { Command ~'#1'~not~yet~defined! } +\msg_new:nnnn { cmd } { undefined } + { Command ~'#1'~undefined. } { You~have~used~#2~ with~a~command~that~was~never~defined. \c_@@_ignore_def_tl } -\msg_new:nnnn { cmd } { environment-already-defined } - { Environment~'#1'~already~defined! } +\msg_new:nnnn { cmd } { env-already-defined } + { Environment~'#1'~already~defined. } { You~have~used~\NewDocumentEnvironment with~an~environment~that~already~has~a~definition. \\ \\ The~existing~definition~of~'#1'~will~not~be~altered. } -\msg_new:nnnn { cmd } { environment-not-yet-defined } - { Environment~'#1'~not~yet~defined! } +\msg_new:nnnn { cmd } { env-end-already-defined } + { End~of~environment~'#1'~already~defined. } + { + You~have~used~\NewDocumentEnvironment + with~an~environment~that~already~has~a~definition~for~'end#1'. \\ \\ + The~existing~definition~of~'#1'~will~not~be~altered. + } +\msg_new:nnnn { cmd } { env-undefined } + { Environment~'#1'~undefined. } { You~have~used~\RenewDocumentEnvironment with~an~environment~that~was~never~defined. \c_@@_ignore_def_tl } \msg_new:nnnn { cmd } { expandable-ending-optional } - { - Argument~specification~'#2'~for~expandable~command~'#1'~ - ends~with~optional~argument. - } + { Bad~argument~specification~'#2'~for~#1. } { Expandable~commands~must~have~a~final~mandatory~argument~ (or~no~arguments~at~all).~You~cannot~have~a~terminal~optional~ argument~with~expandable~commands. } -\msg_new:nnnn { cmd } { inconsistent-long } - { Inconsistent~long~arguments~for~expandable~command~'#1'. } +\msg_new:nnnn { cmd } { long-short-mix } + { Invalid~argument~prefix~'+'~in~command~'#1'. } { The~arguments~for~an~expandable~command~must~not~involve~short~ - arguments~after~long~arguments.~You~have~tried~to~mix~the~two~types. + arguments~after~long~arguments.~You~have~tried~to~mix~the~two~types~ + when~defining~'#1'. } \msg_new:nnnn { cmd } { invalid-command-arg } - { Argument~type~'#2'~not~available~for~#1. } + { Invalid~argument~type~'#2'~in~#1. } { The~letter~'#2'~can~only~be~used~in~environment~argument~ - specifications,~not~for~commands. + specifications,~but~not~for~commands. \\ \\ - LaTeX~will~ignore~this~entire~definition. + LaTeX~will~ignore~the~entire~definition. } -\msg_new:nnnn { cmd } { invalid-expandable-argument-type } - { Argument~type~'#2'~not~available~for~expandable~command~'#1'. } +\msg_new:nnnn { cmd } { invalid-expandable-arg } + { Invalid~argument~type~'#2'~in~#1. } { The~letter~'#2'~specifies~an~argument~type~which~cannot~be~used~ in~an~expandable~command. \c_@@_ignore_def_tl } \msg_new:nnnn { cmd } { invalid-after-optional-expandably } - { - Argument~type~'#2'~not~available~after~optional~argument~ - for~expandable~command~'#1'. - } + { Argument~'#2'~invalid~after~optional~arg~in~#1. } { The~letter~'#2'~specifies~an~argument~type~which~cannot~be~used~ in~an~expandable~command~after~an~optional~argument. \c_@@_ignore_def_tl } -\msg_new:nnnn { cmd } { non-trailing-obey-spaces } - { Prefix~'!'~used~before~mandatory~argument~'#2'~of~#1. } +\msg_new:nnnn { cmd } { invalid-bang } + { Invalid~argument~prefix~'!'~in~#1. } { - The~prefix~'!'~can~only~apply~to~trailing~optional~arguments. + The~prefix~'!'~is~only~allowed~for~trailing~optional~arguments.~ + You~tried~to~apply~it~to~'#2'. \c_@@_ignore_def_tl } \msg_new:nnnn { cmd } { not-definable } @@ -3611,75 +4348,75 @@ \c_@@_ignore_def_tl } \msg_new:nnnn { cmd } { not-single-token } + { Argument~delimiter~'#2'~invalid~in~#1. } { - Argument~delimiter~'#2'~for~the~#1~should~be~ - a~single~non-space~token. - } - { - The~argument~specification~provided~was~not~valid:~in~a~place~ - where~a~single~token~is~required,~LaTeX~found~'#2'. + The~argument~specification~contains~ + \tl_if_empty:nTF{#2}{nothing}{'#2'}~ + in~a~place~ + where~a~single~token~is~required. \c_@@_ignore_def_tl } -\msg_new:nnnn { cmd } { forbidden-implicit-group-token } - { Argument~delimiter~'#2'~for~the~#1~is~not~allowed. } +\msg_new:nnnn { cmd } { forbidden-group-token } + { Argument~delimiter~'#2'~invalid~in~#1. } { - The~argument~specification~provided~was~not~valid:~the~implicit~ - #3-group~token~'#2'~is~not~allowed~as~an~argument~delimiter. + The~argument~specification~contains~the~implicit~ + #3-group~token~'#2'~which~is~not~allowed~as~an~argument~delimiter. \c_@@_ignore_def_tl } \msg_new:nnnn { cmd } { processor-in-expandable } - { Argument~processor~'>{#2}'~cannot~be~used~for~the~expandable~command~'#1'. } + { Invalid~argument~prefix~'>'~in~command~'#1'. } { - The~argument~specification~for~#1~contains~a~processor~function:~ - this~is~only~supported~for~standard~robust~commands. + The~argument~specification~for~'#1'~contains~the~processor~function~'>{#2}'.~ + This~is~only~supported~for~robust~commands,~but~not~for~expandable~ones. \c_@@_ignore_def_tl } -\msg_new:nnnn { cmd } { too-many-arguments } - { Too~many~arguments~in~argument~specification~'#2'~of~#1. } +\msg_new:nnnn { cmd } { too-many-args } + { Too~many~arguments~for~#1. } { - The~argument~specification~provided~has~more~than~9~arguments.~ + The~argument~specification~'#2'~asks~for~more~than~9~arguments.~ This~cannot~be~implemented. \c_@@_ignore_def_tl } \msg_new:nnnn { cmd } { two-markers } - { Two~'#2'~apply~to~the~same~argument~in~argument~specification~of~#1. } + { Invalid~argument~prefix~'#2'~in~#1. } { - The~argument~specification~provided~has~two~markers~'#2'~applying~ - to~the~same~argument;~these~are~redundant. + The~argument~specification~provided~for~#1~has~two~'#2'~markers~applied~ + to~the~same~argument;~one~is~redundant. } -\msg_new:nnnn { cmd } { unknown-argument-type } - { Unknown~argument~type~'#2'~for~the~#1. } +\msg_new:nnnn { cmd } { unknown-argument-type } % should be unkown-arg-type but dep in xparse + { Invalid~argument~type~'#2'~in~#1. } { The~letter~'#2'~does~not~specify~a~known~argument~type. \c_@@_ignore_def_tl } -\msg_new:nnnn { cmd } { xparse-argument-type } - { Deprecated~argument~type~'#2'~for~the~#1~requires~xparse. } +\msg_new:nnnn { cmd } { xparse-arg-type } + { Invalid~argument~type~'#2'~in~#1~(requires~xparse). } { - The~letter~'#2'~specifies~a~known~argument~type~that~requires~ - the~xparse~package. + The~letter~'#2'~specifies~a~known~but~deprecated~argument~type.~ + If~you~really~need~it~you~have~to~load~the~xparse~package. \c_@@_ignore_def_tl } % \end{macrocode} % % Errors when using commands/environments. The \texttt{if-boolean} % message is always used in expandable errors. The -% \texttt{loop-in-defaults} and \texttt{missing-required} messages can +% \texttt{default-loop} and \texttt{missing-required} messages can % be expandable or not expandable. % \begin{macrocode} \msg_new:nnn { cmd } { if-boolean } - { Invalid~use~\iow_char:N\\IfBooleanTF~{#1} } -\msg_new:nnnn { cmd } { loop-in-defaults } - { Defaults~of~#1~have~circular~dependency. } + { Invalid~argument~{#1}~to~\iow_char:N\\IfBoolean... } +\msg_new:nnnn { cmd } { default-loop } + { Circular~dependency~in~defaults~of~#1. } { The~default~values~of~two~or~more~arguments~of~the~#1~ depend~on~each~other~in~a~way~that~cannot~be~resolved. } \msg_new:nnnn { cmd } { missing-required } - { Missing~required~argument~for~#1. } + { Required~argument~missing~for~#1. } { - The~current~#1~expects~an~argument~starting~with~'#2'.~ - LaTeX~did~not~find~it,~and~will~insert~a~default~value~to~be~processed. + The~#1~expects~one~of~its~arguments~to~start~with~'#2'.~ + LaTeX~did~not~find~this~argument~and~will~insert~a~default~value~ + for~further~processing. } \msg_new:nnnn { cmd } { non-xparse } { \str_uppercase:n #1~not~defined~using~xparse. } @@ -3687,12 +4424,12 @@ You~have~asked~for~the~argument~specification~for~the~#1,~ but~this~was~not~defined~using~xparse. } -\msg_new:nnnn { cmd } { split-excess-tokens } - { Too~many~'#1'~tokens~when~trying~to~split~argument. } +\msg_new:nnnn { cmd } { arg-split } + { Too~many~'#1'~separators~in~argument. } { LaTeX~was~asked~to~split~the~input~'#3'~ - at~each~occurrence~of~the~token~'#1',~up~to~a~maximum~of~#2~parts.~ - There~were~too~many~'#1'~tokens. + at~each~occurrence~of~the~separator~'#1'~into~#2~parts.~ + Too~many~separators~were~found. } \msg_new:nnnn { cmd } { unknown } { Unknown~document~#1. } @@ -3700,54 +4437,62 @@ You~have~asked~for~the~argument~specification~for~the~#1,~ but~it~is~not~defined. } -\msg_new:nnnn { cmd } { verbatim-newline } - { Verbatim~argument~of~#1~ended~by~end~of~line. } +\msg_new:nnnn { cmd } { verbatim-nl } + { Verbatim-like~#1~ended~by~end~of~line. } { The~verbatim~argument~of~the~#1~cannot~contain~more~than~one~line,~ but~the~end~ of~the~current~line~has~been~reached.~You~may~have~forgotten~the~ closing~delimiter. \\ \\ - LaTeX~will~ignore~'#2'. + LaTeX~will~ignore~'#2'~and~you~may~get~some~additional~ + (low-level)~errors. } \msg_new:nnnn { cmd } { verbatim-tokenized } - { The~verbatim~#1~cannot~be~used~inside~an~argument. } + { Verbatim-like~#1~illegal~in~argument. } { - The~#1~takes~a~verbatim~argument.~ - It~may~not~appear~within~the~argument~of~another~function.~ - It~received~an~illegal~token \tl_if_empty:nF {#3} { ~'#3' } . + The~#1~takes~a~verbatim~argument~and~should~therefore~normally~ + not~be~used~in~arguments~of~other~commands~or~environments.~ + LaTeX~found~an~illegal~token~ \tl_if_empty:nF {#3} { (#3)~ } + after~'#2'~and~will~drop~everything~up~to~this~point. \\ \\ - LaTeX~will~ignore~'#2'. + Expect~further~(low-level)~errors. } % \end{macrocode} % % Intended more for information. % \begin{macrocode} -\msg_new:nnn { cmd } { define-command } +\msg_new:nnn { cmd } { define-command } % should be just ``define'' but dep in xparse { Defining~command~#1~ with~sig.~'#2'~\msg_line_context:. } -\msg_new:nnn { cmd } { define-environment } +\msg_new:nnn { cmd } { define-env } { Defining~environment~'#1'~ with~sig.~'#2'~\msg_line_context:. } -\msg_new:nnn { cmd } { redefine-command } +\msg_new:nnn { cmd } { redefine } { Redefining~command~#1~ with~sig.~'#2'~\msg_line_context:. } -\msg_new:nnn { cmd } { redefine-environment } +\msg_new:nnn { cmd } { redefine-env } { Redefining~environment~'#1'~ with~sig.~'#2'~\msg_line_context:. } \msg_new:nnn { cmd } { optional-mandatory } { - Since~the~mandatory~argument~'#1'~has~the~same~delimiter~'#2'~ - as~a~previous~optional~argument,~it~will~not~be~possible~to~ - omit~all~optional~arguments~when~calling~this~command. + Optional~and~mandatory~argument~with~same~delimiter~'#2'. + \\ \\ + The~mandatory~argument~specified~with~ + '\str_case:nnF{#1}{ {R/r}{r'~or~'R} }{#1}'~has~the~ + same~delimiter~'#2'~as~an~earlier~optional~argument.~ + It~will~therefore~not~be~possible~to~omit~all~the~earlier~ + optional~arguments~when~calling~this~command. + \\ \\ + This~may~be~intentional,~but~then~it~might~be~a~mistake. } \msg_new:nnn { cmd } { unsupported-let } { @@ -3787,7 +4532,7 @@ { \cs_if_exist:NTF #1 { - \msg_error:nnxx { cmd } { command-already-defined } + \msg_error:nnxx { cmd } { already-defined } { \use:nnn \token_to_str:N #1 { } } { \token_to_str:N \NewDocumentCommand } } @@ -3801,7 +4546,7 @@ \cs_if_exist:NTF #1 { \@@_declare_cmd:Nnn #1 {#2} {#3} } { - \msg_error:nnxx { cmd } { command-not-yet-defined } + \msg_error:nnxx { cmd } { undefined } { \use:nnn \token_to_str:N #1 { } } { \token_to_str:N \RenewDocumentCommand } } @@ -3824,6 +4569,7 @@ % \end{macro} % % \begin{macro}{\NewDocumentEnvironment} +% \changes{v1.0h}{2021/08/27}{Check for end-of-environment command} % \begin{macro}{\RenewDocumentEnvironment} % \begin{macro}{\ProvideDocumentEnvironment} % \begin{macro}{\DeclareDocumentEnvironment} @@ -3832,14 +4578,18 @@ \cs_new_protected:Npn \NewDocumentEnvironment #1#2#3#4 { \cs_if_exist:cTF {#1} - { \msg_error:nnx { cmd } { environment-already-defined } {#1} } - { \@@_declare_env:nnnn {#1} {#2} {#3} {#4} } + { \msg_error:nnx { cmd } { env-already-defined } {#1} } + { + \cs_if_exist:cTF { end #1 } + { \msg_error:nnx { cmd } { env-end-already-defined } {#1} } + { \@@_declare_env:nnnn {#1} {#2} {#3} {#4} } + } } \cs_new_protected:Npn \RenewDocumentEnvironment #1#2#3#4 { \cs_if_exist:cTF {#1} { \@@_declare_env:nnnn {#1} {#2} {#3} {#4} } - { \msg_error:nnx { cmd } { environment-not-yet-defined } {#1} } + { \msg_error:nnx { cmd } { env-undefined } {#1} } } \cs_new_protected:Npn \ProvideDocumentEnvironment #1#2#3#4 { \cs_if_exist:cF {#1} { \@@_declare_env:nnnn {#1} {#2} {#3} {#4} } } @@ -3866,7 +4616,7 @@ { \cs_if_exist:NTF #1 { - \msg_error:nnxx { cmd } { command-already-defined } + \msg_error:nnxx { cmd } { already-defined } { \use:nnn \token_to_str:N #1 { } } { \token_to_str:N \NewExpandableDocumentCommand } } @@ -3880,7 +4630,7 @@ \cs_if_exist:NTF #1 { \@@_declare_expandable_cmd:Nnn #1 {#2} {#3} } { - \msg_error:nnxx { cmd } { command-not-yet-defined } + \msg_error:nnxx { cmd } { undefined } { \use:nnn \token_to_str:N #1 { } } { \token_to_str:N \RenewExpandableDocumentCommand } } @@ -4032,3 +4782,4 @@ % \end{macrocode} % % \Finale + diff --git a/Master/texmf-dist/source/latex/base/ltcmdhooks.dtx b/Master/texmf-dist/source/latex/base/ltcmdhooks.dtx index 40cd55e52c7..208f7c3d22c 100644 --- a/Master/texmf-dist/source/latex/base/ltcmdhooks.dtx +++ b/Master/texmf-dist/source/latex/base/ltcmdhooks.dtx @@ -13,21 +13,14 @@ % %%% From File: ltcmdhooks.dtx % -\def\ltcmdhooksversion{v1.0b} -\def\ltcmdhooksdate{2021/05/26} +\def\ltcmdhooksversion{v1.0f} +\def\ltcmdhooksdate{2021/10/20} % % % %<*driver> \documentclass{l3doc} %\usepackage{ltcmdhooks} -\makeatletter -\providecommand\footref[1]{% - \begingroup - \unrestored@protected@xdef\@thefnmark{\ref{#1}}% - \endgroup - \@footnotemark} -\makeatother \EnableCrossrefs \CodelineIndex \begin{document} @@ -360,19 +353,46 @@ % \end{macro} % % \begin{macro}{\l_@@_patch_prefixes_tl} -% \begin{macro}{\l_@@_patch_param_text_tl} -% \begin{macro}{\l_@@_patch_replacement_tl} +% \begin{macro}{\l_@@_param_text_tl} +% \begin{macro}{\l_@@_replace_text_tl} % The prefixes and parameters of the definition for the macro being % patched. % \begin{macrocode} \tl_new:N \l_@@_patch_prefixes_tl -\tl_new:N \l_@@_patch_param_text_tl -\tl_new:N \l_@@_patch_replacement_tl +\tl_new:N \l_@@_param_text_tl +\tl_new:N \l_@@_replace_text_tl % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % +% \begin{macro}{\c_@@_hash_tl} +% A constant token list that contains two parameter tokens. +% \begin{macrocode} +\tl_const:Nn \c_@@_hash_tl { # # } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\@@_exp_not:NN} +% \begin{macro}{\@@_def_cmd:w} +% Two temporary macros that change depending on the macro being +% patched. +% \begin{macrocode} +\cs_new_eq:NN \@@_exp_not:NN ? +\cs_new_eq:NN \@@_def_cmd:w ? +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\q_@@_recursion_tail,\q_@@_recursion_stop} +% Internal quarks for recursion: they can't appear in any macro being +% patched. +% \begin{macrocode} +\quark_new:N \q_@@_recursion_tail +\quark_new:N \q_@@_recursion_stop +% \end{macrocode} +% \end{macro} +% % \begin{macro}{\g_@@_delayed_patches_prop} % A list containing the patches delayed to |\begin{document}|, so that % patching is not attempted twice. @@ -400,24 +420,44 @@ % % \subsection{Patching or delaying} % -% \begin{macro}{\@@_try_put_cmd_hook:n,\@@_try_put_cmd_hook:w} % Before |\begin{document}| all patching is delayed. +% +% \begin{macro}{\@@_try_put_cmd_hook:n,\@@_try_put_cmd_hook:w} % This function is called from within \cs{AddToHook}, when code is -% added to a generic |cmd| hook is newly declared. It checks whether -% the patch position is valid, then proceeds to trying to patch or -% delaying to |\begin{document}| if in the preamble. +% first added to a generic |cmd| hook. +% If it is called within in the preamble, it delays the action +% until |\begin{document}|; +% otherwise it tries to update the hook. +% \changes{v1.0d}{2021/08/25}{Simplify generic hook detection} % \begin{macrocode} +%\IncludeInRelease{2021/11/15}{\@@_try_put_cmd_hook:n}% +% {Standardise~generic~hook~names} \cs_new_protected:Npn \@@_try_put_cmd_hook:n #1 { \@@_try_put_cmd_hook:w #1 / / / \s_@@_mark {#1} } \cs_new_protected:Npn \@@_try_put_cmd_hook:w #1 / #2 / #3 / #4 \s_@@_mark #5 { \@@_debug:n { \iow_term:n { ->~Adding~cmd~hook~to~'#2'~(#3): } } - \str_case:nnTF {#3} - { { before } { } { after } { } } - { \exp_args:Nc \@@_patch_cmd_or_delay:Nnn {#2} {#2} {#3} } - { \msg_error:nnnn { hooks } { wrong-cmd-hook } {#2} {#3} } + \exp_args:Nc \@@_patch_cmd_or_delay:Nnn {#2} {#2} {#3} } +%\EndIncludeInRelease +% \end{macrocode} +% +% \begin{macrocode} +%\IncludeInRelease{2021/06/01}{\@@_try_put_cmd_hook:n}% +% {Standardise~generic~hook~names} +%\cs_new_protected:Npn \@@_try_put_cmd_hook:n #1 +% { \@@_try_put_cmd_hook:w #1 / / / \s_@@_mark {#1} } +%\cs_new_protected:Npn \@@_try_put_cmd_hook:w +% #1 / #2 / #3 / #4 \s_@@_mark #5 +% { +% \@@_debug:n { \iow_term:n { ->~Adding~cmd~hook~to~'#2'~(#3): } } +% \str_case:nnTF {#3} +% { { before } { } { after } { } } +% { \exp_args:Nc \@@_patch_cmd_or_delay:Nnn {#2} {#2} {#3} } +% { \msg_error:nnnn { hooks } { wrong-cmd-hook } {#2} {#3} } +% } +%\EndIncludeInRelease % \end{macrocode} % \end{macro} % @@ -592,17 +632,28 @@ % % With \cs{@@_patch_DeclareRobustCommand:Nnn} we check if the command % has an optional argument (with a test counter-intuitively called -% \tn{@if@newcommand}). If so, we forward the action to -% \cs{@@_patch_newcommand:Nnn}, otherwise call the patching engine +% \tn{@if@newcommand}; also make sure the command doesn't take args by +% calling \cs{robust@command@chk@safe}). If so, we pass the patching action +% to \cs{@@_patch_newcommand:Nnn}, otherwise we call the patching engine % \cs{@@_patch_expand_redefine:NNnn} with a \cs{c_false_bool} to % indicate that there is no optional argument. +% +% \changes{v1.0c}{2021/07/20} +% {Use \cs{robust@command@chk@safe} before \cs{@if@newcommand}.} % \begin{macrocode} \cs_new_protected:Npn \@@_patch_DeclareRobustCommand:Nnn #1 { - \exp_args:Nc \@if@newcommand { \cs_to_str:N #1 ~ } - { \exp_args:Nc \@@_patch_newcommand:Nnn } - { \exp_args:NNc \@@_patch_expand_redefine:NNnn \c_false_bool } - { \cs_to_str:N #1 ~ } + \exp_args:Nc \@@_patch_DeclareRobustCommand_aux:Nnn + { \cs_to_str:N #1 ~ } + } +\cs_new_protected:Npn \@@_patch_DeclareRobustCommand_aux:Nnn #1 + { + \robust@command@chk@safe #1 + { \@if@newcommand #1 } + { \use_ii:nn } + { \@@_patch_newcommand:Nnn } + { \@@_patch_expand_redefine:NNnn \c_false_bool } + #1 } % \end{macrocode} % \end{macro} @@ -639,13 +690,71 @@ % % % +% % \begin{macro}{\@@_patch_expand_redefine:NNnn} +% \begin{macro}{\@@_redefine_with_hooks:Nnnn} % \begin{macro}[EXP]{\@@_make_prefixes:w} % Now the real action begins. Here we have in |#1| a boolean -% indicating if the command has a |[|\ldots|]|-delimited argument, in -% |#2| the command control sequence, in |#3| the name of the command -% (note that |#1|${}\ne{}$|\csname#2\endcsname| at this point!), and -% in |#4| the hook position, either |before| or |after|. +% indicating if the command has a leading |[|\ldots|]|-delimited +% argument, in |#2| the command control sequence, in |#3| the name of +% the command (note that |#1|${}\ne{}$|\csname#2\endcsname| at this +% point!), and in |#4| the hook position, either |before| or |after|. +% +% \changes{v1.0f}{2021/10/20} +% {Correct patching by expansion+redefinition when the macro +% contains a parameter tokens (gh/697).} +% Patching with expansion+redefinition is trickier than it looks like +% at first glance. Suppose the simple definition: +% \begin{verbatim} +% \def\foo#1{#1##2} +% \end{verbatim} +% When defined, its \meta{replacement text} will be a token list +% containing: +% \begin{quote} +% \itshape +% out\_param |1|, mac\_param |#|, character |2| +% \end{quote} +% +% Then, after expanding \cs{foo}|{##1}| (here |##| denotes a single +% |#|$_6$) we end up with a token list with \textit{out\_param}~|1| +% replaced: +% \begin{quote} +% \itshape +% mac\_param |#|, character |1|, mac\_param |#|, character |2| +% \end{quote} +% that is, the definition would be: +% \begin{verbatim} +% \def\foo#1{#1#2} +% \end{verbatim} +% which obviously fails, because the original input in the definition +% was |##| but \TeX{} reduced that to a single parameter token |#|$_6$ +% when carrying out the definition. That leaves no room for a clever +% solution with (say) \cs{unexpanded}, because anything that would +% double the second |#|$_6$, would also (incorrectly) double the +% first, so there's not much to do other than a manual solution. +% +% There are three cases we can distinguish to make things hopefully +% faster on simpler cases: +% \begin{enumerate} +% \item a macro with no parameters; +% \item a macro with no parameter tokens in its definition; +% \item a macro with parameters \emph{and} parameter tokens. +% \end{enumerate} +% +% The first case is trivial: if the macro has no parameters, we can +% just use \cs{unexpanded} around it, and if there is a parameter +% token in it, it is handled correctly (the macro can be treated as a +% |tl| variable). +% +% The second case requires looking at the \meta{replacement text} of +% the macro to see if it has a parameter token in there. If it does +% not, then there is no worry, and the macro can be redefined normally +% (without \cs{unexpanded}). +% +% The third case, as usual, is the devious one. Here we'll have to +% loop through the definition token by token, and double every +% parameter token, so that this case can be handled like the previous +% one. % \begin{macrocode} \cs_new_protected:Npn \@@_patch_expand_redefine:NNnn #1 #2 #3 #4 { @@ -665,36 +774,93 @@ % \end{macrocode} % Now build two token lists: % \begin{description} -% \item[\cs{l_@@_patch_param_text_tl}] will contain the +% \item[\cs{l_@@_param_text_tl}] will contain the % \meta{parameter text} to be used when redefining the macro. It % should be identical to the \meta{parameter text} used when % originally defining that macro. -% \item[\cs{l_@@_patch_replacement_tl}] will contain braced pairs of -% |#|$_{12}$\meta{num} to feed to the macro when expanded. This -% token list as well as the previous will have the first item +% \item[\cs{l_@@_replace_text_tl}] will contain braced pairs of +% \cs{c_@@_hash_tl}\meta{num} to feed to the macro when expanded. +% This token list as well as the previous will have the first item % surrounded by |[|\ldots|]| in the case of an optional argument. % \end{description} +% +% The use of \cs{c_@@_hash_tl} here is to differentiate actual +% parameters in the macro from parameter tokens in the original +% definition of the macro. Later on, \cs{c_@@_hash_tl} is either +% replaced by actual parameter tokens, or expanded into them. % \begin{macrocode} \int_compare:nNnTF { \l_@@_patch_num_args_int } > { \c_zero_int } { - \tl_set:Nx \l_@@_patch_param_text_tl - { \bool_if:NTF #1 { [####1] } { ####1 } } - \tl_set:Nx \l_@@_patch_replacement_tl - { \bool_if:NTF #1 { [####1] } { {####1} } } +% \end{macrocode} +% We'll first check if the command has any parameter token in its +% definition (feeding it empty arguments), and set \cs{@@_exp_not:n} +% accordingly. \cs{@@_exp_not:n} will be used later to either leave +% \cs{c_@@_hash_tl} or expand it, and also to remember the result of +% \cs{@@_if_has_hash:nTF} to avoid testing twice (the test can be +% rather slow). +% \begin{macrocode} + \tl_set:Nx \l_@@_tmpa_tl { \bool_if:NTF #1 { [ ] } { { } } } \int_step_inline:nnn { 2 } { \l_@@_patch_num_args_int } + { \tl_put_right:Nn \l_@@_tmpa_tl { { } } } + \exp_args:NNo \exp_args:No \@@_if_has_hash:nTF + { \exp_after:wN #2 \l_@@_tmpa_tl } + { \cs_set_eq:NN \@@_exp_not:n \exp_not:n } + { \cs_set_eq:NN \@@_exp_not:n \use:n } + \cs_set_protected:Npn \@@_tmp:w ##1 ##2 { - \tl_put_right:Nn \l_@@_patch_param_text_tl { ## ####1 } - \tl_put_right:Nn \l_@@_patch_replacement_tl { { ## ####1 } } + ##1 \l_@@_param_text_tl { \use:n ##2 } + ##1 \l_@@_replace_text_tl { \@@_exp_not:n {##2} } } +% \end{macrocode} +% Here we'll conditionally add |[|\ldots|]| around the first +% parameter: +% \begin{macrocode} + \bool_if:NTF #1 + { \@@_tmp:w \tl_set:Nx { [ \c_@@_hash_tl 1 ] } } + { \@@_tmp:w \tl_set:Nx { { \c_@@_hash_tl 1 } } } +% \end{macrocode} +% Then, for every parameter from the second, just add it normally: +% \begin{macrocode} + \int_step_inline:nnn { 2 } { \l_@@_patch_num_args_int } + { \@@_tmp:w \tl_put_right:Nx { { \c_@@_hash_tl ##1 } } } +% \end{macrocode} +% Now, if the command has any parameter token in its definition +% (then \cs{@@_exp_not:n} is \cs{exp_not:n}), call +% \cs{@@_double_hashes:n} to double them, and replace every +% \cs{c_@@_hash_tl} by |#|: +% \begin{macrocode} + \tl_set:Nx \l_@@_replace_text_tl + { \exp_not:N #2 \exp_not:V \l_@@_replace_text_tl } + \tl_set:Nx \l_@@_replace_text_tl + { + \token_if_eq_meaning:NNTF \@@_exp_not:n \exp_not:n + { \exp_args:NNV \exp_args:No \@@_double_hashes:n } + { \exp_args:NV \exp_not:o } + \l_@@_replace_text_tl + } +% \end{macrocode} +% And now, set a few auxiliaries for the case that the macro has +% parameters, so it won't be passed through \cs{unexpanded} (twice): +% \begin{macrocode} + \cs_set_eq:NN \@@_def_cmd:w \tex_gdef:D + \cs_set_eq:NN \@@_exp_not:NN \prg_do_nothing: } { - \tl_clear:N \l_@@_patch_param_text_tl - \tl_clear:N \l_@@_patch_replacement_tl +% \end{macrocode} +% In the case the macro has no parameters, we'll treat it as a token +% list and things are much simpler (expansion control looks a bit +% complicated, but it's just a pair of \cs{exp_not:N} preventing +% another \cs{exp_not:n} from expanding): +% \begin{macrocode} + \tl_clear:N \l_@@_param_text_tl + \tl_set_eq:NN \l_@@_replace_text_tl #2 + \cs_set_eq:NN \@@_def_cmd:w \tex_xdef:D + \cs_set:Npn \@@_exp_not:NN ##1 { \exp_not:N ##1 \exp_not:N } } % \end{macrocode} -% Finally, before redefining, we need to also get the prefixes used -% when defining the command. Here we ensure that the \tn{escapechar} -% is printable, otherwise a macro defined with prefixes +% Before redefining, we need to also get the prefixes used when +% defining the command. Here we ensure that the \tn{escapechar} is +% printable, otherwise a macro defined with prefixes % |\protected \long| will have it \tn{meaning} printed as % |protectedlong|, making life unnecessarily complicated. Here the % \tn{escapechar} is changed to |/|, then we loop between pairs of @@ -709,34 +875,47 @@ { \exp_not:N \@@_make_prefixes:w \cs_prefix_spec:N #2 / / } } % \end{macrocode} -% Now that all the needed tools are ready, without further ado we'll -% redefine the command |#2|. The definition uses the prefixes -% gathered in \cs{l_@@_patch_prefixes_tl}, a primitive \cs{tex_def:D} -% to avoid adding extra prefixes, and the \meta{parameter text} from -% \cs{l_@@_patch_param_text_tl}. -% -% Then finally, in the body of the definition, we insert -% \hook{cmd/\#3/before} if |#4| is |before|, the code of the -% command expanded once grabbing the parameters in -% \cs{l_@@_patch_replacement_tl}, and \hook{cmd/\#3/after} if |#4| is -% |after|. +% Finally, call \cs{@@_redefine_with_hooks:Nnnn} with the macro being +% redefined in |#1|, then \cs{UseHook}|{cmd//before}| in |#2| or +% \cs{UseHook}|{cmd//after}| in |#3| (one is always empty), and +% in |#4| the \meta{replacement text} of the macro. % \begin{macrocode} \use:x { - \l_@@_patch_prefixes_tl \tex_def:D - \exp_not:N #2 \exp_not:V \l_@@_patch_param_text_tl - { - \str_if_eq:nnT {#4} { before } - { \exp_not:N \UseHook { cmd / #3 / #4 } } - \exp_args:No \exp_not:o - { \exp_after:wN #2 \l_@@_patch_replacement_tl } - \str_if_eq:nnT {#4} { after } - { \exp_not:N \UseHook { cmd / #3 / #4 } } - } + \@@_redefine_with_hooks:Nnnn \exp_not:N #2 + \str_if_eq:nnTF {#4} { after } + { \use_ii_i:nn } + { \use:nn } + { { \@@_exp_not:NN \exp_not:N \UseHook { cmd / #3 / #4 } } } + { { } } + { \@@_exp_not:NN \exp_not:V \l_@@_replace_text_tl } } } % \end{macrocode} % +% Now that all the needed tools are ready, without further ado we'll +% redefine the command. The definition uses the prefixes gathered in +% \cs{l_@@_patch_prefixes_tl}, a primitive \cs{@@_def_cmd:w} (which is +% \cs{tex_gdef:D} or \cs{tex_xdef:D}) to avoid adding extra prefixes, +% and the \meta{parameter text} from \cs{l_@@_param_text_tl}. +% +% Then finally, in the body of the definition, we insert |#2|, which +% is \hook{cmd/\#1/before} or empty, |#4| which is the +% \meta{replacement text}, and |#3| which is \hook{cmd/\#1/after} or +% empty. +% +% \changes{v1.0e}{2021/09/28} +% {Make patching of commands a global operation (gh/674)} +% \begin{macrocode} +\cs_new_protected:Npn \@@_redefine_with_hooks:Nnnn #1 #2 #3 #4 + { + \l_@@_patch_prefixes_tl + \exp_after:wN \@@_def_cmd:w + \exp_after:wN #1 \l_@@_param_text_tl + { #2 #4 #3 } + } +% \end{macrocode} +% % Here's the auxiliary that makes the prefix control sequences for the % redefinition. Each item has to be \cs{tl_trim_spaces:n}'d because % the last item (and not any other) has a trailing space. @@ -752,11 +931,125 @@ % \end{macrocode} % \end{macro} % \end{macro} +% \end{macro} % % +% Here are some auxiliaries for the contraption above. % +% \begin{macro}[pTF]{\@@_if_has_hash:n} +% \begin{macro}{\@@_if_has_hash:w,\@@_if_has_hash_check:w} +% \cs{@@_if_has_hash:nTF} searches the token list |#1| for a catcode~6 +% token, and if any is found, it returns |true|, and |false| +% otherwise. The searching doesn't care about preserving groups or +% spaces: we can ignore those safely (braces are removed) so that +% searching is as fast as possible. +% \begin{macrocode} +\prg_new_conditional:Npnn \@@_if_has_hash:n #1 { TF } + { \@@_if_has_hash:w #1 ## \s_@@_mark } +\cs_new:Npn \@@_if_has_hash:w #1 + { + \tl_if_single_token:nTF {#1} + { + \token_if_eq_catcode:NNTF ## #1 + { \@@_if_has_hash_check:w } + { \@@_if_has_hash:w } + } + { \@@_if_has_hash:w #1 } + } +\cs_new:Npn \@@_if_has_hash_check:w #1 \s_@@_mark + { \tl_if_empty:nTF {#1} { \prg_return_false: } { \prg_return_true: } } +% \end{macrocode} +% \end{macro} +% \end{macro} % % +% \begin{macro}[rEXP]{\@@_double_hashes:n} +% \begin{macro}[rEXP]{ +% \@@_double_hashes:w, +% \@@_double_hashes_output:N, +% \@@_double_hashes_stop:w, +% \@@_double_hashes_group:n, +% \@@_double_hashes_space:w, +% } +% \cs{@@_double_hashes:n} loops through the token list |#1| and +% duplicates any catcode~6 token, and expands tokens \cs{ifx}-equal to +% \cs{c_@@_hash_tl}, and leaves all other tokens \cs{notexpanded} with +% \cs{exp_not:N}. Unfortunately pairs of explicit catcode~1 and +% catcode~2 character tokens are normalised to |{|$_1$ and |}|$_1$ +% because it's not feasible to expandably detect the character code +% (\emph{maybe} it could be done using something along the lines of +% \url{https://tex.stackexchange.com/a/527538}, but it's far too much +% work for close to zero benefit). +% +% \cs{@@_double_hashes:w} is the tail-recursive loop macro, that tests +% which of the three types of item is in the head of the token list. +% \begin{macrocode} +\cs_new:Npn \@@_double_hashes:n #1 + { \@@_double_hashes:w #1 \q_@@_recursion_tail \q_@@_recursion_stop } +\cs_new:Npn \@@_double_hashes:w #1 \q_@@_recursion_stop + { + \tl_if_head_is_N_type:nTF {#1} + { \@@_double_hashes_output:N } + { + \tl_if_head_is_group:nTF {#1} + { \@@_double_hashes_group:n } + { \@@_double_hashes_space:w } + } + #1 \q_@@_recursion_stop + } +% \end{macrocode} +% +% \cs{@@_double_hashes_output:N} checks for the end of the token list, +% then checks if the token is \cs{c_@@_hash_tl}, and if so just leaves +% it. +% \begin{macrocode} +\cs_new:Npn \@@_double_hashes_output:N #1 + { + \if_meaning:w \q_@@_recursion_tail #1 + \@@_double_hashes_stop:w + \fi: + \if_meaning:w \c_@@_hash_tl #1 +% \end{macrocode} +% (this \cs{use_i:nnnn} uses \cs{fi:} and consumes \cs{use:n}, the +% whole \cs{if_catcode:w} block, and the \cs{exp_not:N}, leaving just +% |#1| which is \cs{c_@@_hash_tl}.) +% \begin{macrocode} + \use_i:nnnn + \fi: + \use:n + { +% \end{macrocode} +% If |#1| is not \cs{c_@@_hash_tl}, then check if its catcode is~6, +% and if so, leave it doubled in \cs{exp_not:n} and consume the +% following |\exp_not:N #1|. +% \begin{macrocode} + \if_catcode:w ## \exp_not:N #1 + \exp_after:wN \use_ii:nnnn + \fi: + \use_none:n + { \exp_not:n { #1 #1 } } + } +% \end{macrocode} +% If both previous tests returned |false|, then leave the token +% unexpanded and resume the loop. +% \begin{macrocode} + \exp_not:N #1 + \@@_double_hashes:w + } +\cs_new:Npn \@@_double_hashes_stop:w #1 \q_@@_recursion_stop { \fi: } +% \end{macrocode} +% +% Dealing with spaces and grouped tokens is trivial: +% \begin{macrocode} +\cs_new:Npn \@@_double_hashes_group:n #1 + { { \@@_double_hashes:n {#1} } \@@_double_hashes:w } +\exp_last_unbraced:NNo +\cs_new:Npn \@@_double_hashes_space:w \c_space_tl + { ~ \@@_double_hashes:w } +% \end{macrocode} +% \end{macro} +% \end{macro} +% % % \subsubsection{Patching by retokenization} % @@ -1030,8 +1323,11 @@ % \end{macrocode} % And to close, copy the newly-defined command into the old name and % the patching is finally completed: +% +% \changes{v1.0e}{2021/09/28} +% {Make patching of commands a global operation (gh/674)} % \begin{macrocode} - \cs_set_eq:NN #1 \kerneltmpDoNotUse + \cs_gset_eq:NN #1 \kerneltmpDoNotUse } % \end{macrocode} % \end{macro} @@ -1039,15 +1335,21 @@ % \subsection{Messages} % % \begin{macrocode} -\msg_new:nnnn { hooks } { wrong-cmd-hook } - { - Generic~hook~`cmd/#1/#2'~is~invalid. -% The~hook~should~be~`cmd/#1/before'~or~`cmd/#1/after'. - } - { - You~tried~to~add~a~generic~hook~to~command~\iow_char:N \\#1,~but~`#2'~ - is~an~invalid~component.~Only~`before'~or~`after'~are~allowed. - } +%\IncludeInRelease{2021/11/15}{wrong-cmd-hook}% +% {Standardise~generic~hook~names} +%\EndIncludeInRelease +%\IncludeInRelease{2021/11/15}{wrong-cmd-hook}% +% {Standardise~generic~hook~names} +%\msg_new:nnnn { hooks } { wrong-cmd-hook } +% { +% Generic~hook~`cmd/#1/#2'~is~invalid. +%% The~hook~should~be~`cmd/#1/before'~or~`cmd/#1/after'. +% } +% { +% You~tried~to~add~a~generic~hook~to~command~\iow_char:N \\#1,~but~`#2'~ +% is~an~invalid~component.~Only~`before'~or~`after'~are~allowed. +% } +%\EndIncludeInRelease \msg_new:nnnn { hooks } { cant-patch } { Generic~hooks~cannot~be~added~to~'#1'. diff --git a/Master/texmf-dist/source/latex/base/ltcounts.dtx b/Master/texmf-dist/source/latex/base/ltcounts.dtx index 445cac2f2e4..39fb47728d3 100644 --- a/Master/texmf-dist/source/latex/base/ltcounts.dtx +++ b/Master/texmf-dist/source/latex/base/ltcounts.dtx @@ -33,7 +33,7 @@ %<*driver> % \fi \ProvidesFile{ltcounts.dtx} - [2020/12/04 v1.1l LaTeX Kernel (Counters)] + [2021/07/08 v1.1m LaTeX Kernel (Counters)] % \iffalse \documentclass{ltxdoc} \GetFileInfo{ltcounts.dtx} @@ -106,20 +106,22 @@ % % % \DescribeMacro\counterwithin -% |\counterwithin|\marg{counter}\marg{within-counter}: +% |\counterwithin|\oarg{format}\marg{counter}\marg{within-counter}: % Resets \meta{counter} whenever % \meta{within-counter} is stepped. Also % redefines |\the|\meta{counter} command to produce -% |\the|\meta{within-counter}|.\arabic|\marg{counter}. +% |\the|\meta{within-counter}.\meta{format}\marg{counter} with \cs{arabic} as +% the default for \meta{format}. % Star form omits redefining the print representation. % % \DescribeMacro\counterwithout -% |\counterwithout|\marg{counter}\marg{within-counter}: +% |\counterwithout|\oarg{format}\marg{counter}\marg{within-counter}: % Removes \meta{counter} from the reset list of \meta{within-counter}. % Also % redefines |\the|\meta{counter} command to produce -% |\arabic|\marg{counter}. +% \meta{format}\marg{counter} with \cs{arabic} as +% the default for \meta{format}. % Star form omits redefining the print representation. % % \StopEventually{} @@ -371,67 +373,94 @@ #3}}} % \end{macrocode} % \end{macro} - - -% \begin{macro}{\counterwithout} % -% \changes{v1.1k}{2018/03/08}{Interface added} % \begin{macrocode} -\def\counterwithout {\@ifstar\counterwithout@s\counterwithout@x} +% +%\EndIncludeInRelease +%\IncludeInRelease{0000-00-00} +% {\@removefromreset}{Add interfaces}% +%\let \@removefromreset \undefined +%\let \@ifbothcounters \undefined +%\EndIncludeInRelease +%<*2ekernel> % \end{macrocode} % -% \begin{macrocode} -\def\counterwithout@s#1#2{% - \@ifbothcounters{#1}{#2}{\@removefromreset{#1}{#2}}} -% \end{macrocode} % -% \begin{macrocode} -\def\counterwithout@x#1#2{% - \@ifbothcounters{#1}{#2}% - {\@removefromreset{#1}{#2}% - \expandafter - \gdef\csname the#1\expandafter\endcsname\expandafter - {\expandafter - \@arabic\csname c@#1\endcsname}}} -% \end{macrocode} -% \end{macro} - - - -% \begin{macro}{\counterwithin} % -% \changes{v1.1k}{2018/03/08}{Interface added} +% +% \begin{macro}{\counterwithout,\counterwithin} +% New implementation using xparse and supporting an optional +% format argument. +% \changes{v1.1m}{2021/07/08}{New implementation for +% \cs{counterwithout} and \cs{counterwithin}} % \begin{macrocode} -\def\counterwithin{\@ifstar\counterwithin@s\counterwithin@x} +% +%<*2ekernel|latexrelease> +%\IncludeInRelease{2021/11/15}% +% {\counterwithout}{counter without/within}% % \end{macrocode} % % \begin{macrocode} -\def\counterwithin@s#1#2{% - \@ifbothcounters{#1}{#2}{\@addtoreset{#1}{#2}}} +\NewDocumentCommand \counterwithout {sO{\arabic}mm}{% + \@ifbothcounters{#3}{#4}{% + \@removefromreset{#3}{#4}% + \IfBooleanF #1% + {\expandafter + \gdef\csname the#3\endcsname {#2{#3}}}% + }% +} +% \end{macrocode} +% +% \begin{macrocode} +\NewDocumentCommand \counterwithin {sO{\arabic}mm}{% + \@ifbothcounters{#3}{#4}{% + \@addtoreset{#3}{#4}% + \IfBooleanF #1% + {\expandafter + \gdef\csname the#3\expandafter\endcsname + \expandafter + {\csname the#4\endcsname .#2{#3}}}% + }% +} % \end{macrocode} % -% \changes{v1.1l}{2018/04/11}{Correct default (issue/38)} +% \changes{v1.1k}{2018/03/08}{Interface added} % \begin{macrocode} -\def\counterwithin@x#1#2{% - \@ifbothcounters{#1}{#2}% - {\@addtoreset{#1}{#2}% - \expandafter - \gdef\csname the#1\expandafter\endcsname\expandafter - {\csname the#2\expandafter\endcsname\expandafter - .\expandafter - \@arabic\csname c@#1\endcsname}}} +% +%\EndIncludeInRelease +%\IncludeInRelease{2018-04-01} +% {\counterwithout}{counter without/within}% +% +%\def\counterwithout {\@ifstar\counterwithout@s\counterwithout@x} +%\def\counterwithout@s#1#2{% +% \@ifbothcounters{#1}{#2}{\@removefromreset{#1}{#2}}} +%\def\counterwithout@x#1#2{% +% \@ifbothcounters{#1}{#2}% +% {\@removefromreset{#1}{#2}% +% \expandafter +% \gdef\csname the#1\expandafter\endcsname\expandafter +% {\expandafter +% \@arabic\csname c@#1\endcsname}}} +% +%\def\counterwithin{\@ifstar\counterwithin@s\counterwithin@x} +%\def\counterwithin@s#1#2{% +% \@ifbothcounters{#1}{#2}{\@addtoreset{#1}{#2}}} % \end{macrocode} -% \end{macro} - - % +% \changes{v1.1l}{2018/04/11}{Correct default (issue/38)} % \begin{macrocode} -% +%\def\counterwithin@x#1#2{% +% \@ifbothcounters{#1}{#2}% +% {\@addtoreset{#1}{#2}% +% \expandafter +% \gdef\csname the#1\expandafter\endcsname\expandafter +% {\csname the#2\expandafter\endcsname\expandafter +% .\expandafter +% \@arabic\csname c@#1\endcsname}}} +% %\EndIncludeInRelease %\IncludeInRelease{0000-00-00} -% {\@removefromreset}{Add interfaces}% -%\let \@removefromreset \undefined -%\let \@ifbothcounters \undefined +% {\counterwithout}{counter without/within}% %\let \counterwithout \undefined %\let \counterwithout@s \undefined %\let \counterwithout@x \undefined @@ -441,6 +470,9 @@ %\EndIncludeInRelease %<*2ekernel> % \end{macrocode} +% \end{macro} +% +% % % % Numbering commands for definitions of |\theCOUNTER| and |\list| @@ -596,7 +628,7 @@ % recommended) this unfortunate side effect is not present. % \begin{macrocode} % -%\IncludeInRelease{2015/01/01}{\@fnsymbol}{Use \TexOrMath}% +%\IncludeInRelease{2015/01/01}{\@fnsymbol}{Use \TextOrMath}% %<*2ekernel|latexrelease> \def\@fnsymbol#1{% \ifcase#1\or \TextOrMath\textasteriskcentered *\or @@ -612,7 +644,7 @@ }% % %\EndIncludeInRelease -%\IncludeInRelease{0000/00/00}{\@fnsymbol}{Use \TexOrMath}% +%\IncludeInRelease{0000/00/00}{\@fnsymbol}{Use \TextOrMath}% %\def\@fnsymbol#1{\ensuremath{% % \ifcase#1\or *\or \dagger\or \ddagger\or \mathsection\or % \mathparagraph\or \|\or **\or \dagger\dagger diff --git a/Master/texmf-dist/source/latex/base/ltdefns.dtx b/Master/texmf-dist/source/latex/base/ltdefns.dtx index 4f39d922cce..6c85ca915d2 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} - [2021/05/27 v1.5p LaTeX Kernel (definition commands)] + [2021/06/04 v1.5q LaTeX Kernel (definition commands)] % \iffalse \documentclass{ltxdoc} \GetFileInfo{ltdefns.dtx} @@ -1231,7 +1231,7 @@ \count@=\escapechar \escapechar=`\\ \@ifundefined{\expandafter\@gobble\string#1}{% - \@latex@error{Command `\string#1' is undefined!% + \@latex@error{Command `\string#1' undefined.% \MessageBreak There is nothing here to make robust}% \@eha }% diff --git a/Master/texmf-dist/source/latex/base/lterror.dtx b/Master/texmf-dist/source/latex/base/lterror.dtx index 7f480a0171f..10d93a1dbd1 100644 --- a/Master/texmf-dist/source/latex/base/lterror.dtx +++ b/Master/texmf-dist/source/latex/base/lterror.dtx @@ -32,7 +32,7 @@ %<*driver> % \fi \ProvidesFile{lterror.dtx} - [2019/08/30 v1.2q LaTeX Kernel (errors)] + [2021/08/20 v1.2t LaTeX Kernel (errors)] % \iffalse \documentclass{ltxdoc} \GetFileInfo{lterror.dtx} @@ -375,6 +375,58 @@ Type H for immediate help.}% % \end{macro} % \end{macro} % +% +% +% \begin{macro}{\ClassNote,\ClassNoteNoLine, +% \PackageNote,\PackageNoteNoLine} +% +% \changes{v1.2s}{2021/07/11}{Provide \cs{ClassNote} and \cs{PackageNote}} +% \begin{macrocode} +% +%<*2ekernel|latexrelease> +%\IncludeInRelease{2021/11/15}% +% {\ClassNote}{Notes for classes/packages}% +% \end{macrocode} +% +% \begin{macrocode} +\def\ClassNote#1#2{% + \GenericWarning{% + (#1) \space\space\@spaces\@spaces + }{% + Class #1 Info: #2% + }% +} +\def\ClassNoteNoLine#1#2{\ClassNote{#1}{#2\@gobble}} +% \end{macrocode} +% +% \begin{macrocode} +\def\PackageNote#1#2{% + \GenericWarning{% + (#1) \@spaces\@spaces\@spaces + }{% + Package #1 Info: #2% + }% +} +\def\PackageNoteNoLine#1#2{\PackageNote{#1}{#2\@gobble}} +% +%\EndIncludeInRelease +% \end{macrocode} +% We don't roll back, because if this code is used by packages then +% most often they will not have rollback code implemented, so they +% would immediately break even if they otherwise would work fine. +% \begin{macrocode} +%\IncludeInRelease{0000/00/00}% +% {\ClassNote}{Notes for classes/packages}% +% +%\EndIncludeInRelease +%<*2ekernel> +% \end{macrocode} +% \end{macro} +% +% +% +% +% % \begin{macro}{\@latex@error} % \begin{macro}{\@latex@warning} % \begin{macro}{\@latex@warning@no@line} @@ -446,6 +498,50 @@ Type H for immediate help.}% % \end{macro} % \end{macro} % +% \begin{macro}{\@latex@note} +% \begin{macro}{\@latex@note@no@line} +% These are ``info'' messages that display on the terminal not +% just in the transcript. +% \changes{v1.2r}{2021/06/09}{Macros added} +% \begin{macrocode} +% +%<*2ekernel|latexrelease> +%\IncludeInRelease{2021/11/15}% +% {\@latex@note}{Display notes}% +\def\@latex@note#1{% + \GenericWarning{% + \@spaces\@spaces\@spaces + }{% + LaTeX Info: #1% + }% +} +% \end{macrocode} +% +% \begin{macrocode} +\def\@latex@note@no@line#1{% + \@latex@note{#1\@gobble}} +% \end{macrocode} +% +% We don't make them undefined but rather point to \cs{@latex@info} +% because that's what they replace. This way we can change +% \cs{@latex@info} elsewhere without the need to further rollback +% sections. +% \begin{macrocode} +% +%\EndIncludeInRelease +%\IncludeInRelease{0000/00/00}% +% {\@latex@note}{Display notes}% +% +%\let\@latex@note\@latex@info +%\let\@latex@note@no@line\@latex@info@no@line +%\EndIncludeInRelease +%<*2ekernel> +% \end{macrocode} +% +% \end{macro} +% \end{macro} +% +% % \begin{macro}{\c@errorcontextlines} % \changes{LaTeX2e}{1993/11/22}{Macro added} % |\errorcontextlines| as a \LaTeX\ counter, so that it may be @@ -591,10 +687,19 @@ Type H for immediate help.}% % RmS 1992/08/24: added code to |\@badend| to display position of % non-matching |\begin|. % FMi 1993/01/14: missing space added. +% +% The environment name has to literally match, i.e., what is stored +% in \cs{@currenvir} (after one expansion) must match what is +% passed to \cs{end} (without expansion). If not we complain. Not +% the absolute best solution but at least it avoids getting +% \verb=\begin{foo} ended by \end{foo}= which was possible in the +% past. +% \changes{v1.2t}{2021/08/20}{Improve \cs{@badend} error message (gh/587)} % \begin{macrocode} \gdef\@badend#1{% - \@latex@error{\protect\begin{\@currenvir}\@currenvline - \space ended by \protect\end{#1}}\@eha} + \@latex@error{\protect\begin + {\detokenize\expandafter{\@currenvir}}\@currenvline + \space ended by \protect\end{\detokenize{#1}}}\@eha} % \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 6d7ec3ff60b..021edc644c3 100644 --- a/Master/texmf-dist/source/latex/base/ltexpl.dtx +++ b/Master/texmf-dist/source/latex/base/ltexpl.dtx @@ -86,7 +86,7 @@ % \end{macrocode} % We only initialize these kernel hooks if they are not already % existing. Otherwise they would be set to \cs{@empty} on rollback -% which would be wrong because code that has been added to to them +% which would be wrong because code that has been added to them % may still have to be executed in the rollback situation . Instead % code that writes to them needs to handle the rollback as needed. % It is likely that we have to change that approach in the future, diff --git a/Master/texmf-dist/source/latex/base/ltfilehook.dtx b/Master/texmf-dist/source/latex/base/ltfilehook.dtx index 5d0acc8fdfb..000f4d8c2a2 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.0k} -\providecommand\ltfilehookdate{2021/05/25} +\providecommand\ltfilehookversion{v1.0l} +\providecommand\ltfilehookdate{2021/08/27} % \end{macrocode} % %<*driver> @@ -48,7 +48,7 @@ \vbox_unpack_drop:N \l__codedoc_macro_box \hbox { \llap { \__codedoc_print_macroname:nN {#1} #2 \MacroFont % <----- without it the \ is in lmr10 if a link is made - \ + \ } } } \int_incr:N \l__codedoc_macro_int @@ -115,12 +115,12 @@ % \cs{usepackage}, etc. They are not called for files read using % internal low-level methods, such as \cs{@input} or \cs{openin}. % -% \begin{variable}{file/before,file/before/..., -% file/after/...,file/after, +% \begin{variable}{file/before,file/.../before, +% file/.../after,file/after, % } % These are: % \begin{description} -% \item[\texttt{file/before}, \texttt{file/before/\meta{file-name}}] +% \item[\texttt{file/before}, \texttt{file/\meta{file-name}/before}] % % These hooks are executed in that order just before the file is % loaded for reading. The code of the first hook is used @@ -128,7 +128,7 @@ % file with matching \meta{file-name} allowing you to specify % code that only applies to one file. % -% \item[\texttt{file/after/\meta{file-name}}, \texttt{file/after}] +% \item[\texttt{file/\meta{file-name}/after}, \texttt{file/after}] % % These hooks are after the file with name \meta{file-name} has % been fully consumed. The order is swapped (the specific one @@ -149,9 +149,9 @@ % \begin{tabbing} % mm\=mm\=mm\=mm\=\kill % \>\cs{UseHook}\marg{\hook{file/before}} \\ -% \>\cs{UseHook}\marg{\hook{file/before/\meta{file name}}} \\ +% \>\cs{UseHook}\marg{\hook{file/\meta{file name}/before}} \\ % \>\> \meta{file contents} \\ -% \>\cs{UseHook}\marg{\hook{file/after/\meta{file name}}} \\ +% \>\cs{UseHook}\marg{\hook{file/\meta{file name}/after}} \\ % \>\cs{UseHook}\marg{\hook{file/after}} % \end{tabbing} % @@ -172,8 +172,8 @@ % % When a file is input, the \meta{file name} is available in % \cs{CurrentFile}, which is then used when accessing the -% \hook{file/before/\meta{file name}} and -% \hook{file/after/\meta{file name}}. +% \hook{file/\meta{file name}/before} and +% \hook{file/\meta{file name}/after}. % % \begin{variable}{\CurrentFile} % The name of the file about to be read (or just finished) is @@ -216,7 +216,7 @@ % \cs{RequirePackage}, \cs{LoadPackageWithOptions}, etc.) offer the % hooks from section~\ref{sec:general-file-hooks} when they are % used to load a package or class file, e.g., -% \texttt{file/after/array.sty} would be called after the +% \texttt{file/array.sty/after} would be called after the % \pkg{array} package got loaded. But as packages and classes form as special group % of files, there are some additional hooks available that only % apply when a package or class is loaded. @@ -224,9 +224,9 @@ % % \begin{variable}{ % package/before,package/after, -% package/before/...,package/after/..., +% package/.../before,package/.../after, % class/before,class/after, -% class/before/...,class/after/..., +% class/.../before,class/.../after, % } % These are: % \begin{description} @@ -234,8 +234,8 @@ % % These hooks are called for each package being loaded. % -% \item[\texttt{package/before/\meta{name}}, -% \texttt{package/after/\meta{name}}] +% \item[\texttt{package/\meta{name}/before}, +% \texttt{package/\meta{name}/after}] % % These hooks are additionally called if the package name is % \meta{name} (without extension). @@ -244,7 +244,7 @@ % % These hooks are called for each class being loaded. % -% \item[\texttt{class/before/\meta{name}}, \texttt{class/after/\meta{name}}] +% \item[\texttt{class/\meta{name}/before}, \texttt{class/\meta{name}/after}] % % These hooks are additionally called if the class name is % \meta{name} (without extension). @@ -258,16 +258,16 @@ % \begin{tabbing} % mm\=mm\=mm\=mm\=\kill % \>\cs{UseHook}\marg{\hook{package/before}} \\ -% \>\cs{UseHook}\marg{\hook{package/before/\meta{package name}}} \\[5pt] +% \>\cs{UseHook}\marg{\hook{package/\meta{package name}/before}} \\[5pt] % \>\>\cs{UseHook}\marg{\hook{file/before}} \\ -% \>\>\cs{UseHook}\marg{\hook{file/before/\meta{package name}.sty}} \\ +% \>\>\cs{UseHook}\marg{\hook{file/\meta{package name}.sty/before}} \\ % \>\>\> \meta{package contents} \\ -% \>\>\cs{UseHook}\marg{\hook{file/after/\meta{package name}.sty}} \\ +% \>\>\cs{UseHook}\marg{\hook{file/\meta{package name}.sty/after}} \\ % \>\>\cs{UseHook}\marg{\hook{file/after}} \\[5pt] % \>\>\emph{code from \cs{AtEndOfPackage} if % used inside the package} \\[5pt] -% \>\cs{UseHook}\marg{\hook{package/after/\meta{package name}}} \\ -% \>\cs{UseHook}\marg{\hook{package/after}} +% \>\cs{UseHook}\marg{\hook{package/\meta{package name}/after}} \\ +% \>\cs{UseHook}\marg{\hook{package/after}} % \end{tabbing} % and similar for class file loading, except that \texttt{package/} % is replaced by \texttt{class/} and \cs{AtEndOfPackage} by @@ -276,6 +276,20 @@ % If a package or class is not loaded (or it was loaded before the % hooks were set) none of the hooks are executed! % +% All class or package hooks involving the name of the class or +% package are implemented as +% one-time hooks, whereas all other such hooks are normal hooks. +% This allows for the following use case +%\begin{verbatim} +% \AddToHook{package/varioref/after} +% { ... apply my customizations if the package gets +% loaded (or was loaded already) ... } +%\end{verbatim} +% without the need to first test if the package is already loaded. +% +% +% +% % \subsection{Hooks for \cs{include} files} % % To manage \cs{include} files, \LaTeX{} issues a \cs{clearpage} @@ -300,14 +314,14 @@ % is \enquote{\texttt{No file \meta{filename}.tex}}). % % -% \begin{variable}{include/before,include/before/..., -% include/end,include/end/..., -% include/after,include/after/..., +% \begin{variable}{include/before,include/.../before, +% include/end,include/.../end, +% include/after,include/.../after, % } % These are: % \begin{description} % -% \item[\texttt{include/before}, \texttt{include/before/\meta{name}}] +% \item[\texttt{include/before}, \texttt{include/\meta{name}/before}] % % These hooks are executed (in that order) after the initial % \cs{clearpage} and after \texttt{.aux} file is changed to use @@ -317,14 +331,14 @@ % file. % % -% \item[\texttt{include/end/\meta{name}}, \texttt{include/end}] +% \item[\texttt{include/\meta{name}/end}, \texttt{include/end}] % % These hooks are executed (in that order) after \LaTeX{} has % stopped reading from the \cs{include} file, but before it has % issued a \cs{clearpage} to output any deferred floats. % % -% \item[\texttt{include/after/\meta{name}}, \texttt{include/after}] +% \item[\texttt{include/\meta{name}/after}, \texttt{include/after}] % % These hooks are executed (in that order) after \LaTeX{} has % issued the \cs{clearpage} but before is has switched back @@ -341,6 +355,13 @@ % normally does nothing, but starts a new page if further material % got added this way.} % +% +% All \hook{include} hooks involving the name of the included file are implemented as +% one-time hooks (whereas all other such hooks are normal hooks). +% +% +% +% % \subsection{High-level interfaces for \LaTeX{}} % % We do not provide any additional wrappers around the hooks (like @@ -531,7 +552,7 @@ % The output of \cs{@@_file_parse_full_name:nN} is passed on to the % |#2|---a 3-argument macro that takes the \meta{path}, \meta{base}, % and \meta{ext} parts of the file name. -% +% % \begin{macrocode} \cs_new:Npn \@@_file_parse_full_name:nN #1 { @@ -591,6 +612,7 @@ % \changes{v1.0h}{2021/03/18} % {Define \cs{g_@@_input_file_seq} to avoid losing data when % rolling back.} +% \changes{v1.0l}{2021/08/27}{Internal message name changes} % \begin{macrocode} \tl_new:N \l_@@_internal_tl \seq_if_exist:NF \g_@@_input_file_seq @@ -608,7 +630,7 @@ \seq_gpop:NNTF \g_@@_input_file_seq \l_@@_internal_tl { \exp_after:wN \@@_file_pop_assign:nnnn \l_@@_internal_tl } { - \msg_error:nnn { kernel } { should-not-happen } + \msg_error:nnn { latex2e } { should-not-happen } { Tried~to~pop~from~an~empty~file~name~stack. } } } @@ -624,7 +646,7 @@ % \end{macro} % \end{macro} % \end{macro} -% +% % \begin{macrocode} % %\EndIncludeInRelease @@ -683,7 +705,7 @@ % { \use_none:n #1 \prg_do_nothing: } % {#2} % } -%} +%} %\ExplSyntaxOff % %\EndIncludeInRelease @@ -697,16 +719,17 @@ % % \subsection{Declaring the file-related hooks} % -% All hooks starting with \texttt{file/} \texttt{include/}, -% \texttt{class/} or \texttt{package/} are generic and will be -% allocated if code is added to them. Thus there is no need to -% explicitly declare any hook in the code below. -% -% Furthermore, those named \texttt{.../after} or \texttt{.../end} are -% automatically declared as reversed hooks if filled with code, so this -% is also automatically taken care of. -% +% These hooks have names with three-parts that +% start with \hook{file/}, \hook{include/}, +% \hook{class/} or \hook{package/} and end with \hook{/before} or +% \hook{/after} (or \hook{/end} in the case of \hook{include/}). +% They are all generic hooks +% so will be declared only if code is added to them; +% this declaration is done for you automatically and, indeed, they should +% not be declared explicitly. % +% Those named \hook{.../after} and \texttt{include/.../end} +% are, when code is added, declared as reversed hooks. % % % \subsection{Patching \LaTeX{}'s \cs{InputIfFileExists} command} @@ -760,7 +783,7 @@ % 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 restore it for the -% \texttt{file/after/...} hook. +% \texttt{file/.../after} hook. % % The hook always refers to the file requested by the user. The hook % is \emph{always} loaded for \cs{CurrentFile} which usually is the @@ -814,20 +837,27 @@ % The current file name is available in \cs{CurrentFile} so we use % that in the specific hook. % \begin{macrocode} - \UseHook{file/before/\CurrentFile}% + \UseHook{file/\CurrentFile/before}% \@@input #1% <- trailing space comes from \@filef@und }% % \end{macrocode} % And here, \cs{CurrentFile} is restored % (by \cs{@expl@@@filehook@file@pop@assign@@nnnn}) so we can use it once more. % \begin{macrocode} - \UseHook{file/after/\CurrentFile}% + \UseHook{file/\CurrentFile/after}% \UseHook{file/after}} \def\unqu@tefilef@und"#1" \@nil{#1} +% \end{macrocode} +% +% \changes{v1.0l}{2021/08/25}{Declare non-generic file hooks} +% Now declare the non-generic file hooks used above: +% \begin{macrocode} +\NewHook{file/before} +\NewReversedHook{file/after} %\EndIncludeInRelease % % \end{macrocode} -% +% % \changes{v0.9b} % {1993/12/04}{Macro added} % \changes{v0.9p} @@ -949,7 +979,7 @@ { \if_meaning:w #1 #2 .tex \else: \token_to_str:N #2 \fi: } % \end{macrocode} % \end{macro} -% +% % \begin{macro}[int]{\use_ii_iii:nnn} % A variant of \cs[no-index]{use_...} to discard the first of three % arguments. @@ -1085,7 +1115,7 @@ % %\EndIncludeInRelease % \end{macrocode} -% +% % \begin{macrocode} %\IncludeInRelease{2020/10/01}% % {\set@curr@file}{Setting current file name}% @@ -1108,7 +1138,7 @@ % \endgroup} %\EndIncludeInRelease % \end{macrocode} -% +% % \begin{macrocode} %\IncludeInRelease{2019/10/01}% % {\set@curr@file}{Setting current file name}% @@ -1124,7 +1154,7 @@ %} %\EndIncludeInRelease % \end{macrocode} -% +% % \begin{macrocode} %\IncludeInRelease{0000/00/00}% % {\set@curr@file}{Setting current file name}% @@ -1383,6 +1413,7 @@ % \@@_file_subst_cycle_error:NN, % \@@_file_subst_cycle_error:cN, % } +% \changes{v1.0l}{2021/08/27}{Use \cs{msg_...} not \cs{__kernel_msg_...}} % Showing this type of error expandably is tricky, as we have a very % limited amount of characters to show and a potentially large list. % As a work around, several errors are printed, each showing one step @@ -1390,7 +1421,7 @@ % \begin{macrocode} \cs_new:Npn \@@_file_subst_cycle_error:NN #1 #2 { - \__kernel_msg_expandable_error:nnff { kernel } { file-cycle } + \msg_expandable_error:nnff { latex2e } { file-cycle } {#1} { \use:c { @file-subst@ #1 } } \token_if_eq_meaning:NNF #1 #2 { \@@_file_subst_cycle_error:cN { @file-subst@ #1 } #2 } @@ -1400,7 +1431,7 @@ % % And the error message: % \begin{macrocode} -\__kernel_msg_new:nnn { kernel } { file-cycle } +\msg_new:nnn { latex2e } { file-cycle } { File~loop!~#1~replaced~by~#2... } % \end{macrocode} % \end{macro} @@ -1412,7 +1443,7 @@ %\EndIncludeInRelease %<*2ekernel> % \end{macrocode} -% +% % % \begin{macrocode} %<@@=> @@ -1438,7 +1469,7 @@ \def\disable@package@load#1#2{% \global\@namedef{@pkg-disable@#1.\@pkgextension}{#2}} % \end{macrocode} -% +% % \begin{macrocode} \def\@disable@packageload@do#1#2{% \@ifundefined{@pkg-disable@#1}{#2}% @@ -1453,7 +1484,7 @@ \csname @pkg-disable@#1.\@pkgextension \endcsname \@undefined} % \end{macrocode} % -% +% % \begin{macrocode} % %\EndIncludeInRelease @@ -1502,7 +1533,7 @@ % {\@expl@@@filehook@if@no@extension@@nTF}{2e tmp interfaces}% \ExplSyntaxOn % \end{macrocode} -% +% % \begin{macrocode} \cs_new_eq:NN \@expl@@@filehook@if@no@extension@@nTF \__filehook_if_no_extension:nTF @@ -1512,7 +1543,7 @@ \cs_new_eq:NN \@expl@@@filehook@set@curr@file@@nNN \__filehook_set_curr_file:nNN % \end{macrocode} -% +% % \begin{macrocode} \cs_new_eq:NN \@expl@@@filehook@resolve@file@subst@@w \__filehook_resolve_file_subst:w @@ -1522,7 +1553,7 @@ \cs_new_eq:NN \@expl@@@filehook@normalize@file@name@@w \__filehook_normalize_file_name:w % \end{macrocode} -% +% % \begin{macrocode} \cs_new_eq:NN \@expl@@@filehook@if@file@replaced@@TF \__filehook_if_file_replaced:TF @@ -1537,23 +1568,23 @@ \cs_new_eq:NN \@expl@@@filehook@drop@extension@@N \__filehook_drop_extension:N % \end{macrocode} -% +% % \begin{macrocode} \cs_new_eq:NN \@expl@@@filehook@file@push@@ \__filehook_file_push: % \end{macrocode} -% +% % \begin{macrocode} \cs_new_eq:NN \@expl@@@filehook@file@pop@@ \__filehook_file_pop: % \end{macrocode} -% +% % \begin{macrocode} \cs_new_eq:NN \@expl@@@filehook@file@pop@assign@@nnnn \__filehook_file_pop_assign:nnnn % \end{macrocode} % \InternalDetectionOn -% +% % % \begin{macrocode} \ExplSyntaxOff @@ -1682,7 +1713,7 @@ %<*atveryend-ltx> \ProvidesPackage{atveryend-ltx} [2020/08/19 v1.0a - Emulation of the original atvery package^^Jwith kernel methods] + Emulation of the original atveryend package^^Jwith kernel methods] % \end{macrocode} % % @@ -1698,14 +1729,14 @@ % \begin{macrocode} \newcommand\AtEndAfterFileList{\AddToHook{enddocument/info}} % \end{macrocode} -% +% % \begin{macrocode} \newcommand\AtVeryVeryEnd {\AddToHook{enddocument/end}} % \end{macrocode} % % \begin{macro}{\BeforeClearDocument} % This one is the only one we don't implement or rather don't have -% a dedicated hook in the code. +% a dedicated hook in the code. % \begin{macrocode} \ExplSyntaxOn \newcommand\BeforeClearDocument[1] @@ -1713,7 +1744,7 @@ \atveryend@DEPRECATED{BeforeClearDocument \tl_to_str:n{#1}} } % \end{macrocode} -% +% % \begin{macrocode} \cs_new:Npn\atveryend@DEPRECATED #1 {\iow_term:x{======~DEPRECATED~USAGE~#1~==========}} @@ -1721,7 +1752,7 @@ % \end{macrocode} % \end{macro} % -% +% % \begin{macrocode} % % \end{macrocode} @@ -1735,4 +1766,3 @@ \endinput %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % - diff --git a/Master/texmf-dist/source/latex/base/ltfiles.dtx b/Master/texmf-dist/source/latex/base/ltfiles.dtx index bcaac582208..4c24716df65 100644 --- a/Master/texmf-dist/source/latex/base/ltfiles.dtx +++ b/Master/texmf-dist/source/latex/base/ltfiles.dtx @@ -32,7 +32,7 @@ %<*driver> % \fi \ProvidesFile{ltfiles.dtx} - [2021/04/17 v1.2m LaTeX Kernel (File Handling)] + [2021/10/14 v1.2p LaTeX Kernel (File Handling)] % \iffalse \documentclass{ltxdoc} \GetFileInfo{ltfiles.dtx} @@ -823,8 +823,16 @@ % % \changes{v1.2j}{2020/10/04}{Quotes around the aux file name removed, % they are not needed and upset BibTeX (gh/400)} +% \changes{v1.2p}{2021/10/14}{Warn about use in preamble} % \begin{macrocode} \def\@include#1 {% +% \end{macrocode} +% +% \begin{macrocode} +\ifx\@nodocument\relax +% \end{macrocode} +% +% \begin{macrocode} \clearpage \if@filesw \immediate\write\@mainaux{\string\@input{#1.aux}}% @@ -850,16 +858,19 @@ % \end{macrocode} % Execute the \texttt{before} hooks just after we switched the % \texttt{.aux} file \ldots +% \changes{v1.2n}{2021/07/23}{Make include/name/before a one-time hook} +% \changes{v1.2o}{2021/08/25}{Standardise generic hook names (gh/648)} % \begin{macrocode} \UseHook{include/before}% - \UseHook{include/before/#1}% + \UseOneTimeHook{include/#1/before}% %----------------------------------------- \@input@{#1.tex}% %----------------------------------------- % \end{macrocode} % \ldots{} then \texttt{end} hooks \ldots +% \changes{v1.2n}{2021/07/23}{Make include/name/end a one-time hook} % \begin{macrocode} - \UseHook{include/end/#1}% + \UseOneTimeHook{include/#1/end}% \UseHook{include/end}% %----------------------------------------- \clearpage @@ -869,8 +880,9 @@ % followed by another \cs{clearpage} just in case new material got % added (after all we need to be in well defined state after the % \cs{include}). +% \changes{v1.2n}{2021/07/23}{Make include/name/after a one-time hook} % \begin{macrocode} - \UseHook{include/after/#1}% + \UseOneTimeHook{include/#1/after}% \UseHook{include/after}% \clearpage %----------------------------------------- @@ -888,7 +900,23 @@ \deadcycles\z@ \@nameuse{cp@#1}% \fi - \let\@auxout\@mainaux} + \let\@auxout\@mainaux +% \end{macrocode} +% +% \begin{macrocode} +\else +\@latex@warning{% + \noexpand\include should only be used after \string\begin{document}}% +\@input@{#1}% +\fi} +% \end{macrocode} +% +% \changes{v1.2o}{2021/08/25}{Declare non-generic include hooks} +% Now declare the non-generic \hook{include} hooks used above: +% \begin{macrocode} +\NewHook{include/before} +\NewReversedHook{include/end} +\NewReversedHook{include/after} %\EndIncludeInRelease % % \end{macrocode} diff --git a/Master/texmf-dist/source/latex/base/ltfinal.dtx b/Master/texmf-dist/source/latex/base/ltfinal.dtx index 19f82934aa6..40017a205a4 100644 --- a/Master/texmf-dist/source/latex/base/ltfinal.dtx +++ b/Master/texmf-dist/source/latex/base/ltfinal.dtx @@ -33,7 +33,7 @@ %<*driver> % \fi \ProvidesFile{ltfinal.dtx} - [2021/04/18 v2.2o LaTeX Kernel (Final Settings)] + [2021/09/06 v2.2q LaTeX Kernel (Final Settings)] % \iffalse \documentclass{ltxdoc} \GetFileInfo{ltfinal.dtx} @@ -1074,9 +1074,11 @@ }} % \end{macrocode} % +% \changes{v2.2q}{2021/09/06}{Correctly upper and lowercase +% \cs{ij} and \cs{IJ} (gh/658)} % \begin{macrocode} \def\@uclclist{\oe\OE\o\O\ae\AE - \dh\DH\dj\DJ\l\L\ng\NG\ss\SS\th\TH} + \dh\DH\dj\DJ\l\L\ng\NG\ss\SS\ij\IJ\th\TH} % \end{macrocode} % The above code works, but has the nasty side-effect that if you % say something like: @@ -1244,6 +1246,39 @@ % \end{macro} % \end{macro} % +% \subsection{Preparation for supporting PDF in backends} +% +% At the current point in time, basic support for PDF in +% backends is not part of \LaTeX{} core; it is provided by external +% packages. At some time in the future that work will be placed +% into the kernel but for now it is separate and has to be +% explicitly loaded in the document. +% +% In that code there is a command \cs{IfPDFManagementActiveTF} +% which can be used by packages in order to execute different +% code depending on the whether this basic backend support is loaded. +% +% To make this also work properly when this external package is not +% loaded at all, we here add this command already in the +% kernel (with a trivial definition); thus any package can +% query this loading state in all circumstances. +% Once this basic PDF backend +% support gets moved to the kernel, this definition will vanish +% again from here or, rather, it will be replaced by a real test. +% +% \begin{macro}{\IfPDFManagementActiveTF} +% So long as the code for the basic backend support for PDF is not +% loaded, the test that is implicit here will +% always return the false branch. +% Once this code is loaded, this definition will get +% replaced by a real test (as it is then possible that the +% management code is either activated or not activated). +% \changes{v2.2p}{2021/08/08}{Default definition added (gh/640)} +% \begin{macrocode} +\let \IfPDFManagementActiveTF \@secondoftwo +% \end{macrocode} +% \end{macro} +% % % % \subsection{Do some temporary work for pre-release} @@ -1253,7 +1288,7 @@ % \begin{macrocode} % \end{macrocode} % -% \subsection{Some last minute initializations \ldots} +% \subsection{Some last minute initializations \ldots} % % Load the first aid set of definitions for external packages that await updates. % \changes{v2.2j}{2020/09/26} diff --git a/Master/texmf-dist/source/latex/base/ltfloat.dtx b/Master/texmf-dist/source/latex/base/ltfloat.dtx index ed25db3ed10..ac3b6418171 100644 --- a/Master/texmf-dist/source/latex/base/ltfloat.dtx +++ b/Master/texmf-dist/source/latex/base/ltfloat.dtx @@ -31,7 +31,7 @@ % %<*driver> % \fi -\ProvidesFile{ltfloat.dtx}[2021/03/03 v1.2f LaTeX Kernel (Floats)] +\ProvidesFile{ltfloat.dtx}[2021/10/14 v1.2g LaTeX Kernel (Floats)] % \iffalse \documentclass{ltxdoc} \GetFileInfo{ltfloat.dtx} @@ -1510,10 +1510,12 @@ % {Missing percent, again} % \changes{v1.2e}{2021/02/10}{Explicitly run \cs{par} at the end of footnote text % in preparation for paragraph hooks} +% \changes{v1.2g}{2021/10/14} +% {Explicitly set \cs{@currentcounter} (gh/687)} % \begin{macrocode} % %<*2ekernel|latexrelease> -%\IncludeInRelease{2021/06/01}% +%\IncludeInRelease{2021/11/15}% % {\@footnotetext}{footnotetext tagging}% \long\def\@footnotetext#1{\insert\footins{% \reset@font\footnotesize @@ -1521,6 +1523,7 @@ \splittopskip\footnotesep \splitmaxdepth \dp\strutbox \floatingpenalty \@MM \hsize\columnwidth \@parboxrestore + \def\@currentcounter{footnote}% \protected@edef\@currentlabel{% \csname p@footnote\endcsname\@thefnmark }% @@ -1534,6 +1537,26 @@ % \end{macrocode} % % \begin{macrocode} +%\IncludeInRelease{2021/06/01}% +% {\@footnotetext}{footnotetext tagging}% +%\long\def\@footnotetext#1{\insert\footins{% +% \reset@font\footnotesize +% \interlinepenalty\interfootnotelinepenalty +% \splittopskip\footnotesep +% \splitmaxdepth \dp\strutbox \floatingpenalty \@MM +% \hsize\columnwidth \@parboxrestore +% \protected@edef\@currentlabel{% +% \csname p@footnote\endcsname\@thefnmark +% }% +% \color@begingroup +% \@makefntext{% +% \rule\z@\footnotesep\ignorespaces#1\@finalstrut\strutbox}% +% \par +% \color@endgroup}}% +%\EndIncludeInRelease +% \end{macrocode} +% +% \begin{macrocode} %\IncludeInRelease{0000/00/00}% % {\@footnotetext}{footnotetext tagging}% % diff --git a/Master/texmf-dist/source/latex/base/ltfntcmd.dtx b/Master/texmf-dist/source/latex/base/ltfntcmd.dtx index 5f70053a688..6c4ec4b3d16 100644 --- a/Master/texmf-dist/source/latex/base/ltfntcmd.dtx +++ b/Master/texmf-dist/source/latex/base/ltfntcmd.dtx @@ -32,7 +32,7 @@ %<*driver> % \fi \ProvidesFile{ltfntcmd.dtx} - [2020/12/05 v3.4c LaTeX Kernel (Font commands)] + [2021/09/12 v3.5a LaTeX Kernel (Font commands)] % \iffalse \documentclass{ltxdoc} \GetFileInfo{ltfntcmd.dtx} @@ -466,9 +466,10 @@ % Is this the correct action in the `empty' case? It is efficient but % typographically it is, strictly, incorrect! % \changes{v3.3l}{1994/06/18}{Added check for empty text} +% \changes{v3.5a}{2021/09/12}{use \cs{unexpanded} to make \# safe} % \begin{macrocode} \def \text@command #1{% - \def \reserved@a {#1}% + \edef \reserved@a {\unexpanded{#1}}% \ifx \reserved@a \@empty \let \check@icl \@empty \let \check@icr \@empty diff --git a/Master/texmf-dist/source/latex/base/ltfssbas.dtx b/Master/texmf-dist/source/latex/base/ltfssbas.dtx index df265d0b0fc..1f30372d063 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} - [2021/04/26 v3.2i LaTeX Kernel (NFSS Basic Macros)] + [2021/06/09 v3.2j LaTeX Kernel (NFSS Basic Macros)] % \iffalse \documentclass{ltxdoc} \begin{document} @@ -280,11 +280,12 @@ % may have dropped an ``m''. If nothing has changes, % fine. Otherwise there was a wrong value which is now corrected in % \cs{reservedb} so we use that and also issue a warning. +% \changes{v3.2j}{2021/06/09}{Improve information message} % \begin{macrocode} \edef\reserved@a{#3}% \series@maybe@drop@one@m\reserved@a\reserved@b \ifx\reserved@a\reserved@b\else - \@latex@warning{Font shape declaration has incorrect series + \@latex@note{Font shape #1/#2/#3/#4 has incorrect series value `#3'.\MessageBreak It should not contain an `m'! Please correct it.\MessageBreak Found}% \fi diff --git a/Master/texmf-dist/source/latex/base/ltfssdcl.dtx b/Master/texmf-dist/source/latex/base/ltfssdcl.dtx index 9710d543829..4f2cabd613b 100644 --- a/Master/texmf-dist/source/latex/base/ltfssdcl.dtx +++ b/Master/texmf-dist/source/latex/base/ltfssdcl.dtx @@ -36,7 +36,7 @@ % % \ProvidesFile{ltfssdcl.dtx} - [2021/02/15 v3.0w LaTeX Kernel (NFSS Declarative Interface)] + [2021/10/15 v3.0y LaTeX Kernel (NFSS Declarative Interface)] % \iffalse \documentclass{ltxdoc} \begin{document} @@ -454,25 +454,88 @@ % \end{macrocode} % \end{macro} % +% +% +% +% \begin{macro}{\c@localalphabets} +% \changes{v3.0x}{2021/09/26}{Counter added for (gh/676)} +% To avoid hitting the ``no more math fams available'' limit of 16, we +% keep a defined number of math alphabets flexible/local. If we have to +% allocate any of those we roll back the allocation after the +% formula has ended, so the next formula can use other alphabets in +% the slot(s). This makes the processing a bit slower if you are +% working at the limit, but that is better than dying with ``out of memory''. +% \begin{macrocode} +% +%\IncludeInRelease{2021/11/15} +% {\document@select@group}{\document@select@group}% +%<*2ekernel|latexrelease> +% \end{macrocode} +% We don't really undo the declaration on rollback (as that would +% be hard to maintain), so rolling +% forward needs to check if the declaration was already made. +% \begin{macrocode} +\ifx\c@localmathalphabets\@undefined +% \end{macrocode} +% There is no need to have this counter as part of the include +% checkpoints, given that it makes little sense to alter its +% settings mid document. All we want is the ability to change it +% using the \cs{setcounter} interface. +% +% By default we keep two math fams flexible. +% \begin{macrocode} + \newcount\c@localmathalphabets + \setcounter{localmathalphabets}{2} +\fi +% \end{macrocode} +% \end{macro} +% +% +% +% +% % \begin{macro}{\document@select@group} -% We surround |\select@group| with braces so that functions using it -% can be used directly after |_| or |^|. -% \changes{v2.1p}{1994/12/10}{Surround with braces (add fourth arg)} -% \changes{v2.1q}{1995/04/02}{fix problem for pr/1275} +% The \cs{document@select@group} command is the version of +% \cs{select@group} (inside math versions) that is used in the +% document body to set up math alphabets (if used). +% % \changes{v3.0g}{1997/11/20} % {(DPC) inline use of \cs{stepcounter} (faster, and saves a csname % per math version as no reset list)} % \changes{v3.0q}{2015/03/18}{Introduce \cs{e@mathgroup@top}} % \begin{macrocode} -% -%\IncludeInRelease{2020/10/01} -% {\document@select@group}{\document@select@group}% -%<*2ekernel|latexrelease> \def\document@select@group#1#2#3#4{% \ifx\math@bgroup\bgroup\else\relax\expandafter\@firstofone\fi {% \ifmmode +% \end{macrocode} +% We first check if there is still room for allocating another +% mathgroup. If there is, we check if it can be globally allocated +% or if we have reached the limit which is given by +% \cs{e@mathgroup@top} with \cs{c@localmathalphabets} subtracted. +% +% \changes{v3.0x}{2021/09/26}{Test if we should freeze the version (gh/676)} +% \begin{macrocode} \ifnum\csname c@mv@\math@version\endcsname<\e@mathgroup@top + \ifnum \numexpr\e@mathgroup@top-\c@localmathalphabets + >\csname c@mv@\math@version\endcsname + \else +% \end{macrocode} +% If we are past this point we freeze the current state of the math +% version so that we can return to it after the formula has +% ended. Of course, that should be done only once, so we check if +% \cs{mv@\meta{version}@frozen} already exists. +% \begin{macrocode} + \ifcsname mv@\math@version @frozen\endcsname \else +% \end{macrocode} +% We have to pass the current value of \cs{math@version} not the +% macro itself, because some of the processing is delayed to a +% point where the value may have changed again---not doing this +% caused a puzzling error in one setup. +% \begin{macrocode} + \expandafter\freeze@math@version\expandafter{\math@version}% + \fi + \fi \begingroup \escapechar\m@ne \getanddefine@fonts{\csname c@mv@\math@version\endcsname}#3% @@ -486,16 +549,21 @@ \global\advance\csname c@mv@\math@version\endcsname\@ne \else \let#1\relax - \@latex@error{Too many math alphabets used - in version \math@version}% + \@latex@error{Too many math alphabets used in + version \math@version}% \@eha \fi % \end{macrocode} -% extra \cs{expandafter} to remove the \cs{expandafter} added below -% \changes{v3.0w}{2021/02/115}{fix for (gh/501)} +% Extra \cs{expandafter} to remove the \cs{expandafter} added below +% \changes{v3.0w}{2021/02/15}{fix for (gh/501)} % \begin{macrocode} \else \expandafter\expandafter\expandafter\non@alpherr\fi % \end{macrocode} +% We surround |\select@group| with braces so that functions using it +% can be used directly after |_| or |^|. +% \changes{v2.1p}{1994/12/10}{Surround with braces (add fourth arg)} +% \changes{v2.1q}{1995/04/02}{fix problem for pr/1275} +% % If the legacy interface is used, e.g., \verb=$\sf -1$= the math % alphabet \verb=#1= does not take an argument so we better do not % surround \verb=#4= with braces, because then we get @@ -507,8 +575,142 @@ \expandafter#1\ifx\math@bgroup\bgroup{#4}\else#4\fi }% } +% \end{macrocode} +% +% +% +% \begin{macro}{\freeze@math@version} +% \changes{v3.0x}{2021/09/26}{Macro added for (gh/676)} +% This command stores the current state of the math version and sets +% things up to return to it after each formula from now on. We use +% L3 programming layer code to set it up. +% \begin{macrocode} +\ExplSyntaxOn +\cs_new_protected:Npn\freeze@math@version #1 { +% \end{macrocode} +% Save the current \cs{mv@\meta{version}} code and the number of +% allocated mathgroups inside. +% \begin{macrocode} + \@font@info{Freeze~ math~ alphabet~ allocation~ in~ version~ + #1.\MessageBreak + Allocated~math~groups:~\int_use:c{ c@mv@ #1 }~ + (local:~ \int_use:N\c@localmathalphabets) } + \cs_gset_eq:cc { mv@#1@frozen }{ mv@#1 } + \tl_gset:cx { g__nfss_frozen_mv_ #1 _tl }{ \int_use:c { c@mv@#1 } } +% \end{macrocode} +% Doing the reset the first time, we wait until we are out of +% math mode, so we use some recursive \cs{group_insert_after:N} for this +% before we execute \cs{mv@\meta{version}@reset}. +% \begin{macrocode} + \group_insert_after:N \__nfss_init_mv_freeze:N \exp_after:wN + \group_insert_after:N \cs:w mv@#1@reset \cs_end: +% \end{macrocode} +% The \cs{check@mathfonts} is called at the very beginning of each +% math formula, so it is a good way to hook in the resetting. +% Again that has to happen after the formula has ended, but we know +% because of the place where \cs{check@mathfonts} is used +% that a single \cs{aftergoup} is sufficient. +% \begin{macrocode} + \tl_gput_right:No \check@mathfonts + { + \exp_after:wN \group_insert_after:N \cs:w mv@#1@reset \cs_end: + } +% \end{macrocode} +% Here is the definition of \cs{mv@\meta{version}@reset}. If there +% has been no new math alphabet allocation, doing a reset would +% just cause a lot of unnecessary processing, so we do a quick +% check upfront for this. +% \begin{macrocode} + \cs_gset:cpn{mv@#1@reset} + { + \int_compare:nNnTF { \int_use:c{c@mv@#1} } > + { \tl_use:c{g__nfss_frozen_mv_ #1 _tl} } + { + \@font@info{Undo~ math~ alphabet~ allocation~ in~ version~ #1} +% \end{macrocode} +% If the undo is necessary, we restore the \cs{mv@\meta{version}} code. +% \begin{macrocode} + \cs_gset_eq:cc { mv@#1 }{ mv@#1@frozen } + \int_gset:cn { c@mv@#1 }{ \tl_use:c {g__nfss_frozen_mv_ #1 _tl} } +% \end{macrocode} +% But we also should undo changes to the math alphabet +% definitions. We therefore run this code with a modified +% definition for \cs{getanddefine@fonts} because there is no need +% to do anything to the symbol fonts that are permanently allocated. +% \begin{macrocode} + \group_begin: + \cs_set_eq:NN \getanddefine@fonts \use_none:nn + \use:c {mv@#1} + \group_end: + } + { +% \end{macrocode} +% If there was no change, we report that in the log (but this +% branch could go completely). +% \begin{macrocode} + \@font@info{No~ math~ alphabet~ change~ to~ frozen~ version~ #1} + } + } +} +% \end{macrocode} +% \end{macro} +% +% +% \begin{macro}{\__nfss_init_mv_freeze:N} +% \changes{v3.0x}{2021/09/26}{Macro added for (gh/676)} +% To do the initial freeze in a safe place, we check if we are in +% math mode and if so try again after the group has ended by pushing +% the command and its single token argument with two +% \cs{group_insert_after:N}s after the current group. If we are no longer in +% math mode we bypass the +% conditional and so the next token is our argument +% which is then finally executed. +% \begin{macrocode} +\cs_new_protected:Npn \__nfss_init_mv_freeze:N #1 {% + \mode_if_math:T { \group_insert_after:N \__nfss_init_mv_freeze:N + \group_insert_after:N } #1 +} +% \end{macrocode} +% \end{macro} +% +% +% \begin{macrocode} +\ExplSyntaxOff +% \end{macrocode} +% +% \begin{macrocode} % %\EndIncludeInRelease +%\IncludeInRelease{2020/10/01} +% {\document@select@group}{\document@select@group}% +% +%\def\document@select@group#1#2#3#4{% +% \ifx\math@bgroup\bgroup\else\relax\expandafter\@firstofone\fi +% {% +% \ifmmode +% \ifnum\csname c@mv@\math@version\endcsname<\e@mathgroup@top +% \begingroup +% \escapechar\m@ne +% \getanddefine@fonts{\csname c@mv@\math@version\endcsname}#3% +% \globaldefs\@ne \math@fonts +% \endgroup +% \expandafter\extract@alph@from@version +% \csname mv@\math@version\expandafter\endcsname +% \expandafter{\number\csname +% c@mv@\math@version\endcsname}% +% #1% +% \global\advance\csname c@mv@\math@version\endcsname\@ne +% \else +% \let#1\relax +% \@latex@error{Too many math alphabets used +% in version \math@version}% +% \@eha +% \fi +% \else \expandafter\expandafter\expandafter\non@alpherr\fi +% \expandafter#1\ifx\math@bgroup\bgroup{#4}\else#4\fi +% }% +%} +%\EndIncludeInRelease %\IncludeInRelease{2015/01/01} % {\document@select@group}{\document@select@group}% % @@ -653,9 +855,36 @@ % % \begin{macro}{\DeclareMathVersion} % \begin{macrocode} +% +%<*2ekernel|latexrelease> +%\IncludeInRelease{2021/11/15}% +% {\DeclareMathVersion}{local alphabets}% \def\DeclareMathVersion#1{% +% \end{macrocode} +% When declaring a new math version we need to instantiate an L3 +% variable that is used when we freeze the version, because too many +% alphabets got allocated. If we don't do this, L3 programming layer +% complains if it is run in checking mode. +% \changes{v3.0y}{2021/10/15}{Initialize variable for freezing +% math version (gh/676)} +% \begin{macrocode} + \@namedef{g__nfss_frozen_mv_#1_tl}{}% +% \end{macrocode} +% +% \begin{macrocode} \expandafter\new@mathversion\csname mv@#1\endcsname} \@onlypreamble\DeclareMathVersion +% +%\EndIncludeInRelease +% \end{macrocode} +% +% \begin{macrocode} +%\IncludeInRelease{0000/00/00}% +% {\DeclareMathVersion}{local alphabets}% +%\def\DeclareMathVersion#1{% +% \expandafter\new@mathversion\csname mv@#1\endcsname} +%\EndIncludeInRelease +%<*2ekernel> % \end{macrocode} % \end{macro} % diff --git a/Master/texmf-dist/source/latex/base/ltfssini.dtx b/Master/texmf-dist/source/latex/base/ltfssini.dtx index b06fc161b08..f817fdd8473 100644 --- a/Master/texmf-dist/source/latex/base/ltfssini.dtx +++ b/Master/texmf-dist/source/latex/base/ltfssini.dtx @@ -36,7 +36,7 @@ % % \ProvidesFile{ltfssini.dtx} - [2021/04/26 v3.2h LaTeX Kernel (NFSS Initialisation)] + [2021/09/10 v3.2i LaTeX Kernel (NFSS Initialisation)] % \iffalse \documentclass{ltxdoc} \begin{document} @@ -207,7 +207,7 @@ % \begin{macrocode} % %<*2ekernel|latexrelease> -%\IncludeInRelease{2020/02/02}% +%\IncludeInRelease{2021/11/15}% % {\DeclareFontSeriesDefault}{Custom series}% % \end{macrocode} % @@ -280,6 +280,17 @@ % \begin{macrocode} \let\DeclareFontSeriesDefault\@undefined % for rollback \newcommand\DeclareFontSeriesDefault[3][]{% +% \end{macrocode} +% +% \changes{v3.2i}{2021/09/10}{Do delayed changes to \cs{bfdefault} or +% \cs{mddefault} first (gh/663)} +% \begin{macrocode} + \expand@font@defaults + \maybe@update@bfseries@defaults + \maybe@update@mdseries@defaults +% \end{macrocode} +% +% \begin{macrocode} \def\reserved@a{#1}% % \end{macrocode} % No optional argument: set up general default. @@ -333,7 +344,77 @@ % \end{macro} +% \begin{macrocode} +% +%\EndIncludeInRelease +%\IncludeInRelease{2020/02/02}% +% {\DeclareFontSeriesDefault}{Custom series}% +% +%\let\DeclareFontSeriesDefault\@undefined % for rollback +%\newcommand\DeclareFontSeriesDefault[3][]{% +% \def\reserved@a{#1}% +% \ifx\reserved@a\@empty +% \ifcsname #2series\endcsname % supported are +% % \[md/bf]default +% \expandafter\def +% \csname #2default\endcsname{#3\@empty}% +% \expandafter\def +% \csname #2default@previous\endcsname{#3\@empty}% +% \else +% \@latex@error{Wrong syntax for \string\DeclareFontSeriesDefault}% +% {Mandatory first argument must be 'md' or 'bf'.} +% \fi +% \else +% \ifcsname #2series@#1\endcsname % supported are +% % \[md/bf]series@[rm/sf/tt] +% \expandafter\edef +% \csname #2series@#1\endcsname{#3}% +% \expandafter\let +% \csname #2series@#1@kernel\endcsname\@undefined +% \else +% \@latex@error{Wrong syntax for \string\DeclareFontSeriesDefault}% +% {Optional argument must be 'rm', 'sf', or 'tt'. \MessageBreak +% Mandatory first argument must be 'md' or 'bf'.} +% \fi +% \fi +%} +% +%\EndIncludeInRelease +%\IncludeInRelease{0000/00/00}% +% {\DeclareFontSeriesDefault}{Custom series}% +% +%\let\DeclareFontSeriesDefault\@undefined +%\let\bfseries@rm\@undefined +%\let\bfseries@sf\@undefined +%\let\bfseries@tt\@undefined +%\let\bfseries@rm@kernel\@undefined +%\let\bfseries@sf@kernel\@undefined +%\let\bfseries@tt@kernel\@undefined +%\let\mdseries@rm\@undefined +%\let\mdseries@sf\@undefined +%\let\mdseries@tt\@undefined +%\expandafter\let\csname ver@mweights.sty\endcsname\@undefined +% +%\let\@meta@family@list\@undefined +%\let\prepare@family@series@update\@undefined +%\let\update@series@target@value\@undefined +% +% \end{macrocode} +% This is always called in \cs{document} so don't make it undefined. +% \begin{macrocode} +%\let\init@series@setup\relax +% +%\EndIncludeInRelease +%<*2ekernel> +% \end{macrocode} + +% \begin{macrocode} +% +%<*2ekernel|latexrelease> +%\IncludeInRelease{2020/02/02}% +% {\mdseries@rm}{Custom series}% +% \end{macrocode} % \begin{macro}{\mdseries@rm} % \begin{macro}{\mdseries@sf} @@ -704,9 +785,8 @@ % %\EndIncludeInRelease %\IncludeInRelease{0000/00/00}% -% {\DeclareFontSeriesDefault}{Custom series}% +% {\mdseries@rm}{Custom series}% % -%\let\DeclareFontSeriesDefault\@undefined %\let\bfseries@rm\@undefined %\let\bfseries@sf\@undefined %\let\bfseries@tt\@undefined @@ -735,55 +815,11 @@ % \begin{macrocode} % %<*2ekernel|latexrelease> -%\IncludeInRelease{2020/10/01}% +%\IncludeInRelease{2021/11/15}% % {\bfseries}{Custom series with hooks}% % \end{macrocode} -% \begin{macro}{\expand@font@defaults} -% \begin{macro}{\rm@def@ult} -% \begin{macro}{\sf@def@ult} -% \begin{macro}{\tt@def@ult} -% \begin{macro}{\md@def@ult} -% \begin{macro}{\bf@def@ult} -% -% The family specific defaults are fully expanded, i.e., they are -% defined via \cs{edef} inside \cs{DeclareFontSeriesDefault}. -% However, the overall defaults, e.g., \cs{bfdefault} may have been -% redefined by the user and thus may not be fully expanded. So to -% enable reliable comparison we make expanded versions of -% them. That we rerun each time. The alternative would be to only -% allow for changes before begin document. -% \begin{macrocode} -\def\expand@font@defaults{% - \edef\rmdef@ult{\rmdefault}% - \edef\sfdef@ult{\sfdefault}% - \edef\ttdef@ult{\ttdefault}% -% \end{macrocode} -% The series defaults may contain some surplus \texttt{m} that we -% need to drop here. -% \changes{v3.1j}{2020/02/25}{Drop surplus ``m'' from \cs{bfdef@ult} -% and \cs{mddef@ult} (gh/291)} -% \begin{macrocode} - \series@maybe@drop@one@m\bfdefault\bfdef@ult - \series@maybe@drop@one@m\mddefault\mddef@ult -% \end{macrocode} -% Formats that set up parallel fonts, e.g., for Japanese, can use -% this hook to add additional code here. -% \changes{v3.1m}{2020/04/06}{Hook added (gh/306)} -% \changes{v3.2b}{2020/08/21}{Integration of new hook management interface} -% \begin{macrocode} - \UseHook{expand@font@defaults}% -} -% \end{macrocode} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} - - % \begin{macro}{\bfseries} % This document command switches to the bold series. % \begin{macrocode} @@ -797,9 +833,35 @@ % \cs{ttdef@ult} and the select the correct family default in that case. % \changes{v3.1i}{2020/02/18}{Make the \cs{ifx} selection outside % of \cs{fontseries} argument so that it is not done several times} +% \changes{v3.2i}{2021/09/10}{Do delayed changes to \cs{bfdefault} in +% a separate macro for better reuse (gh/663)} % \begin{macrocode} \expand@font@defaults + \maybe@update@bfseries@defaults +% \end{macrocode} +% +% \begin{macrocode} + \ifx\f@family\rmdef@ult \fontseries\bfseries@rm + \else\ifx\f@family\sfdef@ult \fontseries\bfseries@sf + \else\ifx\f@family\ttdef@ult \fontseries\bfseries@tt +% \end{macrocode} +% If not \cs{bfdefault} is used. +% \begin{macrocode} + \else \fontseries\bfdefault + \fi\fi\fi % \end{macrocode} +% This hook in contrast is always executed. +% \begin{macrocode} + \UseHook{bfseries}% + \selectfont +} +% \end{macrocode} +% \end{macro} + + + +% \begin{macro}{\maybe@update@bfseries@defaults} +% % If \cs{bfdefault} and \cs{bfdefault@previous} are different then % the default got changed directly through the legacy interface % (i.e., via \cs{def} or \cs{renewcommand}. In that case we reset @@ -807,7 +869,10 @@ % the case before the new mechanism was introduced. % \changes{v3.1k}{2020/03/19}{Support legacy use of \cs{bfdefault} % and \cs{mddefault} (gh/306)} +% \changes{v3.2i}{2021/09/10}{Do delayed changes to \cs{bfdefault} in +% a separate macro for better reuse (gh/663)} % \begin{macrocode} +\def\maybe@update@bfseries@defaults{% \ifx\bfdefault\bfdefault@previous\else % \end{macrocode} % We add \cs{@empty} and then let \cs{bfdefault@previous} to @@ -835,28 +900,11 @@ % \begin{macrocode} \UseHook{bfseries/defaults}% \fi -% \end{macrocode} -% -% \begin{macrocode} - \ifx\f@family\rmdef@ult \fontseries\bfseries@rm - \else\ifx\f@family\sfdef@ult \fontseries\bfseries@sf - \else\ifx\f@family\ttdef@ult \fontseries\bfseries@tt -% \end{macrocode} -% If not \cs{bfdefault} is used. -% \begin{macrocode} - \else \fontseries\bfdefault - \fi\fi\fi -% \end{macrocode} -% This hook in contrast is always executed. -% \begin{macrocode} - \UseHook{bfseries}% - \selectfont } % \end{macrocode} % \end{macro} - % \begin{macro}{\mdseries} % This document command switches to the medium series. % \changes{v3.1i}{2020/02/18}{Make the \cs{ifx} selection outside @@ -865,10 +913,30 @@ % and \cs{mddefault} (gh/306)} % \changes{v3.2d}{2020/09/30}{\cs{mddefault@previous} not \cs{mdseries@previous} % (gh/395)} +% \changes{v3.2i}{2021/09/10}{Do delayed changes to \cs{mddefault} in +% a separate macro for better reuse (gh/663)} % \begin{macrocode} \DeclareRobustCommand\mdseries{% \not@math@alphabet\mdseries\relax \expand@font@defaults + \maybe@update@mdseries@defaults + \ifx\f@family\rmdef@ult \fontseries\mdseries@rm + \else\ifx\f@family\sfdef@ult \fontseries\mdseries@sf + \else\ifx\f@family\ttdef@ult \fontseries\mdseries@tt + \else \fontseries\mddefault + \fi\fi\fi + \UseHook{mdseries}% + \selectfont +} +% \end{macrocode} +% \end{macro} + +% \begin{macro}{\maybe@update@mdseries@defaults} +% +% \changes{v3.2i}{2021/09/10}{Do delayed changes to \cs{mddefault} in +% a separate macro for better reuse (gh/663)} +% \begin{macrocode} +\def\maybe@update@mdseries@defaults{% \ifx\mddefault\mddefault@previous\else \expandafter\def\expandafter\mddefault\expandafter{\mddefault\@empty}% \let\mddefault@previous\mddefault @@ -884,17 +952,161 @@ % \begin{macrocode} \UseHook{mdseries/defaults}% \fi - \ifx\f@family\rmdef@ult \fontseries\mdseries@rm - \else\ifx\f@family\sfdef@ult \fontseries\mdseries@sf - \else\ifx\f@family\ttdef@ult \fontseries\mdseries@tt - \else \fontseries\mddefault - \fi\fi\fi - \UseHook{mdseries}% - \selectfont } % \end{macrocode} % \end{macro} +% +% \begin{macrocode} +% +%\EndIncludeInRelease +%\IncludeInRelease{2020/10/01}% +% {\bfseries}{Custom series with hooks}% +% +%\let\maybe@update@bfseries@defaults\@undefined +%\let\maybe@update@mdseries@defaults\@undefined +% +%\DeclareRobustCommand\bfseries{% +% \not@math@alphabet\bfseries\mathbf +% \expand@font@defaults +% \ifx\bfdefault\bfdefault@previous\else +% \expandafter\def\expandafter\bfdefault +% \expandafter{\bfdefault\@empty}% +% \let\bfdefault@previous\bfdefault +% \let\bfseries@rm\bfdef@ult +% \let\bfseries@sf\bfdef@ult +% \let\bfseries@tt\bfdef@ult +% \UseHook{bfseries/defaults}% +% \fi +% \ifx\f@family\rmdef@ult \fontseries\bfseries@rm +% \else\ifx\f@family\sfdef@ult \fontseries\bfseries@sf +% \else\ifx\f@family\ttdef@ult \fontseries\bfseries@tt +% \else \fontseries\bfdefault +% \fi\fi\fi +% \UseHook{bfseries}% +% \selectfont +%} +% +%\DeclareRobustCommand\mdseries{% +% \not@math@alphabet\mdseries\relax +% \expand@font@defaults +% \ifx\mddefault\mddefault@previous\else +% \expandafter\def\expandafter\mddefault\expandafter{\mddefault\@empty}% +% \let\mddefault@previous\mddefault +% \let\mdseries@rm\mddef@ult +% \let\mdseries@sf\mddef@ult +% \let\mdseries@tt\mddef@ult +% \UseHook{mdseries/defaults}% +% \fi +% \ifx\f@family\rmdef@ult \fontseries\mdseries@rm +% \else\ifx\f@family\sfdef@ult \fontseries\mdseries@sf +% \else\ifx\f@family\ttdef@ult \fontseries\mdseries@tt +% \else \fontseries\mddefault +% \fi\fi\fi +% \UseHook{mdseries}% +% \selectfont +%} +%\EndIncludeInRelease +%\IncludeInRelease{2020/02/02}% +% {\bfseries}{Custom series with hooks}% +% +% +%\DeclareRobustCommand\bfseries{% +% \not@math@alphabet\bfseries\mathbf +% \expand@font@defaults +% \ifx\f@family\rmdef@ult \fontseries\bfseries@rm +% \else\ifx\f@family\sfdef@ult \fontseries\bfseries@sf +% \else\ifx\f@family\ttdef@ult \fontseries\bfseries@tt +% \else \fontseries\bfdefault +% \fi\fi\fi +% \selectfont +%} +% +%\DeclareRobustCommand\mdseries{% +% \not@math@alphabet\mdseries\relax +% \expand@font@defaults +% \ifx\f@family\rmdef@ult \fontseries\mdseries@rm +% \else\ifx\f@family\sfdef@ult \fontseries\mdseries@sf +% \else\ifx\f@family\ttdef@ult \fontseries\mdseries@tt +% \else \fontseries\mddefault +% \fi\fi\fi +% \selectfont +%} +% +% +% \end{macrocode} +% +% \begin{macrocode} +% +%\EndIncludeInRelease +%\IncludeInRelease{0000/00/00}% +% {\bfseries}{Custom series with hooks}% +% +%\DeclareRobustCommand\bfseries +% {\not@math@alphabet\bfseries\mathbf +% \fontseries\bfdefault\selectfont} +%\DeclareRobustCommand\mdseries +% {\not@math@alphabet\mdseries\relax +% \fontseries\mddefault\selectfont} +% +%\EndIncludeInRelease +%<*2ekernel> + + + + +% +%<*2ekernel|latexrelease> +%\IncludeInRelease{2020/10/01}% +% {\expand@font@defaults}{Custom series with hooks}% +% \end{macrocode} + + + +% \begin{macro}{\expand@font@defaults} +% \begin{macro}{\rm@def@ult} +% \begin{macro}{\sf@def@ult} +% \begin{macro}{\tt@def@ult} +% \begin{macro}{\md@def@ult} +% \begin{macro}{\bf@def@ult} +% +% The family specific defaults are fully expanded, i.e., they are +% defined via \cs{edef} inside \cs{DeclareFontSeriesDefault}. +% However, the overall defaults, e.g., \cs{bfdefault} may have been +% redefined by the user and thus may not be fully expanded. So to +% enable reliable comparison we make expanded versions of +% them. That we rerun each time. The alternative would be to only +% allow for changes before begin document. +% \begin{macrocode} +\def\expand@font@defaults{% + \edef\rmdef@ult{\rmdefault}% + \edef\sfdef@ult{\sfdefault}% + \edef\ttdef@ult{\ttdefault}% +% \end{macrocode} +% The series defaults may contain some surplus \texttt{m} that we +% need to drop here. +% \changes{v3.1j}{2020/02/25}{Drop surplus ``m'' from \cs{bfdef@ult} +% and \cs{mddef@ult} (gh/291)} +% \begin{macrocode} + \series@maybe@drop@one@m\bfdefault\bfdef@ult + \series@maybe@drop@one@m\mddefault\mddef@ult +% \end{macrocode} +% Formats that set up parallel fonts, e.g., for Japanese, can use +% this hook to add additional code here. +% \changes{v3.1m}{2020/04/06}{Hook added (gh/306)} +% \changes{v3.2b}{2020/08/21}{Integration of new hook management interface} +% \begin{macrocode} + \UseHook{expand@font@defaults}% +} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} + + % \begin{macro}{\rmfamily} % Here are the document level commands for changing the main font @@ -1094,7 +1306,7 @@ % %\EndIncludeInRelease %\IncludeInRelease{2020/02/02}% -% {\bfseries}{Custom series with hooks}% +% {\expand@font@defaults}{Custom series with hooks}% % %\def\expand@font@defaults{% % \edef\rmdef@ult{\rmdefault}% @@ -1105,27 +1317,6 @@ % \edef\famdef@ult{\familydefault}% %} % -%\DeclareRobustCommand\bfseries{% -% \not@math@alphabet\bfseries\mathbf -% \expand@font@defaults -% \ifx\f@family\rmdef@ult \fontseries\bfseries@rm -% \else\ifx\f@family\sfdef@ult \fontseries\bfseries@sf -% \else\ifx\f@family\ttdef@ult \fontseries\bfseries@tt -% \else \fontseries\bfdefault -% \fi\fi\fi -% \selectfont -%} -% -%\DeclareRobustCommand\mdseries{% -% \not@math@alphabet\mdseries\relax -% \expand@font@defaults -% \ifx\f@family\rmdef@ult \fontseries\mdseries@rm -% \else\ifx\f@family\sfdef@ult \fontseries\mdseries@sf -% \else\ifx\f@family\ttdef@ult \fontseries\mdseries@tt -% \else \fontseries\mddefault -% \fi\fi\fi -% \selectfont -%} % %\DeclareRobustCommand\rmfamily{% % \not@math@alphabet\rmfamily\mathrm @@ -1152,7 +1343,7 @@ % %\EndIncludeInRelease %\IncludeInRelease{0000/00/00}% -% {\bfseries}{Custom series with hooks}% +% {\expand@font@defaults}{Custom series with hooks}% % %\let\expand@font@defaults\@undefined % diff --git a/Master/texmf-dist/source/latex/base/ltfsstrc.dtx b/Master/texmf-dist/source/latex/base/ltfsstrc.dtx index c6aec105ba5..f562a4fa907 100644 --- a/Master/texmf-dist/source/latex/base/ltfsstrc.dtx +++ b/Master/texmf-dist/source/latex/base/ltfsstrc.dtx @@ -495,7 +495,7 @@ \delayed@f@adjustment % \end{macrocode} % We then check if the resulting cominbation is valid but for this -% we have to make sure the the appropiate \texttt{.fd} is loaded if +% we have to make sure that the appropiate \texttt{.fd} is loaded if % that hasn't happened so far. % \begin{macrocode} \maybe@load@fontshape diff --git a/Master/texmf-dist/source/latex/base/lthooks.dtx b/Master/texmf-dist/source/latex/base/lthooks.dtx index 20e172a57f2..5b3d80e9844 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.0n} -\def\lthooksdate{2021/05/26} +\def\lthooksversion{v1.0s} +\def\lthooksdate{2021/09/28} % \end{macrocode} % %<*driver> @@ -47,7 +47,7 @@ \vbox_unpack_drop:N \l__codedoc_macro_box \hbox { \llap { \__codedoc_print_macroname:nN {#1} #2 \MacroFont % <----- without it the \ is in lmr10 if a link is made - \ + \ } } } \int_incr:N \l__codedoc_macro_int @@ -74,9 +74,9 @@ % \providecommand\pho[1]{\marginpar{\footnotesize PhO: #1}} % \providecommand\phoinline[1]{\begin{quote}\itshape\footnotesize PhO: #1\end{quote}} % -% % -% \title{The \texttt{lthooks} package\thanks{This package has version +% +% \title{\LaTeX{}'s hook management\thanks{This module has version % \lthooksversion\ dated \lthooksdate, \copyright\ \LaTeX\ % Project.}} % @@ -127,22 +127,18 @@ % % \subsubsection{Declaring hooks} % -% With a few exceptions, hooks have to be declared before they can -% be used. The exceptions are the generic hooks for commands, -% environments (i.e., executed at \cs{begin} and \cs{end}) and -% hooks run when loading files, e.g. before and after a package is -% loaded, etc. Their hook names depend on the command, -% environment or the -% file name and so declaring them beforehand is not practical. -% +% With a few exceptions, hooks have to be declared before they can +% be used. The exceptions are the generic hooks for commands and +% environments (executed at \cs{begin} and \cs{end}), and the +% hooks run when loading files (see section~\ref{sec:generic}). % % \begin{function}{\NewHook} % \begin{syntax} % \cs{NewHook} \Arg{hook} % \end{syntax} % Creates a new \meta{hook}. -% If this is a hook provided as part of a package it is suggested -% that the \meta{hook} name is always structured as follows: +% If this hook is declared within a package it is suggested +% that its name is always structured as follows: % \meta{package-name}\texttt{/}\meta{hook-name}. If necessary you % can further subdivide the name by adding more \texttt{/} parts. % If a hook name is already taken, an error is raised and the hook @@ -180,17 +176,19 @@ % \end{function} % % -% \subsubsection{Special declarations for hooks} +% \subsubsection{Special declarations for generic hooks} % % The declarations here should normally not be used. They are available % to provide support for special use cases mainly involving % generic command hooks. % -% \begin{function}{\DisableHook} +% \changes{v1.0p}{2021/08/20}{Documentation updates for generic hook commands (gh/638)} +% +% \begin{function}{\DisableGenericHook} % \begin{syntax} -% \cs{DisableHook} \Arg{hook} +% \cs{DisableGenericHook} \Arg{hook} % \end{syntax} -% After this declaration the \meta{hook} is no longer usable: Any +% After this declaration\footnotemark{} the \meta{hook} is no longer usable: Any % attempt to add further code to it will result in an error and any % use, e.g., via \cs{UseHook}, will simply do nothing. % @@ -201,37 +199,27 @@ % % The \meta{hook} can be specified using the dot-syntax to denote % the current package name. See section~\ref{sec:default-label}. -% \end{function} +% \end{function}\footnotetext{In the 2020/06 release this command was +% called \cs{DisableHook}, but that name was misleading as it +% shouldn't be used to disable non-generic hooks.} % % -% \begin{function}{\ProvideHook} +% \begin{function}{\ActivateGenericHook} % \begin{syntax} -% \cs{ProvideHook} \Arg{hook} +% \cs{ActivateGenericHook} \Arg{hook} % \end{syntax} -% Like \cs{NewHook} but does nothing if the hook was previously -% declared with \cs{NewHook}. This declaration should only be used -% in special situations, e.g., when command of another package -% need to be altered and it is is not clear if for that command a -% generic hook was already explicitly declared before. -% -% Normally \cs{NewHook} should be used instead. +% This declaration activates a generic hook provided by a package/class +% (e.g., one used in code with \cs{UseHook} or +% \cs{UseOneTimeHook}) without it being explicitly declared with +% \cs{NewHook}). +% This command undoes the effect of \cs{DisableGenericHook}. +% If the hook is already activated, this command does nothing. +% +% See section~\ref{sec:generic-hooks} for a discussion of when this +% declaration is appropriate. % \end{function} % -% \begin{function}{\ProvideReversedHook} -% \begin{syntax} -% \cs{ProvideReversedHook} \Arg{hook} -% \end{syntax} -% Like \cs{NewReversedHook} but does nothing if the hook was -% previously declared as a reversed hook. -% \end{function} % -% \begin{function}{\ProvideMirroredHookPair} -% \begin{syntax} -% \cs{ProvideMirroredHookPair} \Arg{hook-1} \Arg{hook-2} -% \end{syntax} -% A shorthand for -% \cs{ProvideHook}\Arg{hook-1}\cs{ProvideReversedHook}\Arg{hook-2}. -% \end{function} % % % @@ -272,12 +260,20 @@ % consumed and any further attempt to add to it will result in % executing the code to be added immediately. % -% \fmiinline{Maybe add an error version as well?} -% % The \meta{hook} \emph{cannot} be specified using the dot-syntax. % A leading |.| is treated literally. See % section~\ref{sec:default-label} for details. - +% +% Using \cs{UseOneTimeHook} several times with the same +% \Arg{hook} means that it only executes the first time it is used. +% For example, if it is used in a command that can be called several times +% then the hook executes during only the \emph{first} invocation of that +% command; this allows its use as an \enquote{initialization hook}. +% +% Mixing \cs{UseHook} and \cs{UseOneTimeHook} for the same +% \Arg{hook} should be avoided, but if this is done then neither will execute +% after the first \cs{UseOneTimeHook}. +% % \end{function} % % @@ -321,15 +317,19 @@ % 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 -% that label, the removal order takes action and the code is not -% added. +% If there is no code under the \meta{label} in the \meta{hook}, +% or if the \meta{hook} does not exist, a warning is issued when +% you attempt to \cs{RemoveFromHook}, and the command is ignored. +% \cs{RemoveFromHook} should be used only when you know exactly what +% labels are in a hook. Typically this will be when some code gets added to a hook +% by a package, then later this code is removed by that same package. +% If you want to prevent the execution of code from another +% package, use the |voids| rule instead (see section~\ref{sec:rules}). % % If the optional \meta{label} argument is \texttt{*}, then all code chunks are -% removed. This is rather dangerous as it drops code from other -% packages one may not know about and should therefore not by used -% by packages but only in document preambles! +% removed. This is rather dangerous as it may well drop code from other +% packages (that one may not know about); it should therefore not be used +% in packages but only in document preambles! % % The \meta{hook} and \meta{label} can be specified using the % dot-syntax to denote the current package name. @@ -378,14 +378,28 @@ % The code is executed after the normal hook code has finished and % it is executed only once, i.e. it is deleted after it was used. % -% Using the declaration is a global operation, i.e., the code is -% not lost, even if the declaration is used inside a group and the -% next invocation happens after the group. If the declaration is +% Using this declaration is a global operation, i.e., the code is +% not lost even if the declaration is used inside a group and the +% next invocation of the hook happens after the end of that group. +% If the declaration is % used several times before the hook is executed then all code is % executed in the order in which it was declared.\footnotemark % -% It is possible to nest declarations using the same hook (or -% different hooks), e.g., +% If this declaration is used with a one-time hook then the code +% is only ever used if the declaration comes before the hook’s +% invocation. This is because, in contrast +% to \cs{AddToHook}, the code in this declaration is not +% executed immediately in the case when the invocation of the hook +% has already happened---in other words, this code will truly execute +% only on the next invocation of the hook (and in the case of a +% one-time hook there is no such \enquote{next invocation}). +% This gives you a choice: should my code execute +% always, or should it execute only at the point where the +% one-time hook is used (and not at all if this is impossible)? For +% both of these possibilities there are use cases. +% +% It is possible to nest this declaration using the same hook (or +% different hooks): e.g., % \begin{quote} % \cs{AddToHookNext}\Arg{hook}\verb={=\meta{code-1}^^A % \cs{AddToHookNext}\Arg{hook}\Arg{code-2}\verb=}= @@ -404,6 +418,25 @@ % \end{function}\footnotetext{There is % no mechanism to reorder such code chunks (or delete them).} % +% +% +% \begin{function}{\ClearHookNext} +% \begin{syntax} +% \cs{ClearHookNext}\Arg{hook} +% \end{syntax} +% Normally \cs{AddToHookNext} is only used when you know precisely +% where it will apply and why you want some extra code at that +% point. However, there are a few use cases in which such a +% declaration needs to be canceled, for example, when +% discarding a page with \cs{DiscardShipoutBox} (but even then not +% always), and in such situations \cs{ClearHookNext} can be +% used. +% \end{function} +% +% +% +% +% % \subsubsection{Hook names and default labels} % \label{sec:default-label} % @@ -424,7 +457,7 @@ % % Except for \cs{UseHook}, \cs{UseOneTimeHook} and \cs{IfHookEmptyTF} % (and their \pkg{expl3} interfaces \cs{hook_use:n}, -% \cs{hook_use_once:n} and \cs{hook_if_empty:nTF}, all \meta{hook} +% \cs{hook_use_once:n} and \cs{hook_if_empty:nTF}), all \meta{hook} % and \meta{label} arguments are processed in the same way: first, % spaces are trimmed around the argument, then it is fully expanded % until only character tokens remain. If the full expansion of the @@ -458,7 +491,7 @@ % \AddToHook {./hook}[.]{code} % Same as \AddToHook{./hook}{code} % \AddToHook {./hook}[./sub]{code} % \DeclareHookRule{begindocument}{.}{before}{babel} -% \AddToHook {file/after/foo.tex}{code} +% \AddToHook {file/foo.tex/after}{code} % \end{verbatim} % are equivalent to: % \begin{verbatim} @@ -466,7 +499,7 @@ % \AddToHook {mypackage/hook}[mypackage]{code} % \AddToHook {mypackage/hook}[mypackage/sub]{code} % \DeclareHookRule{begindocument}{mypackage}{before}{babel} -% \AddToHook {file/after/foo.tex}{code} % unchanged +% \AddToHook {file/foo.tex/after}{code} % unchanged % \end{verbatim} % % The \meta{default label} is automatically set equal to the name of the @@ -534,7 +567,7 @@ % 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 +% dedicated labels and to emulate \cs{usepackage}-like hook behavior % within those contexts. % % The |top-level| label is treated differently, and is reserved to the @@ -588,6 +621,7 @@ % with that label from a package results in an error. % % \subsubsection{Defining relations between hook code} +% \label{sec:rules} % % The default assumption is that code added to hooks by different % packages are independent and the order in which they are executed is @@ -712,8 +746,8 @@ % \item exist and be non-empty; and % \item not exist (in which case emptiness doesn't apply); % \end{itemize} -% Hooks are a bit more complicated: -% a hook may exist or not, and either way it may or may not be empty. +% Hooks are a bit more complicated: +% a hook may exist or not, and independently it may or may not be empty. % This means that even a hook that doesn't exist may be non-empty and % it can also be disabled. % @@ -854,7 +888,7 @@ % \end{quote} % which means that the \meta{relation} applies to \meta{label-1} and % \meta{label-2}, in that order, as detailed in \cs{DeclareHookRule}. -% If the relation is \texttt{default} it means that that rule applies +% If the relation is \texttt{default} it means that this rule applies % to \meta{label-1} and \meta{label-2} in \emph{all} hooks, (unless % overridden by a non-default relation). % @@ -905,9 +939,9 @@ % % % -% \begin{function}{\hook_disable:n} +% \begin{function}{\hook_disable_generic:n} % \begin{syntax} -% \cs{hook_disable:n} \Arg{hook} +% \cs{hook_disable_generic:n} \Arg{hook} % \end{syntax} % Marks \Arg{hook} as disabled. Any further attempt to add code to % it or declare it, will result in an error and any call to @@ -921,34 +955,20 @@ % the current package name. See section~\ref{sec:default-label}. % \end{function} % -% \begin{function}{\hook_provide:n} -% \begin{syntax} -% \cs{hook_provide:n} \Arg{hook} -% \end{syntax} -% Like \cs{hook_new:n} but does nothing if the hook was previously -% declared with \cs{hook_new:n}. This declaration should only be used -% in special situations, e.g., when a command of another package -% needs to be altered and it is is not clear if for that command a -% generic \hook{cmd} hook was already explicitly declared before. -% -% Normally \cs{hook_new:n} should be used instead. -% \end{function} -% -% \begin{function}{\hook_provide_reversed:n} +% \begin{function}{\hook_activate_generic:n} % \begin{syntax} -% \cs{hook_provide_reversed:n} \Arg{hook} +% \cs{hook_activate_generic:n} \Arg{hook} % \end{syntax} -% Like \cs{hook_new_reversed:n} but does nothing if the hook was -% previously declared as a reversed hook. +% This is like \cs{hook_new:n} but it does nothing if the hook was previously +% declared with \cs{hook_new:n}. This declaration should be used +% only in special situations, e.g., when a command from another package +% needs to be altered and it is not clear whether a +% generic \hook{cmd} hook (for that command) has been previously +% explicitly declared. +% +% Normally \cs{hook_new:n} should be used instead of this. % \end{function} % -% \begin{function}{\hook_provide_pair:nn} -% \begin{syntax} -% \cs{hook_provide_pair:nn} \Arg{hook-1} \Arg{hook-2} -% \end{syntax} -% A shorthand for -% \cs{hook_provide:n}\Arg{hook-1}\cs{hook_provide_reversed:n}\Arg{hook-2}. -% \end{function} % % % @@ -1013,6 +1033,15 @@ % \end{function} % % +% \begin{function} +% {\hook_gclear_next_code:n} +% \begin{syntax} +% \cs{hook_gclear_next_code:n} \Arg{hook} +% \end{syntax} +% Undo any earlier \cs{hook_gput_next_code:nn}. +% \end{function} +% +% % % \begin{function}{\hook_gremove_code:nn} % \begin{syntax} @@ -1020,10 +1049,9 @@ % \end{syntax} % Removes any code for \meta{hook} labeled \meta{label}. % -% If the code for that \meta{label} wasn't yet added to the -% \meta{hook}, an order is set so that when some code attempts to add -% that label, the removal order takes action and the code is not -% added. +% If there is no code under the \meta{label} in the \meta{hook}, +% or if the \meta{hook} does not exist, a warning is issued when +% you attempt to use \cs{hook_gremove_code:nn}, and the command is ignored. % % If the second argument is \texttt{*}, then all code chunks are % removed. This is rather dangerous as it drops code from other @@ -1138,7 +1166,7 @@ % which key-value pairs got added. However, that is only true if % nothing other than adding happens! % -% Suppose, or example, you want to replace the code chunk for +% Suppose, for example, you want to replace the code chunk for % \texttt{packageA}, e.g., %\begin{verbatim} % \RemoveFromHook{myhook}[packageA] @@ -1297,7 +1325,7 @@ % \cs{AtBeginDocument} which is why it is supported.} (all three % code chunks are executed one after another), but it makes little % sense with a normal hook, because with a normal hook the first time -% \verb=\UseHook{myhook}= is executed it would +% \verb=\UseHook{myhook}= is executed it would % \begin{itemize} % \item % execute \meta{code-1}, @@ -1315,6 +1343,70 @@ % % % +% \subsection{Generic hooks provided by packages} +% \label{sec:generic-hooks} +% +% \changes{v1.0p}{2021/08/20}{Section on generic hooks added (gh/638)} +% +% The hook management system also implements a category of hooks +% that are called \enquote{Generic Hooks}. Normally a hook has to +% be explicitly declared before it can be used in code. This +% ensures that different packages are not using the same hook name +% for unrelated purposes---something that would result in absolute +% chaos. However, there are a number of \enquote{standard} hooks +% where it is unreasonable to declare them beforehand, e.g, each +% and every command has (in theory) an associated \texttt{before} +% and \texttt{after} hook. In such cases, i.e., for command, +% environment or file hooks, they can be used simply by adding code +% to them with \cs{AddToHook}. For more specialized generic hooks, +% e.g., those provided by \pkg{babel}, you have to additionally +% enable them with \cs{ActivateGenericHook} as explained below. +% +% The generic hooks provided by \LaTeX{} are those for +% \hook{cmd}, +% \hook{env}, +% \hook{file}, +% \hook{include} +% \hook{package}, and +% \hook{class}, +% and all these are available out of the box: you only have to +% use \cs{AddToHook} to +% add code to them, but you don't have to add \cs{UseHook} or +% \cs{UseOneTimeHook} to your code, because this is already done for +% you (or, in the case of \hook{cmd} hooks, the command’s code is +% patched at \verb=\begin{document}=, if necessary). +% +% However, if you want to provide further generic hooks in your own +% code, the situation is slightly different. To do this you should +% use \cs{UseHook} or \cs{UseOneTimeHook}, but +% \emph{without declaring the hook} with \cs{NewHook}. As +% mentioned earlier, a call to \cs{UseHook} with an undeclared hook +% name does nothing. So as an additional setup step, you need to +% explicitly activate your generic hook. Note that a generic hook +% produced in this way is always a normal hook. +% +% For a truly generic hook, with a variable part in the hook name, +% such upfront activation would be difficult or impossible, because +% you typically do not know what kind of variable parts may come up +% in real documents. +% +% For example, \pkg{babel} may want to provide hooks such as +% \hook{babel/afterextras/\meta{language}}. Language support in +% \pkg{babel} is often done through external language +% packages. Thus doing the activation for all languages inside the +% core \pkg{babel} code is not a viable approach. Instead it needs +% to be done by each language package (or by the user who wants to +% use a particular hook). +% +% Because the hooks are not declared with \cs{NewHook} their names +% should be carefully chosen to ensure that they are (likely to be) +% unique. Best practice is to include the package or +% command name, as was done in the \pkg{babel} example above. +% +% Generic hooks defined in this way are always normal hooks (i.e., +% you can't implement reversed hooks this way). This is a +% deliberate limitation, because it speeds up the processessing +% conciderably. % % % \subsection{Private \LaTeX{} kernel hooks} @@ -1354,8 +1446,8 @@ % % \subsection{Legacy \LaTeXe{} interfaces} % -% \newcommand\onetimetext{% -% This is a one-time hook, so after it is executed, all further +% \newcommand\onetimetext{This is a one-time hook, so after it +% is executed, all further % attempts to add code to it will execute such code immediately % (see section~\ref{sec:onetime-hooks}).} % @@ -1363,7 +1455,7 @@ % add to them. They are listed here and are retained for backwards % compatibility. % -% With the new hook management several additional hooks have been added +% With the new hook management, several additional hooks have been added % to \LaTeX\ and more will follow. See the next section for what % is already available. % @@ -1374,7 +1466,7 @@ % \end{syntax} % If used without the optional argument \meta{label}, it works essentially % like before, i.e., it is adding \meta{code} to the hook -% \hook{begindocument} +% \hook{begindocument} % (which is executed inside \verb=\begin{document}=). % However, all code added this way is labeled with the label % \hook{top-level} (see section~\ref{sec:top-level}) @@ -1430,10 +1522,54 @@ % the processing. % % -% \subsection{\LaTeXe{} commands and environments augmented by -% hooks} -% -% \emph{intro to be written} +% \section{\LaTeXe{} commands and environments augmented by hooks} +% +% In this section we describe the standard hooks that are now +% offered by \LaTeX{}, or give pointers to other documents in which +% they are described. This section will grow over time (and +% perhaps eventually move to usrguide3). +% +% \subsection{Generic hooks} +% \label{sec:generic} +% +% As stated earlier, with the exception of generic hooks, all hooks must +% be declared with \cs{NewHook} before they can be used. +% All generic hooks have names of the form +% \enquote{\meta{type}/\meta{name}/\meta{position}}, where \meta{type} +% is from the predefined list shown below, and \meta{name} is the variable +% part whose meaning will depend on the \meta{type}. The last component, +% \meta{position}, has more complex possibilities: +% it can always be |before| or |after|; for |env| hooks, it can also be |begin| +% or |end|; and for |include| hooks it can also be |end|. Each specific +% hook is documented below, or in \texttt{ltcmdhooks-doc.pdf} or +% \texttt{ltfilehook-doc.pdf}. +% +% The generic hooks provided by \LaTeX{} belong to one of the six types: +% \begin{description} +% \item[env] Hooks executed before and after environments -- +% \meta{name} is the name of the environment, and available values +% for \meta{position} are |before|, |begin|, |end|, and |after|; +% \item[cmd] Hooks added to and executed before and after commands -- +% \meta{name} is the name of the command, and available values +% for \meta{position} are |before| and |after|; +% \item[file] Hooks executed before and after reading a file -- +% \meta{name} is the name of the file (with extension), and +% available values for \meta{position} are |before| and |after|; +% \item[package] Hooks executed before and after loading packages -- +% \meta{name} is the name of the package, and available values for +% \meta{position} are |before| and |after|; +% \item[class] Hooks executed before and after loading classes -- +% \meta{name} is the name of the class, and available values for +% \meta{position} are |before| and |after|; +% \item[include] Hooks executed before and after \cs{include}d files -- +% \meta{name} is the name of the included file (without the |.tex| +% extension), and available values for \meta{position} are |before|, +% |end|, and |after|. +% \end{description} +% +% Each of the hooks above are detailed in the following sections and +% in linked documentation. +% ^^A^^A^^A \pho{Wouldn't it be better to document all hooks here?} % % \subsubsection{Generic hooks for all environments} % @@ -1495,9 +1631,15 @@ % to add the outer hooks, etc. % % +% Largely for compatibility with existing packages, the following +% four commands are also available to set the environment hooks; but for +% new packages we recommend directly using the hook names and +% \cs{AddToHook}. +% +% % \begin{function}{\BeforeBeginEnvironment} % \begin{syntax} -% \cs{BeforeBeginEnvironment} \oarg{label} \Arg{code} +% \cs{BeforeBeginEnvironment} \oarg{label} \Arg{env} \Arg{code} % \end{syntax} % This declaration adds to the \hook{env/\meta{env}/before} hook % using the \meta{label}. If \meta{label} is not given, the @@ -1506,23 +1648,23 @@ % % \begin{function}{\AtBeginEnvironment} % \begin{syntax} -% \cs{AtBeginEnvironment} \oarg{label} \Arg{code} +% \cs{AtBeginEnvironment} \oarg{label} \Arg{env} \Arg{code} % \end{syntax} -% Like \cs{BeforeBeginEnvironment} but adds to the \hook{env/\meta{env}/begin} hook. +% This is like \cs{BeforeBeginEnvironment} but it adds to the \hook{env/\meta{env}/begin} hook. % \end{function} % % \begin{function}{\AtEndEnvironment} % \begin{syntax} -% \cs{AtEndEnvironment} \oarg{label} \Arg{code} +% \cs{AtEndEnvironment} \oarg{label} \Arg{env} \Arg{code} % \end{syntax} -% Like \cs{BeforeBeginEnvironment} but adds to the \hook{env/\meta{env}/end} hook. +% This is like \cs{BeforeBeginEnvironment} but it adds to the \hook{env/\meta{env}/end} hook. % \end{function} % % \begin{function}{\AfterEndEnvironment} % \begin{syntax} -% \cs{AfterEndEnvironment} \oarg{label} \Arg{code} +% \cs{AfterEndEnvironment} \oarg{label} \Arg{env} \Arg{code} % \end{syntax} -% Like \cs{BeforeBeginEnvironment} but adds to the \hook{env/\meta{env}/after} hook. +% This is like \cs{BeforeBeginEnvironment} but it adds to the \hook{env/\meta{env}/after} hook. % \end{function} % % @@ -1559,7 +1701,7 @@ % % % -% \subsubsection{Hooks provided by \cs{begin}\texttt{\{document\}}} +% \subsection{Hooks provided by \cs{begin}\texttt{\{document\}}} % \label{sec:begindocument-hooks} % % Until 2020 \cs{begin}\texttt{\{document\}} offered exactly one @@ -1618,7 +1760,7 @@ % % % -% \subsubsection{Hooks provided by \cs{end}\texttt{\{document\}}} +% \subsection{Hooks provided by \cs{end}\texttt{\{document\}}} % % \LaTeXe{} always provided \cs{AtEndDocument} to add code to the % execution of \verb=\end{document}= just in front of the code that @@ -1726,7 +1868,7 @@ % % % -% \subsubsection{Hooks provided by \cs{shipout} operations} +% \subsection{Hooks provided by \cs{shipout} operations} % \label{sec:shipout} % % There are several hooks and mechanisms added to \LaTeX{}'s @@ -1735,36 +1877,44 @@ % \texttt{ltshipout-code.pdf}. % % +% \subsection{Hooks provided for paragraphs} +% \label{sec:para} +% +% The paragraph processing has been augmented to include a number of +% internal and public hooks. These are documented in +% \texttt{ltpara-doc.pdf} or with code in +% \texttt{ltpara-code.pdf}. +% % -% \subsubsection{Hooks provided in NFSS commands} +% +% \subsection{Hooks provided in NFSS commands} % % In languages that need to support for more than one script in -% parallel (and thus several sets of fonts), e.g., Latin and -% Japanese fonts, NFSS font commands, such as \cs{sffamily}, need +% parallel (and thus several sets of fonts, e.g., supporting both Latin and +% Japanese fonts), NFSS font commands such as \cs{sffamily} need % to switch both the Latin family to ``Sans Serif'' and in addition % alter a second set of fonts. % -% To support this several NFSS have hooks in which such support can -% be added. +% To support this, several NFSS commands have hooks to which +% such support can be added. % \begin{description} % % \item[\hook{rmfamily}] % % After \cs{rmfamily} has done its initial checks and prepared a -% any font series update this hook is executed and only -% afterwards \cs{selectfont}. +% font series update, this hook is executed before \cs{selectfont}. % % \item[\hook{sffamily}] % -% Like the \hook{rmfamily} hook but for the \cs{sffamily} command. +% This is like the \hook{rmfamily} hook, but for the \cs{sffamily} command. % % \item[\hook{ttfamily}] % -% Like the \hook{rmfamily} hook but for the \cs{ttfamily} command. +% This is like the \hook{rmfamily} hook, but for the \cs{ttfamily} command. % % \item[\hook{normalfont}] % -% The \cs{normalfont} command resets font encoding family series +% The \cs{normalfont} command resets the font encoding, family, series % and shape to their document defaults. It then executes this % hook and finally calls \cs{selectfont}. % @@ -1779,21 +1929,36 @@ % % \item[\hook{bfseries/defaults}, \hook{bfseries}] % -% If the \cs{bfdefault} was explicitly changed by the user its +% If the \cs{bfdefault} was explicitly changed by the user, its % new value is used to set the bf series defaults for the meta -% families (rm/sf/tt) when \cs{bfseries} is called. In the -% \hook{bfseries/defaults} hook further adjustments can be made +% families (rm/sf/tt) when \cs{bfseries} is called. The +% \hook{bfseries/defaults} hook allows further adjustments to be made % in this case. This hook is only executed if such a change is -% detected. In contrast the \hook{bfseries} hook is always +% detected. In contrast, the \hook{bfseries} hook is always % executed just before \cs{selectfont} is called to change to the % new series. % % % \item[\hook{mdseries/defaults}, \hook{mdseries}] % -% These two hooks are like the previous ones but used in +% These two hooks are like the previous ones but they are in the % \cs{mdseries} command. % +% \item[\hook{selectfont}] +% +% This hook is executed inside \cs{selectfont}, after the current +% values for \textit{encoding}, \textit{family}, \textit{series}, +% \textit{shape}, and \textit{size} are evaluated and the new font +% is selected (and if necessary loaded). After the hook has +% executed, NFSS will still do any updates necessary for a new +% \textit{size} (such as changing the size of \cs{strut}) and any +% updates necessary to a change in \textit{encoding}. +% +% This hook is intended for use cases where, in parallel to a +% change in the main font, some other fonts need to be altered +% (e.g., in CJK processing where you may need to deal with several +% different alphabets). +% % \end{description} % % @@ -1859,7 +2024,7 @@ % % \begin{macro}[EXP]{\@@_str_compare:nn} % Private copy of \cs{__str_if_eq:nn} -% \InternalDetectionOff +% \InternalDetectionOff % \begin{macrocode} \cs_new_eq:NN \@@_str_compare:nn \__str_if_eq:nn % \end{macrocode} @@ -1892,13 +2057,6 @@ % \end{macrocode} % \end{macro} % -% \begin{macro}{\g_@@_removal_list_prop} -% A token list to hold delayed removals. -% \begin{macrocode} -\tl_new:N \g_@@_removal_list_tl -% \end{macrocode} -% \end{macro} -% % \begin{macro}{\l_@@_cur_hook_tl} % Stores the name of the hook currently being sorted. % \begin{macrocode} @@ -1916,13 +2074,6 @@ % \end{macrocode} % \end{macro} % -% \begin{macro}{\g_@@_execute_immediately_prop} -% List of hooks that from no on should not longer receive code. -% \begin{macrocode} -\prop_new:N \g_@@_execute_immediately_prop -% \end{macrocode} -% \end{macro} -% % \begin{macro}{\g_@@_used_prop} % All hooks that receive code (for use in debugging display). % \begin{macrocode} @@ -1963,6 +2114,13 @@ % \end{macrocode} % \end{macro} % +% \begin{macro}{\@@_clean_to_scan:w} +% Removes tokens until the next \cs{s_@@_mark}. +% \begin{macrocode} +\cs_new:Npn \@@_clean_to_scan:w #1 \s_@@_mark { } +% \end{macrocode} +% \end{macro} +% % \begin{macro}{\@@_tl_set:Nn,\@@_tl_set:Nx, % \@@_tl_set:cn,\@@_tl_set:cx} % Private copies of a few \pkg{expl3} functions. \pkg{l3debug} will @@ -2055,7 +2213,7 @@ % \item[\cs{g_@@_\meta{hook}_code_prop}] A property list holding the code % for the hook in separate chunks. The keys are by default the % package names that add code to the hook, but it is possible -% for packages to define other keys. +% for packages to define other keys. % % \item[{\cs[no-index]{g_@@_\meta{hook}_rule_\meta{label1}\string|\meta{label2}_tl}}] % A token list holding the relation between \meta{label1} and @@ -2108,19 +2266,19 @@ % \label{sec:existence} % % A hook may be in different states of existence. Here we give an -% overview of internal commands to set up hooks and explain how the +% overview of the internal commands to set up hooks and explain how the % different states are distinguished. The actual implementation -% then follows in the next sections. +% then follows in subsequent sections. % -% One problem we have to solve is, that we need to be able to add +% One problem we have to solve is that we need to be able to add % code to hooks (e.g., with \cs{AddToHook}) even if that code has -% not been declared yet. For example, one package needs to write -% into a hook of another package, but that package ay not get -% loaded or only loaded later. Another problem most hooks require -% declaration but this is not the case for the generic hooks. +% not yet been declared. For example, one package needs to write +% into a hook of another package, but that package may not get +% loaded, or is loaded only later. Another problem is that most hooks, +% but not the generic hooks, require a declaration. % -% We therefore distinguish the following states for a hook and they -% are managed with four different tests: structure existence +% We therefore distinguish the following states for a hook, which +% are managed by four different tests: structure existence % (\cs{@@_if_structure_exist:nTF}), creation % (\cs{@@_if_usable:nTF}), declaration (\cs{@@_if_declared:nTF}) % and disabled or not (\cs{@@_if_disabled:nTF}) @@ -2151,12 +2309,12 @@ % \item [@@_if_disabled:nTF] returns |false|. % \end{itemize} % -% The allowed acctions are the same as in the \enquote{not +% The allowed actions are the same as in the \enquote{not % existing} state. % % \item[declared] % -% A hook is in this state it is not disabled and was explicity declared (e.g., +% A hook is in this state it is not disabled and was explicitly declared (e.g., % with \cs{NewHook}). In this case the four tests give the % following results: % \begin{itemize} @@ -2187,8 +2345,8 @@ % % \item[disabled] % -% A hook in any state is moved to this state when -% \cs{DisableHook} is used. This changes the tests to give the +% A generic hook in any state is moved to this state when +% \cs{DisableGenericHook} is used. This changes the tests to give the % following results: % \begin{itemize} % \item [@@_if_structure_exist:nTF] \emph{unchanged}. @@ -2197,7 +2355,7 @@ % \item [@@_if_disabled:nTF] returns |true|. % \end{itemize} % The structure test is unchanged (if the hook was unknown before it is -% false, otherwise true). The usable test returns false so that +% |false|, otherwise |true|). The usable test returns |false| so that % any \cs{UseHook} will bypass the hook from now on. The % declared test returns true so that any further \cs{NewHook} % generates an error and the disabled test returns true so that @@ -2240,8 +2398,8 @@ % \end{macrocode} % \end{macro} % -% -% +% +% % \begin{macro}{\@@_make_usable:n} % % This initializes all hook data structures for the hook but if @@ -2315,7 +2473,7 @@ % (\cs[no-index]{g_@@_\meta{hook}_code_prop}) and the |top-level| % and |next| token lists. A hook is initialized with % \cs{@@_init_structure:n} the first time anything is added to it. -% Inizializing a hook just with \cs{@@_init_structure:n} will not +% Initializing a hook just with \cs{@@_init_structure:n} will not % make it usable with \cs{hook_use:n}. % \begin{macrocode} \cs_new_protected:Npn \@@_init_structure:n #1 @@ -2407,7 +2565,9 @@ % % \subsubsection{Disabling and providing hooks} % -% \begin{macro}{\hook_disable:n} +% \changes{v1.0p}{2021/08/20}{Renames of generic hook commands (gh/638)} +% +% \begin{macro}{\hook_disable_generic:n} % \begin{macro}{\@@_disable:n} % \begin{macro}[pTF]{\@@_if_disabled:n} % @@ -2423,11 +2583,11 @@ % % \begin{macrocode} %\IncludeInRelease{2021/06/01}% -% {\hook_disable:n}{Disable~hooks} +% {\hook_disable_generic:n}{Disable~hooks} % \end{macrocode} -% +% % \begin{macrocode} -\cs_new_protected:Npn \hook_disable:n #1 +\cs_new_protected:Npn \hook_disable_generic:n #1 { \@@_normalize_hook_args:Nn \@@_disable:n {#1} } \cs_new_protected:Npn \@@_disable:n #1 { @@ -2447,9 +2607,9 @@ % % \begin{macrocode} %\IncludeInRelease{2020/10/01} -% {\hook_disable:n}{Disable~hooks} +% {\hook_disable_generic:n}{Disable~hooks} % -%\cs_new_protected:Npn \hook_disable:n #1 {} +%\cs_new_protected:Npn \hook_disable_generic:n #1 {} % %\EndIncludeInRelease % \end{macrocode} @@ -2457,71 +2617,47 @@ % \end{macro} % \end{macro} % -% \begin{macro}{\hook_provide:n} -% \begin{macro}{\hook_provide_reversed:n} -% \begin{macro}{\@@_provide:n} -% The \cs{hook_provide:n} declaration declares a new hook if it +% \begin{macro}{\hook_activate_generic:n} +% \begin{macro}{\@@_activate_generic:n} +% The \cs{hook_activate_generic:n} declaration declares a new hook if it % wasn't declared already, in which case it only checks that the % already existing hook is not a reversed hook. -% The \cs{hook_provide_reversed:n} does the same for reversed hooks. -% \hook{begindocument}. % \begin{macrocode} %\IncludeInRelease{2021/06/01}% -% {\hook_provide:n}{Providing~hooks} +% {\hook_activate_generic:n}{Providing~hooks} % \end{macrocode} % % \begin{macrocode} -\cs_new_protected:Npn \hook_provide:n #1 - { \@@_normalize_hook_args:Nn \@@_provide:nn {#1} { } } -\cs_new_protected:Npn \hook_provide_reversed:n #1 - { \@@_normalize_hook_args:Nn \@@_provide:nn {#1} { - } } +\cs_new_protected:Npn \hook_activate_generic:n #1 + { \@@_normalize_hook_args:Nn \@@_activate_generic:nn {#1} { } } % \end{macrocode} % % \begin{macrocode} -\cs_new_protected:Npn \@@_provide:nn #1 #2 +\cs_new_protected:Npn \@@_activate_generic:nn #1 #2 { % \end{macrocode} -% If the hook to be provided was disabled we warn (for now --- this +% If the hook to be activated was disabled we warn (for now --- this % may change). % \begin{macrocode} \@@_if_disabled:nTF {#1} - { \msg_warning:nnn { hooks } { provide-disabled } {#1} } + { \msg_warning:nnn { hooks } { activate-disabled } {#1} } % \end{macrocode} -% Otherwise we check if it was already declared. +% Otherwise we check if the hook is not declared, and if it isn't, +% figure out if it's reversed or not, then declare it accordingly. % \begin{macrocode} { - \@@_if_declared:nTF {#1} - { -% \end{macrocode} -% Issue an error if we try to provide a a hook that is reversed and -% the already existing one is not (or vice versa). -% \begin{macrocode} - \str_if_eq:eeF { \tl_use:c { g_@@_#1_reversed_tl } } {#2} - { \msg_error:nnn { hooks } { provide-error } {#1} } - } -% \end{macrocode} -% If it wasn't declared, we declared as a normal or reversed hook -% as appropriate. -% \begin{macrocode} + \@@_if_declared:nF {#1} { \tl_new:c { g_@@_#1_declared_tl } \@@_make_usable:n {#1} - \tl_gset:cn { g_@@_#1_reversed_tl } {#2} + \tl_gset:cx { g_@@_#1_reversed_tl } + { \@@_if_generic_reversed:nT {#1} { - } } } } } % \end{macrocode} % \end{macro} % \end{macro} -% \end{macro} -% -% \begin{macro}{\hook_provide_pair:nn} -% A shorthand for providing a normal and a (matching) reversed hook in one go. -% \begin{macrocode} -\cs_new_protected:Npn \hook_provide_pair:nn #1#2 - { \hook_provide:n {#1} \hook_provide_reversed:n {#2} } -% \end{macrocode} -% \end{macro} % % \begin{macrocode} %\EndIncludeInRelease @@ -2529,11 +2665,9 @@ % % \begin{macrocode} %\IncludeInRelease{2020/10/01} -% {\hook_provide:n}{Providing~hooks} +% {\hook_activate_generic:n}{Providing~hooks} % -%\cs_new_protected:Npn \hook_provide_reversed:n #1 {} -%\cs_new_protected:Npn \hook_provide:n #1 {} -%\cs_new_protected:Npn \hook_provide_pair:nn #1#2 {} +%\cs_new_protected:Npn \hook_activate_generic:n #1 {} % %\EndIncludeInRelease % \end{macrocode} @@ -2600,8 +2734,8 @@ % \end{macro} % % \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, raises an error and uses the +% This uses \cs{g_@@_hook_curr_name_tl} if it is set, otherwise it tries +% \cs{@currname}. If neither is set, it raises an error and uses the % fallback value \verb|label-missing|. % \begin{macrocode} \cs_new:Npn \@@_currname_or_default: @@ -2610,7 +2744,7 @@ { \tl_if_empty:NTF \@currname { - \msg_expandable_error:nnn { kernel } { should-not-happen } + \msg_expandable_error:nnn { latex2e } { should-not-happen } { Empty~default~label. } \@@_make_name:n { label-missing } } @@ -2622,7 +2756,7 @@ % \end{macro} % % \begin{macro}[EXP]{\@@_make_name:n,\@@_make_name:w} -% Provides a standard sanitization of a hook's name. +% This provides a standard sanitization of a hook's name. % It uses \cs{cs:w} to build a control sequence out of the hook name, % then uses \cs{cs_to_str:N} to get the string representation of that, % without the escape character. \cs{cs:w}-based expansion is used @@ -2646,7 +2780,7 @@ % \begin{macro}{\@@_normalize_hook_args:Nnn} % \begin{macro}{\@@_normalize_hook_rule_args:Nnnnn} % \begin{macro}{\@@_normalize_hook_args_aux:Nn} -% Standard route for normalising hook and label arguments. The main +% This is the standard route for normalizing hook and label arguments. The main % macro does the entire operation within a group so that csnames made % by \cs{@@_make_name:n} are wiped off before continuing. This means % that this function cannot be used for \cs{hook_use:n}! @@ -2689,16 +2823,151 @@ % \end{macro} % \end{macro} % +% \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 the default label in hooks. +% Providing a consistent interface is tricky because packages can +% be loaded within packages, and some packages may not use +% \cs{SetDefaultHookLabel} to change the default label (in which +% case \cs{@currname} is used). +% +% 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} +\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: +% \changes{v1.0i}{2021/03/18} +% {Only add \texttt{top-level} if not already there.} +% \begin{macrocode} +%\seq_if_empty:NT \g_@@_name_stack_seq +% { \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} +%\cs_set_protected:Npn \@@_tmp:w #1 #2 #3 +% { +% \quark_if_recursion_tail_stop:n {#1} +% \seq_gput_right:Nn \g_@@_name_stack_seq {#1} +% \@@_tmp:w +% } +%\exp_after:wN \@@_tmp:w \@currnamestack +% \q_recursion_tail \q_recursion_tail +% \q_recursion_tail \q_recursion_stop +% \end{macrocode} +% and finally set the default label to be the \cs{@currname}: +% \changes{v1.0i}{2021/03/18} +% {Remove the (empty) \enquote{top-level} from \cs{@currnamestack}.} +% \begin{macrocode} +%\tl_gset:Nx \g_@@_hook_curr_name_tl { \@currname } +%\seq_gpop_right:NN \g_@@_name_stack_seq \l_@@_tmpa_tl +% \end{macrocode} +% +% Two commands keep track of the stack: when a file is input, +% \cs{@@_curr_name_push:n} pushes the current default label onto the +% stack and sets the new default label (all 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 + { + \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 that label will not be used again, and \cs{g_@@_hook_curr_name_tl} +% is updated to equal the now topmost item of the stack: +% \begin{macrocode} +\cs_new_protected:Npn \@@_curr_name_pop: + { + \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:n} 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: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} +% +% The token list \cs{g_@@_hook_curr_name_tl} is but a mirror of the +% top of the stack. % +% \begin{macro}{\@@_set_default_hook_label:n,\@@_set_default_label:n} +% 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} +\cs_new_protected:Npn \@@_set_default_hook_label:n #1 + { + \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} } + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} % % \subsection{Adding or removing hook code} % % \begin{macro}{\hook_gput_code:nnn} -% \begin{macro}{\@@_gput_code:nnn,\@@_gput_code:nxv,\@@_hook_gput_code_do:nnn} +% \begin{macro}{\@@_gput_code:nnn,\@@_hook_gput_code_do:nnn} % % With \cs{hook_gput_code:nnn}\Arg{hook}\Arg{label}\Arg{code} a % chunk of \meta{code} is added to an existing \meta{hook} labeled % with \meta{label}. +% \changes{v1.0o}{2021/07/22}{Do not queue removals (gh/625)} % \begin{macrocode} \cs_new_protected:Npn \hook_gput_code:nnn #1 #2 { \@@_normalize_hook_args:Nnn \@@_gput_code:nnn {#1} {#2} } @@ -2708,61 +2977,46 @@ \cs_new_protected:Npn \@@_gput_code:nnn #1 #2 #3 { % \end{macrocode} -% First check if the hook was used as a one-time hook: +% First check if the code should be executed immediately, rather than +% stored: +% \changes{v1.0r}{2021/09/06}{Use dedicated conditional (gh/606)} % \begin{macrocode} - \prop_if_in:NnTF \g_@@_execute_immediately_prop {#1} + \@@_if_execute_immediately:nTF {#1} {#3} { % \end{macrocode} -% Then check if the current \meta{hook}/\meta{label} pair was marked -% for removal, in which case \cs{@@_unmark_removal:nn} is used to -% remove that mark (once). This may happen when a package removes -% code from another package which was not yet loaded: the removal -% order is stored, and at this stage it is executed by not adding to -% the hook. -% \begin{macrocode} - \@@_if_marked_removal:nnTF {#1} {#2} - { \@@_unmark_removal:nn {#1} {#2} } - { -% \end{macrocode} -% If no removal is queued, we are free to add. Start by checking if -% the hook exists. +% Then check if the hook is usable. % \begin{macrocode} - \@@_if_usable:nTF {#1} + \@@_if_usable:nTF {#1} % \end{macrocode} % If so we simply add (or append) the new code to the property list % holding different chunks for the hook. At \verb=\begin{document}= % this is then sorted into a token list for fast execution. % \begin{macrocode} - { - \@@_hook_gput_code_do:nnn {#1} {#2} {#3} + { + \@@_hook_gput_code_do:nnn {#1} {#2} {#3} % \end{macrocode} % However, if there is an update within the document we need to alter % this execution code which is done by % \cs{@@_update_hook_code:n}. In the preamble this does nothing. % \begin{macrocode} - \@@_update_hook_code:n {#1} - } + \@@_update_hook_code:n {#1} + } % \end{macrocode} % -% If the hook does not exist, however, before giving up try to -% declare it as a generic hook, if its name matches one of the valid -% patterns. +% If the hook is not usable, before giving up, check if it's not +% disabled and otherwise try to declare it as a generic hook, if its +% name matches one of the valid patterns. % \begin{macrocode} - { - \@@_if_disabled:nTF {#1} - { \msg_error:nnn { hooks } { hook-disabled } {#1} } - { \@@_try_declaring_generic_hook:nnn {#1} {#2} {#3} } - } + { + \@@_if_disabled:nTF {#1} + { \msg_error:nnn { hooks } { hook-disabled } {#1} } + { \@@_try_declaring_generic_hook:nnn {#1} {#2} {#3} } } } } % \end{macrocode} % -% \begin{macrocode} -\cs_generate_variant:Nn \@@_gput_code:nnn { nxv } -% \end{macrocode} -% % This macro will unconditionally add a chunk of code to the given hook. % \begin{macrocode} \cs_new_protected:Npn \@@_hook_gput_code_do:nnn #1 #2 #3 @@ -2839,21 +3093,40 @@ % next-execution hooks does the same: it defers the code to % \cs{hook_gput_next_code:nn} if the generic hook was declared, or % to \cs{@@_gput_next_do:nn} otherwise. +% \changes{v1.0p}{2021/08/25}{Standardise generic hook names (gh/648)} % \begin{macrocode} +%\IncludeInRelease{2021/11/15}{\@@_try_declaring_generic_hook:nnn} +% {Standardise~generic~hook~names} \cs_new_protected:Npn \@@_try_declaring_generic_hook:nnn #1 { - \@@_try_declaring_generic_hook:nNNnn {#1} - \hook_gput_code:nnn \@@_gput_undeclared_hook:nnn + \@@_try_declaring_generic_hook:wnTF #1 / / / \scan_stop: {#1} + \hook_gput_code:nnn + \@@_gput_undeclared_hook:nnn + {#1} } \cs_new_protected:Npn \@@_try_declaring_generic_next_hook:nn #1 { - \@@_try_declaring_generic_hook:nNNnn {#1} - \hook_gput_next_code:nn \@@_gput_next_do:nn + \@@_try_declaring_generic_hook:wnTF #1 / / / \scan_stop: {#1} + \hook_gput_next_code:nn + \@@_gput_next_do:nn + {#1} } +%\EndIncludeInRelease +%\IncludeInRelease{2020/10/01}{\@@_try_declaring_generic_hook:nnn} +% {Standardise~generic~hook~names} +%\cs_new_protected:Npn \@@_try_declaring_generic_hook:nnn #1 +% { +% \@@_try_declaring_generic_hook:nNNnn {#1} +% \hook_gput_code:nnn \@@_gput_undeclared_hook:nnn +% } +%\cs_new_protected:Npn \@@_try_declaring_generic_next_hook:nn #1 +% { +% \@@_try_declaring_generic_hook:nNNnn {#1} +% \hook_gput_next_code:nn \@@_gput_next_do:nn +% } % \end{macrocode} % \end{macro} % -% % \begin{macro}{\@@_try_declaring_generic_hook:nNNnn, % \@@_try_declaring_generic_hook_split:nNNnn} % @@ -2866,44 +3139,43 @@ % component to see if we have to make a reversed hook. In either case % the function returns \meta{true} for a generic hook and \meta{false} % in other cases. +% +% \changes{v1.0s}{2021/09/28} +% {Correct usage of older \cs{@@_if_file_hook:wTF} (gh/675)} % \begin{macrocode} -\cs_new_protected:Npn \@@_try_declaring_generic_hook:nNNnn #1 - { - \@@_if_file_hook:wTF #1 / / \s_@@_mark - { - \exp_args:Ne \@@_try_declaring_generic_hook_split:nNNnn - { \exp_args:Ne \@@_file_hook_normalize:n {#1} } - } - { \@@_try_declaring_generic_hook_split:nNNnn {#1} } - } +%\cs_new_protected:Npn \@@_try_declaring_generic_hook:nNNnn #1 +% { +% \@@_if_file_hook:wTF #1 / \s_@@_mark +% { +% \exp_args:Ne \@@_try_declaring_generic_hook_split:nNNnn +% { \exp_args:Ne \@@_file_hook_normalize:n {#1} } +% } +% { \@@_try_declaring_generic_hook_split:nNNnn {#1} } +% } % \end{macrocode} % % \begin{macrocode} -\cs_new_protected:Npn \@@_try_declaring_generic_hook_split:nNNnn #1 #2 #3 - { - \@@_try_declaring_generic_hook:wnTF #1 / / / \scan_stop: {#1} - { #2 } - { #3 } {#1} - } +%\cs_new_protected:Npn \@@_try_declaring_generic_hook_split:nNNnn #1 #2 #3 +% { +% \@@_try_declaring_generic_hook:wnTF #1 / / / \scan_stop: {#1} +% { #2 } +% { #3 } {#1} +% } +%\EndIncludeInRelease % \end{macrocode} % \end{macro} % -% % \begin{macro}[TF]{\@@_try_declaring_generic_hook:wn} -% % \begin{macrocode} -%\IncludeInRelease{2021/06/01}% -% {\@@_try_declaring_generic_hook:wn}{Support~cmd~hooks} +%\IncludeInRelease{2021/11/15}{\@@_try_declaring_generic_hook:wn}% +% {Standardise~generic~hook~names} \prg_new_protected_conditional:Npnn \@@_try_declaring_generic_hook:wn #1 / #2 / #3 / #4 \scan_stop: #5 { TF } { - \tl_if_empty:nTF {#2} - { \prg_return_false: } + \@@_if_generic:nTF {#5} { - \prop_if_in:NnTF \c_@@_generics_prop {#1} + \@@_if_usable:nF {#5} { - \@@_if_usable:nF {#5} - { % \end{macrocode} % If the hook doesn't exist yet we check if it is a \texttt{cmd} % hook and if so we attempt patching the command in addition to @@ -2913,8 +3185,8 @@ % \cs{@@_patch_cmd_or_delay:Nnn} (defined in \texttt{ltcmdhooks}) % will generate an appropriate error message. % \begin{macrocode} - \str_if_eq:nnT {#1} { cmd } - { \@@_try_put_cmd_hook:n {#5} } + \str_if_eq:nnT {#1} { cmd } + { \@@_try_put_cmd_hook:n {#5} } % \end{macrocode} % % Declare the hook always even if it can't really be used (error @@ -2923,26 +3195,125 @@ % Here we use \cs{@@_make_usable:n}, so that a \cs{hook_new:n} is still % possible later. % \begin{macrocode} - \@@_make_usable:n {#5} - } - \prop_if_in:NnTF \c_@@_generics_reversed_ii_prop {#2} - { \tl_gset:cn { g_@@_#5_reversed_tl } { - } } - { - \prop_if_in:NnT \c_@@_generics_reversed_iii_prop {#3} - { \tl_gset:cn { g_@@_#5_reversed_tl } { - } } - } - \prg_return_true: + \@@_make_usable:n {#5} } - { \prg_return_false: } + \@@_if_generic_reversed:nT {#5} + { \tl_gset:cn { g_@@_#5_reversed_tl } { - } } + \prg_return_true: } - } -%\EndIncludeInRelease + { % \end{macrocode} % +% Generic hooks are all named \meta{type}/\meta{name}/\meta{place}, +% where \meta{type} and \meta{place} are predefined +% (\cs{c_@@_generic_\meta{type}/./\meta{place}_tl}), and \meta{name} +% is the variable component. Older releases had some hooks with the +% \meta{name} in the third part, so the code below supports that +% syntax for a while, with a warning. +% +% The \cs{exp_after:wN} |...| \cs{exp:w} trick is there to remove the +% conditional structure inserted by +% \cs{@@_try_declaring_generic_hook:wnTF} and thus allow access to the +% tokens that follow it, as is needed to keep things going. +% +% When the deprecation cycle ends, the lines below should all be +% replaced by \cs{prg_return_false:}. % \begin{macrocode} -%\IncludeInRelease{2020/10/01}% -% {\@@_try_declaring_generic_hook:wn}{Support~cmd~hooks} -% + \@@_if_deprecated_generic:nTF {#5} + { + \@@_deprecated_generic_warn:n {#5} + \exp_after:wN \@@_declare_deprecated_generic:NNn + \exp:w % \exp_end: + } + { \prg_return_false: } + } + } +% \end{macrocode} +% +% \begin{macro}{ +% \@@_deprecated_generic_warn:Nn, +% \@@_deprecated_generic_warn:Nw, +% } +% \cs{@@_deprecated_generic_warn:n} will issue a deprecation warning +% for a given hook, and mark that hook such that the warning will not +% be issued again (multiple warnings can be issued, but only once per +% hook). +% \begin{macrocode} +\cs_new_protected:Npn \@@_deprecated_generic_warn:n #1 + { \@@_deprecated_generic_warn:w #1 \s_@@_mark } +\cs_new_protected:Npn \@@_deprecated_generic_warn:w + #1 / #2 / #3 \s_@@_mark + { + \if_cs_exist:w @@~#1/#2/#3 \cs_end: \else: + \msg_warning:nnnnn { hooks } { generic-deprecated } {#1} {#2} {#3} + \fi: + \cs_gset_eq:cN { @@~#1/#2/#3 } \scan_stop: + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{ +% \@@_do_deprecated_generic:Nn, +% \@@_do_deprecated_generic:Nw, +% \@@_declare_deprecated_generic:NNw, +% \@@_declare_deprecated_generic:NNw, +% } +% Now that the user has been told about the deprecation, we proceed by +% swapping \meta{name} and \meta{place} and adding the code to the +% correct hook. +% \begin{macrocode} +\cs_new_protected:Npn \@@_do_deprecated_generic:Nn #1 #2 + { \@@_do_deprecated_generic:Nw #1 #2 \s_@@_mark } +\cs_new_protected:Npn \@@_do_deprecated_generic:Nw #1 + #2 / #3 / #4 \s_@@_mark + { #1 { #2 / #4 / #3 } } +\cs_new_protected:Npn \@@_declare_deprecated_generic:NNn #1 #2 #3 + { \@@_declare_deprecated_generic:NNw #1 #2 #3 \s_@@_mark } +\cs_new_protected:Npn \@@_declare_deprecated_generic:NNw #1 #2 + #3 / #4 / #5 \s_@@_mark + { + \@@_try_declaring_generic_hook:wnTF #3 / #5 / #4 / \scan_stop: + { #3 / #5 / #4 } + #1 #2 { #3 / #5 / #4 } + } +%\EndIncludeInRelease +% \end{macrocode} +% \end{macro} +% +% \begin{macrocode} +%\IncludeInRelease{2021/06/01}{\@@_try_declaring_generic_hook:wn} +% {Support~cmd~hooks} +%\prg_new_protected_conditional:Npnn \@@_try_declaring_generic_hook:wn +% #1 / #2 / #3 / #4 \scan_stop: #5 { TF } +% { +% \tl_if_empty:nTF {#2} +% { \prg_return_false: } +% { +% \prop_if_in:NnTF \c_@@_generics_prop {#1} +% { +% \@@_if_usable:nF {#5} +% { +% \str_if_eq:nnT {#1} { cmd } +% { \@@_try_put_cmd_hook:n {#5} } +% \@@_make_usable:n {#5} +% } +% \prop_if_in:NnTF \c_@@_generics_reversed_ii_prop {#2} +% { \tl_gset:cn { g_@@_#5_reversed_tl } { - } } +% { +% \prop_if_in:NnT \c_@@_generics_reversed_iii_prop {#3} +% { \tl_gset:cn { g_@@_#5_reversed_tl } { - } } +% } +% \prg_return_true: +% } +% { \prg_return_false: } +% } +% } +%\EndIncludeInRelease +% \end{macrocode} +% +% \begin{macrocode} +%\IncludeInRelease{2020/10/01}{\@@_try_declaring_generic_hook:wn}% +% {Support~cmd~hooks} %\prg_new_protected_conditional:Npnn \@@_try_declaring_generic_hook:wn % #1 / #2 / #3 / #4 \scan_stop: #5 { TF } % { @@ -2968,77 +3339,107 @@ % \end{macrocode} % \end{macro} % +% % \begin{macro}[pTF]{\@@_if_file_hook:w} % \cs{@@_if_file_hook:wTF} checks if the argument is a valid % file-specific hook (not, for example, |file/before|, but -% |file/before/foo.tex|). If it is a file-specific hook, then it +% |file/foo.tex/before|). If it is a file-specific hook, then it % executes the \meta{true} branch, otherwise \meta{false}. -% -% A file-specific hook is \hook{file/\meta{position}/\meta{name}}. -% If any of these parts don't exist, it is a general file hook or not -% a file hook at all, so the conditional evaluates to \meta{false}. -% Otherwise, it checks that the first part is |file| and that the -% \meta{position} is in the \cs{c_@@_generics_file_prop}. -% -% A property list is used here to avoid having to worry with catcodes, -% because \pkg{expl3}'s file name parsing turns all characters into -% catcode-12 tokens, which might differ from hand-input letters. % \begin{macrocode} +%\IncludeInRelease{2021/11/15}{\@@_if_file_hook:w}% +% {Standardise~generic~hook~names} \prg_new_conditional:Npnn \@@_if_file_hook:w - #1 / #2 / #3 \s_@@_mark { TF } + #1 / #2 \s_@@_mark #3 { TF } { - \str_if_eq:nnTF {#1} { file } + \@@_if_generic:nTF {#3} { - \bool_lazy_or:nnTF - { \tl_if_empty_p:n {#3} } - { \str_if_eq_p:nn {#3} { / } } + \str_if_eq:nnTF {#1} { file } + { \prg_return_true: } { \prg_return_false: } - { - \prop_if_in:NnTF \c_@@_generics_file_prop {#2} - { \prg_return_true: } - { \prg_return_false: } - } } { \prg_return_false: } } +%\EndIncludeInRelease +% \end{macrocode} +% +% \begin{macrocode} +%\IncludeInRelease{2020/10/01}{\@@_if_file_hook:w}% +% {Standardise~generic~hook~names} +%\prg_new_conditional:Npnn \@@_if_file_hook:w +% #1 / #2 / #3 \s_@@_mark { TF } +% { +% \str_if_eq:nnTF {#1} { file } +% { +% \bool_lazy_or:nnTF +% { \tl_if_empty_p:n {#3} } +% { \str_if_eq_p:nn {#3} { / } } +% { \prg_return_false: } +% { +% \prop_if_in:NnTF \c_@@_generics_file_prop {#2} +% { \prg_return_true: } +% { \prg_return_false: } +% } +% } +% { \prg_return_false: } +% } +%\EndIncludeInRelease % \end{macrocode} % \end{macro} % % \begin{macro}[EXP]{\@@_file_hook_normalize:n} % \begin{macro}[EXP]{\@@_strip_double_slash:n,\@@_strip_double_slash:w} +% +% \begin{macrocode} +%\IncludeInRelease{2021/11/15}{\@@_file_hook_normalize:n}% +% {Standardise~generic~hook~names} +%\EndIncludeInRelease +% \end{macrocode} +% % When a file-specific hook is found, before being declared it is % lightly normalized by \cs{@@_file_hook_normalize:n}. The current % implementation just replaces two consecutive slashes (|//|) by a % single one, to cope with simple cases where the user did something % like \verb|\def\input@path{{./mypath/}}|, in which case a hook would -% have to be \verb|\AddToHook{file/after/./mypath//file.tex}|. +% have to be \verb|\AddToHook{file/./mypath//file.tex/after}|. % \begin{macrocode} -\cs_new:Npn \@@_file_hook_normalize:n #1 - { \@@_strip_double_slash:n {#1} } -\cs_new:Npn \@@_strip_double_slash:n #1 - { \@@_strip_double_slash:w #1 // \s_@@_mark } +%\IncludeInRelease{2020/10/01}{\@@_file_hook_normalize:n}% +% {Standardise~generic~hook~names} +%\cs_new:Npn \@@_file_hook_normalize:n #1 +% { \@@_strip_double_slash:n {#1} } +%\cs_new:Npn \@@_strip_double_slash:n #1 +% { \@@_strip_double_slash:w #1 // \s_@@_mark } % \end{macrocode} % This function is always called after testing if the argument is a % file hook with \cs{@@_if_file_hook:wTF}, so we can assume it has -% three parts (it is either \verb|file/before/...| or -% \verb|file/after/...|), so we use \verb|#1/#2/#3 //| instead of just +% three parts (it is either \verb|file/.../before| or +% \verb|file/.../after|), so we use \verb|#1/#2/#3 //| instead of just % \verb|#1 //| to prevent losing a slash if the file name is empty. % \changes{v1.0h}{2021/01/07}{Assume hook name has at least three % nonempty parts (gh/464)} % \begin{macrocode} -\cs_new:Npn \@@_strip_double_slash:w #1/#2/#3 // #4 \s_@@_mark - { - \tl_if_empty:nTF {#4} - { #1/#2/#3 } - { \@@_strip_double_slash:w #1/#2/#3 / #4 \s_@@_mark } - } +%\cs_new:Npn \@@_strip_double_slash:w #1/#2/#3 // #4 \s_@@_mark +% { +% \tl_if_empty:nTF {#4} +% { #1/#2/#3 } +% { \@@_strip_double_slash:w #1/#2/#3 / #4 \s_@@_mark } +% } +%\EndIncludeInRelease % \end{macrocode} % \end{macro} % \end{macro} % -% \begin{macro}{\c_@@_generics_prop} -% Property list holding the generic names. We don't provide any user -% interface to this as this is meant to be static. +% \begin{macro}{ +% \c_@@_generic_cmd/./before_tl,\c_@@_generic_cmd/./after_tl, +% \c_@@_generic_env/./before_tl,\c_@@_generic_env/./after_tl, +% \c_@@_generic_file/./before_tl,\c_@@_generic_file/./after_tl, +% \c_@@_generic_package/./before_tl,\c_@@_generic_package/./after_tl, +% \c_@@_generic_class/./before_tl,\c_@@_generic_class/./after_tl, +% \c_@@_generic_include/./before_tl,\c_@@_generic_include/./after_tl, +% \c_@@_generic_env/./begin_tl,\c_@@_generic_env/./end_tl, +% \c_@@_generic_include/./end_tl +% } +% Token lists defining the possible generic hooks. We don't provide +% any user interface to this as this is meant to be static. % \begin{description} % \item[\texttt{cmd}] % The generic hooks used for commands. @@ -3048,28 +3449,65 @@ % The generic hooks used when loading a file % \end{description} % \begin{macrocode} -\prop_const_from_keyval:Nn \c_@@_generics_prop - {cmd=,env=,file=,package=,class=,include=} +%\IncludeInRelease{2021/11/15}{\c_@@_generics_prop}% +% {Standardise~generic~hook~names} +\clist_map_inline:nn { cmd , env , file , package , class , include } + { + \tl_const:cn { c_@@_generic_#1/./before_tl } { + } + \tl_const:cn { c_@@_generic_#1/./after_tl } { - } + } +\tl_const:cn { c_@@_generic_env/./begin_tl } { + } +\tl_const:cn { c_@@_generic_env/./end_tl } { + } +\tl_const:cn { c_@@_generic_include/./end_tl } { - } +% \end{macrocode} +% +% Deprecated generic hooks: +% \begin{macrocode} +\clist_map_inline:nn { file , package , class , include } + { + \tl_const:cn { c_@@_deprecated_#1/./before_tl } { } + \tl_const:cn { c_@@_deprecated_#1/./after_tl } { } + } +\tl_const:cn { c_@@_deprecated_include/./end_tl } { } +%\EndIncludeInRelease +% \end{macrocode} +% +% \begin{macrocode} +%\IncludeInRelease{2020/10/01}{\c_@@_generics_prop}% +% {Standardise~generic~hook~names} +%\prop_const_from_keyval:Nn \c_@@_generics_prop +% {cmd=,env=,file=,package=,class=,include=} +%\EndIncludeInRelease % \end{macrocode} % \end{macro} % % \begin{macro}{\c_@@_generics_reversed_ii_prop, % \c_@@_generics_reversed_iii_prop, % \c_@@_generics_file_prop} -% Some of the generic hooks are supposed to use reverse ordering, these are -% the following (only the second or third sub-component is checked): +% The following generic hooks are supposed to use reverse ordering +% (the |ii| and |iii| names are kept for the deprecation cycle): +% \begin{macrocode} +%\IncludeInRelease{2021/11/15}{\c_@@_generics_reversed_ii_prop}% +% {Standardise~generic~hook~names} +%\EndIncludeInRelease +% \end{macrocode} +% % \begin{macrocode} -\prop_const_from_keyval:Nn \c_@@_generics_reversed_ii_prop {after=,end=} -\prop_const_from_keyval:Nn \c_@@_generics_reversed_iii_prop {after=} -\prop_const_from_keyval:Nn \c_@@_generics_file_prop {before=,after=} +%\IncludeInRelease{2020/10/01}{\c_@@_generics_reversed_ii_prop}% +% {Standardise~generic~hook~names} +%\prop_const_from_keyval:Nn \c_@@_generics_reversed_ii_prop {after=,end=} +%\prop_const_from_keyval:Nn \c_@@_generics_reversed_iii_prop {after=} +%\prop_const_from_keyval:Nn \c_@@_generics_file_prop {before=,after=} +%\EndIncludeInRelease % \end{macrocode} % \end{macro} % % \begin{macro}{\hook_gremove_code:nn} % \begin{macro}{\@@_gremove_code:nn} -% +% % With \cs{hook_gremove_code:nn}\Arg{hook}\Arg{label} any code % for \meta{hook} stored under \meta{label} is removed. +% \changes{v1.0o}{2021/07/22}{Do not queue removals (gh/625)} % \begin{macrocode} \cs_new_protected:Npn \hook_gremove_code:nn #1 #2 { \@@_normalize_hook_args:Nnn \@@_gremove_code:nn {#1} {#2} } @@ -3101,27 +3539,13 @@ { % \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{@@_toplevel\textvisiblespace\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. +% there is under the same label. % \begin{macrocode} \str_if_eq:nnTF {#2} { top-level } { \@@_tl_gclear:c { @@_toplevel~#1 } } { -% \end{macrocode} -% 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_gpop:cnNF { g_@@_#1_code_prop } {#2} \l_@@_return_tl + { \msg_warning:nnnn { hooks } { cannot-remove } {#1} {#2} } } } % \end{macrocode} @@ -3132,82 +3556,21 @@ } % \end{macrocode} % -% If the code pool for this hook doesn't exist it means that nothing -% tried to add to it before, so we just queue this removal order for -% later. -% \begin{macrocode} - { \@@_mark_removal:nn {#1} {#2} } - } -% \end{macrocode} -% -% \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} } -% \end{macrocode} -% \end{macro} -% \end{macro} -% \end{macro} -% -% \begin{macro}{\@@_mark_removal:nn} -% Marks \meta{label} (\verb=#2=) to be removed from \meta{hook} -% (\verb=#1=). The number of removals should be fairly small, and -% \cs{tl_gremove_once:Nx} is fairly efficient even for longer token -% lists, so we use a single global token list, rather than one for -% each hook. -% -% A hand-crafted token list is used here because property lists don't -% hold repeated items, so multiple usages of \cs{@@_mark_removal:nn} -% would be cancelled by a single \cs{@@_unmark_removal:nn}. -% \begin{macrocode} -\cs_new_protected:Npn \@@_mark_removal:nn #1 #2 - { - \tl_gput_right:Nx \g_@@_removal_list_tl - { \@@_removal_tl:nn {#1} {#2} } - } -% \end{macrocode} -% \end{macro} -% -% \begin{macro}{\@@_unmark_removal:nn} -% Unmarks \meta{label} (\verb=#2=) to be removed from \meta{hook} -% (\verb=#1=). \cs{tl_gremove_once:Nx} is used rather than -% \cs{tl_gremove_all:Nx} so that two additions are needed to cancel -% two marked removals, rather than only one. +% If the code pool for this hook doesn't exist, show a warning: % \begin{macrocode} -\cs_new_protected:Npn \@@_unmark_removal:nn #1 #2 - { - \tl_gremove_once:Nx \g_@@_removal_list_tl - { \@@_removal_tl:nn {#1} {#2} } - } -% \end{macrocode} -% \end{macro} -% -% \begin{macro}[TF]{\@@_if_marked_removal:nn} -% Checks if the \cs{g_@@_removal_list_tl} contains the current -% \meta{label} (\verb=#2=) and \meta{hook} (\verb=#1=). -% \begin{macrocode} -\prg_new_protected_conditional:Npnn \@@_if_marked_removal:nn #1 #2 { TF } - { - \exp_args:NNx \tl_if_in:NnTF \g_@@_removal_list_tl - { \@@_removal_tl:nn {#1} {#2} } - { \prg_return_true: } { \prg_return_false: } + { + \@@_if_deprecated_generic:nTF {#1} + { + \@@_deprecated_generic_warn:n {#1} + \@@_do_deprecated_generic:Nn \@@_gremove_code:nn {#1} {#2} + } + { \msg_warning:nnnn { hooks } { cannot-remove } {#1} {#2} } + } } % \end{macrocode} % \end{macro} -% -% \begin{macro}[rEXP]{\@@_removal_tl:nn} -% Builds a token list with \verb=#1= and \verb=#2= which can only be -% matched by \verb=#1= and \verb=#2=. The |&|$_4$ anchors a removal, -% so that \verb=#1= can't be mistaken by \verb=#2= and vice versa, and -% the two |$|$_3$ delimit the two arguments -% \begin{macrocode} -\cs_new:Npn \@@_removal_tl:nn #1 #2 - { & \tl_to_str:n {#2} $ \tl_to_str:n {#1} $ } -% \end{macrocode} % \end{macro} % -% % \begin{macro}{ % \g_@@_??_code_prop, % \@@~??, @@ -3263,6 +3626,13 @@ % \begin{macrocode} \cs_new_protected:Npn \@@_gset_rule:nnnn #1#2#3#4 { + \@@_if_deprecated_generic:nT {#1} + { + \@@_deprecated_generic_warn:n {#1} + \@@_do_deprecated_generic:Nn \@@_gset_rule:nnnn {#1} + {#2} {#3} {#4} + \exp_after:wN \use_none:nnnnnnnnn \use_none:n + } % \end{macrocode} % First we ensure the basic data structure of the hook exists: % \begin{macrocode} @@ -3399,12 +3769,12 @@ % |#1| is lexically greater, and \cs{use_iii:nn} otherwise. % \begin{macrocode} \cs_new:Npn \@@_if_label_case:nnnnn #1#2 - { - \cs:w use_ - \if_case:w \@@_str_compare:nn {#1} {#2} - i \or: ii \else: iii \fi: :nnn - \cs_end: - } + { + \cs:w use_ + \if_case:w \@@_str_compare:nn {#1} {#2} + i \or: ii \else: iii \fi: :nnn + \cs_end: + } % \end{macrocode} % \end{macro} % @@ -3440,7 +3810,7 @@ } % \end{macrocode} % If we are debugging we show results hook by hook for all hooks -% that have data. +% that have data. % \begin{macrocode} \@@_debug:n { \iow_term:x{^^JAll~ initialized~ (non-empty)~ hooks:} @@ -3492,7 +3862,7 @@ % \begin{macrocode} \@@_if_usable:nT {#1} { - \prop_if_empty:cTF {g_@@_#1_code_prop} + \prop_if_empty:cTF { g_@@_#1_code_prop } { \@@_tl_gset:co { @@~#1 } { @@ -3503,11 +3873,11 @@ { % \end{macrocode} % By default the algorithm sorts the code chunks and then saves the -% result in a token list for fast execution by adding the code one -% after another using \cs{tl_gput_right:NV}. When we sort code for +% result in a token list for fast execution; this is done by adding the code chunks +% one after another, using \cs{tl_gput_right:NV}. When we sort code for % a reversed hook, all we have to do is to add the code chunks in % the opposite order into the token list. So all we have to do -% in preparation is to change two definitions used later on. +% in preparation is to change two definitions that are used later on. % \begin{macrocode} \@@_if_reversed:nTF {#1} { \cs_set_eq:NN \@@_tl_gput:Nn \@@_tl_gput_left:Nn @@ -3518,8 +3888,9 @@ % % When sorting, some relations (namely \verb|voids|) need to % act destructively on the code property lists to remove code that -% shouldn't appear in the sorted hook token list, so we temporarily -% save the old code property list so that it can be restored later. +% shouldn't appear in the sorted hook token list, so we make a copy +% of the code property list that we can safely work on without +% changing the main one. % \begin{macrocode} \prop_set_eq:Nc \l_@@_work_prop { g_@@_#1_code_prop } \@@_initialize_single:ccn @@ -3606,8 +3977,8 @@ % alphanumeric labels. As usual Don's data structures are chosen in % a way that one can omit a lot of tests and I have mimicked that as % 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 ... maybe} +% the moment: a label can't be equal to the number 0! +% \fmiinline{Needs checking for, just in case ... maybe} % % ^^A #1 <- \@@~#1 % ^^A #2 <- \g_@@_#1_labels_clist @@ -3626,11 +3997,11 @@ % \begin{macrocode} \tl_set:Nn \l_@@_cur_hook_tl {#3} % \end{macrocode} -% +% % We loop over the property list holding the code and record all -% labels listed there. Only rules for those labels are of interest +% the labels listed there. Only the rules for those labels are of interest % to us. While we are at it we count them (which gives us the $N$ -% in Knuth's algorithm. The prefix |label_| is added to the variables +% in Knuth's algorithm). The prefix |label_| is added to the variables % to ensure that labels named |front|, |rear|, |labels|, or |return| % don't interact with our code. % \begin{macrocode} @@ -3642,11 +4013,11 @@ \seq_clear_new:c { \@@_seq_csname:n {##1} } } % \end{macrocode} -% Steps T2 and T3: Sort the relevant rules into the data structure\ldots -% +% Steps T2 and T3: Here we sort the relevant rules into the data structure\ldots +% % This loop constitutes a square matrix of the labels in % \cs{l_@@_work_prop} in the -% vertical and the horizontal directions. However since the rule +% vertical and the horizontal directions. However, since the rule % $l_A\meta{rel}l_B$ is the same as $l_B\meta{rel}^{-1}l_A$ we can cut % the loop short at the diagonal of the matrix (\emph{i.e.}, when % both labels are equal), saving a good amount of time. The way the @@ -3668,12 +4039,12 @@ } } % \end{macrocode} -% Take a breath and take a look at the data structures that have +% Now take a breath, and look at the data structures that have % been set up: % \begin{macrocode} \@@_debug:n { \@@_debug_label_data:N \l_@@_work_prop } % \end{macrocode} -% +% % % Step T4: % \begin{macrocode} @@ -3689,13 +4060,13 @@ } \tl_set_eq:Nc \l_@@_front_tl { \@@_tl_csname:n { 0 } } % \end{macrocode} -% +% % \begin{macrocode} \@@_tl_gclear:N #1 \clist_gclear:N #2 % \end{macrocode} % -% The whole loop combines steps T5--T7: +% The whole loop gets combined in steps T5--T7: % \begin{macrocode} \bool_while_do:nn { ! \str_if_eq_p:Vn \l_@@_front_tl { 0 } } { @@ -3706,13 +4077,13 @@ \prop_get:NVN \l_@@_work_prop \l_@@_front_tl \l_@@_return_tl \exp_args:NNV \@@_tl_gput:Nn #1 \l_@@_return_tl % \end{macrocode} -% +% % \begin{macrocode} \@@_clist_gput:NV #2 \l_@@_front_tl \@@_debug:n{ \iow_term:x{Handled~ code~ for~ \l_@@_front_tl} } % \end{macrocode} % -% This is step T6 except that we don't use a pointer $P$ to move +% This is step T6, except that we don't use a pointer $P$ to move % through the successors, but instead use \verb=##1= of the mapping % function. % \begin{macrocode} @@ -3730,7 +4101,7 @@ } } % \end{macrocode} -% and step T7: +% and here is step T7: % \begin{macrocode} \tl_set_eq:Nc \l_@@_front_tl { \@@_tl_csname:n { \l_@@_front_tl } } @@ -3748,14 +4119,14 @@ % \end{macrocode} % % This is not really the information one needs in the error case -% but will do for now \ldots \fmi{improve output on a rainy day} +% but it will do for now \ldots \fmiinline{improve output on a rainy day} % \begin{macrocode} \@@_debug_label_data:N \l_@@_work_prop \iow_term:x{====================} } % \end{macrocode} -% After we have added all hook code to \verb=#1= we finish it off -% with adding extra code for the |top-level| (\verb=#2=) and for one +% After we have added all hook code to \verb=#1=, we finish it off +% by 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 @@ -3905,10 +4276,10 @@ % \begin{macro}{\@@_apply_rule_->:nnn,\@@_apply_rule_<-:nnn} % If we see \texttt{\detokenize{->}} we have to drop code for label % \verb=#3= and carry on. We could do a little better and drop -% everything for that label since it doesn't matter where we sort -% in the empty code. However that would complicate the algorithm a -% lot with little gain.\footnote{This also hase the advantage that -% the result of the sorting doesn't change which might otherwise +% everything for that label since it doesn't matter where we put +% such empty code. However that would complicate the algorithm a +% lot with little gain.\footnote{This also has the advantage that +% the result of the sorting doesn't change, as it might otherwise do % (for unrelated chunks) if we aren't careful.} So we still % unnecessarily try to sort it in and depending on the rules that % might result in a loop that is otherwise resolved. If that turns @@ -3916,8 +4287,8 @@ % % Here the code is removed from \cs{l_@@_cur_hook_tl} rather than % \verb=#3= because the latter may be \verb=??=, and the default -% hook doesn't store any code. Removing from \cs{l_@@_cur_hook_tl} -% makes default rules \verb=->= and \verb=<-= work properly. +% hook doesn't store any code. Removing it instead from \cs{l_@@_cur_hook_tl} +% makes the default rules \verb=->= and \verb=<-= work properly. % \begin{macrocode} \cs_new_protected:cpn { @@_apply_rule_->:nnn } #1#2#3 { @@ -3978,7 +4349,7 @@ % % % \begin{macro}{\@@_debug_label_data:N} -% +% % \begin{macrocode} \cs_new_protected:Npn \@@_debug_label_data:N #1 { \iow_term:x{Code~ labels~ for~ sorting:} @@ -4024,8 +4395,15 @@ % \begin{macrocode} \cs_new_protected:Npn \@@_log:nN #1 #2 { + \@@_if_deprecated_generic:nT {#1} + { + \@@_deprecated_generic_warn:n {#1} + \@@_do_deprecated_generic:Nn \@@_log:nN {#1} #2 + \exp_after:wN \use_none:nnnnnnnnn \use_none:nnnnn + } \@@_preamble_hook:n {#1} - \@@_log_cmd:x { ^^J ->~The~hook~'#1': } + \@@_log_cmd:x + { ^^J ->~The~ \@@_if_generic:nT {#1} { generic~ } hook~'#1': } % \end{macrocode} % % \begin{macrocode} @@ -4234,16 +4612,14 @@ % % \begin{macro}{\@@_gput_next_code:nn, % \@@_gput_next_do:nn, -% \@@_gput_next_do:Nnn, -% \@@_clear_next:n} +% \@@_gput_next_do:Nnn} % \begin{macrocode} \cs_new_protected:Npn \@@_gput_next_code:nn #1 #2 { \@@_if_disabled:nTF {#1} { \msg_error:nnn { hooks } { hook-disabled } {#1} } { - \@@_init_structure:n {#1} - \@@_if_usable:nTF {#1} + \@@_if_structure_exist:nTF {#1} { \@@_gput_next_do:nn {#1} {#2} } { \@@_try_declaring_generic_next_hook:nn {#1} {#2} } } @@ -4275,13 +4651,21 @@ { \@@_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 } % \end{macrocode} % \end{macro} % % % +% \begin{macro}{\hook_gclear_next_code:n,\@@_clear_next:n} +% Discard anything set up for next invocation of the hook. +% \changes{v1.0o}{2021/07/27}{Macro made public} +% \begin{macrocode} +\cs_new_protected:Npn \hook_gclear_next_code:n #1 + { \@@_normalize_hook_args:Nn \@@_clear_next:n {#1} } +\cs_new_protected:Npn \@@_clear_next:n #1 + { \cs_gset_eq:cN { @@_next~#1 } \c_empty_tl } +% \end{macrocode} +% \end{macro} % % % @@ -4302,44 +4686,68 @@ % the preamble. \cs{@@_preamble_hook:n} initializes the hook in the % preamble, and is redefined to \cs{use_none:n} at |\begin{document}|. % -% Both versions do the same internally: check if the hook exist as -% given, and if so use it as quickly as possible. If it doesn't -% exist, the a call to \cs{@@_use:wn} checks for file hooks. +% Both versions do the same thing internally: they check that the hook exists as +% given, and if so they use it as quickly as possible. % % At |\begin{document}|, all hooks are initialized, and any change in % them causes an update, so \cs{hook_use:n} can be made expandable. % This one is better not protected so that it can expand into nothing % if containing no code. Also important in case of generic hooks that -% we do not generate a \cs[no-index]{relax} as a side effect of checking for a -% csname. In contrast to the \TeX{} low-level +% we do not generate a \cs[no-index]{relax} as a side effect of +% checking for a csname. In contrast to the \TeX{} low-level % \verb=\csname ...\endcsname= construct \cs{tl_if_exist:c} is % careful to avoid this. % \begin{macrocode} +%\IncludeInRelease{2021/11/15}{\hook_use:n} +% {Standardise~generic~hook~names} \cs_new_protected:Npn \hook_use:n #1 { - \tl_if_exist:cTF { @@~#1 } + \tl_if_exist:cT { @@~#1 } { \@@_preamble_hook:n {#1} \cs:w @@~#1 \cs_end: } - { \@@_use:wn #1 / \s_@@_mark {#1} } } \cs_new:Npn \@@_use_initialized:n #1 { \if_cs_exist:w @@~#1 \cs_end: - \else: - \@@_use_undefined:w + \cs:w @@~#1 \exp_after:wN \cs_end: \fi: - \cs:w @@~#1 \@@_use_end: - } -\cs_new:Npn \@@_use_undefined:w #1 #2 @@~#3 \@@_use_end: - { - #1 % fi - \@@_use:wn #3 / \s_@@_mark {#3} } \cs_new_protected:Npn \@@_preamble_hook:n #1 { \@@_initialize_hook_code:n {#1} } -\cs_new_eq:NN \@@_use_end: \cs_end: +%\EndIncludeInRelease +% \end{macrocode} +% +% \begin{macrocode} +%\IncludeInRelease{2020/10/01}{\hook_use:n} +% {Standardise~generic~hook~names} +%\cs_new_protected:Npn \hook_use:n #1 +% { +% \tl_if_exist:cTF { @@~#1 } +% { +% \@@_preamble_hook:n {#1} +% \cs:w @@~#1 \cs_end: +% } +% { \@@_use:wn #1 / \s_@@_mark {#1} } +% } +%\cs_new:Npn \@@_use_initialized:n #1 +% { +% \if_cs_exist:w @@~#1 \cs_end: +% \else: +% \@@_use_undefined:w +% \fi: +% \cs:w @@~#1 \@@_use_end: +% } +%\cs_new:Npn \@@_use_undefined:w #1 #2 @@~#3 \@@_use_end: +% { +% #1 % fi +% \@@_use:wn #3 / \s_@@_mark {#3} +% } +%\cs_new_protected:Npn \@@_preamble_hook:n #1 +% { \@@_initialize_hook_code:n {#1} } +%\cs_new_eq:NN \@@_use_end: \cs_end: +%\EndIncludeInRelease % \end{macrocode} % \end{macro} % \end{macro} @@ -4360,63 +4768,123 @@ % \cs{@@_if_usable_use:n} checks if the hook exist, and calls % \cs{@@_preamble_hook:n} if so, then uses the hook. % \begin{macrocode} -\cs_new:Npn \@@_use:wn #1 / #2 \s_@@_mark #3 - { - \str_if_eq:nnTF {#1} { file } - { \@@_try_file_hook:n {#3} } - { } % Hook doesn't exist - } +%\IncludeInRelease{2021/11/15}{\@@_use:wn} +% {Standardise~generic~hook~names} +%\EndIncludeInRelease +%\IncludeInRelease{2020/10/01}{\@@_use:wn} +% {Standardise~generic~hook~names} +%\cs_new:Npn \@@_use:wn #1 / #2 \s_@@_mark #3 +% { +% \str_if_eq:nnTF {#1} { file } +% { \@@_try_file_hook:n {#3} } +% { } % Hook doesn't exist +% } % \end{macrocode} % +% \changes{v1.0s}{2021/09/28} +% {Correct usage of older \cs{@@_if_file_hook:wTF} (gh/675)} % \begin{macrocode} -\cs_new_protected:Npn \@@_try_file_hook:n #1 - { - \@@_if_file_hook:wTF #1 / / \s_@@_mark - { - \exp_args:Ne \@@_if_usable_use:n - { \exp_args:Ne \@@_file_hook_normalize:n {#1} } - } - { \@@_if_usable_use:n {#1} } % file/ generic hook (e.g. file/before) - } +%\cs_new_protected:Npn \@@_try_file_hook:n #1 +% { +% \@@_if_file_hook:wTF #1 / \s_@@_mark +% { +% \exp_args:Ne \@@_if_usable_use:n +% { \exp_args:Ne \@@_file_hook_normalize:n {#1} } +% } +% { \@@_if_usable_use:n {#1} } % file/ generic hook (e.g. file/before) +% } % \end{macrocode} % % \begin{macrocode} -\cs_new_protected:Npn \@@_if_usable_use:n #1 - { - \tl_if_exist:cT { @@~#1 } - { - \@@_preamble_hook:n {#1} - \cs:w @@~#1 \cs_end: - } - } +%\cs_new_protected:Npn \@@_if_usable_use:n #1 +% { +% \tl_if_exist:cT { @@~#1 } +% { +% \@@_preamble_hook:n {#1} +% \cs:w @@~#1 \cs_end: +% } +% } +%\EndIncludeInRelease % \end{macrocode} % \end{macro} % \end{macro} % -% \begin{macro}{\hook_use_once:n} -% For hooks that can and should be used only once we have a special -% use command that remembers the hook name in -% \cs{g_@@_execute_immediately_prop}. This has the effect that any -% further code added to the hook is executed immediately rather -% than stored in the hook. +% \begin{macro}{\hook_use_once:n} +% \begin{macro}{\@@_use_once:n} +% For hooks that can and should be used only once we have a special +% use command that further inhibits the hook from getting more code +% added to it. This has the effect that any +% further code added to the hook is executed immediately rather +% than stored in the hook. % -% The code needs some gymnastics to prevent space trimming from the -% hook name, since \cs{hook_use:n} and \cs{hook_use_once:n} are -% documented to not trim spaces. +% The code needs some gymnastics to prevent space trimming from the +% hook name, since \cs{hook_use:n} and \cs{hook_use_once:n} are +% documented to not trim spaces. % +% \changes{v1.0r}{2021/09/06}{Clean up after \cs{UseOneTimeHook} (gh/606)} % \begin{macrocode} \cs_new_protected:Npn \hook_use_once:n #1 { - \tl_if_exist:cT { @@~#1 } + \@@_if_execute_immediately:nF {#1} + { \@@_normalize_hook_args:Nn \@@_use_once:n { \use:n {#1} } } + } +\cs_new_protected:Npn \@@_use_once:n #1 + { + \@@_preamble_hook:n {#1} + \@@_use_once_set:n {#1} + \@@_use_initialized:n {#1} + \@@_use_once_clear:n {#1} + } +% \end{macrocode} +% +% \begin{macro}{\@@_use_once_set:n} +% \begin{macro}{\@@_use_once_clear:n} +% \cs{@@_use_once_set:n} is used before the actual hook code is +% executed so that any usage of \cs{AddToHook} inside the hook causes +% the code to execute immediately. Setting +% \cs[no-index]{g_@@_\meta{hook}_reversed_tl} to |I| prevents further +% code from being added to the hook. \cs{@@_use_once_clear:n} then +% clears the hook so that any further call to \cs{hook_use:n} or +% \cs{hook_use_once:n} will expand to nothing. +% \changes{v1.0r}{2021/09/06}{Clean up after \cs{UseOneTimeHook} (gh/606)} +% \begin{macrocode} +\cs_new_protected:Npn \@@_use_once_set:n #1 + { \@@_tl_gset:cn { g_@@_#1_reversed_tl } { I } } +\cs_new_protected:Npn \@@_use_once_clear:n #1 + { + \@@_tl_gclear:c { @@~#1 } + \@@_tl_gclear:c { @@_next~#1 } + \@@_tl_gclear:c { @@_toplevel~#1 } + \prop_gclear:c { g_@@_#1_code_prop } + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}[pTF]{\@@_if_execute_immediately:n} +% To check whether the code being added should be executed immediately (that +% is, if the hook is a one-time hook), we check if it's usable (it +% can't be one-time if it was not already usable), then we check that +% \cs[no-index]{g_@@_\meta{hook}_reversed_tl} is |I|. The gymnastics +% around \cs{if:w} is there to allow the |reversed| token list to be +% empty. +% \changes{v1.0r}{2021/09/06}{Macro added (gh/606)} +% \begin{macrocode} +\prg_new_conditional:Npnn \@@_if_execute_immediately:n #1 { F, TF } + { + \@@_if_usable:nTF {#1} { - \tl_set:Nn \l_@@_return_tl {#1} - \@@_normalize_hook_args:Nn \@@_use_once_store:n - { \l_@@_return_tl } - \hook_use:n {#1} + \exp_after:wN \@@_clean_to_scan:w + \if:w I \cs:w g_@@_#1_reversed_tl \cs_end: + \s_@@_mark \prg_return_true: + \else: + \s_@@_mark \prg_return_false: + \fi: } + { \prg_return_false: } } -\cs_new_protected:Npn \@@_use_once_store:n #1 - { \prop_gput:Nnn \g_@@_execute_immediately_prop {#1} { } } % \end{macrocode} % \end{macro} % @@ -4504,9 +4972,8 @@ } % \end{macrocode} % \end{macro} -% -% -% +% +% % \begin{macro}[pTF]{\@@_if_declared:n} % % Internal test to check if the hook was officially declared with @@ -4526,28 +4993,76 @@ % \begin{macrocode} \prg_new_conditional:Npnn \@@_if_reversed:n #1 { p , T , F , TF } { - \if_int_compare:w \cs:w g_@@_#1_reversed_tl \cs_end: 1 < 0 \exp_stop_f: + \exp_after:wN \@@_clean_to_scan:w + \if:w - \cs:w g_@@_#1_reversed_tl \cs_end: + \s_@@_mark \prg_return_true: + \else: + \s_@@_mark \prg_return_false: + \fi: + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[pTF]{\@@_if_generic:n} +% \begin{macro}[pTF]{\@@_if_deprecated_generic:n} +% An internal conditional that checks if a name belongs to a generic +% hook. The deprecated version needs to check if |#3| is empty to +% avoid returning true on \hook{file/before}, for example. +% \begin{macrocode} +\prg_new_conditional:Npnn \@@_if_generic:n #1 { T, TF } + { \@@_if_generic:w #1 / / / \s_@@_mark } +\cs_new:Npn \@@_if_generic:w #1 / #2 / #3 / #4 \s_@@_mark + { + \cs_if_exist:cTF { c_@@_generic_#1/./#3_tl } + { \prg_return_true: } + { \prg_return_false: } + } +\prg_new_conditional:Npnn \@@_if_deprecated_generic:n #1 { T, TF } + { \@@_if_deprecated_generic:w #1 / / / \s_@@_mark } +\cs_new:Npn \@@_if_deprecated_generic:w #1 / #2 / #3 / #4 \s_@@_mark + { + \cs_if_exist:cTF { c_@@_deprecated_#1/./#2_tl } + { + \tl_if_empty:nTF {#3} + { \prg_return_false: } + { \prg_return_true: } + } + { \prg_return_false: } + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}[pTF]{\@@_if_generic_reversed:n} +% An internal conditional that checks if a name belongs to a generic +% reversed hook. +% \begin{macrocode} +\prg_new_conditional:Npnn \@@_if_generic_reversed:n #1 { T } + { \@@_if_generic_reversed:w #1 / / / \scan_stop: } +\cs_new:Npn \@@_if_generic_reversed:w #1 / #2 / #3 / #4 \scan_stop: + { + \if_charcode:w - \cs:w c_@@_generic_#1/./#3_tl \cs_end: \prg_return_true: \else: \prg_return_false: \fi: } % \end{macrocode} -% \end{macro} -% +% \end{macro} % % \subsection{Messages} % -% Hook errors are LaTeX kernel errors: +% Hook errors are LaTeX kernel errors: % \begin{macrocode} \prop_gput:Nnn \g_msg_module_type_prop { hooks } { LaTeX } % \end{macrocode} +% \changes{v1.0q}{2021/08/27}{Internal message name changes} % And so are kernel errors (this should move elsewhere eventually). % \begin{macrocode} -\prop_gput:Nnn \g_msg_module_type_prop { kernel } { LaTeX } -%\prop_gput:Nnn \g_msg_module_name_prop { kernel } { } % <-- currently not working +\prop_gput:Nnn \g_msg_module_type_prop { latex2e } { LaTeX } +\prop_gput:Nnn \g_msg_module_name_prop { latex2e } { kernel } % \end{macrocode} -% +% % \begin{macrocode} \msg_new:nnnn { hooks } { labels-incompatible } { @@ -4560,7 +5075,7 @@ { LaTeX~found~two~incompatible~labels~in~the~same~hook.~ This~indicates~an~incompatibility~between~packages. } % \end{macrocode} -% +% % \begin{macrocode} \msg_new:nnnn { hooks } { exists } { Hook~'#1'~ has~ already~ been~ declared. } @@ -4568,14 +5083,14 @@ name.\\ Please~ use~ a~ different~ name~ for~ your~ hook.} % \end{macrocode} -% +% % % \begin{macrocode} \msg_new:nnnn { hooks } { hook-disabled } { Cannot~add~code~to~disabled~hook~'#1'. } { The~hook~'#1'~you~tried~to~add~code~to~was~previously~disabled~ - with~\iow_char:N\\hook_disable:n~or~\iow_char:N\\DisableHook,~so~ + with~\iow_char:N\\hook_disable_generic:n~or~\iow_char:N\\DisableGenericHook,~so~ it~cannot~have~code~added~to~it. } % \end{macrocode} @@ -4601,7 +5116,7 @@ { Unknown~ relationship~ '#3'~ between~ labels~ '#2'~ and~ '#4'~ \str_if_eq:nnF {#1} {??} { ~in~hook~'#1' }. ~ - Perhaps~ a~ missspelling? + Perhaps~ a~ misspelling? } { The~ relation~ used~ not~ known~ to~ the~ system.~ Allowed~ values~ are~ @@ -4613,7 +5128,7 @@ 'unrelated'. } % \end{macrocode} -% +% % \begin{macrocode} \msg_new:nnnn { hooks } { misused-top-level } { @@ -4651,7 +5166,7 @@ % \end{macrocode} % % \begin{macrocode} -\msg_new:nnn { kernel } { should-not-happen } +\msg_new:nnn { latex2e } { should-not-happen } { This~should~not~happen.~#1 \\ Please~report~at~https://github.com/latex3/latex2e. @@ -4661,32 +5176,31 @@ % % % \begin{macrocode} -\msg_new:nnn { hooks } { provide-disabled } +\msg_new:nnn { hooks } { activate-disabled } { - Cannot~ provide~ hook~ '#1'~ because~ it~ is~ disabled! + Cannot~ activate~ hook~ '#1'~ because~ it~ is~ disabled! } % \end{macrocode} % % \begin{macrocode} -\msg_new:nnnn { hooks } { provide-error } +\msg_new:nnn { hooks } { cannot-remove } { - Hook~'#1'~ already~ declared~ as~ a~ - \@@_if_reversed:nTF {#1} { reversed } { normal }~ hook! + Cannot~remove~chunk~'#2'~from~hook~'#1'~because~ + \@@_if_structure_exist:nTF {#1} + { it~does~not~exist~in~that~hook. } + { the~hook~does~not~exist. } } +% \end{macrocode} +% +% \begin{macrocode} +\msg_new:nnn { hooks } { generic-deprecated } { - You~ attempted~ to~ provide~ the~ hook~'#1'~ as~ a~ - \@@_if_reversed:nTF {#1} { normal } { reversed }~ hook,~ but~ it~ - was~ already~ previously~ declared~ as~ a~ - \@@_if_reversed:nTF {#1} { reversed } { normal }~ hook.~ - A~ redeclaration~ is~ not~ possible. + Generic~hook~'#1/#2/#3'~is~deprecated. \\ + Use~hook~'#1/#3/#2'~instead. } % \end{macrocode} % % -% -% -% -% % \subsection{\LaTeXe{} package interface commands} % % @@ -4704,42 +5218,38 @@ % % \begin{macrocode} %\IncludeInRelease{2021/06/01}% -% {\hook_provide:n}{Providing~hooks} +% {\hook_activate_generic:n}{Providing~hooks} % \end{macrocode} % -% \begin{macro}{\ProvideHook,\ProvideReversedHook,\ProvideMirroredHookPair} +% \begin{macro}{\ActivateGenericHook} % Providing new hooks \ldots % \changes{v1.0m}{2021/04/29}{Add \cs{ProvideHook} etc.} +% \changes{v1.0o}{2021/08/02}{Change name} % \begin{macrocode} -\NewDocumentCommand \ProvideHook { m }{ \hook_provide:n {#1} } -\NewDocumentCommand \ProvideReversedHook { m }{ \hook_provide_reversed:n {#1} } -\NewDocumentCommand \ProvideMirroredHookPair { mm }{ \hook_provide_pair:nn {#1}{#2} } +\NewDocumentCommand \ActivateGenericHook { m }{ \hook_activate_generic:n {#1} } % \end{macrocode} % \end{macro} % -% -% \begin{macro}{\DisableHook} -% Disabling a (generic) hook. +% \begin{macro}{\DisableGenericHook} +% Disabling a generic hook. +% \changes{v1.0o}{2021/08/02}{Change name} % \begin{macrocode} -\NewDocumentCommand \DisableHook { m }{ \hook_disable:n {#1} } +\NewDocumentCommand \DisableGenericHook { m }{ \hook_disable_generic:n {#1} } % \end{macrocode} % \end{macro} % % \begin{macrocode} %\EndIncludeInRelease %\IncludeInRelease{2020/10/01} -% {\hook_provide:n}{Providing~hooks} +% {\hook_activate_generic:n}{Providing~hooks} % -%\def \ProvideHook#1{} -%\def \ProvideReversedHook#1{} -%\def \ProvideMirroredHookPair#1#2{} +%\def \ActivateGenericHook#1{} % %\EndIncludeInRelease % \end{macrocode} % % % \begin{macro}{\AddToHook} -% % \begin{macrocode} \NewDocumentCommand \AddToHook { m o +m } { \hook_gput_code:nnn {#1} {#2} {#3} } @@ -4747,16 +5257,22 @@ % \end{macro} % % \begin{macro}{\AddToHookNext} -% % \begin{macrocode} \NewDocumentCommand \AddToHookNext { m +m } { \hook_gput_next_code:nn {#1} {#2} } % \end{macrocode} % \end{macro} % +% \begin{macro}{\ClearHookNext} +% \changes{v1.0o}{2021/07/27}{Macro added} +% \begin{macrocode} +\NewDocumentCommand \ClearHookNext { m } + { \hook_gclear_next_code:n {#1} } +% \end{macrocode} +% \end{macro} +% % % \begin{macro}{\RemoveFromHook} -% % \begin{macrocode} \NewDocumentCommand \RemoveFromHook { m o } { \hook_gremove_code:nn {#1} {#2} } @@ -4766,140 +5282,11 @@ % \begin{macro}{\SetDefaultHookLabel} % \begin{macro}{\PushDefaultHookLabel} % \begin{macro}{\PopDefaultHookLabel} -% -% \fmiinline{Docu task: At some point this code for this should be moved to the -% label section earlier and here we should keep only the interface commands.} -% -% \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{SetDefaultHookLabel} to change the default label (in which -% case \cs{@currname} is used). -% -% 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} -\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: -% \changes{v1.0i}{2021/03/18} -% {Only add \texttt{top-level} if not already there.} -% \begin{macrocode} -%\seq_if_empty:NT \g_@@_name_stack_seq -% { \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} -%\cs_set_protected:Npn \@@_tmp:w #1 #2 #3 -% { -% \quark_if_recursion_tail_stop:n {#1} -% \seq_gput_right:Nn \g_@@_name_stack_seq {#1} -% \@@_tmp:w -% } -%\exp_after:wN \@@_tmp:w \@currnamestack -% \q_recursion_tail \q_recursion_tail -% \q_recursion_tail \q_recursion_stop -% \end{macrocode} -% and finally set the default label to be the \cs{@currname}: -% \changes{v1.0i}{2021/03/18} -% {Remove the (empty) \enquote{top-level} from \cs{@currnamestack}.} -% \begin{macrocode} -%\tl_gset:Nx \g_@@_hook_curr_name_tl { \@currname } -%\seq_gpop_right:NN \g_@@_name_stack_seq \l_@@_tmpa_tl -% \end{macrocode} -% -% Two commands keep track of the stack: when a file is input, -% \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 - { - \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} -% is updated to the now topmost item of the stack: -% \begin{macrocode} -\cs_new_protected:Npn \@@_curr_name_pop: - { - \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:n} 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: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} -% -% The token list \cs{g_@@_hook_curr_name_tl} is but a mirror of the top -% of the stack. -% % Now define a wrapper that replaces the top of the stack with the % argument, and updates \cs{g_@@_hook_curr_name_tl} accordingly. % \begin{macrocode} \NewDocumentCommand \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} } - } -% \end{macrocode} + { \@@_set_default_hook_label:n {#1} } % % The label is only automatically updated with \cs{@onefilewithoptions} % (\cs{usepackage} and \cs{documentclass}), but some packages, like @@ -4907,7 +5294,7 @@ % \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 +% package-like behavior also for hooks in these files, we provide % high-level access to the default label stack. % \begin{macrocode} \NewDocumentCommand \PushDefaultHookLabel { m } @@ -4935,9 +5322,6 @@ % \end{macro} % \end{macro} % \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} % % % @@ -4961,7 +5345,7 @@ % \end{macro} % % \begin{macro}{\DebugHooksOn,\DebugHooksOff} -% +% % \begin{macrocode} \cs_new_protected:Npn \DebugHooksOn { \hook_debug_on: } \cs_new_protected:Npn \DebugHooksOff { \hook_debug_off: } @@ -4971,7 +5355,7 @@ % % % \begin{macro}{\DeclareHookRule} -% +% % \begin{macrocode} \NewDocumentCommand \DeclareHookRule { m m m m } { \hook_gset_rule:nnnn {#1}{#2}{#3}{#4} } @@ -5001,7 +5385,7 @@ % \begin{macro}[EXP]{\IfHookEmptyTF} % Here we avoid the overhead of \pkg{xparse}, since \cs{IfHookEmptyTF} % is used in \cs{end} (that is, every \LaTeX{} environment). As a -% further optimisation, use \cs{let} rather than \cs{def} to avoid one +% further optimization, use \cs{let} rather than \cs{def} to avoid one % expansion step. % \begin{macrocode} \cs_new_eq:NN \IfHookEmptyTF \hook_if_empty:nTF @@ -5025,6 +5409,111 @@ % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % +% \subsection{Deprecated that needs cleanup at some point} +% +% \changes{v1.0p}{2021/08/20}{Added deprecation warnings for +% old generic hook commands (gh/638)} +% +% \begin{macro}{ +% \hook_disable:n, +% \hook_provide:n, +% \hook_provide_reversed:n, +% \hook_provide_pair:nn, +% \@@_activate_generic_reversed:n, +% \@@_activate_generic_pair:nn, +% } +% Deprecated. +% \begin{macrocode} +\cs_new_protected:Npn \hook_disable:n + { + \@@_deprecated_warn:nn + { hook_disable:n } + { hook_disable_generic:n } + \hook_disable_generic:n + } +\cs_new_protected:Npn \hook_provide:n + { + \@@_deprecated_warn:nn + { hook_provide:n } + { hook_activate_generic:n } + \hook_activate_generic:n + } +\cs_new_protected:Npn \hook_provide_reversed:n + { + \@@_deprecated_warn:nn + { hook_provide_reversed:n } + { hook_activate_generic:n } + \@@_activate_generic_reversed:n + } +\cs_new_protected:Npn \hook_provide_pair:nn + { + \@@_deprecated_warn:nn + { hook_provide_pair:nn } + { hook_activate_generic:n } + \@@_activate_generic_pair:nn + } +\cs_new_protected:Npn \@@_activate_generic_reversed:n #1 + { \@@_normalize_hook_args:Nn \@@_activate_generic:nn {#1} { - } } +\cs_new_protected:Npn \@@_activate_generic_pair:nn #1#2 + { \hook_activate_generic:n {#1} \@@_activate_generic_reversed:n {#2} } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{ +% \DisableHook, +% \ProvideHook, +% \ProvideReversedHook, +% \ProvideMirroredHookPair, +% } +% Deprecated. +% \begin{macrocode} +\cs_new_protected:Npn \DisableHook + { + \@@_deprecated_warn:nn + { DisableHook } + { DisableGenericHook } + \hook_disable_generic:n + } +\cs_new_protected:Npn \ProvideHook + { + \@@_deprecated_warn:nn + { ProvideHook } + { ActivateGenericHook } + \hook_activate_generic:n + } +\cs_new_protected:Npn \ProvideReversedHook + { + \@@_deprecated_warn:nn + { ProvideReversedHook } + { ActivateGenericHook } + \@@_activate_generic_reversed:n + } +\cs_new_protected:Npn \ProvideMirroredHookPair + { + \@@_deprecated_warn:nn + { ProvideMirroredHookPair } + { ActivateGenericHook } + \@@_activate_generic_pair:nn + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\@@_deprecated_warn:nn} +% Warns about a deprecation, telling what should be used instead. +% \begin{macrocode} +\cs_new_protected:Npn \@@_deprecated_warn:nn #1 #2 + { \msg_warning:nnnn { hooks } { deprecated } {#1} {#2} } +\msg_new:nnn { hooks } { deprecated } + { + Command~\iow_char:N\\#1~is~deprecated~and~will~be~removed~in~a~ + future~release. \\ \\ + Use~\iow_char:N\\#2~instead. + } +% \end{macrocode} +% \end{macro} +% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% % % \subsection{Internal commands needed elsewhere} % @@ -5068,7 +5557,7 @@ %\def \NewReversedHook#1{} %\def \NewMirroredHookPair#1#2{} % -%\def \DisableHook #1{} +%\def \DisableGenericHook #1{} % %\long\def\AddToHookNext#1#2{} % @@ -5105,6 +5594,6 @@ % \Finale % % -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \endinput -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% diff --git a/Master/texmf-dist/source/latex/base/ltluatex.dtx b/Master/texmf-dist/source/latex/base/ltluatex.dtx index 3b9a3377312..258ac482977 100644 --- a/Master/texmf-dist/source/latex/base/ltluatex.dtx +++ b/Master/texmf-dist/source/latex/base/ltluatex.dtx @@ -28,7 +28,7 @@ \ProvidesFile{ltluatex.dtx} % %<*tex> -[2021/04/18 v1.1t +[2021/10/15 v1.1v % % LuaTeX support for plain TeX (core) %<*tex> @@ -912,12 +912,14 @@ local luatexbase = luatexbase % \end{macro} % % Some Lua best practice: use local versions of functions where possible. +% \changes{v1.1u}{2021/08/11}{Define missing local function} % \begin{macrocode} local string_gsub = string.gsub local tex_count = tex.count local tex_setattribute = tex.setattribute local tex_setcount = tex.setcount local texio_write_nl = texio.write_nl +local flush_list = node.flush_list % \end{macrocode} % \changes{v1.0i}{2015/11/29}{Declare this as local before used in the module error definitions (PHG)} % \begin{macrocode} @@ -1413,6 +1415,7 @@ local callbacktypes = callbacktypes or { % \changes{v1.1j}{2019/06/18}{font\_descriptor\_objnum\_provider added} % \changes{v1.1l}{2020/02/02}{glyph\_info added} % \changes{v1.1t}{2021/04/18}{input\_level\_string added} +% \changes{v1.1v}{2021/10/15}{provide\_charproc\_data added} % \begin{macrocode} define_font = exclusive, glyph_info = exclusive, @@ -1421,6 +1424,7 @@ local callbacktypes = callbacktypes or { make_extensible = exclusive, font_descriptor_objnum_provider = exclusive, input_level_string = exclusive, + provide_charproc_data = exclusive, % \end{macrocode} % \changes{v1.0m}{2016/02/11}{pdf\_stream\_filter\_callback removed} % \begin{macrocode} diff --git a/Master/texmf-dist/source/latex/base/ltmath.dtx b/Master/texmf-dist/source/latex/base/ltmath.dtx index aadb96fb023..59e0d89a106 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} - [2021/04/20 v1.2i LaTeX Kernel (Math Setup)] + [2021/10/14 v1.2j LaTeX Kernel (Math Setup)] % \iffalse % % @@ -915,10 +915,13 @@ % whole display. Note that we can't use \cs{refstepcounter} as this % results in |\@currentlabel| getting restored at the wrong and % thus always writing the first label to the \texttt{.aux} file. +% \changes{v1.2j}{2021/10/14} +% {Explicitly set \cs{@currentcounter} (gh/687)} % \begin{macrocode} \def\eqnarray{% \stepcounter{equation}% \def\@currentlabel{\p@equation\theequation}% + \def\@currentcounter{equation}% \global\@eqnswtrue \m@th \global\@eqcnt\z@ @@ -1231,10 +1234,13 @@ % % \begin{environment}{eqnarray} % The \textsf{eqnarray} environment +% \changes{v1.2j}{2021/10/14} +% {Explicitly set \cs{@currentcounter} (gh/687)} % \begin{macrocode} \renewenvironment{eqnarray}{% \stepcounter{equation}% \def\@currentlabel{\p@equation\theequation}% + \def\@currentcounter{equation}% \global\@eqnswtrue\m@th \global\@eqcnt\z@ \tabskip\mathindent diff --git a/Master/texmf-dist/source/latex/base/ltmiscen.dtx b/Master/texmf-dist/source/latex/base/ltmiscen.dtx index 8bae3f9bfa3..6cc58907a0d 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} - [2021/02/08 v1.1y LaTeX Kernel (Misc. Environments)] + [2021/06/05 v1.1z LaTeX Kernel (Misc. Environments)] % \iffalse \documentclass{ltxdoc} \GetFileInfo{ltmiscen.dtx} @@ -1471,12 +1471,13 @@ \def\@sverb#1{\if\noexpand#1 \expandafter\@sverb\else\@@sverb{#1}\fi} % \end{macrocode} % +% \changes{v1.1z}{2021/06/05}{Normalize error message} % \begin{macrocode} \def\@@sverb#1{% \catcode`#1\active \lccode`\~`#1% \gdef\verb@balance@group{\verb@egroup - \@latex@error{\noexpand\verb illegal in command argument}\@ehc}% + \@latex@error{\noexpand\verb illegal in argument}\@ehc}% \aftergroup\verb@balance@group \lowercase{\let~\verb@egroup}% % \end{macrocode} diff --git a/Master/texmf-dist/source/latex/base/ltoutenc.dtx b/Master/texmf-dist/source/latex/base/ltoutenc.dtx index eb2ecd1e537..61ea381823c 100644 --- a/Master/texmf-dist/source/latex/base/ltoutenc.dtx +++ b/Master/texmf-dist/source/latex/base/ltoutenc.dtx @@ -44,7 +44,7 @@ %<*driver> % \fi \ProvidesFile{ltoutenc.dtx} - [2021/04/29 v2.0v LaTeX Kernel (font encodings)] + [2021/10/16 v2.0x LaTeX Kernel (font encodings)] % \iffalse \documentclass{ltxdoc} \GetFileInfo{ltoutenc.dtx} @@ -199,7 +199,7 @@ % commands, such as accents. It also contains the code for some of % the encoding files, including |omlenc.def|, % |omsenc.def|, |t1enc.def| and |ot1enc.def| files, which define -% the |OLM|, +% the |OML|, % |OMS|, |T1| and |OT1| encodings, and the |fontenc| package % for selecting encodings. % @@ -845,10 +845,11 @@ % We also ignore \cs{ignorespaces} which has the same issue and may % show up as part of \cs{normalfont} if that is used. % \changes{v2.0m}{2019/12/18}{Avoid code that breaks \cs{accent}} +% \changes{v2.0x}{2021/10/16}{Dont set \cs{spacefactor in math mode gh/643}} % \begin{macrocode} \let\maybe@load@fontshape\relax \let\ignorespaces\relax - \accent#1 #2\egroup\spacefactor\accent@spacefactor} + \accent#1 #2\egroup\ifmmode\else\spacefactor\accent@spacefactor\fi} % \end{macrocode} % % @@ -1783,12 +1784,14 @@ % {Added \cs{ij} and \cs{IJ} from babel. (pr/3771)} % The dutch language uses the letter `ij'. It is available in % \texttt{T1} encoded fonts, but not in the \texttt{OT1} encoded -% fonts. Therefor we fake it for the \texttt{OT1} encoding. +% fonts. Therefore we fake it for the \texttt{OT1} encoding. +% \changes{v2.0w}{2021/09/12}{Move zero skip between +% i and j for hyphenation (gh/658)} % \begin{macrocode} \DeclareTextCommand{\ij}{OT1}{% - \nobreak\hskip\z@skip i\kern-0.02em j\nobreak\hskip\z@skip} + \nobreak\hskip\z@skip i\kern-0.02em\nobreak\hskip\z@skip j} \DeclareTextCommand{\IJ}{OT1}{% - \nobreak\hskip\z@skip I\kern-0.02em J\nobreak\hskip\z@skip} + \nobreak\hskip\z@skip I\kern-0.02em\nobreak\hskip\z@skip J} % \end{macrocode} % In the OT1 encoding, \pounds~and \$ share a slot. % \changes{v1.9y}{2000/01/30}{Use \cs{hmode@bgroup} where applicable diff --git a/Master/texmf-dist/source/latex/base/ltoutput.dtx b/Master/texmf-dist/source/latex/base/ltoutput.dtx index b1b3a240965..78b0f2335f8 100644 --- a/Master/texmf-dist/source/latex/base/ltoutput.dtx +++ b/Master/texmf-dist/source/latex/base/ltoutput.dtx @@ -30,14 +30,14 @@ %%% From File: ltoutput.dtx %\ProvidesPackage{flafter} %\ProvidesPackage{fltrace} -% [2018/11/28 v1.4d +% [2021/07/31 v1.4e % Standard LaTeX floats after reference (FMi)] % Tracing LaTeX floats algorithm (FMi)] % %<*driver> % \fi \ProvidesFile{ltoutput.dtx} - [2021/05/05 v1.4g LaTeX Kernel (Output Routine)] + [2021/09/03 v1.4h LaTeX Kernel (Output Routine)] % \iffalse \documentclass{ltxdoc} \GetFileInfo{ltoutput.dtx} @@ -3945,10 +3945,69 @@ \fi \fi } +% \end{macrocode} +% \end{macro} +% +% +% +% +% +% \begin{macro}{\ShowFloat} +% This command provides some information about the contenta of a +% float register. Float registers have internal names of the form +% \cs{bx@}\meta{Uppercase-letter(s)-or numbers} and you specify just this +% letter or letters as the argument, e.g., \verb=\ShowFloat{A}=. +% (There is not much error recovery if you specify something that +% isn't a float.) +% \changes{v1.4g}{2021/07/31}{Macro added} +% \changes{v1.4h}{2021/09/03}{Renamed, original name never distributed} +% \begin{macrocode} % +%<*2ekernel|latexrelease> +%\IncludeInRelease{2021/11/15}% +% {\ShowFloat}{Show float register contents}% +\def\ShowFloat#1{\begingroup + \let \fl@trace \fl@tracemessage + \fl@trace{***Float #1 details:}% + \ifcsname bx@#1\endcsname + \expandafter\fl@ShowFloat\csname bx@#1\endcsname + \else + \fl@trace{Not a float!}% + \fi + \endgroup +} +\def\fl@ShowFloat#1{% + \fl@traceval{\count#1}% % this here should be interpreted on day + \fl@traceval{\ht#1}% + \fl@traceval{\dp#1}% + \fl@traceval{\wd#1}% + {\tracingonline1\showboxbreadth10\showboxdepth3\showbox#1}% +} +% \end{macrocode} +% Here are two definitions from \texttt{fltrace} that make the above +% code work: +% \begin{macrocode} +\def \fl@traceval #1{\fl@trace{\string #1 = \the #1}} +\def \fl@tracemessage #1{{\let\@elt\@empty\typeout{LaTeX2e: #1}}} +% +%\EndIncludeInRelease +% \end{macrocode} +% +% \begin{macrocode} +%\IncludeInRelease{0000/00/00}% +% {\ShowFloat}{Show float register contents}% +% +%\let\ShowFloat\@undefined +%\let\fl@ShowFloat\@undefined +%\let\fl@traceval\@undefined +%\let\fl@tracemessage\@undefined +%\EndIncludeInRelease % \end{macrocode} % \end{macro} % +% +% +% % \subsubsection{Float control} % % This part implements controllable floats and other changes @@ -4025,6 +4084,16 @@ % wrong value.\footnote{This is a somewhat questionable design.} % \begin{macrocode} \begingroup +% \end{macrocode} +% When the user requests \cs{tracefloatvals} then they should show +% regardless of the tracing state, so locally we make sure that it +% is activated. +% \changes{v1.4e}{2021/07/31}{Enable display when doing \cs{tracefloatvals}} +% \begin{macrocode} + \tracefloats +% \end{macrocode} +% +% \begin{macrocode} \@dblfloatplacement \@floatplacement \fl@trace{***Float placement parameters:}% @@ -4052,6 +4121,7 @@ {trace float vals}% \def \tracefloatvals{% \begingroup + \tracefloats \@dblfloatplacement \@floatplacement \fl@trace{***Float placement parameters:}% @@ -4077,6 +4147,10 @@ } \EndIncludeInRelease % \end{macrocode} +% +% +% +% % We need to make sure that \texttt{fltrace} comes before % \texttt{flafter} to make the tracing work. % \begin{macrocode} diff --git a/Master/texmf-dist/source/latex/base/ltpara.dtx b/Master/texmf-dist/source/latex/base/ltpara.dtx index 5ab52a5e9bc..a2da67198a6 100644 --- a/Master/texmf-dist/source/latex/base/ltpara.dtx +++ b/Master/texmf-dist/source/latex/base/ltpara.dtx @@ -14,8 +14,8 @@ %%% From File: ltpara.dtx % % \begin{macrocode} -\def\ltparaversion{v1.0g} -\def\ltparadate{2021/05/27} +\def\ltparaversion{v1.0k} +\def\ltparadate{2021/11/11} % \end{macrocode} %<*driver> \documentclass{l3doc} @@ -23,6 +23,7 @@ %\usepackage{ltpara} % Fixing footnotes in functions and variables: this should be in l3doc! + \newcommand\fixfootnote[2]{\footnotemark \AddToHookNext{env/#1/after}{\footnotetext{#2}}} \AddToHook{env/function/begin}{\def\footnote{\fixfootnote{function}}} @@ -122,8 +123,8 @@ % \verb=\hbox{a\par b}= is ignored, but \verb=$a\par b$= would complain. % % If this primitive ends the paragraph it does some special -% \enquote{end of horizontal list} processing, then calls \TeX{} paragraph -% builder that breaks the horizontal list into lines then these +% \enquote{end of horizontal list} processing, then calls \TeX{}’s paragraph +% builder; this breaks the horizontal list into lines and then these % lines are added as boxes to the enclosing vertical list and % \TeX{} returns to vertical mode. % @@ -133,13 +134,14 @@ % automatically changed to a \cs{par} command which is then % executed. The other possibility is that \TeX{} encounters a % command which is incompatible with horizontal processing, e.g., -% \cs{vskip} (a request for adding vertical space). In such case it +% \cs{vskip} (a request for adding vertical space). In such cases it % silently backs up, and inserts a \cs{par} in the hope that this -% gets it out of horizontal mode and makes the offending command +% gets it out of horizontal mode and makes the vertical command % acceptable. % The important point to note here is that \TeX{} really inserts -% the command \cs{par} which can be redefined. Thus, it may not have +% the command with the name \cs{par}, which can be redefined. +% Thus, it may not have % its original \enquote{primitive} meaning and therefore may not end the % horizontal list and call the paragraph builder. This approach % offers some flexibility but also allows you to easily produce a @@ -151,31 +153,30 @@ % then sees \cs{vskip} and inserts \cs{par} to end the % paragraph. But this now only runs \cs{relax} so nothing changes % and \cs{vskip} is read again, issues a \cs{par} which \ldots. In -% short, it takes a plain \TeX{} document with five tokens to run -% forever (as not even memory is consumed and therefore eventually +% short, it only takes a plain \TeX{} document with five tokens to run +% forever (since no memory is consumed and therefore eventually % exhausted). % -% There are no other ways than changing \cs{par} to gain control at +% There is no way other than changing \cs{par} to gain control at % the end of a paragraph, i.e., there is no token list like -% \cs{everypar} that is inserted, i.e., the only way to change the -% default behavior is to modify the action that \cs{par} executes +% \cs{everypar} that is inserted. Hence the only way to change the +% default behavior is to modify the action that \cs{par} executes, % with similar issues as outlined before: different processes need % to ensure that they do not overwrite their modifications or % worse, think that the \cs{par} in front of them is the engine % primitive while in fact it has already been changed by other % code. % -% % To make matters slightly worse there are a few places where % \TeX{} handles the situation differently (most likely for speed % reasons back when computers were much slower). If \TeX{} finds % itself in unrestricted horizontal mode at the end of building a -% vertical box (or an \cs{insert}, \cs{vadjust} or at the end of +% vertical box (for an \cs{insert}, \cs{vadjust} or % executing the output routine code), it will finish the horizontal % list not by issuing a \cs{par} command (which would be consistent -% with all other places, but by simply executing the primitive version -% of \cs{par} regardless of the definition that \cs{par} has at the -% time. +% with all other places) but by simply executing the primitive meaning +% of \cs{par}, regardless of the actual definition that \cs{par} +% has at the time. % % Thus, if you have carefully crafted a redefined \cs{par} to execute % some special actions at the end of a paragraph and you write @@ -183,27 +184,28 @@ %\begin{verbatim} % \vbox{Some paragraph ... text.} %\end{verbatim} -% you will find that your code has never run for the last paragraph +% you will find that your code does not get run for the last paragraph % in that box. \LaTeX{} avoids this problem, by making sure that -% all its boxes (such as \cs{parbox} or the \env{minipage} +% its boxes (such as \cs{parbox} or the \env{minipage} % environment, etc.) all internally add an explicit \cs{par} at the % end so that such code is run and \TeX{} finds itself in vertical % mode already without the need to start up the paragraph builder % internally. But, of course, this only works for boxes under direct -% control of the \LaTeX{} kernel, if some package uses low-level +% control of the \LaTeX{} kernel; if some package uses low-level % \cs{vbox}es without adding this precaution the \TeX{} % optimization kicks in and no special \cs{par} code is executed. % % And there is another optimization that is painful: if a paragraph % is interrupted by a mathematical display, e.g., \verb=\[...\]= in % \LaTeX{} or \verb=$$...$$= in plain \TeX{}, then \TeX{} will -% resume horizontal mode afterward, i.e., build a new horizontal -% list (without inserting an indentation box or \cs{everypar} at -% that point). However, if that list immediately ends with an +% resume horizontal mode afterward, i.e., it will start to build +% a new horizontal +% list without inserting an indentation box or \cs{everypar} at +% that point. However, if that list immediately ends with an % explicit or implicit \cs{par} then \TeX{} will simply throw away % this \enquote{null} paragraph and not do its usual \enquote{end -% of horizontal list} processing, so this special case need to be -% accounted for when introducing some extended processing. +% of horizontal list} processing, so this special case also needs to be +% accounted for when introducing any extended processing. % % % @@ -214,8 +216,8 @@ % the start and end of the paragraph processing. The public hooks % can be used by packages (or by the user in the preamble or % within the document) and using the hook mechanisms it is possible -% to reorder or arrange code from different packages in a way that -% it can safely coexist. +% to reorder or arrange code from different packages in such a way that +% these can safely coexist. % % To make that happen we have to make use of the basic % functionality that is offered by \TeX{}, e.g., we install @@ -248,7 +250,7 @@ % Fortunately, \LaTeX{} has already redefined \cs{par} for its own % purposes. As a result there aren't many packages that attempt to % change \cs{par}, because without a lot of extra care that would -% fail miserably. But bottom line, if you load a package that +% fail miserably. But the bottom line is that, if you load a package that % alters \cs{par} then the end of paragraph hooks are most likely % not executing while that redefinition is % active.\footnote{Similarly to the \cs{everypar} situation, the @@ -326,7 +328,7 @@ % % This hook is executed at the end of a paragraph when \TeX{} is % ready to return to vertical mode and after it has removed the -% last horizontal glue (but not kern) placed on the horizontal +% last horizontal glue (but not any kerns) placed on the horizontal % list. The code is still executed in horizontal mode so it is % possible to add further horizontal material at this point, but % it should not alter the mode (even a temporary exit from @@ -415,20 +417,20 @@ % \subsection{Altered and newly provided commands} % % \begin{function}{\par,\endgraf,\para_end:} -% An explicit request for ending a paragraph is known in plain -% \TeX{} under the name \cs{endgraf} where it simply calls the -% paragraph primitive (regardless of what \cs{par} may have as its -% current definition). In \LaTeX{} \cs{endgraf} with that behavior -% was also made available. +% An explicit request for ending a paragraph is provided in plain +% \TeX{} under the name \cs{endgraf}, which simply uses the +% primitive meaning (regardless of what \cs{par} may have as its +% current definition). In \LaTeX{} \cs{endgraf} (with that behavior) +% was originally also available. % % With the new paragraph handling in \LaTeX{}, ending a paragraph % means a bit more than just calling the engine's paragraph % builder: the process also has to add any hook code for the end of % a paragraph. Thus % \cs{endgraf} was changed to provide this additional functionality -% (and so by extension \cs{par} subject to its current meaning). +% (along with \cs{par} remaining subject to its current meaning). % -% The \pkg{expl3} name for the functionality is \cs{para_end:}. +% The \pkg{expl3} name for this functionality is \cs{para_end:}. % \end{function} % % \begin{quote} @@ -468,7 +470,7 @@ % % The commands \cs{RawIndent} and \cs{RawNoindent} are not meant % for normal paragraph building (where the result is a textual -% paragraph in the the traditional meaning of the word), but for +% paragraph in the traditional meaning of the word), but for % special cases where \TeX{}'s low-level algorithm is used to % achieve special effects, but where the result is not a % \enquote{paragraph}. @@ -538,7 +540,7 @@ % sequence numbers. This is most easily done using \pkg{expl3} % functions, so we switch over. This is not a very general % implementation, just enough for what we need and a bit of -% \LaTeXe{} thrown in as well. When popping the result gets stored +% \LaTeXe{} thrown in as well. When popping, the result gets stored % in \cs{paracntvalue} and the \cs{ERROR} should never happen % because it means we have tried to pop from an empty stack. %\begin{verbatim} @@ -602,8 +604,8 @@ % % \subsubsection{Mark the first paragraph of each \env{itemize}} % -% The code for this is rather simple. We apply hook code that is -% executed only once inside a hook that is executed at the begin of +% The code for this is rather simple. We supply some code that is +% executed only once inside a hook at the start of % each \env{itemize}. We explicitly change the color back and % forth so that we don't introduce grouping around the paragraph. %\begin{verbatim} @@ -629,7 +631,7 @@ % \subsubsection{Glue items between paragraphs (found with \pkg{fancypar})} % % In the past \LaTeX{} placed two glue items between two -% consecutive paragraph, e.g., +% consecutive paragraphs, e.g., %\begin{verbatim} % text1 \par text2 \par %\end{verbatim} @@ -644,12 +646,12 @@ % \glue(\parskip) 0.0 % \glue(\baselineskip) 5.16669 %\end{verbatim} -% The reason is that we generate a \enquote{fake}'' paragraph to +% The reason is that we generate a \enquote{fake} paragraph to % gain control and safely add the early hooks, but this generates % an additional glue item. That item doesn't contribute anything -% vertically but ifsomebody writes code the unravels a constructed +% vertically but if somebody writes code that unravels a constructed % list using \cs{lastbox}, \cs{unskip} and \cs{unpenalty} then the -% code has to remove one additional glue item or else will fail. +% code has to remove one additional glue item or else it will fail. % % ^^A \subsubsection{} @@ -828,8 +830,8 @@ % % But if we have already replaced it by a token register then all % they do is to give that token register a new name. Thus our code -% in \cs{tex_everypar:D} would call \cs{everypar} (which is their -% now token register) and the code that they added ends up in our +% in \cs{tex_everypar:D} would call \cs{everypar} (which is now their +% token register) and the code that they added ends up in our % token register which is then never used at all. A bit mind % boggling I guess. % @@ -927,7 +929,7 @@ % \end{itemize} % % Unfortunately, \TeX{} has some (these days) unnecessary -% optimization: if a \cs{vbox} ends and \TeX{} is still in +% optimizations: if a \cs{vbox} ends and \TeX{} is still in % horizontal mode it simply exercises the paragraph builder instead % of issuing a \cs{par}. It is therefore necessary for \LaTeX{} to % ensure that this case doesn't happen and all boxes internally @@ -940,11 +942,11 @@ % \texttt{latex.ltx}. For this \LaTeXe{} code has the following % conventions: \cs{@@@@par} and \cs{endgraf} both refer to the % default meaning (in the past this was the initex primitive) while -% \cs{par} is the current meaning which may does something else. +% \cs{par} is the current meaning which maybe does something else. % % -% We are now going to change this default meaning to run -% \cs{para_end:} instead, which ultimately executes the initex +% We are now going to change this default meaning to instead run +% \cs{para_end:}, which ultimately executes the initex % primitive but additionally adds our hooks when appropriate. % This way the change is again transparent to the legacy \LaTeXe{} % code. @@ -953,110 +955,158 @@ % primitive and we achieve this by simply expanding it to the % primitive which is available to us as \cs{tex_par:D}. This way we % don't have to care about whether \TeX{} just does nothing (e.g., -% if in vertical mode already) or generate an error, etc. +% if in vertical mode already) or generates an error, etc. % \begin{macrocode} \cs_new_protected:Npn \para_end: { % \end{macrocode} % +% CCC Maybe needs more explanation. +% TEMP NOTE: What should happen if in outer hmode with an empty hlist? +% % The only case we care about is when we are in horizontal mode % (i.e., doing typesetting) and not also in inner mode (i.e., % making paragraphs and not building an \cs{hbox}. -% \begin{macrocode} +%\begin{verbatim} % \bool_lazy_and:nnT % { \mode_if_horizontal_p: } % { \bool_not_p:n { \mode_if_inner_p: } } % { ... -% \end{macrocode} +%\end{verbatim} % Since this is executed for each and every paragraph in a document -% we try to stay a fast as possible, So we are aren't using the +% we try to stay as fast as possible, so we do not use the % above construct but two conditionals instead. Using low-level % \cs{if_mode...} conditions would be even faster but has the % danger to conflict with conditionals in the user hooks. +% +% If \cs{para_end:} is executed while \TeX{} is currently doing a +% low-level assignment the test for horizontal mode may get +% executed as part of the assignment. That is normally not an issue +% but we just found one case where it is: +%\begin{verbatim} +% \afterassignment\lst@vskip\@tempskipa \z@ \par +%\end{verbatim} +% If \TeX{} is in hmode while that assignment happens then the +% \cs{par} is seen in hmode because in the above case the +% assignment may not be finished (one should have used \cs{z@skip}) and +% the \cs{lst@vskip} will get inserted into the middle of the +% conditional. The \cs{lst@vskip} then changes to vmode and you get +% a surprising error about the \texttt{para/end} hook having +% changed modes even if you don't have any hook code(!): it is +% the inserted \cs{lst@vskip} that is actually causing the change of +% mode.This is what happened +% when the output routines got started while a \texttt{lstlisting} +% environment (that redefines \cs{vskip} in this way) was +% active. This is really faulty coding, but we try to be proactive +% and guard the conditional so that any scanning is first stopped, thus: +% \begin{macrocode} + \scan_stop: +% \end{macrocode} +% % \begin{macrocode} \mode_if_horizontal:TF { \mode_if_inner:F { % \end{macrocode} % In that case the action of the primitive would be to remove the -% last glue (not kern) from the horizontal list constructed to form -% a paragraph then append the a penalty of 10000 and the -% \cs{parfillskip} at the end and pass the whole list to the -% paragraph builder which breaks it into lines and \TeX{} then +% last glue (but no kerns) from the horizontal list (constructed to form +% a paragraph) and then to append a penalty of 10000 and the +% \cs{parfillskip}; it then passes the whole list to the +% paragraph builder, which breaks it into lines and \TeX{} then % returns to vertical mode. % -% What we want to do instead is to add our hook code at the end of -% the horizontal list before that happens and the code is passed to -% the paragraph builder. If there was a glue item at the end then +% What we want to do is to add this hook code at the end of +% the horizontal list before any of the above happens. +% If there was a glue item at the end of the list then % it should get removed before the hook code gets added so we have -% to arrange for its removal ourselves. +% to arrange for this removal. +% +% As in other simular cases, it maybe best to add here +% a \cs{nobreak} in case the hook itself adds glue and thus +% creates a non-explicit and unwanted potential breakpoont. +% On the other hand (as has been argued) the code in the hook +% should perhaps have the responsibility for adding such a +% guard penalty in this casse. +% This needs further analysis and decisions (as in emails). +% +% In either case, good documentation of these hooks is essential, +% covering what the hook may or should provide and all +% such related considerations convernimg the content. % % There is not much point in checking if there was really a glue % item at the end of the horizontal list, instead we simply try to -% remove one using \cs{tex_unskip:D}, if there wasn't one this will +% remove one using \cs{tex_unskip:D}: if there wasn't one this will % do nothing. % \begin{macrocode} \tex_unskip:D % \end{macrocode} -% The we execute the public hook (which may add final typesetting -% material) followed by the kernel hook we need for adding tagging +% We then execute the public hook (which may add some final typeset +% material) followed by the kernel hook that we need for adding tagging % support. None of this is supposed to change the mode---at the % moment we make only a very simple test for this, more devious -% changes go unnoticed, but too bad, that will then probably -% badly backfire. +% changes go unnoticed, but too bad as they will then probably +% backfire badly. % \begin{macrocode} \hook_use:n{para/end} \@kernel@after@para@end \mode_if_horizontal:TF { % \end{macrocode} % The final action (before getting to the point where -% \cs{tex_par:D} is called) is to add a kern item so that the -% primitive is prevented from removing glue (if there was some). If -% we don't do this and the -% horizontal list ended in several glue items we would end up with -% removing two instead of just the last one, which would be wrong. -% We use a kern as that is minimally faster. +% \cs{tex_par:D} is called) is to add an extra glue item so that the +% primitive is prevented from removing intended glue +% (if there was some). If we don't do this and the +% horizontal list ends in several glue items we would end up removing +% two glue items instead of just the last one, which would be wrong. +% We use glue (rather than a kern) as that will be removed by the +% primitive. % % There is however one other \TeX{} optimization that hurts: in a -% sequence like this \verb=$$ ... $$ \par= \TeX{} will be in +% sequence like this \verb=$$ ... $$ \par= (with \cs{par} being the primitive) +% \TeX{} will be in % horizontal mode after the display, ready to receive further % paragraph text, but since the \cs{par} follows immediately there % is a ``null'' paragraph at the end and \TeX{} simply throws that -% away. The space between \verb=$$= and \cs{par} got already +% away. +% The space between \verb=$$= and \cs{par} got already % dropped during the display processing so the \cs{par} is not % removing any space and appending \cs{parfillskip}, instead it -% simply goes silently to vmode. Now if we would had added something (to +% simply goes silently to vmode. +% +% Now if we would have added something (to % prevent glue removal) that would look to \TeX{} like material % after the display and so we would end up with an empty paragraph -% just containing \cs{parfillskip}. +% just containing a penalty and \cs{parfillskip}. % -% We therefore check if the current hlist is empty -% (\cs{tex_lastnodetype:D} has the value \texttt{-1} and -% only if not we add our kern. +% We therefore check if the current hlist does end in glue +% (\cs{tex_lastnodetype:D} has the value \texttt{11}) and +% if so we add a zero-length guard skip which will be removed by the +% following \cs{tex_par:D}. +% \changes{v1.0i}{2021/09/18}{Use skip rather than kern as guard.} % \begin{macrocode} - \if_int_compare:w 0 < \tex_lastnodetype:D - \tex_kern:D \c_zero_dim + \if_int_compare:w 11 = \tex_lastnodetype:D + \tex_hskip:D \c_zero_dim \fi: % \end{macrocode} % To run the \hook{para/after} hook we first end the % paragraph. This means that the \cs{tex_par:D} at the very end is % unnecessary but executing it there unnecessarily is better than -% having code that test for all the different mode possibilities. +% having code that tests for all the different mode possibilities. % \begin{macrocode} \tex_par:D \hook_use:n{para/after} \@kernel@after@para@after } % \end{macrocode} -% If we haven't been in horizontal mode then the earlier hook -% \hook{para/end} is at fault and we report that. +% If we were not horizontal mode (the F case from above) +% then the earlier hook +% \hook{para/end} must have been at fault, so we report that. % \begin{macrocode} { \msg_error:nnnn { hooks }{ para-mode }{end}{horizontal} } % \end{macrocode} % Finally close out the nested conditionals. % \begin{macrocode} } - } + } % \end{macrocode} -% +% And then we can use the primitive to truly end the paragraph. % \begin{macrocode} \tex_par:D } @@ -1090,7 +1140,7 @@ \@@_handle_indent: \the\everypar } } - { \msg_error:nn { kernel }{ raw-para } } + { \msg_error:nn { latex2e }{ raw-para } } \tex_indent:D } % \end{macrocode} @@ -1103,7 +1153,7 @@ \tex_everypar:D { \g_@@_standard_everypar_tl } \the\everypar } } - { \msg_error:nn { kernel }{ raw-para } } + { \msg_error:nn { latex2e }{ raw-para } } \tex_noindent:D } % \end{macrocode} @@ -1133,10 +1183,11 @@ % \begin{macro}[int]{\@@par} % % Having the new default definition for \cs{par} we also have to -% set it up so that it gets used. This is needed in three places +% set it up so that it gets used. This involves three commands: % \cs{par}, \cs{@@par} (to which \LaTeX{} resets \cs{par} -% occasionally) and \cs{endgraf} which is another name for the +% occasionally) and \cs{endgraf}, which is another name for the % ``default'' action of \cs{par}. +% % \begin{macrocode} \cs_set_eq:NN \par \para_end: \cs_set_eq:NN \@@par \para_end: @@ -1161,7 +1212,7 @@ % The first argument is the hook name second the mode % it should have stayed in but didn't. % -% \begin{macrocode} +% \begin{macrocode} \msg_new:nnnn { hooks } { para-mode } { Illegal~mode~ change~ in~ hook~ 'para/#1'.\\ @@ -1175,10 +1226,11 @@ } % \end{macrocode} % +% \changes{v1.0i}{2021/08/27}{Internal message name changes} % And here is one used in the \enquote{raw} commands when they are -% used outside of vertical mode. +% used outside of vertical mode. % \begin{macrocode} -\msg_new:nnnn { kernel } { raw-para } +\msg_new:nnnn { latex2e } { raw-para } { Not~ in~ vertical~ mode. } @@ -1206,7 +1258,17 @@ %\cs_set_eq:NN \par \tex_par:D %\cs_set_eq:NN \@@par \tex_par:D %\cs_set_eq:NN \endgraf \tex_par:D -% +% +% \end{macrocode} +% We also need to clean up the primitive ``everypar'' as that +% should no longer execute any code by default. And, of course, +% make \cs{everypar} become the primitive again. +% \changes{v1.0k}{2021/10/19}{Remove content from \cs{tex_everypar:D} +% on rollback} +% \begin{macrocode} +%\tex_everypar:D {} +%\cs_set_eq:NN \everypar \tex_everypar:D +% %\EndModuleRelease \ExplSyntaxOff % @@ -1220,4 +1282,3 @@ \endinput %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % - diff --git a/Master/texmf-dist/source/latex/base/ltplain.dtx b/Master/texmf-dist/source/latex/base/ltplain.dtx index e0fbcecf1b6..5fa70396794 100644 --- a/Master/texmf-dist/source/latex/base/ltplain.dtx +++ b/Master/texmf-dist/source/latex/base/ltplain.dtx @@ -32,7 +32,7 @@ %<*driver> % \fi \ProvidesFile{ltplain.dtx} - [2021/04/18 v2.3f LaTeX Kernel (Plain TeX)] + [2021/07/16 v2.3g LaTeX Kernel (Plain TeX)] % \iffalse \documentclass{ltxdoc} \GetFileInfo{ltplain.dtx} @@ -906,6 +906,7 @@ \finalhyphendemerits=5000 \adjdemerits=10000 % \end{macrocode} +% \begin{macrocode} % \looseness=0, cleared by TeX after each paragraph % \pausing=0 % \holdinginserts=0 @@ -915,9 +916,24 @@ % \tracingparagraphs=0 % \tracingpages=0 % \tracingoutput=0 +% \end{macrocode} +% In the past \LaTeX{} used the default value of \texttt{1} for +% \cs{tracinglostchars} because this was the best it could do. This +% way one would at least get a warning in the \texttt{.log} +% file. e-\TeX{} improved on that and supported a value of \texttt{2} +% to show the warning on the terminal, so we could have changed the +% default when we made the e-\TeX{} extensions required---however, +% we overlooked that oportunity. +% In 2021 this parameter was improved on again and now also accepts +% the value \texttt{3} +% (error on the terminal). This made us realize that we should +% change the default. Using \texttt{3} would really be the +% best, but for compatibility reasons we only use \texttt{2}. +% \changes{v2.3g}{2021/07/16}{Use 2 as default value for \cs{tracinglostchars}} % \begin{macrocode} -\tracinglostchars=1 +\tracinglostchars=2 % \end{macrocode} +% \begin{macrocode} % \tracingcommands=0 % \tracingrestores=0 % \end{macrocode} diff --git a/Master/texmf-dist/source/latex/base/ltsect.dtx b/Master/texmf-dist/source/latex/base/ltsect.dtx index 29ea142ba6c..67974c73874 100644 --- a/Master/texmf-dist/source/latex/base/ltsect.dtx +++ b/Master/texmf-dist/source/latex/base/ltsect.dtx @@ -31,7 +31,7 @@ %%% From File: ltsect.dtx %<*driver> % \fi -\ProvidesFile{ltsect.dtx}[2020/12/05 v1.1e LaTeX Kernel (Sectioning)] +\ProvidesFile{ltsect.dtx}[2021/07/28 v1.1f LaTeX Kernel (Sectioning)] % \iffalse \documentclass{ltxdoc} \GetFileInfo{ltsect.dtx} @@ -765,7 +765,7 @@ % The |\addcontentsline{|\meta{table}|}{|\meta{type}|}{|% % \meta{entry}|}| command allows the user to add % his/her own entry to a table of contents, etc. The command adds the -% entry |\contentsline{|\meta{type}|}{|\meta{entry}|}{|\meta{page}|}| +% entry |\contentsline{|\meta{type}|}{|\meta{entry}|}{|\meta{page}|}{}| % to the |.|\meta{table} file. % % This macro is implemented as an application of |\addtocontents|. @@ -833,7 +833,7 @@ % \end{macro} % % \begin{macro}{\contentsline} -% The |\contentsline{|\meta{type}|}{|\meta{entry}|}{|\meta{page}|}| +% The |\contentsline{|\meta{type}|}{|\meta{entry}|}{|\meta{page}|}{}| % macro produces a \meta{type} entry in a table of contents, etc. % It will appear in the |.toc| or other file. For example, % The entry for subsection 1.4.3 in the table of contents for @@ -848,10 +848,44 @@ % without expanding them. % % \begin{macrocode} -\def\contentsline#1{\csname l@#1\endcsname} +% +%<*2ekernel|latexrelease> +%\IncludeInRelease{2021/11/15}% +% {\contentsline}{Four arguments}% +% \end{macrocode} +% +% In the toc file \cs{contentsline} is followed by 4 arguments +% these days, but only the first 3 are used in the old +% interface. The fourth was by default empty and only used when +% \pkg{hyperref} was loaded. We now pick up all 4 arguments, save +% the last one away in \cs{@contentsline@destination} and then call +% the old interface. This is done to simplify the interface to +% \pkg{hyperref} and to prepare for future changes. +% \changes{v1.1f}{2021/07/28}{Pick up four arguments (gh/633)} +% \begin{macrocode} +\def\contentsline#1#2#3#4{\gdef\@contentsline@destination{#4}% + \csname l@#1\endcsname{#2}{#3}} +% \end{macrocode} +% Default definition. +% \begin{macrocode} +\let\@contentsline@destination\@empty +% \end{macrocode} +% +% \begin{macrocode} +% +%\EndIncludeInRelease +%\IncludeInRelease{0000/00/00}% +% {\contentsline}{Four arguments}% +% +%\def\contentsline#1{\csname l@#1\endcsname} +%\let\@contentsline@destination\@undefined +%\EndIncludeInRelease +%<*2ekernel> % \end{macrocode} % \end{macro} % +% +% % |\@dottedtocline{|\meta{level}|}{|\meta{indent}|}{|\meta{numwidth}% % |}{|\meta{title}|}{|\meta{page}|}|: % Macro to produce a table of contents line with the following diff --git a/Master/texmf-dist/source/latex/base/ltshipout.dtx b/Master/texmf-dist/source/latex/base/ltshipout.dtx index f773cd23da2..7f6555d18cf 100644 --- a/Master/texmf-dist/source/latex/base/ltshipout.dtx +++ b/Master/texmf-dist/source/latex/base/ltshipout.dtx @@ -32,8 +32,8 @@ %%% From File: ltshipout.dtx % % \begin{macrocode} -\providecommand\ltshipoutversion{v1.0i} -\providecommand\ltshipoutdate{2021/03/17} +\providecommand\ltshipoutversion{v1.0j} +\providecommand\ltshipoutdate{2021/06/09} % \end{macrocode} % %<*driver> @@ -283,7 +283,7 @@ % includes the background and foreground material). % % \textbf{Note:} Just like \hook{shipout/before} this hook is -% not meant to be used for adding adding typeset material back +% not meant to be used for adding typeset material back % to the main vertical list---it might vanish or the % vertical spacing will be wrong! % @@ -867,7 +867,7 @@ % \begin{macrocode} \cs_new:Npn \@@_execute_main_cont:Nnnn #1#2#3#4 { \box_if_empty:NTF #1 - { \@latex@warning{Ignoring~ void~ shipout~ box} } + { \@latex@warning@no@line{ Ignoring~ void~ shipout~ box } } { % \end{macrocode} % Otherwise we assume that we will ship something and prepare for @@ -935,9 +935,8 @@ % practice way is to use the request mechanism. % \begin{macrocode} { \box_if_empty:NTF #1 - { \@latex@warning{ - Shipout~ box~ was~ voided~ by~ hook,\MessageBreak - ignoring~ shipout~ box } + { \@latex@warning@no@line { Ignoring~ void~ shipout~ box. + \MessageBreak The~ shipout~ box~ was~ voided~ by~ hook~ code } } % \end{macrocode} % Finally, if the box is still non-empty we are nearly ready to @@ -1183,9 +1182,8 @@ % \begin{macrocode} \cs_gset_eq:NN \@@_run_firstpage_hook: \prg_do_nothing: \cs_gset:Npn \@@_add_firstpage_material:Nn ##1 ##2 { - \@latex@warning{ - First~ page~ is~ already~ shipped~ out,~ ignoring\MessageBreak - \string##1 } + \@latex@warning{ First~ page~ is~ already~ shipped~ out,~ ignoring + \MessageBreak \string##1 } } } % \end{macrocode} diff --git a/Master/texmf-dist/source/latex/base/ltvers.dtx b/Master/texmf-dist/source/latex/base/ltvers.dtx index c8c3e618a55..9ce8d74cce3 100644 --- a/Master/texmf-dist/source/latex/base/ltvers.dtx +++ b/Master/texmf-dist/source/latex/base/ltvers.dtx @@ -33,7 +33,7 @@ %<*driver> % \fi \ProvidesFile{ltvers.dtx} - [2021/04/16 v1.1g LaTeX Kernel (Version Info)] + [2021/08/10 v1.1h LaTeX Kernel (Version Info)] % \iffalse \documentclass{ltxdoc} \GetFileInfo{ltvers.dtx} @@ -112,10 +112,10 @@ % %\edef\latexreleaseversion %<*2ekernel|latexrelease> - {2021-06-01} + {2021-11-15} % %<*2ekernel> -\def\patch@level{1} +\def\patch@level{0} % \end{macrocode} % % \begin{macro}{\development@branch@name} @@ -230,6 +230,7 @@ % \changes{v1.0o}{2015/01/19}{Optional argument} % \changes{v1.0q}{2015/02/19}{Swap argument order} % \changes{v1.1f}{2021/03/18}{Add support for usage in \cs{NewModuleRelease}} +% \changes{v1.1h}{2021/08/10}{Add error to aid debugging} % % \begin{macrocode} %<*2ekernel|latexrelease> @@ -257,6 +258,15 @@ {\@IncludeInRelease{#1}[#1]}}} \def\finish@module@release#1#2#3{% \toks@{[#1] #3}% + \begingroup + \edef\x{\detokenize\expandafter{\new@modulename}}% + \edef\y{\detokenize{#2}}% + \expandafter\endgroup + \ifx\x\y \else + \@latex@error{\noexpand\IncludeInRelease dated #1 in a module is not + allowed.\MessageBreak Use a date at least equal to \new@moduledate + \space for complete rollback}\@ehd + \fi \ifnum\expandafter\@parse@version\new@moduledate//00\@nil >\expandafter\@parse@version\fmtversion//00\@nil \GenericInfo{}{Applying: \the\toks@}% diff --git a/Master/texmf-dist/source/latex/base/makeindx.dtx b/Master/texmf-dist/source/latex/base/makeindx.dtx index e8e48e60b06..9dc03a8431e 100644 --- a/Master/texmf-dist/source/latex/base/makeindx.dtx +++ b/Master/texmf-dist/source/latex/base/makeindx.dtx @@ -121,7 +121,7 @@ % \begin{macrocode} %\ProvidesPackage{makeidx} %\ProvidesPackage{showidx} - [2014/09/29 v1.0m Standard LaTeX package] + [2021/10/04 v1.0m Standard LaTeX package] % \end{macrocode} % % \subsection{Makeidx} @@ -261,7 +261,7 @@ % % \begin{macro}{\raggedbottom} % \begin{macro}{\flushbottom} -% The definition of these macros from \texttt{latex.dtx} is changed +% The definitions of these macros from the \LaTeX{} format are changed % here to add the execution of |\@mkidx| to |\@texttop|, which is % executed at the top of each page. % \begin{macrocode} diff --git a/Master/texmf-dist/source/latex/base/preload.dtx b/Master/texmf-dist/source/latex/base/preload.dtx index b2ca24bce5b..bf2bfebbfa9 100644 --- a/Master/texmf-dist/source/latex/base/preload.dtx +++ b/Master/texmf-dist/source/latex/base/preload.dtx @@ -45,7 +45,7 @@ %<+tex> \ProvidesFile{preload.ltx} % \fi % \ProvidesFile{preload.dtx} - [2014/09/29 v2.1g LaTeX Kernel (Font Preloading)] + [2021/10/04 v2.1g LaTeX Kernel (Font Preloading)] % % % @@ -179,7 +179,7 @@ % We begin by loading the math extension font (cmex10) % and the \LaTeX{} line and circle fonts. % It is necessary to do this explicitly since these are -% used by \texttt{lplain.tex} and \texttt{latex.tex}. +% used by the \LaTeX{} format. % Since the internal font name contains |/| characters % and digits we construct the name via |\csname|. % These are the only fonts (!) that must be loaded in this file. diff --git a/Master/texmf-dist/source/latex/base/slides.dtx b/Master/texmf-dist/source/latex/base/slides.dtx index 883e7d34f04..e63c1901d6d 100644 --- a/Master/texmf-dist/source/latex/base/slides.dtx +++ b/Master/texmf-dist/source/latex/base/slides.dtx @@ -53,7 +53,7 @@ %<*driver> \ProvidesFile{slides.drv} % - [2020/11/23 v2.4b + [2021/10/04 v2.4b %<+class> Standard LaTeX document class] %<+cmd> SLiTeX definitions] % \end{macrocode} @@ -1342,7 +1342,7 @@ % % \begin{environment}{description} % The description environment is defined here -- while the itemize -% and enumerate environments are defined in \file{latex.dtx}. +% and enumerate environments are defined in the \LaTeX{} format. % % \begin{macrocode} \newenvironment{description}{\list{}{\labelwidth\z@ @@ -1373,7 +1373,7 @@ % \begin{macro}{\theenumii} % \begin{macro}{\theenumiii} % \begin{macro}{\theenumiv} -% The counters are already defined in \file{latex.dtx}, but their +% The counters are already defined in the \LaTeX{} format, but their % representation is changed here. % % \begin{macrocode} @@ -2349,7 +2349,7 @@ COLOR LAYER\\[.75in]% % % \changes{v2.2j}{1994/03/11}{Corrected \cs{@oval}, like previous % \changes{v2.4a}{2016/03/29}{Initialize in \cs{@oval}tests added for -% latex/4452} change to \file{latex.dtx}.} +% latex/4452} change to the \LaTeX{} format.} % \begin{macrocode} \def\line(#1,#2)#3{\if@visible\@xarg #1\relax \@yarg #2\relax \@linelen #3\unitlength diff --git a/Master/texmf-dist/source/latex/base/tulm.fdd b/Master/texmf-dist/source/latex/base/tulm.fdd index 5c1566a5bad..243cbe30cc7 100644 --- a/Master/texmf-dist/source/latex/base/tulm.fdd +++ b/Master/texmf-dist/source/latex/base/tulm.fdd @@ -1,6 +1,6 @@ % \iffalse meta-comment % -% Copyright 2016-2019 +% Copyright 2016-2021 % The LaTeX Project and any individual authors listed elsewhere % in this file. % @@ -30,7 +30,7 @@ %\iffalse This is a META comment % % File `cmfonts.fdd'. -% Copyright (C) 2016-2019 LaTeX Project +% Copyright (C) 2016-2021 LaTeX Project % % %\ProvidesFile{tulmr.fd} @@ -42,7 +42,7 @@ %<*driver> \ProvidesFile{tulm.drv} % - [2017/01/26 v1.8 Standard LaTeX font definitions for Latin Modern] + [2021/07/23 v1.8a Standard LaTeX font definitions for Latin Modern] % %<*driver> \documentclass{ltxdoc} @@ -63,6 +63,7 @@ %\fi % % \section{TUlmr} +% \changes{v1.8a}{2021/07/23}{Use OpenType font for TU/lmr/m/ui} % \begin{macrocode} %<*TUlmr> \DeclareFontFamily{TU}{lmr}{} @@ -93,7 +94,7 @@ \DeclareFontShape{TU}{lmr}{m}{sc}% {<-> \UnicodeFontFile{lmromancaps10-regular}{\UnicodeFontTeXLigatures}}{} \DeclareFontShape{TU}{lmr}{m}{ui}% - {<-> ec-lmu10}{} + {<-> \UnicodeFontFile{lmromanunsl10-regular}{\UnicodeFontTeXLigatures}}{} \DeclareFontShape{TU}{lmr}{m}{scsl}% {<-> \UnicodeFontFile{lmromancaps10-oblique}{\UnicodeFontTeXLigatures}}{} \DeclareFontShape{TU}{lmr}{b}{n} diff --git a/Master/texmf-dist/source/latex/base/utf8ienc.dtx b/Master/texmf-dist/source/latex/base/utf8ienc.dtx index 79c725915c7..75990d1b036 100644 --- a/Master/texmf-dist/source/latex/base/utf8ienc.dtx +++ b/Master/texmf-dist/source/latex/base/utf8ienc.dtx @@ -216,7 +216,7 @@ %<+ts1> \ProvidesFile{ts1enc.dfu} %<+x2> \ProvidesFile{x2enc.dfu} %<+all> \ProvidesFile{utf8enc.dfu} -%<-utf8-2018> [2021/01/27 v1.2l UTF-8 support for inputenc] +%<-utf8-2018> [2021/06/21 v1.2n UTF-8 support] % \end{macrocode} % % \begin{macrocode} @@ -443,14 +443,16 @@ % \changes{v1.1g}{2005/09/27}{Real spaces do not show up so use \cs{space}} % \changes{v1.1o}{2015/08/28}{Show Unicode number of character in hex} % \changes{v1.2a}{2018/03/24}{Error message improved for non-UTF-8 sequences}% +% \changes{v1.2m}{2021/06/08}{Normalize various error messages as kernel errors} % \begin{macrocode} \UTFviii@undefined@err{#1}% % \end{macrocode} % % \begin{macrocode} \else - \PackageError{inputenc}{Invalid UTF-8 byte sequence}% - \UTFviii@invalid@help + \@latex@error{Invalid UTF-8 byte sequence (\expandafter + \@gobblefour\string#1)}% + \UTFviii@invalid@help \fi % \end{macrocode} % @@ -468,8 +470,8 @@ % \changes{v1.2f}{2018/10/05}{Show invalid byte in hex}% % \begin{macrocode} \def\UTFviii@invalid@err#1{% - \PackageError{inputenc}{Invalid UTF-8 byte "\UTFviii@hexnumber{`#1}}% - \UTFviii@invalid@help} + \@latex@error{Invalid UTF-8 byte "\UTFviii@hexnumber{`#1}}% + \UTFviii@invalid@help} % \end{macrocode} % % \begin{macrocode} @@ -487,7 +489,7 @@ % \changes{v1.2a}{2018/03/24}{Macro added}% % \begin{macrocode} \def\UTFviii@undefined@err#1{% - \PackageError{inputenc}{Unicode character \expandafter + \@latex@error{Unicode character \expandafter \UTFviii@splitcsname\string#1\relax \MessageBreak not set up for use with LaTeX}% @@ -776,8 +778,7 @@ \ifnum\catcode\count@=13 \uccode`\~=\count@\uppercase{\def\UTFviii@tmp{\@empty\@empty~}}% \else - \PackageError{inputenc}% - {Cannot define non-active Unicode char value < 00A0}% + \@latex@error{Cannot define non-active Unicode char value < 00A0}% \@eha \def\UTFviii@tmp{\UTFviii@tmp}% \fi @@ -803,7 +804,7 @@ % past this error. % \begin{macrocode} \ifnum\count@>"10FFFF\relax - \PackageError{inputenc}% + \@latex@error {\UTFviii@hexnumber\count@\space too large for Unicode}% {Values between 0 and 10FFFF are permitted}% \fi @@ -1703,17 +1704,31 @@ %\DeclareUnicodeCharacter{1E03}{\.b} % \end{macrocode} % \changes{v1.2k}{2021/01/27}{Added various additional dot accents (gh/484)} +% \changes{v1.2n}{2021/06/21}{more extended latin entries for gh/593} % \begin{macrocode} %\DeclareUnicodeCharacter{1E0D}{\d d} +%\DeclareUnicodeCharacter{1E1E}{\.F} +%\DeclareUnicodeCharacter{1E1F}{\.f} %\DeclareUnicodeCharacter{1E25}{\d h} +%\DeclareUnicodeCharacter{1E30}{\@tabacckludge'K} +%\DeclareUnicodeCharacter{1E31}{\@tabacckludge'k} %\DeclareUnicodeCharacter{1E37}{\d l} +%\DeclareUnicodeCharacter{1E8E}{\.Y} +%\DeclareUnicodeCharacter{1E8F}{\.y} %\DeclareUnicodeCharacter{1E43}{\d m} %\DeclareUnicodeCharacter{1E45}{\.n} %\DeclareUnicodeCharacter{1E47}{\d n} %\DeclareUnicodeCharacter{1E5B}{\d r} %\DeclareUnicodeCharacter{1E63}{\d s} %\DeclareUnicodeCharacter{1E6D}{\d t} +%\DeclareUnicodeCharacter{1E90}{\^Z} +%\DeclareUnicodeCharacter{1E91}{\^z} %\DeclareUnicodeCharacter{1E9E}{\SS} +%\DeclareUnicodeCharacter{1EF2}{\@tabacckludge`Y} +%\DeclareUnicodeCharacter{1EF3}{\@tabacckludge`y} +% \end{macrocode} +% +% \begin{macrocode} %\DeclareUnicodeCharacter{200C}{\textcompwordmark} % \end{macrocode} % \changes{v1.1s}{2016/02/28}{Add more hyphens and dashes} @@ -2083,8 +2098,7 @@ \ifnum\catcode\count@=13 \uccode`\~=\count@\uppercase{\def\UTFviii@tmp{\@empty\@empty~}}% \else - \PackageError{inputenc}% - {Cannot define non-active Unicode char value < 00A0}% + \PackageError{inputenc}{Cannot define non-active Unicode char value < 00A0}% \@eha \def\UTFviii@tmp{\UTFviii@tmp}% \fi -- cgit v1.2.3