From e024a58f1f127a9723f5e381efcedead06cb0373 Mon Sep 17 00:00:00 2001 From: Karl Berry Date: Mon, 20 Sep 2021 20:07:55 +0000 Subject: latex-dev (20sep21) git-svn-id: svn://tug.org/texlive/trunk@60566 c570f23f-e606-0410-a88d-b1316a301751 --- .../texmf-dist/source/latex-dev/base/classes.dtx | 8 +- .../texmf-dist/source/latex-dev/base/ltclass.dtx | 153 +- Master/texmf-dist/source/latex-dev/base/ltcmd.dtx | 805 ++++++++- .../source/latex-dev/base/ltcmdhooks.dtx | 87 +- .../texmf-dist/source/latex-dev/base/ltcounts.dtx | 132 +- .../texmf-dist/source/latex-dev/base/lterror.dtx | 67 +- Master/texmf-dist/source/latex-dev/base/ltexpl.dtx | 2 +- .../source/latex-dev/base/ltfilehook.dtx | 164 +- .../texmf-dist/source/latex-dev/base/ltfiles.dtx | 20 +- .../texmf-dist/source/latex-dev/base/ltfinal.dtx | 40 +- .../texmf-dist/source/latex-dev/base/ltfntcmd.dtx | 5 +- .../texmf-dist/source/latex-dev/base/ltfssini.dtx | 383 +++- .../texmf-dist/source/latex-dev/base/ltfsstrc.dtx | 2 +- .../texmf-dist/source/latex-dev/base/lthooks.dtx | 1899 ++++++++++++-------- .../texmf-dist/source/latex-dev/base/ltluatex.dtx | 4 +- .../texmf-dist/source/latex-dev/base/ltoutenc.dtx | 10 +- .../texmf-dist/source/latex-dev/base/ltoutput.dtx | 78 +- Master/texmf-dist/source/latex-dev/base/ltpara.dtx | 65 +- .../texmf-dist/source/latex-dev/base/ltplain.dtx | 20 +- Master/texmf-dist/source/latex-dev/base/ltsect.dtx | 42 +- .../texmf-dist/source/latex-dev/base/ltshipout.dtx | 2 +- Master/texmf-dist/source/latex-dev/base/ltvers.dtx | 14 +- Master/texmf-dist/source/latex-dev/base/tulm.fdd | 9 +- .../texmf-dist/source/latex-dev/base/utf8ienc.dtx | 16 +- 24 files changed, 2948 insertions(+), 1079 deletions(-) (limited to 'Master/texmf-dist/source/latex-dev/base') diff --git a/Master/texmf-dist/source/latex-dev/base/classes.dtx b/Master/texmf-dist/source/latex-dev/base/classes.dtx index ffe04c620fa..fdf0ef3a5b0 100644 --- a/Master/texmf-dist/source/latex-dev/base/classes.dtx +++ b/Master/texmf-dist/source/latex-dev/base/classes.dtx @@ -53,7 +53,7 @@ %<*driver> \ProvidesFile{classes.drv} % - [2021/02/12 v1.4n + [2021/09/11 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} diff --git a/Master/texmf-dist/source/latex-dev/base/ltclass.dtx b/Master/texmf-dist/source/latex-dev/base/ltclass.dtx index 643587b0ef5..06e0f437af1 100644 --- a/Master/texmf-dist/source/latex-dev/base/ltclass.dtx +++ b/Master/texmf-dist/source/latex-dev/base/ltclass.dtx @@ -33,7 +33,7 @@ %<*driver> % \fi \ProvidesFile{ltclass.dtx} - [2021/06/09 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}% diff --git a/Master/texmf-dist/source/latex-dev/base/ltcmd.dtx b/Master/texmf-dist/source/latex-dev/base/ltcmd.dtx index 6f2153c6ea0..04be2abfbfd 100644 --- a/Master/texmf-dist/source/latex-dev/base/ltcmd.dtx +++ b/Master/texmf-dist/source/latex-dev/base/ltcmd.dtx @@ -34,8 +34,8 @@ %%% From File: ltcmd.dtx % % \begin{macrocode} -\def\ltcmdversion{v1.0f} -\def\ltcmddate{2021-06-04} +\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} @@ -400,7 +399,6 @@ #4 \@@_break_point:n {#2} } -\cs_generate_variant:Nn \@@_declare_cmd_internal:Nnnn { cnx } % \end{macrocode} % \end{macro} % \end{macro} @@ -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} @@ -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} @@ -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 @@ -3541,6 +4274,13 @@ with~an~environment~that~already~has~a~definition. \\ \\ The~existing~definition~of~'#1'~will~not~be~altered. } +\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. } { @@ -3829,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} @@ -3838,7 +4579,11 @@ { \cs_if_exist:cTF {#1} { \msg_error:nnx { cmd } { env-already-defined } {#1} } - { \@@_declare_env:nnnn {#1} {#2} {#3} {#4} } + { + \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 { diff --git a/Master/texmf-dist/source/latex-dev/base/ltcmdhooks.dtx b/Master/texmf-dist/source/latex-dev/base/ltcmdhooks.dtx index 40cd55e52c7..b6c57a41acc 100644 --- a/Master/texmf-dist/source/latex-dev/base/ltcmdhooks.dtx +++ b/Master/texmf-dist/source/latex-dev/base/ltcmdhooks.dtx @@ -13,8 +13,8 @@ % %%% From File: ltcmdhooks.dtx % -\def\ltcmdhooksversion{v1.0b} -\def\ltcmdhooksdate{2021/05/26} +\def\ltcmdhooksversion{v1.0d} +\def\ltcmdhooksdate{2021/08/25} % % % @@ -400,24 +400,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 +612,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} @@ -1039,15 +1070,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-dev/base/ltcounts.dtx b/Master/texmf-dist/source/latex-dev/base/ltcounts.dtx index 445cac2f2e4..39fb47728d3 100644 --- a/Master/texmf-dist/source/latex-dev/base/ltcounts.dtx +++ b/Master/texmf-dist/source/latex-dev/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-dev/base/lterror.dtx b/Master/texmf-dist/source/latex-dev/base/lterror.dtx index 43eef7b2890..10d93a1dbd1 100644 --- a/Master/texmf-dist/source/latex-dev/base/lterror.dtx +++ b/Master/texmf-dist/source/latex-dev/base/lterror.dtx @@ -32,7 +32,7 @@ %<*driver> % \fi \ProvidesFile{lterror.dtx} - [2021/06/09 v1.2r 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} @@ -635,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-dev/base/ltexpl.dtx b/Master/texmf-dist/source/latex-dev/base/ltexpl.dtx index 6d7ec3ff60b..021edc644c3 100644 --- a/Master/texmf-dist/source/latex-dev/base/ltexpl.dtx +++ b/Master/texmf-dist/source/latex-dev/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-dev/base/ltfilehook.dtx b/Master/texmf-dist/source/latex-dev/base/ltfilehook.dtx index 5d0acc8fdfb..000f4d8c2a2 100644 --- a/Master/texmf-dist/source/latex-dev/base/ltfilehook.dtx +++ b/Master/texmf-dist/source/latex-dev/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-dev/base/ltfiles.dtx b/Master/texmf-dist/source/latex-dev/base/ltfiles.dtx index bcaac582208..4dee83c4d6e 100644 --- a/Master/texmf-dist/source/latex-dev/base/ltfiles.dtx +++ b/Master/texmf-dist/source/latex-dev/base/ltfiles.dtx @@ -32,7 +32,7 @@ %<*driver> % \fi \ProvidesFile{ltfiles.dtx} - [2021/04/17 v1.2m LaTeX Kernel (File Handling)] + [2021/08/25 v1.2o LaTeX Kernel (File Handling)] % \iffalse \documentclass{ltxdoc} \GetFileInfo{ltfiles.dtx} @@ -850,16 +850,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 +872,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 %----------------------------------------- @@ -889,6 +893,14 @@ \@nameuse{cp@#1}% \fi \let\@auxout\@mainaux} +% \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-dev/base/ltfinal.dtx b/Master/texmf-dist/source/latex-dev/base/ltfinal.dtx index 19f82934aa6..5d77fb2e834 100644 --- a/Master/texmf-dist/source/latex-dev/base/ltfinal.dtx +++ b/Master/texmf-dist/source/latex-dev/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,38 @@ % \end{macro} % \end{macro} % +% \subsection{Prepare for supporting PDF management in backends} +% +% At the current point in time support for PDF management in +% backends is not part of \LaTeX{} core but 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. +% +% There is a command \cs{IfPDFManagementActiveTF} in that code +% which checks if the PDF management code is activated, which can +% be used by packages to execute different code branches depending +% on the state. +% +% To make this also work properly if the external package is not +% loaded at all this command is already made available in the +% kernel (with a trivial definition) so that other packages can +% query the state in all circumstances. Once the PDF management +% support moves to the kernel this definition here will vanish +% again or rather will be replaced by a real test. +% +% +% \begin{macro}{\IfPDFManagementActiveTF} +% While the PDF management code is not loaded, the test will +% always return the false branch. Once this code is loaded, it +% is replaced by a real test (as then it is possible that the +% management code is activate 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 +1287,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-dev/base/ltfntcmd.dtx b/Master/texmf-dist/source/latex-dev/base/ltfntcmd.dtx index 5f70053a688..6c4ec4b3d16 100644 --- a/Master/texmf-dist/source/latex-dev/base/ltfntcmd.dtx +++ b/Master/texmf-dist/source/latex-dev/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-dev/base/ltfssini.dtx b/Master/texmf-dist/source/latex-dev/base/ltfssini.dtx index b06fc161b08..f817fdd8473 100644 --- a/Master/texmf-dist/source/latex-dev/base/ltfssini.dtx +++ b/Master/texmf-dist/source/latex-dev/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-dev/base/ltfsstrc.dtx b/Master/texmf-dist/source/latex-dev/base/ltfsstrc.dtx index c6aec105ba5..f562a4fa907 100644 --- a/Master/texmf-dist/source/latex-dev/base/ltfsstrc.dtx +++ b/Master/texmf-dist/source/latex-dev/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-dev/base/lthooks.dtx b/Master/texmf-dist/source/latex-dev/base/lthooks.dtx index 20e172a57f2..3969a2be567 100644 --- a/Master/texmf-dist/source/latex-dev/base/lthooks.dtx +++ b/Master/texmf-dist/source/latex-dev/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.0r} +\def\lthooksdate{2021/09/06} % \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,19 @@ % the current package name. See section~\ref{sec:default-label}. % \end{function} % -% \begin{function}{\hook_provide:n} +% \begin{function}{\hook_activate_generic:n} % \begin{syntax} -% \cs{hook_provide:n} \Arg{hook} +% \cs{hook_activate_generic: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 +% needs to be altered and it 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{syntax} -% \cs{hook_provide_reversed:n} \Arg{hook} -% \end{syntax} -% Like \cs{hook_new_reversed:n} but does nothing if the hook was -% previously declared as a reversed hook. -% \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 +1032,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 +1048,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 +1165,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 +1324,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 +1342,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 +1445,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 +1454,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 +1465,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 +1521,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 +1630,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 +1647,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 +1700,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 +1759,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 +1867,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 +1876,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 +1928,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 +2023,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 +2056,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 +2073,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 +2113,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 +2212,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 +2265,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 +2308,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 +2344,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 +2354,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 +2397,8 @@ % \end{macrocode} % \end{macro} % -% -% +% +% % \begin{macro}{\@@_make_usable:n} % % This initializes all hook data structures for the hook but if @@ -2315,7 +2472,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 +2564,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 +2582,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 +2606,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 +2616,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 +2664,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 +2733,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 +2743,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 +2755,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 +2779,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 +2822,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 +2976,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. +% Then check if the hook is usable. % \begin{macrocode} - \@@_if_marked_removal:nnTF {#1} {#2} - { \@@_unmark_removal:nn {#1} {#2} } - { -% \end{macrocode} -% If no removal is queued, we are free to add. Start by checking if -% the hook exists. -% \begin{macrocode} - \@@_if_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 +3092,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} % @@ -2867,43 +3139,39 @@ % the function returns \meta{true} for a generic hook and \meta{false} % in other cases. % \begin{macrocode} -\cs_new_protected:Npn \@@_try_declaring_generic_hook:nNNnn #1 - { - \@@_if_file_hook:wTF #1 / / \s_@@_mark - { - \exp_args:Ne \@@_try_declaring_generic_hook_split:nNNnn - { \exp_args:Ne \@@_file_hook_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 {#1} +% { +% \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 +3181,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,27 +3191,126 @@ % 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} -% -%\prg_new_protected_conditional:Npnn \@@_try_declaring_generic_hook:wn + \@@_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 } % { % \tl_if_empty:nTF {#2} @@ -2968,77 +3335,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 +3445,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 +3535,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 +3552,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 +3622,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 +3765,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 +3806,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 +3858,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 +3869,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 +3884,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 +3973,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 +3993,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 +4009,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 +4035,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 +4056,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 +4073,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 +4097,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 +4115,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 +4272,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 +4283,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 +4345,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 +4391,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 +4608,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 +4647,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 +4682,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 +4764,121 @@ % \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} % % \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 {#1} +% { +% \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 +4966,8 @@ } % \end{macrocode} % \end{macro} -% -% -% +% +% % \begin{macro}[pTF]{\@@_if_declared:n} % % Internal test to check if the hook was officially declared with @@ -4526,28 +4987,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 +5069,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 +5077,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 +5110,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 +5122,7 @@ 'unrelated'. } % \end{macrocode} -% +% % \begin{macrocode} \msg_new:nnnn { hooks } { misused-top-level } { @@ -4651,7 +5160,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 +5170,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 +5212,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 +5251,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 +5276,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 +5288,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 +5316,6 @@ % \end{macro} % \end{macro} % \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} % % % @@ -4961,7 +5339,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 +5349,7 @@ % % % \begin{macro}{\DeclareHookRule} -% +% % \begin{macrocode} \NewDocumentCommand \DeclareHookRule { m m m m } { \hook_gset_rule:nnnn {#1}{#2}{#3}{#4} } @@ -5001,7 +5379,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 +5403,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 +5551,7 @@ %\def \NewReversedHook#1{} %\def \NewMirroredHookPair#1#2{} % -%\def \DisableHook #1{} +%\def \DisableGenericHook #1{} % %\long\def\AddToHookNext#1#2{} % @@ -5105,6 +5588,6 @@ % \Finale % % -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \endinput -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% diff --git a/Master/texmf-dist/source/latex-dev/base/ltluatex.dtx b/Master/texmf-dist/source/latex-dev/base/ltluatex.dtx index 3b9a3377312..2508f5a7cc2 100644 --- a/Master/texmf-dist/source/latex-dev/base/ltluatex.dtx +++ b/Master/texmf-dist/source/latex-dev/base/ltluatex.dtx @@ -28,7 +28,7 @@ \ProvidesFile{ltluatex.dtx} % %<*tex> -[2021/04/18 v1.1t +[2021/08/11 v1.1u % % 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} diff --git a/Master/texmf-dist/source/latex-dev/base/ltoutenc.dtx b/Master/texmf-dist/source/latex-dev/base/ltoutenc.dtx index eb2ecd1e537..14518d2fb24 100644 --- a/Master/texmf-dist/source/latex-dev/base/ltoutenc.dtx +++ b/Master/texmf-dist/source/latex-dev/base/ltoutenc.dtx @@ -44,7 +44,7 @@ %<*driver> % \fi \ProvidesFile{ltoutenc.dtx} - [2021/04/29 v2.0v LaTeX Kernel (font encodings)] + [2021/09/12 v2.0w LaTeX Kernel (font encodings)] % \iffalse \documentclass{ltxdoc} \GetFileInfo{ltoutenc.dtx} @@ -1783,12 +1783,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-dev/base/ltoutput.dtx b/Master/texmf-dist/source/latex-dev/base/ltoutput.dtx index b1b3a240965..78b0f2335f8 100644 --- a/Master/texmf-dist/source/latex-dev/base/ltoutput.dtx +++ b/Master/texmf-dist/source/latex-dev/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-dev/base/ltpara.dtx b/Master/texmf-dist/source/latex-dev/base/ltpara.dtx index 5ab52a5e9bc..bc51e4688ff 100644 --- a/Master/texmf-dist/source/latex-dev/base/ltpara.dtx +++ b/Master/texmf-dist/source/latex-dev/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.0j} +\def\ltparadate{2021/09/18} % \end{macrocode} %<*driver> \documentclass{l3doc} @@ -468,7 +468,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}. @@ -972,6 +972,30 @@ % 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 isn't 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 because it is +% the instered \cs{lst@vskip} that is causing it. That 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 thatany scanning is stopped before it: +% \begin{macrocode} + \scan_stop: +% \end{macrocode} +% % \begin{macrocode} \mode_if_horizontal:TF { \mode_if_inner:F { @@ -1008,12 +1032,13 @@ \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 +% \cs{tex_par:D} is called) is to add a glue 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. +% We use glue (rather than a kern) as that will be removed by the primitive +% par. % % There is however one other \TeX{} optimization that hurts: in a % sequence like this \verb=$$ ... $$ \par= \TeX{} will be in @@ -1023,17 +1048,19 @@ % 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}. % -% 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 @@ -1054,7 +1081,7 @@ % Finally close out the nested conditionals. % \begin{macrocode} } - } + } % \end{macrocode} % % \begin{macrocode} @@ -1090,7 +1117,7 @@ \@@_handle_indent: \the\everypar } } - { \msg_error:nn { kernel }{ raw-para } } + { \msg_error:nn { latex2e }{ raw-para } } \tex_indent:D } % \end{macrocode} @@ -1103,7 +1130,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} @@ -1161,7 +1188,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 +1202,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 +1234,7 @@ %\cs_set_eq:NN \par \tex_par:D %\cs_set_eq:NN \@@par \tex_par:D %\cs_set_eq:NN \endgraf \tex_par:D -% +% %\EndModuleRelease \ExplSyntaxOff % @@ -1220,4 +1248,3 @@ \endinput %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % - diff --git a/Master/texmf-dist/source/latex-dev/base/ltplain.dtx b/Master/texmf-dist/source/latex-dev/base/ltplain.dtx index e0fbcecf1b6..5fa70396794 100644 --- a/Master/texmf-dist/source/latex-dev/base/ltplain.dtx +++ b/Master/texmf-dist/source/latex-dev/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-dev/base/ltsect.dtx b/Master/texmf-dist/source/latex-dev/base/ltsect.dtx index 29ea142ba6c..67974c73874 100644 --- a/Master/texmf-dist/source/latex-dev/base/ltsect.dtx +++ b/Master/texmf-dist/source/latex-dev/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-dev/base/ltshipout.dtx b/Master/texmf-dist/source/latex-dev/base/ltshipout.dtx index 6e687ee4449..7f6555d18cf 100644 --- a/Master/texmf-dist/source/latex-dev/base/ltshipout.dtx +++ b/Master/texmf-dist/source/latex-dev/base/ltshipout.dtx @@ -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! % diff --git a/Master/texmf-dist/source/latex-dev/base/ltvers.dtx b/Master/texmf-dist/source/latex-dev/base/ltvers.dtx index 9ccd2bd02ef..3f2f119cb1b 100644 --- a/Master/texmf-dist/source/latex-dev/base/ltvers.dtx +++ b/Master/texmf-dist/source/latex-dev/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} @@ -115,7 +115,7 @@ {2021-11-15} % %<*2ekernel> -\def\patch@level{-1} +\def\patch@level{-2} % \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-dev/base/tulm.fdd b/Master/texmf-dist/source/latex-dev/base/tulm.fdd index 5c1566a5bad..243cbe30cc7 100644 --- a/Master/texmf-dist/source/latex-dev/base/tulm.fdd +++ b/Master/texmf-dist/source/latex-dev/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-dev/base/utf8ienc.dtx b/Master/texmf-dist/source/latex-dev/base/utf8ienc.dtx index a517459441d..75990d1b036 100644 --- a/Master/texmf-dist/source/latex-dev/base/utf8ienc.dtx +++ b/Master/texmf-dist/source/latex-dev/base/utf8ienc.dtx @@ -216,7 +216,7 @@ %<+ts1> \ProvidesFile{ts1enc.dfu} %<+x2> \ProvidesFile{x2enc.dfu} %<+all> \ProvidesFile{utf8enc.dfu} -%<-utf8-2018> [2021/06/08 v1.2m UTF-8 support] +%<-utf8-2018> [2021/06/21 v1.2n UTF-8 support] % \end{macrocode} % % \begin{macrocode} @@ -1704,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} -- cgit v1.2.3