summaryrefslogtreecommitdiff
path: root/macros/latex/base
diff options
context:
space:
mode:
Diffstat (limited to 'macros/latex/base')
-rw-r--r--macros/latex/base/README.md2
-rw-r--r--macros/latex/base/alltt.dtx4
-rw-r--r--macros/latex/base/alltt.pdfbin223831 -> 223861 bytes
-rw-r--r--macros/latex/base/cfgguide.pdfbin264168 -> 264168 bytes
-rw-r--r--macros/latex/base/changes.txt239
-rw-r--r--macros/latex/base/classes.dtx12
-rw-r--r--macros/latex/base/classes.pdfbin560998 -> 560294 bytes
-rw-r--r--macros/latex/base/clsguide-historic.pdfbin415615 -> 415956 bytes
-rw-r--r--macros/latex/base/clsguide-historic.tex10
-rw-r--r--macros/latex/base/clsguide.pdfbin489925 -> 490149 bytes
-rw-r--r--macros/latex/base/clsguide.tex42
-rw-r--r--macros/latex/base/cmfonts.pdfbin292600 -> 292600 bytes
-rw-r--r--macros/latex/base/cyrguide.pdfbin257359 -> 257359 bytes
-rw-r--r--macros/latex/base/doc-code.pdfbin1075672 -> 1078869 bytes
-rw-r--r--macros/latex/base/doc.dtx227
-rw-r--r--macros/latex/base/doc.pdfbin756052 -> 757812 bytes
-rw-r--r--macros/latex/base/docstrip.dtx14
-rw-r--r--macros/latex/base/docstrip.pdfbin506163 -> 506366 bytes
-rw-r--r--macros/latex/base/encguide.pdfbin1312106 -> 1318576 bytes
-rw-r--r--macros/latex/base/exscale.pdfbin204708 -> 204708 bytes
-rw-r--r--macros/latex/base/fix-cm.pdfbin287727 -> 287727 bytes
-rw-r--r--macros/latex/base/fntguide.pdfbin517708 -> 522678 bytes
-rw-r--r--macros/latex/base/fntguide.tex81
-rw-r--r--macros/latex/base/fontdef.dtx30
-rw-r--r--macros/latex/base/format.ins6
-rw-r--r--macros/latex/base/graphpap.pdfbin161722 -> 161722 bytes
-rw-r--r--macros/latex/base/ifthen.dtx29
-rw-r--r--macros/latex/base/ifthen.pdfbin221219 -> 222460 bytes
-rw-r--r--macros/latex/base/inputenc.dtx6
-rw-r--r--macros/latex/base/inputenc.pdfbin318199 -> 318372 bytes
-rw-r--r--macros/latex/base/lamport-manual.pdfbin170876 -> 170876 bytes
-rw-r--r--macros/latex/base/latexrelease.ins1
-rw-r--r--macros/latex/base/latexrelease.pdfbin282095 -> 282095 bytes
-rw-r--r--macros/latex/base/latexsym.pdfbin200759 -> 200759 bytes
-rw-r--r--macros/latex/base/lb2.err11
-rw-r--r--macros/latex/base/lb2.pdfbin252497 -> 252519 bytes
-rw-r--r--macros/latex/base/letter.pdfbin337934 -> 337678 bytes
-rw-r--r--macros/latex/base/lgc2.pdfbin217659 -> 217663 bytes
-rw-r--r--macros/latex/base/lppl.pdfbin132370 -> 132370 bytes
-rw-r--r--macros/latex/base/ltboxes.dtx42
-rw-r--r--macros/latex/base/ltclass.dtx160
-rw-r--r--macros/latex/base/ltcmd.dtx241
-rw-r--r--macros/latex/base/ltcmdhooks-code.pdfbin755274 -> 753489 bytes
-rw-r--r--macros/latex/base/ltcmdhooks-doc.pdfbin498750 -> 498508 bytes
-rw-r--r--macros/latex/base/ltcmdhooks.dtx46
-rw-r--r--macros/latex/base/ltcounts.dtx19
-rw-r--r--macros/latex/base/ltdefns.dtx35
-rw-r--r--macros/latex/base/ltdirchk.dtx31
-rw-r--r--macros/latex/base/ltexpl.dtx16
-rw-r--r--macros/latex/base/ltfilehook-code.pdfbin803860 -> 806632 bytes
-rw-r--r--macros/latex/base/ltfilehook-doc.pdfbin548528 -> 551976 bytes
-rw-r--r--macros/latex/base/ltfilehook.dtx34
-rw-r--r--macros/latex/base/ltfiles.dtx57
-rw-r--r--macros/latex/base/ltfinal.dtx6
-rw-r--r--macros/latex/base/ltfloat.dtx6
-rw-r--r--macros/latex/base/ltfntcmd.dtx8
-rw-r--r--macros/latex/base/ltfssaxes.dtx10
-rw-r--r--macros/latex/base/ltfssbas.dtx4
-rw-r--r--macros/latex/base/ltfssini.dtx10
-rw-r--r--macros/latex/base/ltfsstrc.dtx23
-rw-r--r--macros/latex/base/lthooks-code.pdfbin1258252 -> 1248534 bytes
-rw-r--r--macros/latex/base/lthooks-doc.pdfbin754740 -> 758204 bytes
-rw-r--r--macros/latex/base/lthooks.dtx405
-rw-r--r--macros/latex/base/ltkeys.dtx2
-rw-r--r--macros/latex/base/ltluatex.dtx26
-rw-r--r--macros/latex/base/ltluatex.pdfbin325191 -> 325142 bytes
-rw-r--r--macros/latex/base/ltmarks-code.pdfbin716422 -> 717841 bytes
-rw-r--r--macros/latex/base/ltmarks-doc.pdfbin586554 -> 575822 bytes
-rw-r--r--macros/latex/base/ltmarks.dtx811
-rw-r--r--macros/latex/base/ltmeta.dtx20
-rw-r--r--macros/latex/base/ltmiscen.dtx12
-rw-r--r--macros/latex/base/ltnews.pdfbin1360066 -> 1404362 bytes
-rw-r--r--macros/latex/base/ltnews.tex2
-rw-r--r--macros/latex/base/ltnews01.pdfbin169553 -> 169553 bytes
-rw-r--r--macros/latex/base/ltnews02.pdfbin151773 -> 151773 bytes
-rw-r--r--macros/latex/base/ltnews03.pdfbin151324 -> 151324 bytes
-rw-r--r--macros/latex/base/ltnews04.pdfbin152551 -> 152551 bytes
-rw-r--r--macros/latex/base/ltnews05.pdfbin175211 -> 175211 bytes
-rw-r--r--macros/latex/base/ltnews06.pdfbin142867 -> 142867 bytes
-rw-r--r--macros/latex/base/ltnews07.pdfbin138214 -> 138214 bytes
-rw-r--r--macros/latex/base/ltnews08.pdfbin155442 -> 155442 bytes
-rw-r--r--macros/latex/base/ltnews09.pdfbin130028 -> 130028 bytes
-rw-r--r--macros/latex/base/ltnews10.pdfbin169433 -> 169433 bytes
-rw-r--r--macros/latex/base/ltnews11.pdfbin112208 -> 112208 bytes
-rw-r--r--macros/latex/base/ltnews12.pdfbin156764 -> 156764 bytes
-rw-r--r--macros/latex/base/ltnews13.pdfbin182483 -> 182483 bytes
-rw-r--r--macros/latex/base/ltnews14.pdfbin170722 -> 170722 bytes
-rw-r--r--macros/latex/base/ltnews15.pdfbin130328 -> 130328 bytes
-rw-r--r--macros/latex/base/ltnews16.pdfbin138107 -> 138107 bytes
-rw-r--r--macros/latex/base/ltnews17.pdfbin166269 -> 166269 bytes
-rw-r--r--macros/latex/base/ltnews18.pdfbin39839 -> 39839 bytes
-rw-r--r--macros/latex/base/ltnews19.pdfbin225936 -> 225936 bytes
-rw-r--r--macros/latex/base/ltnews20.pdfbin318193 -> 318193 bytes
-rw-r--r--macros/latex/base/ltnews21.pdfbin245228 -> 245228 bytes
-rw-r--r--macros/latex/base/ltnews22.pdfbin318026 -> 318026 bytes
-rw-r--r--macros/latex/base/ltnews23.pdfbin286824 -> 286824 bytes
-rw-r--r--macros/latex/base/ltnews24.pdfbin265497 -> 265497 bytes
-rw-r--r--macros/latex/base/ltnews25.pdfbin205100 -> 205100 bytes
-rw-r--r--macros/latex/base/ltnews26.pdfbin379733 -> 379733 bytes
-rw-r--r--macros/latex/base/ltnews27.pdfbin251283 -> 251283 bytes
-rw-r--r--macros/latex/base/ltnews28.pdfbin376933 -> 376950 bytes
-rw-r--r--macros/latex/base/ltnews28.tex4
-rw-r--r--macros/latex/base/ltnews29.pdfbin455437 -> 455437 bytes
-rw-r--r--macros/latex/base/ltnews30.pdfbin512240 -> 512240 bytes
-rw-r--r--macros/latex/base/ltnews31.pdfbin526688 -> 526681 bytes
-rw-r--r--macros/latex/base/ltnews31.tex4
-rw-r--r--macros/latex/base/ltnews32.pdfbin546540 -> 546540 bytes
-rw-r--r--macros/latex/base/ltnews33.pdfbin522757 -> 522757 bytes
-rw-r--r--macros/latex/base/ltnews34.pdfbin508345 -> 508345 bytes
-rw-r--r--macros/latex/base/ltnews35.pdfbin563307 -> 563305 bytes
-rw-r--r--macros/latex/base/ltnews35.tex2
-rw-r--r--macros/latex/base/ltnews36.pdfbin517934 -> 517934 bytes
-rw-r--r--macros/latex/base/ltnews37.pdfbin456933 -> 456933 bytes
-rw-r--r--macros/latex/base/ltnews38.pdfbin523672 -> 523675 bytes
-rw-r--r--macros/latex/base/ltnews38.tex2
-rw-r--r--macros/latex/base/ltnews39.pdfbin0 -> 540170 bytes
-rw-r--r--macros/latex/base/ltnews39.tex893
-rw-r--r--macros/latex/base/ltoutenc.dtx25
-rw-r--r--macros/latex/base/ltoutput.dtx4
-rw-r--r--macros/latex/base/ltpara-code.pdfbin672266 -> 672571 bytes
-rw-r--r--macros/latex/base/ltpara-doc.pdfbin560158 -> 560476 bytes
-rw-r--r--macros/latex/base/ltpara.dtx29
-rw-r--r--macros/latex/base/ltplain.dtx20
-rw-r--r--macros/latex/base/ltproperties-code.pdfbin558691 -> 557307 bytes
-rw-r--r--macros/latex/base/ltproperties-doc.pdfbin433172 -> 431822 bytes
-rw-r--r--macros/latex/base/ltproperties.dtx75
-rw-r--r--macros/latex/base/ltsect.dtx10
-rw-r--r--macros/latex/base/ltshipout-code.pdfbin821688 -> 821491 bytes
-rw-r--r--macros/latex/base/ltshipout-doc.pdfbin566586 -> 567649 bytes
-rw-r--r--macros/latex/base/ltshipout.dtx32
-rw-r--r--macros/latex/base/ltsockets-code.pdfbin606104 -> 598832 bytes
-rw-r--r--macros/latex/base/ltsockets-doc.pdfbin488968 -> 481683 bytes
-rw-r--r--macros/latex/base/ltsockets.dtx36
-rw-r--r--macros/latex/base/ltspace.dtx12
-rw-r--r--macros/latex/base/lttagging.dtx775
-rw-r--r--macros/latex/base/lttemplates.dtx2634
-rw-r--r--macros/latex/base/lttextcomp.dtx688
-rw-r--r--macros/latex/base/ltthm.dtx38
-rw-r--r--macros/latex/base/ltvers.dtx4
-rw-r--r--macros/latex/base/ltx3info.pdfbin219358 -> 219358 bytes
-rw-r--r--macros/latex/base/ltxdoc.dtx9
-rw-r--r--macros/latex/base/ltxdoc.pdfbin244215 -> 244141 bytes
-rw-r--r--macros/latex/base/makeindx.pdfbin165816 -> 165816 bytes
-rw-r--r--macros/latex/base/modguide.pdfbin257825 -> 257825 bytes
-rw-r--r--macros/latex/base/nfssfont.dtx6
-rw-r--r--macros/latex/base/nfssfont.pdfbin211171 -> 211314 bytes
-rw-r--r--macros/latex/base/proc.pdfbin227065 -> 227065 bytes
-rw-r--r--macros/latex/base/slides.pdfbin375493 -> 375493 bytes
-rw-r--r--macros/latex/base/slifonts.fdd6
-rw-r--r--macros/latex/base/slifonts.pdfbin234171 -> 233905 bytes
-rw-r--r--macros/latex/base/source2e.pdfbin6149921 -> 6264724 bytes
-rw-r--r--macros/latex/base/source2e.tex4
-rw-r--r--macros/latex/base/source2edoc.cls87
-rw-r--r--macros/latex/base/syntonly.dtx6
-rw-r--r--macros/latex/base/syntonly.pdfbin190015 -> 189355 bytes
-rw-r--r--macros/latex/base/tlc2.pdfbin291143 -> 290257 bytes
-rw-r--r--macros/latex/base/tlc3.err186
-rw-r--r--macros/latex/base/tlc3.pdfbin326462 -> 368933 bytes
-rw-r--r--macros/latex/base/tulm.pdfbin162773 -> 162773 bytes
-rw-r--r--macros/latex/base/usrguide-historic.pdfbin438602 -> 439393 bytes
-rw-r--r--macros/latex/base/usrguide-historic.tex6
-rw-r--r--macros/latex/base/usrguide.pdfbin477695 -> 487553 bytes
-rw-r--r--macros/latex/base/usrguide.tex153
-rw-r--r--macros/latex/base/utf8ienc.dtx5
-rw-r--r--macros/latex/base/utf8ienc.pdfbin353563 -> 353557 bytes
-rw-r--r--macros/latex/base/webcomp.err2
-rw-r--r--macros/latex/base/webcomp.pdfbin146199 -> 146205 bytes
167 files changed, 7441 insertions, 1056 deletions
diff --git a/macros/latex/base/README.md b/macros/latex/base/README.md
index ef0e530d4b..055ca75f18 100644
--- a/macros/latex/base/README.md
+++ b/macros/latex/base/README.md
@@ -1,7 +1,7 @@
The LaTeX kernel
================
-Release 2023-11-01 patch level 1
+Release 2024-06-01 patch level 0
Overview
--------
diff --git a/macros/latex/base/alltt.dtx b/macros/latex/base/alltt.dtx
index c7e20ba52d..4718c004b4 100644
--- a/macros/latex/base/alltt.dtx
+++ b/macros/latex/base/alltt.dtx
@@ -40,7 +40,7 @@
%<package>\ProvidesPackage{alltt}
%<driver>\ProvidesFile{alltt.drv}
%\ProvidesFile{alltt.dtx}
- [2021/01/29 v2.0g defines alltt environment]
+ [2024/02/08 v2.0g defines alltt environment]
%
%<*driver>
\documentclass{ltxdoc}
@@ -97,7 +97,7 @@
% \end{itemize}
%
% \textbf{NB} When you are using \textsf{OT1} encoded fonts you might
-% be surprsied when you switch to italics, becuase those fonts have
+% be surprised when you switch to italics, because those fonts have
% a different set of glyphs:
% \begin{alltt}
% The glyph at the position of the $ in a slanted font: \textsl{$}.
diff --git a/macros/latex/base/alltt.pdf b/macros/latex/base/alltt.pdf
index f54983cb0e..c2608a701d 100644
--- a/macros/latex/base/alltt.pdf
+++ b/macros/latex/base/alltt.pdf
Binary files differ
diff --git a/macros/latex/base/cfgguide.pdf b/macros/latex/base/cfgguide.pdf
index ffd36d5558..ecf90bbd11 100644
--- a/macros/latex/base/cfgguide.pdf
+++ b/macros/latex/base/cfgguide.pdf
Binary files differ
diff --git a/macros/latex/base/changes.txt b/macros/latex/base/changes.txt
index 6543d553c5..37d22f6a38 100644
--- a/macros/latex/base/changes.txt
+++ b/macros/latex/base/changes.txt
@@ -1,16 +1,229 @@
-================================================================================
-This file lists changes to the LaTeX2e files in reverse chronological order
-of publication (therefore the dates might be out of sequence if there are
-hotfixes). It is provided for convenience only. It therefore makes no claims
-to completeness or accuracy and it contains some references to files that are
-not part of the distribution.
-================================================================================
+================================================================================
+This file lists changes to the LaTeX2e files in reverse chronological order
+of publication (therefore the dates might be out of sequence if there are
+hotfixes). It is provided for convenience only. It therefore makes no claims
+to completeness or accuracy and it contains some references to files that are
+not part of the distribution.
+================================================================================
================================================================================
All changes above are only part of the development branch for the next release.
================================================================================
#########################
+# 2024-06-01 Release
+#########################
+
+2024-05-31 Frank Mittelbach <Frank.Mittelbach@latex-project.org>
+
+ * ltmarks.dtx (subsection{Allocating new mark classes}):
+ Initialize all marks with an id, use 0 when a new class is made (gh/1359)
+ (subsection{Placing and retrieving marks}):
+ Remove the id when returning the mark value (gh/1359)
+
+2024-05-30 Frank Mittelbach <Frank.Mittelbach@latex-project.org>
+
+ * ltmarks.dtx (subsection{Placing and retrieving marks}):
+ Use sequence marker to make all marks unique on nearby
+ regions (gh/1359)
+
+2024-05-30 Frank Mittelbach <Frank.Mittelbach@latex-project.org>
+
+ * ltmarks.dtx (subsection{Core \LaTeXe{} integration}):
+ Correct logic for first mark in page region if first column contains
+ no marks (gh/1359)
+
+2024-05-16 Yukai Chou <muzimuzhi@gmail.com>
+
+ * ltmarks.dtx, ltmeta.dtx, ltpara.dtx:
+ Drop temp fixing for footnotes in function and variable envs.
+ Supported by l3doc since l3kernel 2023-10-10 (latex3 gh/1266)
+
+2024-04-26 Frank Mittelbach <Frank.Mittelbach@latex-project.org>
+
+ * doc.dtx:
+ Do not error with "suspicous date" when rolling back to
+ early years of LaTeX2e (gh/1336)
+
+2024-04-24 Yukai Chou <muzimuzhi@gmail.com>
+
+* lttextcomp.dtx
+ Load the 2018 version when rolling back prior to 2018-08-11 (gh/1333)
+ Clean up \providecommand lines
+
+2024-04-22 Yukai Chou <muzimuzhi@gmail.com>
+
+ * lttextcomp.dtx (section{The \texttt{textcomp} package})
+ Drop default package option "info" which changes kernel info to
+ package info (gh/1333)
+
+2024-04-19 Frank Mittelbach <Frank.Mittelbach@latex-project.org>
+
+ * ltboxes.dtx (section{\LaTeX\ Box commands}):
+ Use a \hrule strut not a \vrule if already in vertical mode
+ (bug seen first with footmisc/14)
+
+2024-04-17 Frank Mittelbach <Frank.Mittelbach@latex-project.org>
+
+ * ltproperties.dtx:
+ Renamed \IfLabelExistTF to \IfLabelExistsTF
+ Renamed \IfPropertyExistTF to \IfPropertyExistsTF
+ Provided T and F variants for both conditionals (gh/1262)
+
+2024-04-17 Joseph Wright <Joseph.Wright@latex-project.org>
+ * ltexpl.dtx, ltdefns.dtx
+ Rename \@expl@cs@argument@spec@@N to \@expl@cs@parameter@spec@@N (gh/1014)
+ * ltexpl.dtx, ltcmd.dtx, ltcmdhooks.dtx
+ Use \cs_parameter_spec:N in place of \cs_argument_spec:N (gh/1014)
+
+2024-04-17 Joseph Wright <Joseph.Wright@latex-project.org>
+ * lttemplates.dtx
+ Use \IfInstanceExistsTF with an 's'
+
+2024-04-15 Joseph Wright <Joseph.Wright@latex-project.org>
+ * lttemplates.dtx
+ Re-factor internals
+
+2024-04-10 Frank Mittelbach <Frank.Mittelbach@latex-project.org>
+
+ * ltclass.dtx (section{Implementation}):
+ Provide \IfFileLoadedTF and variants (gh/1222)
+
+ Provide T and F conditionals not just TF for \IfPackageLoaded...
+ and friends (gh/1262)
+
+2024-03-22 Yukai Chou <muzimuzhi@gmail.com>
+ * ltfilehook.dtx
+ Apply one-step expansion to raw option list, when a package
+ providing key-value options is loaded the second time. The same
+ expansion for first-time loading was requested in gh/580. (gh/1298)
+
+2024-03-21 Joseph Wright <Joseph.Wright@latex-project.org>
+
+ * ltcmd.dtx
+ Collect \endlinechar as \obeyedline
+ * usrguide.tex
+ Document use of \obeyedline in +v arguments
+
+2024-03-16 David Carlisle <David.Carlisle@latex-project.org>
+ * ifthen.dtx guard against active <=> (gh/756)
+
+2024-03-15 Ulrike Fischer <Ulrike.Fischer@latex-project.org>
+ * ltthm.dtx: add link targets to begintheorem commands (hyperref/332)
+
+2024-03-13 Frank Mittelbach <Frank.Mittelbach@latex-project.org>
+ * ltfilehook.dtx (subsection{Kernel, class, and package interfaces for \LaTeX{}}):
+ Clarify that the commands in this section are meant to be usable
+ by the kernel and in classes or packages (gh/1292)
+
+2024-02-15 Joseph Wright <Joseph.Wright@latex-project.org>
+ * lttemplates.dtx
+ Re-introduce \IfInstanceExist(TF)
+
+2024-01-30 David Carlisle <David.Carlisle@latex-project.org>
+ * ltclass.dtx: check that \RequirePackage, \documentclass, \usepackage
+ and related commands are at top level (gh/1185)
+
+2023-11-12 Joseph Wright <Joseph.Wright@latex-project.org>
+ * lttemplates.dtx
+ New file to replace loading xtemplate
+
+2024-01-30 Jérôme Laurens <jerome.laurens@u-bourgogn.fr>
+ * lthooks.dtx:
+ Fix rollback to 2020-10-01.
+
+2024-01-29 Frank Mittelbach <Frank.Mittelbach@latex-project.org>
+
+ * ltmarks.dtx:
+ Generalized the support for extracting marks to cover cases like multicols.
+
+ Some internal commands renamed and extended.
+ Renamed \__mark_update_structure:nn to \__mark_update_structure_from_material:nn
+ Added \__mark_get_marks_for_reinsertion:nNN
+ Added \ShowMarksAt for debugging (might not stay this way)
+
+2024-01-27 Frank Mittelbach <Frank.Mittelbach@latex-project.org>
+
+ * lttextcomp.dtx (section{Font family sub-encodings setup}):
+ Adjusted/corrected TS1 sub-encoding declarations for various families.
+ Some families have changed their names (due to licensing issues),
+ some got new glyphs added, and some were simply incorrectly categorized
+ (gh/1257)
+
+ * lttextcomp.dtx (section{The \texttt{checkencodingsubset.tex} file}):
+ Added check file for encoding subset
+
+2024-01-03 Phelype Oleinik <phelype.oleinik@latex-project.org>
+ * lthooks.dtx:
+ Correct expansion of \@@_print_args:nn argument (gh/1221).
+
+2023-12-30 Frank Mittelbach <Frank.Mittelbach@latex-project.org>
+ * doc.dtx (subsection{Macros surrounding the `definition parts'}):
+ Use \@noligs from the LaTeX kernel, so that the upquote
+ package can add its patch (gh/1230)
+
+2023-12-26 Yukai Chou <muzimuzhi@gmai.com>
+ * ltproperties.dtx:
+ Correct typo (gh/1223)
+ * doc.dtx, ltfntcmd.dtx, lthooks.dtx
+ Correct similar typos of missing backslashes
+ * ltfilehook.dtx
+ Change flag markup in macro env
+
+2023-12-22 Yukai Chou <muzimuzhi@gmail.com>
+ * ltcmd.dtx (subsection{Normalizing the argument specifications})
+ Clarify error message when an argument prefix `!' is applied to
+ a non-trailing optional argument. (gh/1198)
+
+2023-12-16 Frank Mittelbach <Frank.Mittelbach@latex-project.org>
+ * lttagging.dtx:
+ First version of lttagging module added
+
+2023-12-07 Ulrike Fischer <Ulrike.Fischer@latex-project.org>
+ * ltproperties.dtx: use \protected@write, (gh1200)
+
+2023-12-02 Frank Mittelbach <Frank.Mittelbach@latex-project.org>
+ * doc.dtx (subsection{API creation}):
+ Provide \ProvideDocElement for use cases where files are processed
+ individually as well as together, e.g., the LaTeX kernel documentation.
+
+2023-12-01 Joseph Wright <Joseph.Wright@latex-project.org>
+ * ltcmd.dtx (subsection{Declaring commands and environments}):
+ Optimize creation of simple document commands (gh/1189)
+ * usrguide.tex (subsection{Performance}):
+ Document efficiency of ltcmd definitions
+
+2023-11-16 Frank Mittelbach <Frank.Mittelbach@latex-project.org>
+ * ltpara.dtx (subsection{Providing hooks for paragraphs}):
+ Correct error message: hook left horizontal not vertical mode (gh/1182)
+
+2023-11-15 Joseph Wright <Joseph.Wright@latex-project.org>
+ * ltfiles.dtx (subsection{Listing files}):
+ Extend \listfiles to optionally include file sizes and hashes
+ * usrguide.tex
+ Re-introduce \listfiles (extended) description
+
+2023-11-09 Yukai Chou <muzimuzhi@gmail.com>
+ * clsguide-historic.tex, usrguide.tex:
+ Replace quotation with quote envs for zero para indent
+
+ * clsguide-historic.tex, usrguide-historic.tex
+ Mention correct source file names in license footnotes
+
+2023-11-07 Frank Mittelbach <Frank.Mittelbach@latex-project.org>
+ * ltoutenc.dtx (subsection{The fontenc package}):
+ Add more explanation to error message about missing encoding (gh/1102)
+
+ * nfssfont.dtx (section{The code}):
+ Corrected spelling in error message.
+
+ * ltcounts.dtx (subsection{Environment Counter Macros}):
+ In \newcounter do not change \the... if already defined (gh/823)
+
+ * ltplain.dtx (section{Plain \TeX}):
+ Set \tracinglostchars to 2 in \tracingnone (gh/549)
+
+#########################
# 2023-11-01 PL1 Release
#########################
@@ -22,9 +235,9 @@ All changes above are only part of the development branch for the next release.
# 2023-11-01 Release
#########################
-2023-10-15 Ulrike Fischer <Ulrike.Fischer@latex-project.org>
- * ltproperties.dtx:
- Add support for pagetarget property.
+2023-10-15 Ulrike Fischer <Ulrike.Fischer@latex-project.org>
+ * ltproperties.dtx:
+ Add support for pagetarget property.
2023-10-26 David Carlisle <David.Carlisle@latex-project.org>
* ltboxes.dtx:
@@ -56,9 +269,9 @@ All changes above are only part of the development branch for the next release.
Explain the steps carried out by the replacement algorithm for @@.
2023-09-13 Ulrike Fischer <Ulrike.Fischer@latex-project.org>
- * ltproperties.dtx:
+ * ltproperties.dtx:
Use \protected@edef for expansion in the LaTeX2e commands.
-
+
2023-09-13 Ulrike Fischer <Ulrike.Fischer@latex-project.org>
* ltproperties.dtx:
Expand consistently the label/property names in the LaTeX2e commands.
@@ -143,7 +356,7 @@ All changes above are only part of the development branch for the next release.
* ltfiles.dtx
Allow for pipes in \input, etc.
-2023-06-16 Phelype Oleinik <Joseph.Wright@latex-project.org>
+2023-06-16 Phelype Oleinik <phelype.oleinik@latex-project.org>
* lthooks.dtx, ltcmdhooks.dtx
Correct some rollback labels and dates.
diff --git a/macros/latex/base/classes.dtx b/macros/latex/base/classes.dtx
index 688380e3e1..f7c53f0f71 100644
--- a/macros/latex/base/classes.dtx
+++ b/macros/latex/base/classes.dtx
@@ -53,7 +53,7 @@
%<*driver>
\ProvidesFile{classes.drv}
%</driver>
- [2023/05/17 v1.4n
+ [2024/02/08 v1.4n
%<article|report|book> Standard LaTeX document class]
%<10pt|11pt|12pt> Standard LaTeX file (size option)]
% \end{macrocode}
@@ -1882,7 +1882,7 @@
% \changes{v1.3a}{1995/05/17}{Use \cs{@makefnmark} in definition of
% \cs{@makefntext}}
% \changes{v1.3g}{1995/06/26}{Fix definition of \cs{@makefnmark} and
-% \cs{@makefntext} to a) work and b) without using math}
+% \cs{@makefntext} to (a) work and (b) without using math}
% \begin{macrocode}
\else
\newcommand\maketitle{\par
@@ -2002,7 +2002,7 @@
% `section'.
% \item[\meta{level}] A number, denoting the depth of the section
% -- e.g., chapter=1, section = 2, etc. A section number
-% will be printed if and only if \meta{level} $<=$ the value
+% will be printed if and only if \meta{level} $\leq$ the value
% of the \Lcount{secnumdepth} counter.
% \item[\meta{indent}] The indentation of the heading from the left
% margin
@@ -3068,7 +3068,7 @@
% list environment's parameters. The user types |\\| to end a line.
% This is implemented by |\let|'ing |\\| equal |\@centercr|.
%
-% \changes{v1.3j}{1995/08/16}{stop \cs{item} scanning for [ with
+% \changes{v1.3j}{1995/08/16}{stop \cs{item} scanning for [ with ^^A ]
% \cs{relax}}
% \begin{macrocode}
\newenvironment{verse}
@@ -3091,7 +3091,7 @@
% are set smaller than |\textwidth|. The first line of a paragraph
% inside this environment is indented.
%
-% \changes{v1.3j}{1995/08/16}{stop \cs{item} scanning for [ with
+% \changes{v1.3j}{1995/08/16}{stop \cs{item} scanning for [ with ^^A ]
% \cs{relax}}
% \begin{macrocode}
\newenvironment{quotation}
@@ -3110,7 +3110,7 @@
% The quote environment is like the quotation environment except
% that paragraphs are not indented.
%
-% \changes{v1.3j}{1995/08/16}{stop \cs{item} scanning for [ with
+% \changes{v1.3j}{1995/08/16}{stop \cs{item} scanning for [ with ^^A ]
% \cs{relax}}
% \begin{macrocode}
\newenvironment{quote}
diff --git a/macros/latex/base/classes.pdf b/macros/latex/base/classes.pdf
index 88da3b9f59..52268c9f63 100644
--- a/macros/latex/base/classes.pdf
+++ b/macros/latex/base/classes.pdf
Binary files differ
diff --git a/macros/latex/base/clsguide-historic.pdf b/macros/latex/base/clsguide-historic.pdf
index 60236a7d26..eee2dca813 100644
--- a/macros/latex/base/clsguide-historic.pdf
+++ b/macros/latex/base/clsguide-historic.pdf
Binary files differ
diff --git a/macros/latex/base/clsguide-historic.tex b/macros/latex/base/clsguide-historic.tex
index 9cdb41cb48..bb5e4b5e96 100644
--- a/macros/latex/base/clsguide-historic.tex
+++ b/macros/latex/base/clsguide-historic.tex
@@ -34,15 +34,15 @@
\title{\LaTeXe~for class and package writers --- historic version}
-\author{Copyright \copyright~1995--2006 The \LaTeX\ Project\\
+\author{Copyright \copyright~1995--2023 The \LaTeX\ Project\\
All rights reserved.%
\footnote{This file may be distributed and/or modified under the
conditions of the \LaTeX{} Project Public License, either version 1.3c
of this license or (at your option) any later version. See the source
- \texttt{clsguide.tex} for full details.}%
+ \texttt{clsguide-historic.tex} for full details.}%
}
-\date{11 January 2023}
+\date{09 November 2023}
\begin{document}
@@ -1481,7 +1481,7 @@ problem, \LaTeX{} provides two new commands |\MakeUppercase| and
|\MakeLowercase| to do this.
For example:
-\begin{quotation}
+\begin{quote}
\begin{tabular}{rl}
|\uppercase{aBcD\ae\AA\ss\OE}| & \uppercase{aBcD\ae\AA\ss\OE}\\
|\lowercase{aBcD\ae\AA\ss\OE}| & \lowercase{aBcD\ae\AA\ss\OE}\\
@@ -1489,7 +1489,7 @@ For example:
\MakeUppercase{aBcD\ae\AA\ss\OE}\\
|\MakeLowercase{aBcD\ae\AA\ss\OE}| & \MakeLowercase{aBcD\ae\AA\ss\OE}
\end{tabular}
-\end{quotation}
+\end{quote}
The commands |\MakeUppercase| and |\MakeLowercase| themselves are
robust, but they have moving arguments.
diff --git a/macros/latex/base/clsguide.pdf b/macros/latex/base/clsguide.pdf
index 084d6047c9..1fb3a4b864 100644
--- a/macros/latex/base/clsguide.pdf
+++ b/macros/latex/base/clsguide.pdf
Binary files differ
diff --git a/macros/latex/base/clsguide.tex b/macros/latex/base/clsguide.tex
index d6675c4b27..6b9e49c4e8 100644
--- a/macros/latex/base/clsguide.tex
+++ b/macros/latex/base/clsguide.tex
@@ -33,8 +33,8 @@
\usepackage[T1]{fontenc} % needed for \textbackslash in tt
\usepackage{csquotes}
-\title{\LaTeX\ for package and class authors --- current version}
-\author{\copyright~Copyright 2023, \LaTeX\ Project Team.\\
+\title{\LaTeX\ for package and class authors\\current version}
+\author{\copyright~Copyright 2023--2024, \LaTeX\ Project Team.\\
All rights reserved.%
\footnote{This file may distributed and/or modified under the
conditions of the \LaTeX{} Project Public License, either version 1.3c
@@ -42,7 +42,7 @@
\texttt{clsguide.tex} for full details.}%
}
-\date{2023-10-24}
+\date{2024-05-24}
\NewDocumentCommand\cs{m}{\texttt{\textbackslash\detokenize{#1}}}
\NewDocumentCommand\marg{m}{\arg{#1}}
@@ -64,7 +64,7 @@
\section{Introduction}
\LaTeXe{} was released in 1994 and added a number of then-new concepts to
-\LaTeX{}. For package and class authors, these are described in
+\LaTeX{}. For package and class authors, these are described in the document
\texttt{clsguide-historic}, which has largely remained unchanged. Since then,
the \LaTeX{} team have worked on a number of ideas, firstly a programming
language for \LaTeX{} (L3 programming layer) and then a range of tools for
@@ -347,7 +347,7 @@ out by using hooks. As a document author, you will likely be familiar with
|\AtBeginDocument|, a wrapper around the more powerful command |\AddToHook|.
The \LaTeX{} kernel provides a large number of dedicated hooks (applying in
a pre-defined location) and generic hooks (applying to arbitrary commands):
-the interface for using these is described in \texttt{lthooks} . There are
+the interface for using these is described in \texttt{lthooks}. There are
also hooks to apply to files, described in \texttt{ltfilehooks}.
\section{The structure of a class or package}
@@ -891,7 +891,7 @@ unknown option on to a non-keyval class such as \pkg{article}:
The |\ProcessKeyOptions| function is used to check the current option list
against the keys defined for \m{family}. Global (class) options and local
(package) options are checked when this function is called in a package.
-The command will process \emph{all} options given the the current
+The command will process \emph{all} options given the current
package or class: there is no need to also apply \cs{ProcessOptions}.
\begin{decl}
@@ -1104,11 +1104,13 @@ team strongly suggest using the L3 programming layer commands in the
Suppose that you want to define an environment for displaying text that is
numbered as an equation. A straightforward way to do this is as follows:
\begin{verbatim}
- \newenvironment{texteqn}
- {\begin{equation}
- \begin{minipage}{0.9\linewidth}}
- {\end{minipage}
- \end{equation}}
+ \newenvironment{texteqn}{%
+ \begin{equation}%
+ \begin{minipage}{0.9\linewidth}%
+ }{%
+ \end{minipage}%
+ \end{equation}%
+ }
\end{verbatim}
However, if you have tried this then you will probably have noticed that it
does not work perfectly when used in the middle of a paragraph because an
@@ -1118,12 +1120,14 @@ environment.
You can avoid this problem using |\ignorespacesafterend|; it should be
inserted as shown here:
\begin{verbatim}
- \newenvironment{texteqn}
- {\begin{equation}
- \begin{minipage}{0.9\linewidth}}
- {\end{minipage}
- \end{equation}
- \ignorespacesafterend}
+ \newenvironment{texteqn}{%
+ \begin{equation}%
+ \begin{minipage}{0.9\linewidth}%
+ }{%
+ \end{minipage}%
+ \end{equation}%
+ \ignorespacesafterend
+ }
\end{verbatim}
This command may also have other uses.
@@ -1216,7 +1220,7 @@ The arguments \meta{label} and \meta{list of properties} can contain
commands that are expanded. \meta{label} can expand to an arbitrary
string (as long as it can safely be written to the \texttt{aux}-file)
but note that the label names of \cs{label} and \cs{RecordProperties}
-share a singe namespace. This means that you get a \texttt{Label `A'
+share a single namespace. This means that you get a \texttt{Label `A'
multiply defined} warning with the following code:
\begin{verbatim}
\label{A}\RecordProperties{A}{abspage}
@@ -1268,7 +1272,7 @@ immediately when \cs{RecordProperties} is used but during the next
the standard \cs{label}/\cs{pageref}.
\item[\texttt{pagenum} (default: \texttt{0}, at shipout)] The current page as arabic number. This is
- suitable for integer operations and comparisions.
+ suitable for integer operations and comparisons.
\item[\texttt{label} (default: \texttt{??})] The content of \cs{@currentlabel}. This is the value
that you get also with the standard \cs{label}/\cs{ref}.
diff --git a/macros/latex/base/cmfonts.pdf b/macros/latex/base/cmfonts.pdf
index 2ac532150e..c95de6ef01 100644
--- a/macros/latex/base/cmfonts.pdf
+++ b/macros/latex/base/cmfonts.pdf
Binary files differ
diff --git a/macros/latex/base/cyrguide.pdf b/macros/latex/base/cyrguide.pdf
index 6ac55d8d2c..a16286382e 100644
--- a/macros/latex/base/cyrguide.pdf
+++ b/macros/latex/base/cyrguide.pdf
Binary files differ
diff --git a/macros/latex/base/doc-code.pdf b/macros/latex/base/doc-code.pdf
index d2d707ee73..11887be5fd 100644
--- a/macros/latex/base/doc-code.pdf
+++ b/macros/latex/base/doc-code.pdf
Binary files differ
diff --git a/macros/latex/base/doc.dtx b/macros/latex/base/doc.dtx
index 8b48f59d6a..946f187389 100644
--- a/macros/latex/base/doc.dtx
+++ b/macros/latex/base/doc.dtx
@@ -34,9 +34,9 @@
%\catcode`\<=14
%<+package|shortvrb>\NeedsTeXFormat{LaTeX2e}[1994/12/01]
%<+package>
-%<+package>\providecommand\DeclareRelease[3]{}
-%<+package>\providecommand\DeclareCurrentRelease[2]{}
-%<+package>
+% Any rollback request before 2016-02-15 we try to fullfil with the 2016 version:
+%<+package>\DeclareRelease{}{1994-06-01}
+%<+package> {doc-2016-02-15.sty}
%<+package>\DeclareRelease{v2.1g}{2016-02-15}
%<+package> {doc-2016-02-15.sty}
%<+package>\DeclareRelease{v2}{2021-06-01}
@@ -45,7 +45,7 @@
%<+package>
%<+package>\ProvidesPackage{doc}
%<+shortvrb>\ProvidesPackage{shortvrb}
-%<+package|shortvrb> [2022/11/13 v3.0m
+%<+package|shortvrb> [2024/04/26 v3.0p
%<+package|shortvrb> Standard LaTeX documentation package V3 (FMi)]
%\catcode`\<=12
%
@@ -57,7 +57,7 @@
%
%
%% Package `doc' to use with LaTeX 2e
-%% Copyright (C) 1989-2022 Frank Mittelbach, all rights reserved.
+%% Copyright (C) 1989-2023 Frank Mittelbach, all rights reserved.
%
%
% Version: Date: Changes:
@@ -143,8 +143,8 @@
% \MakeShortVerb{\|}
% \setcounter{StandardModuleDepth}{1}
%
-% {\catcode`\p=12 \catcode`\t=12 ^^A hack used later on to print
-% \gdef\dimenvalue#1pt{$#1$pt}} ^^A a register value with a - sign
+% {\catcode`\p=12 \catcode`\t=12 ^^A hack used later on to print a
+% \gdef\dimenvalue#1pt{$#1$pt}} ^^A register value with a - sign
%
% \newcommand{\DOC}{\texttt{doc}\xspace}
%
@@ -167,7 +167,7 @@
%\RenewDocElement[macrolike = true ,
% toplevel = false,
% idxtype = ,
-% idxgroup = LaTeX comands\actualchar\LaTeX{} commands ,
+% idxgroup = LaTeX commands\actualchar\LaTeX{} commands ,
% printtype =
% ]{Macro}{macro}
%
@@ -237,7 +237,7 @@
% \changes{v1.9t}{1995/05/11}{Use \cs{GetFileInfo}}
% \GetFileInfo{doc.sty}
%
-% \CheckSum{0} ^^A % keep the checksum in this file but not now :-)
+% \CheckSum{0}
%
% \title{The \DOC{} and \texttt{shortvrb} Packages\thanks
% {This file has version number \fileversion{} dated \filedate{}.}}
@@ -595,7 +595,16 @@
% class file (like \texttt{ltugboat.cls}) use the |\DocstyleParms|
% command described below. Starting with release 2.0a it can now
% be changed directly as long as the redefinition happens before
-% the |\begin{document}|.
+% the |\begin{document}| (if you change it later you might see strange
+% typesetting effects if you are unlucky).
+%
+% |\MacroFont| does not alter the font of
+% |\verb| or |\verb*| because it is often used to make the font size of
+% the code displays smaller, which would look odd if used within a
+% paragraph. If you decide to use a different font family and want to
+% use the same family with
+% |\verb| you need to alter the font setup for |\ttfamily| in addition
+% to |\MacroFont|.
%
% \DescribeEnv{environment}
% For documenting the definition of environments one can use the
@@ -695,6 +704,12 @@
% |\NewDocElement{Env}{environment}|
% though that's not quite what has been done, as we will see later.
%
+% \DescribeInterfaceMacro{\ProvideDocElement}
+% This declaration does nothing when the doc element is already
+% declared, otherwise it works like \cs{NewDocElement}. It can be
+% useful if you have many documentation files that you may want to
+% process individually as well as together.
+%
% \DescribeOption[noprint]{macrolike}
% \DescribeOption[noprint]{envlike}
% \DescribeOption[noprint]{toplevel}
@@ -1367,7 +1382,7 @@
%\RenewDocElement[macrolike = true ,
% toplevel = false,
% idxtype = ,
-% idxgroup = LaTeX comands\actualchar\LaTeX{} commands ,
+% idxgroup = LaTeX commands\actualchar\LaTeX{} commands ,
% printtype =
% ]{Macro}{macro}
%\end{verbatim}
@@ -1515,7 +1530,7 @@
%
% Thirty years is a long time in the life of computer programs, so
% there are a good number of interfaces within \DOC that are really
-% only of historical interest (or when processing equally old sources.
+% only of historical interest (or when processing equally old sources).
% We list them here, but in general we suggest that for new
% documentation they should not be used.
%
@@ -2108,9 +2123,12 @@
% that is, they must be given |\catcode| $12$.
% \changes{v1.8b}{1993/09/21}{Changed to conform to new LaTeX verbatim,
% which handles more ligatures.}
+% \changes{v3.0o}{2023/12/30}{Use \cs{@noligs} from the \LaTeX\
+% kernel, so that the \texttt{upquote} package can
+% add its patch (gh/1230)}
% \begin{macrocode}
\obeylines
- \let\do\do@noligs \verbatim@nolig@list
+ \@noligs
\let\do\@makeother \dospecials
% \end{macrocode}
% \changes{v1.5t}{1989/11/07}{Common code added.}
@@ -2183,7 +2201,7 @@
% \changes{v1.7a}{1992/03/13}{Added \cs{reset@font} for NFSS.}
% \changes{v1.8c}{1993/10/25}{NFSS standard}
% \changes{v1.9t}{1995/05/26}{Removed \cs{math@fontsfalse} (different
-% math setup /pr1622}
+% math setup /pr1622)}
% \begin{macrocode}
\@ifundefined{MacroFont}{%
\if@compatibility
@@ -2220,7 +2238,7 @@
% \changes{v1.7m}{1992/10/11}{Use sltt as default.}
% \changes{v1.8c}{1993/10/25}{NFSS standard}
% \changes{v1.9t}{1995/05/26}{Removed \cs{math@fontsfalse} (different
-% math setup /pr1622}
+% math setup /pr1622)}
% Although most of the macro code is set in |\MacroFont| we want to be
% able to switch to indicate module code set in |\AltMacroFont|.
% |\macro@font| keeps track of which one we're using. We can't do the
@@ -2681,7 +2699,7 @@
% \end{macrocode}
%
% \changes{v2.1j}{2019/11/03}{Kernel now sets up \cs{verbvisiblespace} (gh/205)}
-% \changes{v2.1k}{2019/11/10}{Put the definition into the right command :-( (gh/205)}
+% \changes{v2.1k}{2019/11/10}{Put the definition into the right command (gh/205)}
% \begin{macrocode}
\@setupverbvisiblespace
\MacroFont \@vobeyspaces \@sxverbatim}
@@ -2895,32 +2913,32 @@
% following tasks:
% \begin{itemize}
% \parindent4em
-% \item[1)]
+% \item[(1)]
% |\catcode| all characters used in macro names to
-% 11 (i.e.\ `letter').
-% \item[2)]
+% 11 (i.e., `letter').
+% \item[(2)]
% |\catcode| the `|\|' character to 13
-% (i.e.\ `active').
-% \item[3a)]
+% (i.e., `active').
+% \item[(3a)]
% |\let| the `|\|' equal |\scan@macro|
-% (i.e.\ start the macro scanning mechanism) if there is
-% no special escape character (i.e.\ the
+% (i.e., start the macro scanning mechanism) if there is
+% no special escape character (i.e., the
% |\special@escape@char| is `|\|').
-% \item[3b)]
+% \item[(3b)]
% Otherwise |\let| it equal |\bslash|, i.e.\
% produce a printable |\|.
-% \item[4)]
+% \item[(4)]
% Make the \meta{special escape character} active.
-% \item[5)]
+% \item[(5)]
% |\let| the active version of the special escape
% character
-% (i.e.\ the expansion of |\active@escape@char|) equal
+% (i.e., the expansion of |\active@escape@char|) equal
% |\scan@macro|.
% \end{itemize}
% The reader might ask why we bother to |\catcode| the
% `|\|' first to 12 (at the end of |\macro@code|) then
% re-|\catcode| it to 13 in order to produce a $|\|_{12}$
-% in case 3b) above. This is done because we have to ensure that
+% in case (3b) above. This is done because we have to ensure that
% `|\|' has |\catcode| 13 within the \env{macrocode}
% environment. Otherwise the delimiter for the argument of
% |\xmacro@code| would not be found (parameter matching
@@ -2930,14 +2948,14 @@
% \begin{macrocode}
\begingroup \catcode`\|=\z@ \catcode`\\=\active
% \end{macrocode}
-% We carry out tasks 2) and 3b) first.
+% We carry out tasks (2) and (3b) first.
% \SpecialEscapechar\|
% \begin{macrocode}
|gdef|init@crossref{|catcode`|\|active |let\|bslash
% \end{macrocode}
% Because of the popularity of the `|@|' character as a
% `letter' in macros, we normally have to change its
-% |\catcode| here, and thus fulfill task 1). But the macro
+% |\catcode| here, and thus fulfill task (1). But the macro
% designer might use other characters as private letters as well,
% so we use a macro to do the |\catcode| switching.
% \SpecialEscapechar\|
@@ -2945,8 +2963,8 @@
|MakePrivateLetters
% \end{macrocode}
% Now we |\catcode| the special escape character to 13 and
-% |\let| it equal |\scan@macro|, i.e.\ fulfill tasks 4)
-% and 5). Note the use of |\expandafter| to insert the chosen
+% |\let| it equal |\scan@macro|, i.e., fulfill tasks (4)
+% and (5). Note the use of |\expandafter| to insert the chosen
% escape character saved in |\special@escape@char| and
% |\active@escape@char|.
% \SpecialEscapechar\|
@@ -2955,7 +2973,7 @@
|expandafter|let|active@escape@char|scan@macro}
|endgroup
% \end{macrocode}
-% If there is no special escape character, i.e.\ if
+% If there is no special escape character, i.e., if
% |\SpecialEscapechar| is |\\|, the second last line will
% overwrite the previous definition of $|\|_{13}$. In this
% way all tasks are fulfilled.
@@ -3109,9 +3127,9 @@
% done by the |\ifnot@excluded| macro which assumes that the
% macro name is saved in |\macro@namepart|. The character
% mustn't be stored with a special category code or exclusion from
-% the index won't work, so we we use \cs{string} to normalize it
-% the same way it is done in \cs{DoNotIndex}, i.e. everything ends up catcode 12
-% except for the space character.
+% the index won't work, so we use \cs{string} to normalize it
+% the same way it is done in \cs{DoNotIndex}, i.e. everything ends up
+% catcode 12 except for the space character.
% \changes{v2.0e}{1998/12/28}{Correctly use the case-changing trick.}
% \changes{v3.0l}{2022/11/03}{No longer using the case-changing trick.}
% \begin{macrocode}
@@ -3254,7 +3272,7 @@
% unnecessarily index within that part of the code. As the sequence
% is local it will revert this setting at the end of the
% environment so that the command is indexed elsewhere (unless it
-% is generally disabled from indexing.
+% is generally disabled from indexing).
%
% \DescribeMacro\g__doc_idxtype_prop
% Global property list that holds for all commands that are special
@@ -3282,7 +3300,7 @@
% \DescribeInterfaceMacro\RecordIndexType
% This command takes two arguments: a command (with escape char)
% and its type (i.e., first mandatory
-% argument of a |\NewDocElement| declaration. If |#1| should not be
+% argument of a |\NewDocElement| declaration). If |#1| should not be
% included from the index, then the data is used to record that
% this command is of this type. The information is then used to
% generate appropriate index entries. Obviously, index entries
@@ -3481,7 +3499,7 @@
% \begin{macro}{\__doc_idxtype_put:nn}
% This internal command takes two arguments: a command name as
% string (no backslash) and its type (i.e., first mandatory
-% argument of a |\NewDocElement| declaration. If |#1| is not in
+% argument of a |\NewDocElement| declaration). If |#1| is not in
% |\l__doc_donotindex_seq| it will add this data to the property
% list |\g__doc_idxtype_prop| using |#1| as key and |#2| as its
% value. If the key already exist its value will be overwritten. If
@@ -3884,7 +3902,8 @@
% \begin{imacro}{\RightBraceIndex}
% \changes{v1.5s}{1989/11/05}{Support for code line no. (Undoc)} These
% two macros fix the problems with \prg{makeindex}. Note the
-% `hack' with |\iffalse}\fi| to satisfy both \TeX{} and the
+% `hack' with \iffalse{-to get matching braces\fi |\iffalse}\fi|
+% to satisfy both \TeX{} and the
% \prg{makeindex} program. When this is written to the
% \texttt{.idx} file \TeX{} will see both braces (so we get a
% balanced text). \prg{makeindex} will also see balanced braces
@@ -5539,7 +5558,7 @@
% \begin{macrocode}
\long\def\@doc@env#1#2#3{
% \end{macrocode}
-% The |\endgroup| here closes the scanning of names (using special catcodes.
+% The |\endgroup| here closes the scanning of names (using special catcodes).
% \begin{macrocode}
\endgroup
\clist_map_inline:nn {#3} { \@doc@env@{#1}{#2}{##1} }
@@ -5565,8 +5584,8 @@
% they are technically part of the generated API, only not meant for public
% use.
%
-% \fmi{above docu is no longer right (but code needs further changes
-% anyway}
+% \fmi{above docu is no longer right (but code probably needs further changes
+% anyway)}
%
% |#1| is either \texttt{TT} (for true = macrolike) or \texttt{TF}.
% If true then we drop the first char from |\saved@macroname| and
@@ -5580,7 +5599,7 @@
% If the \DOC element described is macrolike but not a normal
% ``macro'' then its type should be recorded and this is the places
% where this happens. For macros (which should make up the bulk of
-% these items we don't do this and for anything else that looks
+% these items) we don't do this and for anything else that looks
% from an indexing perspective like a macro we don't do that either
% to keep the list of exceptions small. That would be the case if
% the indexing command |\Code|\meta{doc-element}|Index| is
@@ -5635,7 +5654,7 @@
\fi
% \end{macrocode}
% Suppress further |\index| entries when we are within a
-% \texttt{macrolike} environment. (There is no point doing that for
+% \texttt{macrolike} environment. There is no point doing that for
% non-\texttt{macrolike} environments are index entries are only
% generated for items starting with a backslash anyway.
% \fmi{fix}
@@ -5940,6 +5959,16 @@
% \end{macrocode}
% \end{macro}
%
+% \begin{macro}{\doc@ignoredinfo}
+%
+% \begin{macrocode}
+\def\doc@ignoredinfo#1#2{%
+ \PackageInfo{doc}{Doc element '#1/#2' declaration
+ ignored}%
+}
+% \end{macrocode}
+% \end{macro}
+%
%
% \begin{imacro}{\NewDocElement}
% \oarg{options}\marg{name}\marg{envname}
@@ -5963,6 +5992,30 @@
% \end{macrocode}
% \end{imacro}
%
+% \begin{imacro}{\ProvideDocElement}
+% \oarg{options}\marg{name}\marg{envname}
+% This does nothing unless the doc element could be declared with
+% \cs{NewDocElement}.
+% \begin{macrocode}
+\newcommand\ProvideDocElement[3][]{%
+% \end{macrocode}
+%
+% \begin{macrocode}
+ \@ifundefined{Print#2Name}%
+ {\@ifundefined{PrintDescribe#2}%
+ {\@ifundefined{#3}%
+ {\@ifundefined{end#3}%
+ {\@NewDocElement{#1}}%
+ \doc@ignoredinfo
+ }\doc@ignoredinfo
+ }\doc@ignoredinfo
+ }\doc@ignoredinfo
+ {#2}{#3}%
+}
+% \end{macrocode}
+% \end{imacro}
+%
+%
% \begin{imacro}{\RenewDocElement}
% \oarg{options}\marg{name}\marg{envname}
%
@@ -6098,7 +6151,7 @@
% \end{macrocode}
-% \begin{macro}{SpecialMainIndex}
+% \begin{macro}{\SpecialMainIndex}
%
% In \DOC v2 we had \cs{SpecialMainIndex} and
% \cs{SpecialMainEnvIndex} but now with additional \DOC elements we
@@ -6110,7 +6163,7 @@
% \end{macrocode}
% \end{macro}
-% \begin{macro}{SpecialUsageIndex}
+% \begin{macro}{\SpecialUsageIndex}
% \DOC v2 also had \cs{SpecialUsageIndex} which is now called
% \cs{SpecialMacroIndex} generating the ``usage'' index entry for
% a macro. Again we provide that as an alias via |\def|.
@@ -6206,86 +6259,6 @@
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-% \section{Code no longer used}
-%
-% \begin{imacro}{\verb}
-% \changes{v1.7a}{1992/02/27}{Now warns about newlines (from
-% newdoc with `@noligs added).}
-% \changes{v1.8b}{1993/09/21}{Changed to conform to new LaTeX \cs{verb}}
-% We re-define |\verb| to check for newlines in its argument since a
-% missing delimiter is difficult to detect in \DOC{} source.
-% The code is the same as in \texttt{latex.tex} of September 19, 1993.
-% Perhaps there should be a font-changing
-% hook rather than just using |\ttfamily|, but if so it probably should be
-% different from |\MacroFont| since that normally includes |\small|
-% and would look wrong inline.
-% \changes{v1.7a}{1992/02/28}{Added math mode check (from verbatim.sty)}
-% \begin{macrocode}
-%\def\verb{\relax\ifmmode\hbox\else\leavevmode\null\fi
-% \bgroup \let\do\do@noligs \verbatim@nolig@list
-% \ttfamily \verb@eol@error \let\do\@makeother \dospecials
-% \@ifstar{\@sverb}{\@vobeyspaces \frenchspacing \@sverb}}
-% \end{macrocode}
-% \end{imacro}
-%
-% \begin{macro}{\verb@balance@group}
-% \begin{macro}{\verb@egroup}
-% \begin{macro}{\verb@eol@error}
-% \changes{v1.8b}{1993/09/21}{Renamed \cs{verb@err} to
-% \cs{verb@eol@error}, as in new LaTeX verbatim.}
-% \begin{macrocode}
-%\let\verb@balance@group\@empty
-% \end{macrocode}
-%
-% \begin{macrocode}
-%\def\verb@egroup{\global\let\verb@balance@group\@empty\egroup}
-% \end{macrocode}
-%
-% \begin{macrocode}
-%\begingroup
-% \obeylines%
-% \gdef\verb@eol@error{\obeylines%
-% \def^^M{\verb@egroup\@latex@error{%
-% \noexpand\verb command ended by end of line}\@ehc}}%
-%\endgroup
-% \end{macrocode}
-% \end{macro}
-% \end{macro}
-% \end{macro}
-%
-% \begin{macro}{\@sverb}
-% \changes{v1.7a}{1992/02/27}{Added for \cs{verb} change.}
-% \changes{v1.7a}{1992/02/28}{Now same as in verbatim.sty.}
-% \changes{v1.8b}{1993/09/21}{Changed to conform to new LaTeX verbatim,
-% which has better error trapping.}
-% See \cite{art:verbatim} for commentary.
-% \changes{v2.1j}{2019/11/03}{Use the kernel definition, no change needed (gh/205)}
-% \begin{macrocode}
-%\def\@sverb#1{%
-% \catcode`#1\active \lccode`\~`#1%
-% \gdef\verb@balance@group{\verb@egroup
-% \@latex@error{Illegal use of \noexpand\verb command}\@ehc}%
-% \aftergroup\verb@balance@group
-% \lowercase{\let~\verb@egroup}}
-% \end{macrocode}
-% \end{macro}
-%
-%
-% \begin{macro}{\verbatim@nolig@list}
-% \begin{macro}{\do@noligs}
-% These macros replace the old |\@noligs| mechanism by an
-% extensible version to allow more ligatures to be added.
-% \begin{macrocode}
-%\def\verbatim@nolig@list{\do\`\do\<\do\>\do\,\do\'\do\-}
-%\def\do@noligs#1{%
-% \catcode`#1\active
-% \begingroup
-% \lccode`\~`#1\relax
-% \lowercase{\endgroup\def~{\leavevmode\kern\z@\char`#1}}}
-% \end{macrocode}
-% \end{macro}
-% \end{macro}
-
^^A Needed for emacs
^^A
diff --git a/macros/latex/base/doc.pdf b/macros/latex/base/doc.pdf
index 0c8fa0e4a2..34945a5664 100644
--- a/macros/latex/base/doc.pdf
+++ b/macros/latex/base/doc.pdf
Binary files differ
diff --git a/macros/latex/base/docstrip.dtx b/macros/latex/base/docstrip.dtx
index 9677fdad61..d5366b3fdd 100644
--- a/macros/latex/base/docstrip.dtx
+++ b/macros/latex/base/docstrip.dtx
@@ -31,7 +31,7 @@
\def\filename{docstrip.dtx}
\def\fileversion{v2.6b}
\def\filedate{2022-09-03}
-\def\docdate {2023-10-10}
+\def\docdate {2024-02-08}
%%
%
%\iffalse
@@ -450,7 +450,7 @@
% \DescribeMacro{\endbatchfile}
% All batch files should end with this command. Any lines after this
% in the file are ignored. In old files that start
-% |\def\batchfile{|\ldots\ this command is optional, but is a good
+% |\def\batchfile{|\ldots\ \iffalse}\fi this command is optional, but is a good
% idea anyway. If this command is omitted from a batchfile then
% normally \TeX\ will go to its interactive |*| prompt, so you may
% stop \ds{} by typing |\endbatchfile| to this prompt.
@@ -757,7 +757,7 @@
% \meta{Primary}]*\\
% \meta{Primary} & $::=$ &
% \meta{Terminal} $|$ \texttt{!}\meta{Primary}
-% $|$ \texttt{(}\meta{Expression}\texttt{)}\\
+% $|$ \texttt(\meta{Expression}\texttt)\\
% \end{tabular}
%
% The \texttt{|} stands for disjunction, the \texttt{\&} stands for
@@ -1712,7 +1712,7 @@ Z
% \end{macrocode}
%
% \begin{macro}{\quote@name}
-% \changes{v2.5h}{2020/04/18}{Macro added gfh/221)}
+% \changes{v2.5h}{2020/04/18}{Macro added (gh/221)}
% A macro copied from \texttt{ltfiles.dtx} in order to be able to
% allow spaces in filenames.
% \begin{macrocode}
@@ -1994,7 +1994,7 @@ Z
% \meta{Primary} & $::=$ &
% \meta{Terminal} $|$ \texttt{!}\meta{Primary}
% $|$
-% \texttt{(}\meta{Expression}\texttt{)}\\
+% \texttt(\meta{Expression}\texttt)\\
% \end{tabular}
%
% The \texttt{|} stands for disjunction, the \texttt{\&} stands for
@@ -2023,7 +2023,7 @@ Z
% \begin{eqnarray*}
% \tau(\meta{Terminal})&=&"\t@<Terminal>,#1,<Terminal>,\qStop"\\
% \tau(!\meta{Primary})&=&"\if1"\,\tau(\meta{Primary})\,"0\else1\fi"\\
-% \tau(\mbox{\texttt{(}\meta{Expression}\texttt{)}})
+% \tau(\mbox{\texttt(\meta{Expression}\texttt)})
% &=&\tau(\meta{Expression})\\
% \tau(\mbox{\meta{Primary}\texttt{\&}\meta{Secondary}})
% &=&"\if0"\,\tau(\meta{Primary})\,"0\else"
@@ -4473,7 +4473,7 @@ for copying and modification in the file \inFileName.
% {Macro added (DPC)}
% Process the batch file, and then terminate cleanly.
% This may be set to |\relax| for `new style' batch files that
-% do not start with |\def\batchfile{|\ldots
+% do not start with |\def\batchfile{|\ldots \iffalse}\fi
% \begin{macrocode}
\def\process@first@batchfile{%
\processbatchFile
diff --git a/macros/latex/base/docstrip.pdf b/macros/latex/base/docstrip.pdf
index 09f9f4d0bb..303ff3a795 100644
--- a/macros/latex/base/docstrip.pdf
+++ b/macros/latex/base/docstrip.pdf
Binary files differ
diff --git a/macros/latex/base/encguide.pdf b/macros/latex/base/encguide.pdf
index 515a882479..d4833f17c0 100644
--- a/macros/latex/base/encguide.pdf
+++ b/macros/latex/base/encguide.pdf
Binary files differ
diff --git a/macros/latex/base/exscale.pdf b/macros/latex/base/exscale.pdf
index 754af95023..ef6f1f3b21 100644
--- a/macros/latex/base/exscale.pdf
+++ b/macros/latex/base/exscale.pdf
Binary files differ
diff --git a/macros/latex/base/fix-cm.pdf b/macros/latex/base/fix-cm.pdf
index 2bb6951bb5..5939325ed8 100644
--- a/macros/latex/base/fix-cm.pdf
+++ b/macros/latex/base/fix-cm.pdf
Binary files differ
diff --git a/macros/latex/base/fntguide.pdf b/macros/latex/base/fntguide.pdf
index 244cfc1374..98d329e0aa 100644
--- a/macros/latex/base/fntguide.pdf
+++ b/macros/latex/base/fntguide.pdf
Binary files differ
diff --git a/macros/latex/base/fntguide.tex b/macros/latex/base/fntguide.tex
index 7cf5d23981..6106204a55 100644
--- a/macros/latex/base/fntguide.tex
+++ b/macros/latex/base/fntguide.tex
@@ -42,7 +42,7 @@
\title{\LaTeXe{} font selection}
-\author{\copyright~Copyright 1995--2023, \LaTeX\ Project
+\author{\copyright~Copyright 1995--2024, \LaTeX\ Project
Team.\thanks{Thanks to Arash Esbati for documenting the
newer NFSS features of 2020}\\
All rights reserved.%
@@ -52,7 +52,7 @@
\texttt{fntguide.tex} for full details.}%
}
-\date{October 2023}
+\date{March 2024}
\begin{document}
@@ -1997,6 +1997,83 @@ For example,
would use |sb| (semi-bold) when |\rmfamily\bfseries| is requested in
document.
+\subsection{Handling of current and requested font series and shape}
+
+In the original NFSS implementation, the series was a single attribute
+stored in |\f@series| and so one always had to specify both weight and
+width together. Hence, it was impossible to typeset a paragraph in a
+condensed font and inside have a few words in bold weight (but still
+condensed) without doing this manually by requesting
+|\fontseries{bc}\selectfont|.
+
+\NEWfeature{2020/02/02}
+The new implementation now works differently by looking both at the
+current value of |\f@series| and the requested new series and out of
+that combination selects a resulting series value. Thus, if the current
+series is |c| and we ask for |b|, we now get |bc|. This is done by
+consulting a simple lookup table where entries can be added or changed
+with |\DeclareFontSeriesChangeRule|:
+\begin{decl}
+ |\DeclareFontSeriesChangeRule| %
+ \arg{current series} \arg{requested series} \\
+ \leavevmode\hfill \arg{result} \arg{alternative result}
+\end{decl}
+
+The \m{current series} is the value currently stored in |\f@series|,
+\m{requested series} is the new series requested, \m{result} is the
+combined value if it exists for the given font family, and
+\m{alternative result} is a fallback in case \m{result} doesn't exist.
+The example above now looks like this:
+\begin{verbatim}
+ \DeclareFontSeriesChangeRule{c}{b}{bc}{}
+\end{verbatim}
+which means: switch to the |bc| series if |c| is current and |b| is
+(additionally) requested, and if the current font doesn't have the
+combination, start the normal font substitution, i.e., switch back shape
+to |n| and if this combination doesn't succeed, switch back series to
+|m| as well, ending up with |m/n|.
+
+Another example is:
+\begin{verbatim}
+ \DeclareFontSeriesChangeRule{bc}{sc}{bsc}{bc}
+\end{verbatim}
+which means: if the current series is bold condensed (|bc|) and
+semi-condensed (|sc|) is requested (additionally), try bold
+semi-condensed (|bsc|) if available but stay with bold condensed if not.
+
+A special value is |m| which is used to reset both weight and width. In
+order to reset only one of them, the special values |?m| (reset width)
+and |m?| (reset weight) are provided, e.g.:
+\begin{verbatim}
+ \DeclareFontSeriesChangeRule{bc}{m?}{c}{}
+\end{verbatim}
+
+The corresponding macro |\DeclareFontShapeChangeRule| is also provided
+for setting database entries for font shapes:
+\begin{decl}
+ |\DeclareFontShapeChangeRule| %
+ \arg{current shape} \arg{requested shape} \\
+ \leavevmode\hfill \arg{result} \arg{alternative result}
+\end{decl}
+
+An example would be:
+\begin{verbatim}
+ \DeclareFontShapeChangeRule{it}{sc}{scit}{scsl}
+\end{verbatim}
+If italics is the current shape and small caps is requested, switch to
+|scit| (small caps italics) and if that doesn't exist, try |scsl| (small
+caps slanted).
+
+Finally, it is also possible to overrule the entries in the lookup
+tables and forcibly select a series or shape with:
+\begin{decl}
+ |\fontseriesforce| \arg{series} \qquad |\fontshapeforce| \arg{shape}
+\end{decl}
+
+With the example above for the |c| series, issuing |\fontseriesforce{b}|
+means that the series switches to |b| and not to |bc|. Same applies to
+|\fontshapeforce|.
+
\subsection{Handling of nested emphasis}
\begin{decl}
diff --git a/macros/latex/base/fontdef.dtx b/macros/latex/base/fontdef.dtx
index 82b09709af..281add29ef 100644
--- a/macros/latex/base/fontdef.dtx
+++ b/macros/latex/base/fontdef.dtx
@@ -27,7 +27,8 @@
%
% \fi
% \iffalse
-%%% From File: fontdef.dtx
+%%% From File: fontdef.dtx
+%<*!latexrelease>
%<*dtx>
\ProvidesFile{fontdef.dtx}
%</dtx>
@@ -38,17 +39,24 @@
%<+cfgprel>\ProvidesFile{preload.cfg}
%<driver, >\ProvidesFile{fontdef.drv}
% \fi
-% \ProvidesFile{fontdef.dtx}
-%<-latexrelease> [2021/01/15 v3.0i LaTeX Kernel
-% \iftrue (\else
-%<text, >(Text
-%<math, >(Math
-%<+cfgtext>(Uncustomized text
-%<+cfgmath>(Uncustomized math
-%<+cfgprel>(Uncustomized preload
+% \ProvidesFile{fontdef.dtx}
+ [2024/02/09 v3.0i LaTeX Kernel
+% \iffalse
+%<text, > (Text font setup)
+%<math, > (Math font setup)
+%<+cfgtext> (Uncustomized text font setup)
+%<+cfgmath> (Uncustomized math font setup)
+%<+cfgprel> (Uncustomized preload font setup)
+%<*dtx>
% \fi
-%<-latexrelease> font setup)]
-%
+(font setup)
+%\iffalse
+%</dtx>
+%\fi
+]
+% \iffalse
+%</!latexrelease>
+%\fi
%
%\iffalse This is a META comment
%
diff --git a/macros/latex/base/format.ins b/macros/latex/base/format.ins
index 2e14ee0e62..e20ff09438 100644
--- a/macros/latex/base/format.ins
+++ b/macros/latex/base/format.ins
@@ -170,6 +170,7 @@ the system are in the document `cfgguide.tex'.
\from{lthooks.dtx}{2ekernel} % L3 layer module
\from{ltcmdhooks.dtx}{2ekernel} % L3 layer module
\from{ltsockets.dtx}{2ekernel} % L3 layer module
+ \from{lttemplates.dtx}{2ekernel} % L3 layer module
\from{ltalloc.dtx}{2ekernel}
\from{ltcntrl.dtx}{2ekernel}
\from{lterror.dtx}{2ekernel}
@@ -206,11 +207,12 @@ the system are in the document `cfgguide.tex'.
\from{ltbibl.dtx}{2ekernel}
\from{ltmarks.dtx}{trace,2ekernel} % L3 layer module
\from{ltpage.dtx}{2ekernel}
- \from{ltclass.dtx}{2ekernel,tracerollback}
+ \from{ltclass.dtx}{2ekernel,tracerollback}
\from{ltkeys.dtx}{2ekernel} % L3 layer module
\from{ltfilehook.dtx}{2ekernel} % L3 layer module
\from{ltshipout.dtx}{2ekernel} % L3 layer module
\from{ltoutput.dtx}{2ekernel}
+ \from{lttagging.dtx}{2ekernel}
\from{ltfinal.dtx}{2ekernel}}
\file{tracefnt.sty}{%
\from{ltfsstrc.dtx}{package,trace}}
@@ -228,6 +230,8 @@ the system are in the document `cfgguide.tex'.
\from{lttextcomp.dtx}{TS1sty}}
\file{textcomp-2018-08-11.sty}{%
\from{lttextcomp.dtx}{TS1oldsty}}
+ \file{checkencodingsubset.tex}{%
+ \from{lttextcomp.dtx}{TS1check}}
}
\generateFile{oldlfont.sty}{t}{%
diff --git a/macros/latex/base/graphpap.pdf b/macros/latex/base/graphpap.pdf
index f4ac3ec438..a8340e6f13 100644
--- a/macros/latex/base/graphpap.pdf
+++ b/macros/latex/base/graphpap.pdf
Binary files differ
diff --git a/macros/latex/base/ifthen.dtx b/macros/latex/base/ifthen.dtx
index ef7d8ab398..0bbe361211 100644
--- a/macros/latex/base/ifthen.dtx
+++ b/macros/latex/base/ifthen.dtx
@@ -30,7 +30,7 @@
%%
%% File `ifthen.dtx'.
%% Copyright (C) 1991 by Leslie Lamport
-%% Copyright (C) 1994-2001 LaTeX project, David Carlisle
+%% Copyright (C) 1994-2024 LaTeX project, David Carlisle
%% all rights reserved.
%%
%
@@ -42,7 +42,7 @@
%<driver>\ProvidesFile{ifthen.drv}
% \fi
% \ProvidesFile{ifthen.dtx}
- [2022/04/13 v1.1d Standard LaTeX ifthen package (DPC)]
+ [2024/03/16 v1.1e Standard LaTeX ifthen package (DPC)]
%
% \iffalse
%<*driver>
@@ -273,15 +273,35 @@
\ifx##1\relax\z@\else\expandafter##2##1\fi}}}
% \end{macrocode}
% \begin{macrocode}
+\begingroup
+\lccode`\~`\> %
+\catcode`\+\active
+\lccode`\+`\< %
+\catcode`\!\active
+\lccode`\!`\= %
+\lowercase{\endgroup
+% \end{macrocode}
+% \begin{macrocode}
+\def\TE@repl@active{%
+ \TE@repl~>%
+ \TE@repl+<%
+ \TE@repl!=%
+}
+% \end{macrocode}
+% \begin{macrocode}
\long\def\ifthenelse#1{%
% \end{macrocode}
% \changes{v1.0h}{1994/05/14}{Use \cs{TE@repl}}
+% \changes{v1.1e}{2024/03/16}{replace active \cs{ifnum} syntax}
% \begin{macrocode}
\toks@{#1}%
\TE@repl\or\TE@or
\TE@repl\and\TE@and
\TE@repl\not\TE@neg
% \end{macrocode}
+% \begin{macrocode}
+ \TE@repl@active
+% \end{macrocode}
%
% \changes{v1.1c}{2001/05/25}{Added \cs{AND}, \cs{OR} and \cs{NOT} as
% boolean operators as alternative to the lower case versions
@@ -353,7 +373,10 @@
\expandafter\@firstoftwo
\else
\expandafter\@secondoftwo
- \fi}
+ \fi}%
+% \end{macrocode}
+% \begin{macrocode}
+}
% \end{macrocode}
% \end{macro}
%
diff --git a/macros/latex/base/ifthen.pdf b/macros/latex/base/ifthen.pdf
index 349bf582fc..9d86b4dfe0 100644
--- a/macros/latex/base/ifthen.pdf
+++ b/macros/latex/base/ifthen.pdf
Binary files differ
diff --git a/macros/latex/base/inputenc.dtx b/macros/latex/base/inputenc.dtx
index 5858743afd..7ab9713d8e 100644
--- a/macros/latex/base/inputenc.dtx
+++ b/macros/latex/base/inputenc.dtx
@@ -142,7 +142,7 @@
% Originally this command was only to be used in vertical mode (with
% the idea that it should be only within a document when
% using text from several documents to build up a composite work such
-% as a volume of journal articles. However, usages in certain
+% as a volume of journal articles). However, usages in certain
% languages suggested that it might be preferable to allow changing
% the input encoding at any time, which is what is possible now
% (though that is quite computing resource intensive).
@@ -410,7 +410,7 @@
%<cp1252&!ansinew> \ProvidesFile{cp1252.def}
%<cp1250> \ProvidesFile{cp1250.def}
%<cp1257> \ProvidesFile{cp1257.def}
- [2021/02/14 v1.3d Input encoding file]
+ [2024/02/08 v1.3d Input encoding file]
%<cp850>%%
%<cp850>%% If you need a Euro symbol, try cp858 instead.
%<cp850>%%
@@ -2204,7 +2204,7 @@
% \section{The Next encoding}
%
% This input encoding is based on work by Stefan Ried
-% (\texttt{stef@\linebreak[0]theo-phys.uni-essen.de} and Holger Uhr
+% (\texttt{stef@\linebreak[0]theo-phys.uni-essen.de}) and Holger Uhr
% (\texttt{huhr@\linebreak[0]uni-paderborn.de}).
%
% Further extended by
diff --git a/macros/latex/base/inputenc.pdf b/macros/latex/base/inputenc.pdf
index e6ec0400f2..3a048de322 100644
--- a/macros/latex/base/inputenc.pdf
+++ b/macros/latex/base/inputenc.pdf
Binary files differ
diff --git a/macros/latex/base/lamport-manual.pdf b/macros/latex/base/lamport-manual.pdf
index 9cb7e4a508..10690717b6 100644
--- a/macros/latex/base/lamport-manual.pdf
+++ b/macros/latex/base/lamport-manual.pdf
Binary files differ
diff --git a/macros/latex/base/latexrelease.ins b/macros/latex/base/latexrelease.ins
index 8ae19b318d..89c3b0fc3a 100644
--- a/macros/latex/base/latexrelease.ins
+++ b/macros/latex/base/latexrelease.ins
@@ -97,6 +97,7 @@ extension .ins) which are part of the distribution.
\from{lthooks.dtx} {latexrelease}% L3 layer module
\from{ltcmdhooks.dtx} {latexrelease}% L3 layer module
\from{ltsockets.dtx} {latexrelease}% L3 layer module
+ \from{lttemplates.dtx} {latexrelease}% L3 layer module
\from{ltalloc.dtx} {latexrelease}% empty
\from{ltcntrl.dtx} {latexrelease}% empty
\from{lterror.dtx} {latexrelease}% empty
diff --git a/macros/latex/base/latexrelease.pdf b/macros/latex/base/latexrelease.pdf
index 3408be4003..986335b7a0 100644
--- a/macros/latex/base/latexrelease.pdf
+++ b/macros/latex/base/latexrelease.pdf
Binary files differ
diff --git a/macros/latex/base/latexsym.pdf b/macros/latex/base/latexsym.pdf
index d7e20ae305..e7e1fc934f 100644
--- a/macros/latex/base/latexsym.pdf
+++ b/macros/latex/base/latexsym.pdf
Binary files differ
diff --git a/macros/latex/base/lb2.err b/macros/latex/base/lb2.err
index 74c0e222b6..7d22f49814 100644
--- a/macros/latex/base/lb2.err
+++ b/macros/latex/base/lb2.err
@@ -1,4 +1,4 @@
-\newcommand\erratafiledate{2014/09/30}
+\newcommand\erratafiledate{2024/01/03}
\def\comando#1{\texttt{\string#1}}
@@ -1203,6 +1203,14 @@ Streiche den letzten Buchstaben von ausf"uhrliche\u{n}.
\erroronpage{647}{Abs.4, Z.1}{JMa}{2006/03/23}{2}
Streiche den letzten Buchstaben von vertikale\u{r}.
+\erroronpage{649}{Beispiel 10-3-9}{WOs}{2024/01/03}{}
+Das Beispiel verwendet \verb=\frame=, was seinen Inhalt immer auf der
+Zeile positioniert und nicht \verb=\fbox=, was je nach Drehung auch
+unter die Zeile dreht (siehe Beispiel 10.3.10).
+Die Ausgabe ist korrekt aber eher überraschend,
+da der nachfolgende Absatz dann \verb=\fbox= diskutiert und die
+Besonderheit von \verb=\frame= hier nicht erwähnt wird.
+
\erroronpage{649}{Abs.2, Z.8}{FMi/HjG}{2006/10/22}{2}
Ersetze: "`\u{Dieser Punkt} ist in \ldots"' \>
"`\u{Dies} ist in \ldots"'
@@ -1605,6 +1613,7 @@ Die Abkürzung NFSS sollte \textsf{NFSS} geschrieben werden.
\contributor{SZi}{Stefan Ziesemer}
\contributor{TNdz}{Timo Niedenzu}
\contributor{VVo}{Vladimir Volovich}
+\contributor{WOs}{Wolfgang Ostmann}
\contributor{YiL}{Yiannis Lazarides}
\end{multicols}
diff --git a/macros/latex/base/lb2.pdf b/macros/latex/base/lb2.pdf
index 83194744f5..0b4a371ca7 100644
--- a/macros/latex/base/lb2.pdf
+++ b/macros/latex/base/lb2.pdf
Binary files differ
diff --git a/macros/latex/base/letter.pdf b/macros/latex/base/letter.pdf
index 09b933a022..6f1191dada 100644
--- a/macros/latex/base/letter.pdf
+++ b/macros/latex/base/letter.pdf
Binary files differ
diff --git a/macros/latex/base/lgc2.pdf b/macros/latex/base/lgc2.pdf
index fe532c6180..005efe9d27 100644
--- a/macros/latex/base/lgc2.pdf
+++ b/macros/latex/base/lgc2.pdf
Binary files differ
diff --git a/macros/latex/base/lppl.pdf b/macros/latex/base/lppl.pdf
index 8963917172..7982766d32 100644
--- a/macros/latex/base/lppl.pdf
+++ b/macros/latex/base/lppl.pdf
Binary files differ
diff --git a/macros/latex/base/ltboxes.dtx b/macros/latex/base/ltboxes.dtx
index 7c5a7c0139..7e6c787ab8 100644
--- a/macros/latex/base/ltboxes.dtx
+++ b/macros/latex/base/ltboxes.dtx
@@ -33,7 +33,7 @@
%<*driver>
% \fi
\ProvidesFile{ltboxes.dtx}
- [2023/10/26 v1.4e LaTeX Kernel (Box Commands)]
+ [2024/04/22 v1.4f LaTeX Kernel (Box Commands)]
% \iffalse
\documentclass{ltxdoc}
\GetFileInfo{ltboxes.dtx}
@@ -87,7 +87,7 @@
% Note that in this picture mode version of |\makebox| a [b] aligns on
% the \emph{bottom} of the text as documented. If you want to align on
% the \emph{baseline} use
-% |\makebox( , )[b]{\raisebox{0pt}[\height][0pt]{xyz}}}|
+% |\makebox( , )[b]{\raisebox{0pt}[\height][0pt]{xyz}}|
% or |\makebox( , )[b]{\smash{xyz}}|
%
% \DescribeMacro\mbox
@@ -235,7 +235,8 @@
% \begin{macro}{\makebox}
% \changes{v0.1a}{1993/12/03}
% {modified}
-% |\makebox| User level command just looks for optional |[| or |(|.
+% |\makebox| User level command just looks for optional
+% |[| or |(|. \iffalse)]\fi
% \changes{v1.1h}{2015/01/08}{Make Robust (latexrelease)}
% \begin{macrocode}
%</2ekernel>
@@ -1010,7 +1011,7 @@
% set globally to false when they are definitely true.
%
% If anyone is unhappy with this argument then both flags should be
-% treated as in |\set@nobreak|; otherwise this command will be
+% treated as in |\@setnobreak|; otherwise this command will be
% redundant.
% \changes{v1.1a}{1996/10/24}{Added local settings of flags: dangerous!!}
% \begin{macrocode}
@@ -1486,9 +1487,40 @@
%
% The |\nobreak| was added (1995/10/31) to allow hyphenation of the
% final word of the paragraph.
+%
+% In 2024 we changed the macro to account for vertical mode. In
+% that case we use a strut produced with \cs{hrule} to avoid
+% starting a new paragraph (resulting in spurious extra line) and
+% also account for the \cs{prevdepth} of the previous line.
+% \changes{v1.4f}{2024/04/18}
+% {Use a \cs{hrule} strut not a \cs{vrule} if already in
+% vertical mode (bug seen first with footmisc/14)}
% \begin{macrocode}
+%</2ekernel>
+%<*2ekernel|latexrelease>
+%<latexrelease>\IncludeInRelease{2024/06/01}%
+%<latexrelease> {\@finalstrut}{final strut correction}%
\def\@finalstrut#1{%
- \unskip\ifhmode\nobreak\fi\vrule\@width\z@\@height\z@\@depth\dp#1}
+ \unskip
+ \ifhmode \nobreak \vrule
+ \else
+ \ifdim \prevdepth=-\@m\p@
+ \else
+ \vskip-\prevdepth
+ \fi
+ \hrule
+ \fi
+ \@width\z@\@height\z@\@depth\dp#1}
+%</2ekernel|latexrelease>
+%<latexrelease>\EndIncludeInRelease
+%<latexrelease>\IncludeInRelease{0000/00/00}%
+%<latexrelease> {\@finalstrut}{final strut correction}%
+%<latexrelease>\def\@finalstrut#1{%
+%<latexrelease> \unskip\ifhmode\nobreak\fi
+%<latexrelease> \vrule\@width\z@\@height\z@\@depth\dp#1}
+%<latexrelease>
+%<latexrelease>\EndIncludeInRelease
+%<*2ekernel>
% \end{macrocode}
% \end{macro}
%
diff --git a/macros/latex/base/ltclass.dtx b/macros/latex/base/ltclass.dtx
index 139eb7a1a7..35bbb8a55a 100644
--- a/macros/latex/base/ltclass.dtx
+++ b/macros/latex/base/ltclass.dtx
@@ -33,7 +33,7 @@
%<*driver>
% \fi
\ProvidesFile{ltclass.dtx}
- [2023/04/14 v1.5h LaTeX Kernel (Class & Package Interface)]
+ [2024/04/10 v1.5k LaTeX Kernel (Class & Package Interface)]
% \iffalse
\documentclass{ltxdoc}
\GetFileInfo{ltclass.dtx}
@@ -390,7 +390,7 @@
% package files.)
%
% |\DeclareOption*{\PassOptionsToPackage{\CurrentOption}|^^A
-% |{|\meta{pkg-name}|}|\\
+% |{|\meta{pkg-name}|}}|\\
% Handle the current option by passing it on to the package
% \meta{pkg-name}, which will presumably be loaded via
% |\RequirePackage| later in the file. This is useful for building
@@ -1075,19 +1075,20 @@
% \begin{macrocode}
%</2ekernel>
%<*2ekernel|latexrelease>
-%<latexrelease>\IncludeInRelease{2021/11/15}%
-%<latexrelease> {\IfPackageLoadedtTF}{Test package loading}%
+%<latexrelease>\IncludeInRelease{2024/06/01}%
+%<latexrelease> {\IfPackageLoadedTF}{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.
+% For rollback/rollforward pretend everything was available since
+% the beginning of dawn.
% \begin{macrocode}
%</2ekernel|latexrelease>
%<latexrelease>\EndIncludeInRelease
%<latexrelease>\IncludeInRelease{0000/00/00}%
-%<latexrelease> {\IfPackageLoadedtTF}{Test package loading}%
+%<latexrelease> {\IfPackageLoadedTF}{Test package loading}%
%<latexrelease>
%<latexrelease>\let \IfPackageLoadedTF \@ifpackageloaded
%<latexrelease>\let \IfClassLoadedTF \@ifclassloaded
@@ -1102,6 +1103,99 @@
%
%
%
+% \begin{macro}{
+% \IfPackageLoadedT,\IfPackageLoadedF,
+% \IfPackageAtLeastT,\IfPackageAtLeastF,
+% \IfClassAtLeastT,\IfClassAtLeastF,
+% \IfFileAtLeastT,\IfFileAtLeastF,
+% \IfFormatAtLeastT,\IfFormatAtLeastF,
+% \IfPackageLoadedWithOptionsT,\IfPackageLoadedWithOptionsF,
+% \IfClassLoadedT,\IfClassLoadedF,
+% \IfClassLoadedWithOptionsF,\IfClassLoadedWithOptionTF
+% }
+% A few more conditionals for convenience
+% \changes{v1.5k}{2024/04/10}{Provide T and F conditionals not just TF
+% (gh/1262)}
+% \begin{macrocode}
+%</2ekernel>
+%<*2ekernel|latexrelease>
+%<latexrelease>\IncludeInRelease{2024/06/01}%
+%<latexrelease> {\IfPackageLoadedT}{More conditionals}%
+\def\IfPackageLoadedT #1#2{\IfPackageLoadedTF{#1}{#2}{}}
+\def\IfPackageLoadedF #1{\IfPackageLoadedTF{#1}{}}
+\def\IfClassLoadedT #1#2{\IfClassLoadedTF{#1}{#2}{}}
+\def\IfClassLoadedF #1{\IfClassLoadedTF{#1}{}}
+\def\IfPackageAtLeastT#1#2#3{\IfPackageAtLeastTF{#1}{#2}{#3}{}}
+\def\IfPackageAtLeastF #1#2{\IfPackageAtLeastTF{#1}{#2}{}}
+\def\IfClassAtLeastT #1#2#3{\IfClassAtLeastTF{#1}{#2}{#3}{}}
+\def\IfClassAtLeastF #1#2{\IfClassAtLeastTF{#1}{#2}{}}
+\def\IfFileAtLeastT #1#2#3{\IfFileAtLeastTF{#1}{#2}{#3}{}}
+\def\IfFileAtLeastF #1#2{\IfFileAtLeastTF{#1}{#2}{}}
+\def\IfFormatAtLeastT #1#2{\IfFormatAtLeastTF{#1}{#2}{}}
+\def\IfFormatAtLeastF #1{\IfFormatAtLeastTF{#1}{}}
+\def\IfPackageLoadedWithOptionsT #1#2#3{\IfPackageLoadedWithOptionsTF{#1}{#2}{#3}{}}
+\def\IfPackageLoadedWithOptionsF #1#2{\IfPackageLoadedWithOptionsTF{#1}{#2}{}}
+\def\IfClassLoadedWithOptionsT #1#2#3{\IfClassLoadedWithOptionsTF{#1}{#2}{#3}{}}
+\def\IfClassLoadedWithOptionsF #1#2{\IfClassLoadedWithOptionsTF{#1}{#2}{}}
+% \end{macrocode}
+%
+% \begin{macro}{\IfFileLoadedTF,\IfFileLoadedT,\IfFileLoadedF}
+% These three commands haven't been there at all in the past.
+% \changes{v1.5k}{2024/04/10}{Provide \cs{IfFileLoadedTF} and variants
+% (gh/1222)}
+% \begin{macrocode}
+\def\IfFileLoadedTF#1{%
+ \expandafter\ifx\csname ver@#1\endcsname\relax
+ \expandafter\@secondoftwo
+ \else
+ \expandafter\@firstoftwo
+ \fi}
+\def\IfFileLoadedT#1#2{\IfFileLoadedTF{#1}{#2}{}}
+\def\IfFileLoadedF #1{\IfFileLoadedTF{#1}{}}
+% \end{macrocode}
+% For rollback/rollforward pretend everything was available since
+% the beginning of dawn.
+% \begin{macrocode}
+%</2ekernel|latexrelease>
+%<latexrelease>\EndIncludeInRelease
+%<latexrelease>\IncludeInRelease{0000/00/00}%
+%<latexrelease> {\IfPackageLoadedT}{More conditionals}%
+%<latexrelease>
+%<latexrelease>\def\IfPackageLoadedT #1#2{\IfPackageLoadedTF{#1}{#2}{}}
+%<latexrelease>\def\IfPackageLoadedF #1{\IfPackageLoadedTF{#1}{}}
+%<latexrelease>\def\IfClassLoadedT #1#2{\IfClassLoadedTF{#1}{#2}{}}
+%<latexrelease>\def\IfClassLoadedF #1{\IfClassLoadedTF{#1}{}}
+%<latexrelease>\def\IfPackageAtLeastT#1#2#3{\IfPackageAtLeastTF{#1}{#2}{#3}{}}
+%<latexrelease>\def\IfPackageAtLeastF #1#2{\IfPackageAtLeastTF{#1}{#2}{}}
+%<latexrelease>\def\IfClassAtLeastT #1#2#3{\IfClassAtLeastTF{#1}{#2}{#3}{}}
+%<latexrelease>\def\IfClassAtLeastF #1#2{\IfClassAtLeastTF{#1}{#2}{}}
+%<latexrelease>\def\IfFileAtLeastT #1#2#3{\IfFileAtLeastTF{#1}{#2}{#3}{}}
+%<latexrelease>\def\IfFileAtLeastF #1#2{\IfFileAtLeastTF{#1}{#2}{}}
+%<latexrelease>\def\IfFormatAtLeastT #1#2{\IfFormatAtLeastTF{#1}{#2}{}}
+%<latexrelease>\def\IfFormatAtLeastF #1{\IfFormatAtLeastTF{#1}{}}
+%<latexrelease>\def\IfPackageLoadedWithOptionsT #1#2#3{\IfPackageLoadedWithOptionsTF{#1}{#2}{#3}{}}
+%<latexrelease>\def\IfPackageLoadedWithOptionsF #1#2{\IfPackageLoadedWithOptionsTF{#1}{#2}{}}
+%<latexrelease>\def\IfClassLoadedWithOptionsT #1#2#3{\IfClassLoadedWithOptionsTF{#1}{#2}{#3}{}}
+%<latexrelease>\def\IfClassLoadedWithOptionsF #1#2{\IfClassLoadedWithOptionsTF{#1}{#2}{}}
+%<latexrelease>
+%<latexrelease>\def\IfFileLoadedTF#1{%
+%<latexrelease> \expandafter\ifx\csname ver@#1\endcsname\relax
+%<latexrelease> \expandafter\@secondoftwo
+%<latexrelease> \else
+%<latexrelease> \expandafter\@firstoftwo
+%<latexrelease> \fi}
+%<latexrelease>\def\IfFileLoadedT#1#2{\IfFileLoadedTF{#1}{#2}{}}
+%<latexrelease>\def\IfFileLoadedF #1{\IfFileLoadedTF{#1}{}}
+%<latexrelease>
+%<latexrelease>\EndIncludeInRelease
+%<*2ekernel>
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+%
+%
+%
% \begin{macro}{\ProvidesPackage}
% Checks that the current filename is correct, and defines
% |\ver@filename|.
@@ -1327,11 +1421,11 @@
% \changes{v1.4c}{2021/06/06}
% {apply \cs{expandafter} to raw options for gh/580}
% \begin{macrocode}
- \@ifundefined{@raw@opt@#3.#1}%
- {\expandafter\gdef\csname @raw@opt@#3.#1\expandafter\endcsname
- \expandafter{#2}}%
- {\expandafter\g@addto@macro\csname @raw@opt@#3.#1\expandafter\endcsname
- \expandafter{\expandafter,#2}}%
+ \@ifundefined{@raw@opt@#3.#1}%
+ {\expandafter\gdef\csname @raw@opt@#3.#1\expandafter\endcsname
+ \expandafter{#2}}%
+ {\expandafter\g@addto@macro\csname @raw@opt@#3.#1\expandafter\endcsname
+ \expandafter{\expandafter,#2}}%
}
%</2ekernel|latexrelease>
%<latexrelease>\EndIncludeInRelease
@@ -1950,12 +2044,34 @@
% \end{macro}
%
% \begin{macro}{\@fileswithoptions}
+% \changes{v1.5i}{2024/01/30}{Test group level}
% The common part of |\documentclass| and |\usepackage|.
% \begin{macrocode}
+%</2ekernel>
+%<latexrelease>\IncludeInRelease{2024/06/01}%
+%<latexrelease> {\@fileswithoptions}{Check Group}%
+%<*2ekernel|latexrelease>
\def\@fileswithoptions#1{%
+ \ifnum\currentgrouplevel>\z@
+ \@latex@error
+ {Loading a class or package in a group}%
+ {Classes and packages should only be loaded at the top level}%
+ \fi
\@ifnextchar[%]
{\@fileswith@ptions#1}%
{\@fileswith@ptions#1[]}}
+%</2ekernel|latexrelease>
+%<latexrelease>\EndIncludeInRelease
+%<latexrelease>\IncludeInRelease{0000/00/00}%
+%<latexrelease> {\@fileswithoptions}{Check Group}%
+%<latexrelease>\def\@fileswithoptions#1{%
+%<latexrelease> \@ifnextchar[%]
+%<latexrelease> {\@fileswith@ptions#1}%
+%<latexrelease> {\@fileswith@ptions#1[]}}
+%<latexrelease>\EndIncludeInRelease
+%<*2ekernel>
+% \end{macrocode}
+% \begin{macrocode}
\@onlypreamble\@fileswithoptions
% \end{macrocode}
%
@@ -2221,9 +2337,17 @@
% \end{macrocode}
% \changes{v1.5d}{2022/10/10}{Use \cs{protected@edef}.}
% \begin{macrocode}
- \expandafter\protected@edef\csname opt@\@currname.\@currext\endcsname
+ \expandafter\protected@edef
+ \csname opt@\@currname.\@currext\endcsname
{\zap@space#2 \@empty}%
- \@namedef{@raw@opt@\@currname.\@currext}{#2}%
+% \end{macrocode}
+% \changes{v1.5j}{2024/03/22}
+% {Apply one-step expansion to raw option list,
+% to be consistent with change for gh/580 (gh/1298).}
+% \begin{macrocode}
+ \expandafter\def
+ \csname @raw@opt@\@currname.\@currext\expandafter\endcsname
+ \expandafter{#2}%
\@nameuse{opt@handler@\@currname.\@currext}%
}%
}%
@@ -2624,8 +2748,8 @@
%
% Allow code to be saved to be executed at specific later times.
%
-% Save things in macros, I considered using toks registers, (and
-% |\addto@hook| from the NFSS code, that would require stacking the
+% Here we save things in macros. I considered using toks registers (and
+% |\addto@hook| from the NFSS code), but that would require stacking the
% contents in the case of required packages, so just generate a new
% macro for each package.
% \begin{macro}{\@begindocumenthook}
@@ -2997,7 +3121,7 @@
\let\do\@makeother\dospecials%
% \end{macrocode}
% If there are active characters in the upper half (e.g., from
-% \texttt{inputenc} there would be confusion so we render everything
+% \texttt{inputenc}) there would be confusion so we render everything
% harmless.
% \changes{v1.2f}{2018/03/27}
% {Use full file name for old release}
@@ -3585,7 +3709,7 @@
% and therefore we can now test its value. If the value is zero we
% assume that the remaining argument string represents a version
% and change |\pkgcls@targetdate| and set |\pkgcls@targetlabel| to
-% the version name (after stripping off the trailing \texttt{=}.
+% the version name (after stripping off the trailing \texttt{=}).
% \begin{macrocode}
\ifnum \pkgcls@targetdate=\z@
\pkgcls@targetdate\@ne
@@ -3695,7 +3819,7 @@
% late, but if there wasn't one (i.e., if current release is the
% oldest that exists) we use it as the best choice. However in
% that case something is wrong (as there shouldn't be a rollback to
-% a date where a package used doesn't yet exists. So we make a
+% a date when a package used didn't yet exists). So we make a
% complained to the user.
% \begin{macrocode}
\ifx\pkgcls@candidate\@empty
diff --git a/macros/latex/base/ltcmd.dtx b/macros/latex/base/ltcmd.dtx
index 0a6cb1a53c..69bd162e56 100644
--- a/macros/latex/base/ltcmd.dtx
+++ b/macros/latex/base/ltcmd.dtx
@@ -34,8 +34,8 @@
%%% From File: ltcmd.dtx
%
% \begin{macrocode}
-\def\ltcmdversion{v1.2a}
-\def\ltcmddate{2023-08-19}
+\def\ltcmdversion{v1.2e}
+\def\ltcmddate{2024-04-17}
% \end{macrocode}
%
%<*driver>
@@ -415,8 +415,6 @@
\cs_new_protected:Npn \@@_declare_cmd_internal:Nnnn #1#2#3#4
{
\tl_set:Nx \l_@@_function_tl { \cs_to_str:N #1 }
- \tl_set:Nx \l_@@_fn_tl
- { \exp_not:c { \l_@@_function_tl \c_space_tl } }
\@@_normalize_arg_spec:n {#2}
\exp_args:No \@@_prepare_signature:n \l_@@_arg_spec_tl
\@@_declare_cmd_code:Nnn #1 {#2} {#3}
@@ -435,17 +433,93 @@
% \end{macrocode}
% \end{macro}
%
+% \begin{macro}[EXP]{\@@_all_m_check:n, \@@_all_m_check_aux:n}
+% A quick loop to check for all |(+)m|-type arguments.
+% \begin{macrocode}
+\cs_new:Npn \@@_all_m_check:n #1
+ { \tl_map_function:nN {#1} \@@_all_m_check_aux:n }
+\cs_new:Npn \@@_all_m_check_aux:n #1
+ {
+ \str_if_eq:nnF {#1} { m }
+ {
+ \str_if_eq:nnF {#1} { + }
+ { X }
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
% \begin{macro}{\@@_declare_cmd_code:Nnn}
% \begin{macro}
-% {\@@_declare_cmd_code_aux:Nnn, \@@_declare_cmd_code_expandable:Nnn}
-% The appropriate auxiliary is called.
+% {
+% \@@_declare_cmd_optimized:Nnn,
+% \@@_declare_cmd_code_aux:Nnn,
+% \@@_declare_cmd_code_expandable:Nnn
+% }
+% \begin{macro}{\@@_start_optimized:}
+% \changes{v1.2b}{2023/12/01}
+% {Optimize cmd creation for all-\texttt{m} arguments}
+% At this stage we can check for a short-cut possibility: if the argument
+% specification is made up of just |(+)m| tokens, and if all arguments are
+% either short or long, then we can produce an optimized document command.
+% This only applies to document commands, not creation of environments (which
+% are more complex).
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_declare_cmd_code:Nnn #1#2
+ {
+ \bool_lazy_any:nTF
+ {
+ { \l_@@_environment_bool }
+ {
+ \bool_lazy_and_p:nn
+ { \l_@@_some_short_bool }
+ { \l_@@_some_long_bool }
+ }
+ { ! \tl_if_blank_p:e { \@@_all_m_check:n {#2} } }
+ }
+ {
+ \tl_set:Nx \l_@@_fn_tl
+ { \exp_not:c { \l_@@_function_tl \c_space_tl } }
+ \bool_if:NTF \l_@@_grab_expandably_bool
+ { \@@_declare_cmd_code_expandable:Nnn }
+ { \@@_declare_cmd_code_aux:Nnn }
+ }
+ { \@@_declare_cmd_optimized:Nnn }
+ #1 {#2}
+ }
+% \end{macrocode}
+% The optimized version of commands just has to worry about whether to make
+% them protected or long. The commands start with an expandable marker so
+% that other parts of the kernel know these are set up by \pkg{ltcmd}.
+% We need the two layers of redirection so that the \texttt{code} internal
+% function has the same form as it would for any other document command.
+% Optimization means that there is no \cs{group_align_safe_begin:} before
+% grabbing the arguments, so anything involving |&| tokens will not work.
+% However, this is really only intended for making optional argument
+% processing safe anyway, so in practice should not be an issue.
% \begin{macrocode}
-\cs_new_protected:Npn \@@_declare_cmd_code:Nnn
+\cs_new_protected:Npn \@@_declare_cmd_optimized:Nnn #1#2#3
{
- \bool_if:NTF \l_@@_grab_expandably_bool
- { \@@_declare_cmd_code_expandable:Nnn }
- { \@@_declare_cmd_code_aux:Nnn }
- }
+ \bool_if:NTF \l_@@_expandable_bool
+ { \cs_set_nopar:Npe }
+ { \cs_set_protected_nopar:Npe }
+ #1
+ {
+ \exp_not:N \@@_start_optimized:
+ \exp_not:c { \l_@@_function_tl \c_space_tl code }
+ }
+ \exp_args:Ncc \cs_generate_from_arg_count:NNnn
+ { \l_@@_function_tl \c_space_tl code }
+ {
+ cs_set
+ \bool_if:NF \l_@@_expandable_bool { _protected }
+ \bool_if:NF \l_@@_some_long_bool { _nopar }
+ :Npn
+ }
+ \l_@@_current_arg_int
+ {#3}
+ }
+\cs_new:Npn \@@_start_optimized: { }
% \end{macrocode}
% Standard functions call \cs{@@_start:nNNnnn}, which receives the
% argument specification, an auxiliary used for
@@ -544,6 +618,7 @@
% \end{macrocode}
% \end{macro}
% \end{macro}
+% \end{macro}
%
% \begin{macro}{\@@_declare_env:nnnn}
% \begin{macro}{\@@_declare_env_internal:nnnn}
@@ -1286,7 +1361,7 @@
% that is not possible without the risk of mistakenly grabbing the
% entire brace group (potentially leading to a~\texttt{!~Runaway argument}
% error) or trying to grab a |}|$_2$, leading to
-% an~\verb|! Argument of \dots has an extra }| error.
+% \iffalse{\fi an~\verb|! Argument of \dots has an extra }| error.
% \begin{macrocode}
\cs_new_protected:Npn \@@_allowed_token_check:N #1
{
@@ -1373,6 +1448,9 @@
% \end{macro}
%
% \begin{macro}{\@@_add_arg_spec:n, \@@_add_arg_spec_mandatory:n}
+% \changes{v1.2c}{2023/12/22}
+% {Clarify error message when \texttt{!} prefix is applied to
+% non-trailing opt-arg (gh/1198)}
% When adding an argument to the argument specification, set the
% \texttt{some_long} or \texttt{some_short} booleans as appropriate
% and clear the booleans keeping track of |+|, |!| and |=| markers.
@@ -1414,7 +1492,12 @@
\bool_if:NT \l_@@_some_obey_spaces_bool
{
\msg_error:nnxx { cmd } { invalid-bang }
- { \@@_environment_or_command: } { \tl_to_str:n {#1} }
+ { \@@_environment_or_command: }
+ {
+ \bool_if:NTF \l_@@_obey_spaces_bool
+ { \tl_to_str:n {'#1'} }
+ { an~optional~argument~before~mandatory~ \tl_to_str:n {'#1'} }
+ }
\@@_bad_def:wn
}
\tl_clear:N \l_@@_last_delimiters_tl
@@ -1626,8 +1709,10 @@
% 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
+% that: it defines \cs{l_@@_process_one_tl} starting with a
+% \iffalse{\fi |}|$_2$
+% and ending with a |{|$_1$, \iffalse}\fi
+% so that it adds as many processors as
% needed when |x|-expanded.
% \begin{macrocode}
\cs_new_protected:Npn \@@_replicate_processor:nn #1 #2
@@ -2033,7 +2118,7 @@
% \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
+% \cs{@@_cmd_type_cases:NnnnnnF}. 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}
@@ -2042,9 +2127,10 @@
\use:x
{
\int_set:Nn \tex_escapechar:D { 92 }
- \exp_not:N \@@_cmd_type_cases:NnnnnF \exp_not:N #2
+ \exp_not:N \@@_cmd_type_cases:NnnnnnF \exp_not:N #2
{ \@@_copy_command:nnNN }
{ \@@_copy_expandable:nnNN }
+ { \@@_copy_optimized:nnNN }
{ \@@_copy_environment:nnNN }
{ \@@_copy_environment_end:nnNN }
{ \@@_cant_copy:nwn { non-ltcmd } }
@@ -2186,6 +2272,24 @@
%<latexrelease>\EndIncludeInRelease
% \end{macrocode}
%
+% \begin{macro}{\@@_copy_optimized:nnNN}
+% Copy the code, simply define the wrapper.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_copy_optimized:nnNN #1#2#3#4
+ {
+ \cs_set_eq:cc { #1 ~ code } { #2 ~ code }
+ \token_if_protected_macro:NTF #4
+ { \cs_set_protected_nopar:Npe }
+ { \cs_set_nopar:Npe }
+ #3
+ {
+ \exp_not:N \@@_start_optimized:
+ \exp_not:c { #1 ~ code }
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
% \begin{macrocode}
%<latexrelease>\IncludeInRelease{2021/11/15}{\@@_copy:NN (part 2)}%
%<latexrelease> {Support~\NewCommandCopy~in~ltcmd}
@@ -2423,7 +2527,7 @@
%
% \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
+% \cs{@@_cmd_type_cases:NnnnnnF}. The showing command takes the command
% to be shown as argument.
% \begin{macrocode}
\cs_new_protected:Npn \@@_show:N #1
@@ -2431,9 +2535,10 @@
\use:x
{
\int_set:Nn \tex_escapechar:D { 92 }
- \exp_not:N \@@_cmd_type_cases:NnnnnF \exp_not:N #1
+ \exp_not:N \@@_cmd_type_cases:NnnnnnF \exp_not:N #1
{ \@@_show_command:N }
{ \@@_show_expandable:N }
+ { \@@_show_optimized:N }
{ \@@_show_environment:N }
{ \@@_show_environment_end:N }
{ \@@_cant_copy:nwn { non-ltcmd } }
@@ -2450,6 +2555,7 @@
% \@@_show_command:NnNNwN,
% \@@_show_expandable:N,
% \@@_show_expandable:NnNNNNnN,
+% \@@_show_optimized:N,
% \@@_show_command_aux:NnNNn,
% \@@_show_environment:N,
% \@@_show:x,
@@ -2530,6 +2636,48 @@
}
% \end{macrocode}
%
+% Optimized functions need things done a bit differently as we need to
+% reconstruct the argument spec.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_show_optimized:N #1
+ {
+ \exp_args:Nc \@@_show_optimized:NN
+ { \cs_to_str:N #1 \c_space_tl code }
+ #1
+ }
+\cs_new_protected:Npn \@@_show_optimized:NN #1#2
+ {
+ \cs_set:Npe \@@_show_optimized_aux:N ##1
+ {
+ \c_space_tl \c_space_tl \c_hash_str ##1 :
+ \bool_lazy_or:nnT
+ { \token_if_long_macro_p:N #1 }
+ { \token_if_protected_long_macro_p:N #1 }
+ { + } m
+ \iow_newline:
+ }
+ \tl_show:e
+ {
+ \token_to_str:N #2 =
+ \bool_lazy_or:nnF
+ { \token_if_protected_macro_p:N #1 }
+ { \token_if_protected_long_macro_p:N #1 }
+ { expandable ~ } document~command:
+ \iow_newline:
+ \int_step_function:nN
+ {
+ \int_div_truncate:nn
+ { \tl_count:e { \cs_parameter_spec:N #1 } }
+ { 2 }
+ }
+ \@@_show_optimized_aux:N
+ ->
+ \cs_replacement_spec:N #1
+ }
+ }
+\cs_generate_variant:Nn \tl_count:n { e }
+% \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:NnNNn}. Additionally, when
@@ -3533,18 +3681,38 @@
% \end{macro}
%
% \begin{macro}{\@@_grab_v_aux_put:N}
+% \changes{v1.2d}{2024/03/21}{Collect \cs{endlinechar} as \cs{obeyedline}}
% Storing one token in the collected argument. Most tokens are
% converted to category code $12$, with the exception of active
% characters, and spaces (not sure what should be done for those).
% \begin{macrocode}
+%<latexrelease>\IncludeInRelease{2024/06/01}{\@@_grab_v_aux_put:N}%
+%<latexrelease> {Endlines~as~\obeyedline}
\cs_new_protected:Npn \@@_grab_v_aux_put:N #1
{
\tl_put_right:Nx \l_@@_v_arg_tl
{
\token_if_active:NTF #1
- { \exp_not:N #1 } { \token_to_str:N #1 }
+ { \exp_not:N #1 }
+ {
+ \int_compare:nNnTF {`#1} = \tex_endlinechar:D
+ { \exp_not:N \obeyedline }
+ { \token_to_str:N #1 }
+ }
}
}
+%<latexrelease>\EndIncludeInRelease
+%<latexrelease>\IncludeInRelease{2020/10/01}{\@@_grab_v_aux_put:N}%
+%<latexrelease> {Endlines~as~\obeyedline}
+%<latexrelease>\cs_new_protected:Npn \@@_grab_v_aux_put:N #1
+%<latexrelease> {
+%<latexrelease> \tl_put_right:Nx \l_@@_v_arg_tl
+%<latexrelease> {
+%<latexrelease> \token_if_active:NTF #1
+%<latexrelease> { \exp_not:N #1 } { \token_to_str:N #1 }
+%<latexrelease> }
+%<latexrelease> }
+%<latexrelease>\EndIncludeInRelease
% \end{macrocode}
% \end{macro}
%
@@ -4376,13 +4544,16 @@
% \end{macro}
%
% \begin{macro}{\__kernel_cmd_if_xparse:NTF}
-% \begin{macro}{\@@_cmd_type_cases:Nnnnn}
+% \begin{macro}{\@@_cmd_type_cases:NnnnnnF}
% \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:NnnnnF} for
% \cs{NewCommandCopy} and \cs{ShowCommand} support}
% \changes{v1.0l}{2022/03/18}{Fix \cs{@@_cmd_type_cases:NnnnnF}
-%" prematurely expanding macros (gh/795)}
+% prematurely expanding macros (gh/795)}
+% \changes{v1.2b}{2023/12/01}{Extend for optimized commands}
+% \changes{v1.2e}{2024/04/17}{Use \cs{__kernel_cs_parameter_spec:N} instead
+% of \cs{cs_argument_spec:N}/\cs{cs_parameter_spec:N}}
% \begin{macro}{\@@_cmd_if_xparse_aux:N}
%
% To determine whether the command is an \pkg{xparse} command check
@@ -4390,36 +4561,38 @@
% that its |replacement_spec| starts with either
% \cs{@@_start:nNNnnn} (non-expandable command) or
% \cs{@@_start_expandable:nNNNNn} (expandable command) or
+% \cs{@@_start_optimized:} (optimized command) or
% \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 \@@_cmd_type_cases:NnnnnF #1 #2 #3 #4 #5 #6
+\cs_new_protected:Npn \@@_cmd_type_cases:NnnnnnF #1 #2 #3 #4 #5 #6 #7
{
\exp_args:Ne \str_case_e:nnF
{
- \exp_args:Nf \tl_if_empty:nT { \cs_argument_spec:N #1 }
+ \exp_args:Nf \tl_if_empty:nT { \__kernel_cs_parameter_spec:N #1 }
{ \exp_not:N \exp_not:n { \exp_not:e { \tl_head:N #1 } } }
}
{
{ \exp_not:N \@@_start:nNNnnn } {#2}
{ \exp_not:N \@@_start_expandable:nNNNNn } {#3}
- { \exp_not:N \@@_start_env:nnnnn } {#4}
+ { \exp_not:N \@@_start_optimized: } {#4}
+ { \exp_not:N \@@_start_env:nnnnn } {#5}
{
\exp_after:wN \exp_not:N
\cs:w environment~
\exp_last_unbraced:Ne \use_none:nnn
{ \cs_to_str:N #1 } ~end~aux \cs_end:
- } {#5}
+ } {#6}
}
- {#6}
+ {#7}
}
\cs_new_protected:Npn \__kernel_cmd_if_xparse:NTF #1
{
- \@@_cmd_type_cases:NnnnnF #1
- { } { } { } { } { \use_iii:nnn }
+ \@@_cmd_type_cases:NnnnnnF #1
+ { } { } { } { } { } { \use_iii:nnn }
\use_i:nn
}
% \end{macrocode}
@@ -4511,10 +4684,8 @@
\bool_if:NTF \l_@@_environment_bool
{ environment ~ ' \l_@@_environment_str ' }
{
- command ~ '
- \exp_args:Nf \tl_trim_spaces:n
- { \exp_after:wN \token_to_str:N \l_@@_fn_tl }
- '
+ command ~
+ ' \c_backslash_str \tl_to_str:N \l_@@_function_tl '
}
}
% \end{macrocode}
@@ -4522,6 +4693,8 @@
%
% Some messages intended as errors when defining commands/environments.
% \changes{v1.0f}{2021/06/04}{Normalize various error messages}
+% \changes{v1.2c}{2023/12/22}
+% {Generalize message \texttt{invalid-bang} (gh/1198)}
% \begin{macrocode}
\msg_new:nnnn { cmd } { arg-after-body }
{ Argument~type~'b'~must~be~last~in~#1. }
@@ -4612,7 +4785,7 @@
{ Invalid~argument~prefix~'!'~in~#1. }
{
The~prefix~'!'~is~only~allowed~for~trailing~optional~arguments.~
- You~tried~to~apply~it~to~'#2'.
+ You~tried~to~apply~it~to~#2.
\c_@@_ignore_def_tl
}
\msg_new:nnnn { cmd } { not-definable }
diff --git a/macros/latex/base/ltcmdhooks-code.pdf b/macros/latex/base/ltcmdhooks-code.pdf
index 46df7576fd..376d333b4e 100644
--- a/macros/latex/base/ltcmdhooks-code.pdf
+++ b/macros/latex/base/ltcmdhooks-code.pdf
Binary files differ
diff --git a/macros/latex/base/ltcmdhooks-doc.pdf b/macros/latex/base/ltcmdhooks-doc.pdf
index 2c0060bde6..e80feb306e 100644
--- a/macros/latex/base/ltcmdhooks-doc.pdf
+++ b/macros/latex/base/ltcmdhooks-doc.pdf
Binary files differ
diff --git a/macros/latex/base/ltcmdhooks.dtx b/macros/latex/base/ltcmdhooks.dtx
index 73bd7f6351..f8a8699d7e 100644
--- a/macros/latex/base/ltcmdhooks.dtx
+++ b/macros/latex/base/ltcmdhooks.dtx
@@ -1,6 +1,6 @@
% \iffalse meta-comment
%
-%% File: ltcmdhooks.dtx
+%% From File: ltcmdhooks.dtx
%% Copyright (C) 2020-2024
%% Frank Mittelbach, Phelype Oleinik, The LaTeX Project
%
@@ -12,16 +12,20 @@
% https://www.latex-project.org/lppl.txt
%
%
-%%% From File: ltcmdhooks.dtx
-%
-\def\ltcmdhooksversion{v1.0i}
-\def\ltcmdhooksdate{2023/06/16}
-%
+% \fi
%
+% \iffalse
+%%% From File: lthooks.dtx
%
%<*driver>
+% \fi
+\ProvidesFile{ltcmdhooks.dtx}
+ [2024/04/17 v1.0j LaTeX Kernel (Command hooks)]
+% \iffalse
+%
\documentclass{l3doc}
-%\usepackage{ltcmdhooks}
+\GetFileInfo{ltcmdhooks.dtx}
+% \usepackage{ltcmdhooks}
\EnableCrossrefs
\CodelineIndex
\begin{document}
@@ -38,7 +42,7 @@
% \providecommand\phoinline[1]{\begin{quote}\itshape\footnotesize PhO: #1\end{quote}}
%
% \title{The \texttt{ltcmdhooks} module\thanks{This file has version
-% \ltcmdhooksversion\ dated \ltcmdhooksdate, \copyright\ \LaTeX\
+% \fileversion\ dated \filedate, \copyright\ \LaTeX\
% Project.}}
% \author{Frank Mittelbach \and Phelype Oleinik}
%
@@ -125,8 +129,8 @@
% \item
%
% that code can be prepended or appended (i.e., added to the
-% hooks) even if the command itself is not defined, because the
-% defining package has not yet been loaded;
+% hooks) even if the command itself is not (yet) defined, because the
+% defining package has not been loaded at this point;
%
% \item
%
@@ -214,6 +218,14 @@
% optional and mandatory arguments. By adding code to the
% \hook{cmd/section/after} hook, you get in the way of that scanning.
%
+% In such a case, where it is known that a specific generic command
+% hook does not work if code is added to it, the package author can
+% add a \cs{DisableGenericHook}\footnote{Please use
+% \cs{DisableGenericHook} if at all, only on hooks that you
+% \enquote{own}, i.e., for commands your package or class defines and
+% not second guess whether or not hooks of other packages should get
+% disabled!} declaration to prevent this from happening in user
+% documents and thereby avoiding obscure errors.
%
%
% \section{Package Author Interface}
@@ -394,6 +406,8 @@
% \end{macrocode}
%
% \changes{v1.0b}{2021/05/24}{Use \cs{msg_...} instead of \cs{__kernel_msg...}}
+% \changes{v1.0j}{2024/04/17}{Use \cs{__kernel_cs_parameter_spec:N} instead
+% of \cs{cs_argument_spec:N}/\cs{cs_parameter_spec:N}}
%
% \begin{macrocode}
%<*2ekernel|latexrelease>
@@ -643,7 +657,7 @@
}
}
% \end{macrocode}
-% and a conditional \cs{@@_if_public_command:N} to check if a command
+% and a conditional \cs{@@_if_public_command:NTF} to check if a command
% has |__| in its name (no other checking is performed). Primitives
% with |:D| in their name could be included here, but they are already
% discarded in the \cs{token_if_macro:NTF} test above.
@@ -838,14 +852,14 @@
\@@_patch_debug:x { ++~command~can~be~patched~without~rescanning }
% \end{macrocode}
% We'll start by counting the number of arguments in the command by
-% counting the number of characters in the \cs{cs_argument_spec:N} of
+% counting the number of characters in the \cs{cs_parameter_spec:N} of
% the macro, divided by two, and subtracting one if the command has an
% optional argument (that is, an extra |[]| in its
% \meta{parameter text}).
% \begin{macrocode}
\int_set:Nn \l_@@_patch_num_args_int
{
- \exp_args:Nf \str_count:n { \cs_argument_spec:N #2 } / 2
+ \exp_args:Nf \str_count:n { \__kernel_cs_parameter_spec:N #2 } / 2
\bool_if:NT #1 { -1 }
}
% \end{macrocode}
@@ -998,7 +1012,7 @@
%<latexrelease> \@@_patch_debug:x { ++~command~can~be~patched~without~rescanning }
%<latexrelease> \int_set:Nn \l_@@_patch_num_args_int
%<latexrelease> {
-%<latexrelease> \exp_args:Nf \str_count:n { \cs_argument_spec:N #2 } / 2
+%<latexrelease> \exp_args:Nf \str_count:n { \__kernel_cs_parameter_spec:N #2 } / 2
%<latexrelease> \bool_if:NT #1 { -1 }
%<latexrelease> }
%<latexrelease> \int_compare:nNnTF { \l_@@_patch_num_args_int } > { \c_zero_int }
@@ -1248,12 +1262,12 @@
% top-level macro with no arguments, so testing this first would
% short-circuit \tn{robust@command@act} and the top-level macros would
% be incorrectly patched. In that case, we just check if the
-% \cs{cs_argument_spec:N} is empty, and call
+% \cs{cs_parameter_spec:N} is empty, and call
% \cs{@@_patch_expand_redefine:NNnn}.
% \begin{macrocode}
\cs_new_protected:Npn \@@_retokenize_patch:Nnn #1 #2 #3
{
- \str_if_eq:eeTF { \cs_argument_spec:N #1 } { }
+ \str_if_eq:eeTF { \__kernel_cs_parameter_spec:N #1 } { }
{ \@@_patch_expand_redefine:NNnn \c_false_bool #1 {#2} {#3} }
{
\@@_patch_debug:x { ..~command~can~only~be~patched~by~rescanning }
diff --git a/macros/latex/base/ltcounts.dtx b/macros/latex/base/ltcounts.dtx
index c58ad2dcb6..006486d23b 100644
--- a/macros/latex/base/ltcounts.dtx
+++ b/macros/latex/base/ltcounts.dtx
@@ -33,7 +33,7 @@
%<*driver>
% \fi
\ProvidesFile{ltcounts.dtx}
- [2021/07/08 v1.1m LaTeX Kernel (Counters)]
+ [2021/11/08 v1.1n LaTeX Kernel (Counters)]
% \iffalse
\documentclass{ltxdoc}
\GetFileInfo{ltcounts.dtx}
@@ -305,6 +305,7 @@
% \begin{macro}{\@definecounter}
% \changes{v1.1b}{1995/05/20}{Streamlined code}
% \changes{v1.1c}{1995/05/20}{And do it right}
+% \changes{v1.1n}{2023/11/07}{Do not change \cs{the...} if already defined (gh/823)}
%
% \begin{macrocode}
\def\@definecounter#1{\expandafter\newcount\csname c@#1\endcsname
@@ -312,9 +313,21 @@
\global\expandafter\let\csname cl@#1\endcsname\@empty
\@addtoreset{#1}{@ckpt}%
\global\expandafter\let\csname p@#1\endcsname\@empty
+% \end{macrocode}
+% If \cs{the\#1} is undefined or \cs{relax} we define it with the
+% standard definition for counters, otherwise we warn. This will
+% catch, for example, that somebody defines a counter named
+% ``index'' conflicting with the \env{theindex} environment.
+% \begin{macrocode}
\expandafter
- \gdef\csname the#1\expandafter\endcsname\expandafter
- {\expandafter\@arabic\csname c@#1\endcsname}}
+ \ifx\csname the#1\endcsname\relax
+ \expandafter
+ \gdef\csname the#1\expandafter\endcsname\expandafter
+ {\expandafter\@arabic\csname c@#1\endcsname}%
+ \else
+ \@latex@warning{Command `\string\the#1' already
+ defined -- not changed}%
+ \fi}
% \end{macrocode}
% \end{macro}
%
diff --git a/macros/latex/base/ltdefns.dtx b/macros/latex/base/ltdefns.dtx
index 24c1369698..d9ec12e75a 100644
--- a/macros/latex/base/ltdefns.dtx
+++ b/macros/latex/base/ltdefns.dtx
@@ -32,7 +32,7 @@
%<*driver>
% \fi
\ProvidesFile{ltdefns.dtx}
- [2022/11/24 v1.5s LaTeX Kernel (definition commands)]
+ [2024/04/17 v1.5t LaTeX Kernel (definition commands)]
% \iffalse
\documentclass{ltxdoc}
\GetFileInfo{ltdefns.dtx}
@@ -91,6 +91,9 @@
% \changes{v1.4b}{2015/02/21}
% {Removed autoload support}
% \changes{v1.5l}{2020/08/21}{Integration of new hook management interface}
+% \changes{v1.5t}{2024/04/17}
+% {Rename \cs{@expl@cs@argument@spec@@N} to
+% \cs{@expl@cs@parameter@spec@@N} (gh/1014)}
%
% \section{Definitions}
%
@@ -215,12 +218,12 @@
% This section defines the following commands:
%
% \DescribeMacro
-% {\@namedef}\marg{NAME}\\ Expands to |\def\|\marg{NAME},
+% {\@namedef}\marg{NAME}\\ Expands to |\def\|\meta{NAME},
% except name can contain any characters.
%
% \DescribeMacro
% {\@nameuse}\marg{NAME}\\
-% Expands to |\|\marg{NAME}.
+% Expands to |\|\meta{NAME}.
%
% \DescribeMacro
% {\@ifnextchar} X\marg{YES}\marg{NO}\\
@@ -530,9 +533,11 @@
% This macro encapsulates the most common call to |\@ifnextchar|, saving
% several tokens each time it is used in the definition of a command
% with an optional argument.
-% |#1| The code to execute in the case that there is a |[| need not be
+% |#1| The code to execute in the case that there is a |[| \iffalse]\fi
+% need not be
% a single token but can be any sequence of commands that `expects' to
-% be followed by |[|. If this command were only used in |\newcommand|
+% be followed by |[|. \iffalse]\fi
+% If this command were only used in |\newcommand|
% definitions then |#1| would be a single token and the braces could
% be omitted from |{#1}| in the definition below, saving a bit of
% memory.
@@ -595,7 +600,7 @@
% required argument spec by using a delimited argument (delimited
% by the digit). This is faster and uses less tokens. The coding
% is slightly odd to preserve the old interface (using |#2| =
-% |\tw@| as the flag to surround the first argument with |[]|. But
+% |\tw@| as the flag to surround the first argument with |[]|). But
% the new method did not allow for the number of arguments |#3| not
% being given as an explicit digit; hence (further expansion of
% this argument and use of) |\number| was added later in 1999.
@@ -706,13 +711,14 @@
% \begin{macro}{\newenvironment}
% Define a new user environment.
% |#1| is the environment name. |#2#| Grabs all the tokens up to
-% the first |{|. These will be any optional arguments. They are not
+% the first |{|. \iffalse}\fi
+% These will be any optional arguments. They are not
% parsed at this point, but are just passed to |\@newenv| which
% will eventually call |\newcommand|. Any optional arguments will
% then be parsed by |\newcommand| as it defines the command that
% executes the `begin code' of the environment.
%
-% This |#2#| trick removed with version 1.2i as it fails if a |{|
+% This |#2#| trick removed with version 1.2i as it fails if a |{| \iffalse}\fi
% occurs in the optional argument. Now use |\@ifnextchar| directly.
% \begin{macrocode}
\def\newenvironment{\@star@or@long\new@environment}
@@ -888,7 +894,8 @@
% \begin{macro}{\@check@c}
% \changes{v1.2i}{1995/04/25}{Make \cs{long} for latex/1346}
% |\CheckCommand| itself just grabs all the arguments we need,
-% without actually looking for |[| optional argument forms. Now
+% without actually looking for |[| \iffalse]\fi
+% optional argument forms. Now
% define |\reserved@a|. If |\\reserved@a| is then defined, compare it
% with the ``|\#1|' otherwise compare |\reserved@a| with |#1|.
% \begin{macrocode}
@@ -2016,7 +2023,7 @@
\long\def\@show@newcommand@aux#1#2#3{%
\typeout{> \string#1=\@expl@cs@prefix@spec@@N#1macro:}%
#3{default \string##1=\expandafter\detokenize\@gobblethree#2.^^J%
- \@expl@cs@argument@spec@@N#1->\@expl@cs@replacement@spec@@N#1}}
+ \@expl@cs@parameter@spec@@N#1->\@expl@cs@replacement@spec@@N#1}}
% \end{macrocode}
% \end{macro}
% \end{macro}
@@ -2117,7 +2124,7 @@
\@show@environment@end#1}
\long\def\@show@environment@begin#1{%
\typeout{> \string\begin{\@expl@cs@to@str@@N#1}=environment:}%
- \typeout{\@expl@cs@argument@spec@@N#1->%
+ \typeout{\@expl@cs@parameter@spec@@N#1->%
\@expl@cs@replacement@spec@@N#1.^^J}}
% \end{macrocode}
% \end{macro}
@@ -2139,7 +2146,7 @@
\long\def\@show@environment@end@aux#1#2{%
\@show@tokens{\string\end{\@expl@cs@to@str@@N#2}%
\ifx\relax#1=undefined%
- \else:^^J\@expl@cs@argument@spec@@N#1->%
+ \else:^^J\@expl@cs@parameter@spec@@N#1->%
\@expl@cs@replacement@spec@@N#1%
\fi}}
% \end{macrocode}
@@ -2158,7 +2165,7 @@
% \begin{macrocode}
\def\@show@nonstop#1{%
\typeout{> \string#1=\@expl@cs@prefix@spec@@N#1macro:^^J%
- \@expl@cs@argument@spec@@N#1->\@expl@cs@replacement@spec@@N#1.}}
+ \@expl@cs@parameter@spec@@N#1->\@expl@cs@replacement@spec@@N#1.}}
\def\@show@typeout#1{\typeout{> #1.^^J}}
% \end{macrocode}
% \end{macro}
@@ -2296,7 +2303,7 @@
% \changes{v1.3g}{2004/01/23}{Added macro (pr/3501)}
% This macro is the kernel version of |\@ifnextchar| which is used
% in a couple of places to prevent the AMS variant from being used
-% since in some places this produced chaos (for example
+% since in some places this produced chaos. For example,
% if an \texttt{fd} file
% is loaded in a random place then the optional argument to
% |\ProvidesFile| could get printed there instead of being written
diff --git a/macros/latex/base/ltdirchk.dtx b/macros/latex/base/ltdirchk.dtx
index ef959c5693..917431552b 100644
--- a/macros/latex/base/ltdirchk.dtx
+++ b/macros/latex/base/ltdirchk.dtx
@@ -36,8 +36,10 @@
%</unstripped>
%<*driver>
% \fi
+% \fi
\ProvidesFile{ltdirchk.dtx}
- [2021/12/11 v1.3a LaTeX Kernel (System Dependent Parts)]
+ [2024/02/11 v1.3a LaTeX Kernel (System Dependent Parts)]
+% \iffalse
% \iffalse
\documentclass{ltxdoc}
\GetFileInfo{ltdirchk.dtx}
@@ -261,6 +263,10 @@
% In current formats enable primitives with unprefixed names.
% the \textsf{latexrelease} guards allow the primitives to be
% defined with a |\luatex| prefix if older formats are specified.
+%
+% The unprefixed forms are \emph{not} undefined for improved
+% compatibility with external packages when rolling back
+% the format.
% \begin{macrocode}
%</initex>
%</dircheck>
@@ -278,25 +284,6 @@
%<latexrelease> "luatex",
%<latexrelease> tex.extraprimitives("core","omega", "aleph", "luatex")
%<latexrelease> )
-%<latexrelease> local i
-%<latexrelease> local t = { }
-%<latexrelease> for _,i in pairs(tex.extraprimitives("luatex")) do
-%<latexrelease> if not string.match(i,"^U") then
-%<latexrelease> if not string.match(i, "^luatex") then
-%<latexrelease> table.insert(t,i)
-%<latexrelease> end
-%<latexrelease> else
-%<latexrelease> if string.match(i,"^Uchar$") then
-%<latexrelease> table.insert(t,i)
-%<latexrelease> end
-%<latexrelease> end
-%<latexrelease> end
-%<latexrelease> for _,i in pairs(t) do
-%<latexrelease> tex.print(
-%<latexrelease> "\noexpand\\let\noexpand\\" .. i
-%<latexrelease> .. "\noexpand\\undefined"
-%<latexrelease> )
-%<latexrelease> end
%<latexrelease>}
%<latexrelease>\EndIncludeInRelease
%<latexrelease>\fi
@@ -1000,8 +987,8 @@
% \begin{macro}{\@TeXversion}
% \TeX\ versions older than 3.141 require |\@TeXversion| to be
% set. This can be determined automatically due to a trick suggested
-% by Bernd Raichle. (Actually this will not always get the correct
-% version number, eg \TeX3.14 would be detected as \TeX3, but \LaTeX\
+% by Bernd Raichle. Actually this will not always get the correct
+% version number, e.g., \TeX3.14 would be detected as \TeX3, but \LaTeX\
% only needs to take account of \TeX's older than 3, or between 3 and
% 3.14.
% \changes{v1.0h}{1994/10/11}
diff --git a/macros/latex/base/ltexpl.dtx b/macros/latex/base/ltexpl.dtx
index 4aaf799e32..410235a056 100644
--- a/macros/latex/base/ltexpl.dtx
+++ b/macros/latex/base/ltexpl.dtx
@@ -33,7 +33,7 @@
%<*driver>
% \fi
\ProvidesFile{ltexpl.dtx}
- [2023/10/13 v1.3g LaTeX Kernel (expl3-dependent code)]
+ [2024/04/17 v1.3h LaTeX Kernel (expl3-dependent code)]
% \iffalse
\documentclass{ltxdoc}
\GetFileInfo{ltexpl.dtx}
@@ -356,9 +356,19 @@
% \changes{v1.2e}{2020/08/19}
% {Add \cs{@expl@cs@\meta{thing}@spec@@N}
% for \cs{ShowCommand} (gh/373)}
+% \changes{v1.3h}{2024/04/17}
+% {Rename \cs{@expl@cs@argument@spec@@N} to
+% \cs{@expl@cs@parameter@spec@@N} (gh/1014)}
+% \changes{v1.3h}{2024/04/17}
+% {Update name of \pkg{expl3} function}
+% \changes{v1.3h}{2024/04/17}
+% {Add a kernel-level copy of \cs{cs_parameter_spec:N}}
% \begin{macrocode}
\cs_gset_eq:NN \@expl@cs@prefix@spec@@N \cs_prefix_spec:N
-\cs_gset_eq:NN \@expl@cs@argument@spec@@N \cs_argument_spec:N
+\cs_if_exist:NTF \cs_parameter_spec:N
+ { \cs_gset_eq:NN \@expl@cs@parameter@spec@@N \cs_parameter_spec:N }
+ { \cs_gset_eq:NN \@expl@cs@parameter@spec@@N \cs_argument_spec:N }
+\cs_gset_eq:NN \__kernel_cs_parameter_spec:N \@expl@cs@parameter@spec@@N
\cs_gset_eq:NN \@expl@cs@replacement@spec@@N \cs_replacement_spec:N
% \end{macrocode}
%
@@ -387,7 +397,7 @@
%<latexrelease>\let \@expl@cs@to@str@@N \@undefined
%<latexrelease>\let \@expl@str@if@eq@@nnTF \@undefined
%<latexrelease>\let \@expl@cs@prefix@spec@@N \@undefined
-%<latexrelease>\let \@expl@cs@argument@spec@@N \@undefined
+%<latexrelease>\let \@expl@cs@parameter@spec@@N \@undefined
%<latexrelease>\let \@expl@cs@replacement@spec@@N \@undefined
%<latexrelease>\let \@expl@str@map@function@@NN \@undefined
%<latexrelease>\EndIncludeInRelease
diff --git a/macros/latex/base/ltfilehook-code.pdf b/macros/latex/base/ltfilehook-code.pdf
index e4516f1f92..300859f4fa 100644
--- a/macros/latex/base/ltfilehook-code.pdf
+++ b/macros/latex/base/ltfilehook-code.pdf
Binary files differ
diff --git a/macros/latex/base/ltfilehook-doc.pdf b/macros/latex/base/ltfilehook-doc.pdf
index 2dc00a337d..f766d421d0 100644
--- a/macros/latex/base/ltfilehook-doc.pdf
+++ b/macros/latex/base/ltfilehook-doc.pdf
Binary files differ
diff --git a/macros/latex/base/ltfilehook.dtx b/macros/latex/base/ltfilehook.dtx
index 4f88b92871..02e95d0f8f 100644
--- a/macros/latex/base/ltfilehook.dtx
+++ b/macros/latex/base/ltfilehook.dtx
@@ -30,16 +30,22 @@
%
%%% From File: ltfilehook.dtx
%
-% \begin{macrocode}
-\providecommand\ltfilehookversion{v1.0o}
-\providecommand\ltfilehookdate{2023/07/10}
-% \end{macrocode}
-%
+% \fi
+%\iffalse
+%<*driver,structuredlog>
+%\fi
+\def\ltfilehookdate{2024/03/13}
+\def\ltfilehookversion{v1.0o}
+%\iffalse
+%</driver,structuredlog>
%<*driver>
-
+%\fi
+\expanded{\noexpand\ProvidesFile{ltfilehook.dtx}
+[\ltfilehookdate\space \ltfilehookversion\space LaTeX Kernel (hooks)]}
+% \iffalse
+%
\documentclass{l3doc}
-
\providecommand\InternalDetectionOff{}
\providecommand\InternalDetectionOn{}
@@ -375,7 +381,7 @@
%
%
%
-% \subsection{Internal interfaces for \LaTeX{}}
+% \subsection{Kernel, class, and package interfaces for \LaTeX{}}
%
% \begin{function}{\declare@file@substitution,\undeclare@file@substitution}
% \begin{syntax}
@@ -393,6 +399,8 @@
% example, or to provide a version that makes use of new kernel
% functionality while the original package remains available for
% use with older releases.
+% As such it is mainly meant for use in the \LaTeX{} kernel but
+% other use cases are conceivable.
%
% The \cs{undeclare@file@substitution} declaration undoes a
% substitution made earlier.
@@ -407,10 +415,10 @@
%
% \begin{function}{\disable@package@load,\reenable@package@load}
% \begin{syntax}
-% \cs{disable@package@load} \Arg{package} \Arg{alternate-code}
+% \cs{disable@package@load} \Arg{package} \Arg{alternate-code}
% \cs{reenable@package@load} \Arg{package}
% \end{syntax}
-% If \meta{package} is requested do not load it but instead run
+% If \meta{package} is requested, do not load it but instead run
% \meta{alternate-code} which could issue a warning, error or any
% other code.
%
@@ -421,7 +429,9 @@
% are not available.
%
% The function is only implemented for packages not for arbitrary
-% files.
+% files and again it should only be applied if there are good
+% reasons for doing this.\footnote{Just to be sure: \enquote{I don't
+% like this package by somebody else} is not a good one :-)}
% \end{function}
%
%
@@ -1328,7 +1338,7 @@
% \end{macro}
% \end{macro}
%
-% \begin{macro}{flag @@_file_replaced}
+% \begin{macro}{@@_file_replaced}
% \begin{macro}{\@@_if_file_replaced:TF}
% \begin{macro}{\@@_clear_replacement_flag:}
% Since the file replacement is done expandably in a \cs{csname}, use
diff --git a/macros/latex/base/ltfiles.dtx b/macros/latex/base/ltfiles.dtx
index 92a957f6c5..2e2a8884a0 100644
--- a/macros/latex/base/ltfiles.dtx
+++ b/macros/latex/base/ltfiles.dtx
@@ -32,7 +32,7 @@
%<*driver>
% \fi
\ProvidesFile{ltfiles.dtx}
- [2023/06/17 v1.2u LaTeX Kernel (File Handling)]
+ [2024/02/08 v1.2v LaTeX Kernel (File Handling)]
% \iffalse
\documentclass{ltxdoc}
\GetFileInfo{ltfiles.dtx}
@@ -1087,7 +1087,7 @@
% \texttt{-1} we ensure that we don't get a backslash in front. As a
% result we end up with all characters as catcode 12 (plus
% spaces). We then sometimes add quotes around the construct
-% (removing any existing inner quotes. Sometimes we only remove the
+% (removing any existing inner quotes). Sometimes we only remove the
% quotes if they have been supplied by the user. There is clearly
% some room for improvement.
%
@@ -1682,6 +1682,22 @@
% \end{macrocode}
% \end{macro}
%
+% \begin{macro}{\if@listfiles@hashes}
+% \changes{v1.2v}{2023/11/15}{Extend file list information}
+% \begin{macro}{\if@listfiles@sizes}
+% \changes{v1.2v}{2023/11/15}{Extend file list information}
+% \begin{macrocode}
+\ExplSyntaxOn
+\keys_define:nn { __kernel / listfiles }
+ {
+ hashes .legacy_if_set:n = @listfiles@hashes ,
+ sizes .legacy_if_set:n = @listfiles@sizes
+ }
+\ExplSyntaxOff
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
% \begin{macro}{\listfiles}
% A preamble command to cause |\end{document}| to list files input
% from the main file.
@@ -1693,8 +1709,10 @@
% {Stop \cs{listfiles} being run twice}
% \changes{v1.0i}{1994/10/18}
% {code moved here from ltclass}
+% \changes{v1.2v}{2023/11/15}{Extend file list information}
% \begin{macrocode}
-\def\listfiles{%
+\NewDocumentCommand\listfiles{O{}}{%
+ \SetKeys[__kernel/listfiles]{#1}%
\let\listfiles\relax
\def\@listfiles##1##2##3##4##5##6##7##8##9\@@{%
\def\reserved@d{\\}%
@@ -1730,9 +1748,40 @@
\filename@area\filename@base\\\\\\\\\\\\\\\\\\\@@
\typeout{%
\filename@area\reserved@a
- \ifx\reserved@b\relax\else\@spaces\reserved@b\fi}}%
+ \ifx\reserved@b\relax\else\@spaces\reserved@b\fi
+% \end{macrocode}
+% Now we add the additional information if requested.
+% \begin{macrocode}
+ \ifnum0%
+ \if@listfiles@hashes1\fi
+ \if@listfiles@sizes1\fi
+ >0 %
+ ^^J\@spaces
+ (%
+ \if@listfiles@sizes
+ size \@dofilelist@size\@currname
+ \if@listfiles@hashes
+ , %
+ \fi
+ \fi
+ \if@listfiles@hashes
+ hash \@dofilelist@hash\@currname
+ \fi
+ )%
+ \fi
+ }}%
\typeout{ ***********^^J}}}
% \end{macrocode}
+% \begin{macro}{\@dofilelist@hash}
+% \begin{macro}{\@dofilelist@size}
+% \begin{macrocode}
+\ExplSyntaxOn
+\cs_new_eq:NN \@dofilelist@hash \file_mdfive_hash:n
+\cs_new_eq:NN \@dofilelist@size \file_size:n
+\ExplSyntaxOff
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
%
% \changes{LaTeX2e}{1994/03/13}
% {Reset \cs{@addtofilelist} at begin document}
diff --git a/macros/latex/base/ltfinal.dtx b/macros/latex/base/ltfinal.dtx
index f495cd4192..648e3e1b8b 100644
--- a/macros/latex/base/ltfinal.dtx
+++ b/macros/latex/base/ltfinal.dtx
@@ -33,7 +33,7 @@
%<*driver>
% \fi
\ProvidesFile{ltfinal.dtx}
- [2023/05/30 v2.3c LaTeX Kernel (Final Settings)]
+ [2024/02/08 v2.3c LaTeX Kernel (Final Settings)]
% \iffalse
\documentclass{ltxdoc}
\GetFileInfo{ltfinal.dtx}
@@ -273,7 +273,7 @@
% \end{macro}
% \end{macro}
%
-% \begin{macro}{trace\string_stack\string_levels}
+% \begin{macro}{trace_stack_levels}
% Now define the Lua function to emulate \cs{tracingstacklevels} and
% install it in the |input_level_string| callback.
% \begin{macrocode}
@@ -1384,7 +1384,7 @@
% \end{macro}
%
% \begin{macro}{\@filelist}
-% \changes{v1.0w}{1995/10/19}{Move after \cs{reserved@a} setting:-)}
+% \changes{v1.0w}{1995/10/19}{Move after \cs{reserved@a} setting}
% \begin{macro}{\@addtofilelist}
% Reset |\@filelist| so files input while making the format are not
% listed. The list built up so far may take up a lot of memory and so
diff --git a/macros/latex/base/ltfloat.dtx b/macros/latex/base/ltfloat.dtx
index a07e5e81da..ef057def0b 100644
--- a/macros/latex/base/ltfloat.dtx
+++ b/macros/latex/base/ltfloat.dtx
@@ -31,7 +31,7 @@
%
%<*driver>
% \fi
-\ProvidesFile{ltfloat.dtx}[2021/10/14 v1.2g LaTeX Kernel (Floats)]
+\ProvidesFile{ltfloat.dtx}[2024/04/22 v1.2g LaTeX Kernel (Floats)]
% \iffalse
\documentclass{ltxdoc}
\GetFileInfo{ltfloat.dtx}
@@ -559,7 +559,7 @@
% set globally to false when they are definitely true.
%
% If anyone is unhappy with this argument then both flags should be
-% treated as in |\set@nobreak|; otherwise this command will be
+% treated as in |\@setnobreak|; otherwise this command will be
% redundant.
% \changes{v1.1p}{1996/10/24}
% {Added local settings of flags: dangerous!!}
@@ -1061,7 +1061,7 @@
% set globally to false when they are definitely true.
%
% If anyone is unhappy with this argument then both flags should be
-% treated as in |\set@nobreak|; otherwise this command will be
+% treated as in |\@setnobreak|; otherwise this command will be
% redundant.
% \changes{v1.1p}{1996/10/24}
% {Added local settings of flags: dangerous!!}
diff --git a/macros/latex/base/ltfntcmd.dtx b/macros/latex/base/ltfntcmd.dtx
index 360a4de8a4..097b8f692e 100644
--- a/macros/latex/base/ltfntcmd.dtx
+++ b/macros/latex/base/ltfntcmd.dtx
@@ -32,7 +32,7 @@
%<*driver>
% \fi
\ProvidesFile{ltfntcmd.dtx}
- [2021/09/12 v3.5a LaTeX Kernel (Font commands)]
+ [2023/12/26 v3.5a LaTeX Kernel (Font commands)]
% \iffalse
\documentclass{ltxdoc}
\GetFileInfo{ltfntcmd.dtx}
@@ -393,9 +393,9 @@
% \end{macro}
-% \begin{macro}{textulc}
-% \begin{macro}{textsw}
-% \begin{macro}{textssc}
+% \begin{macro}{\textulc}
+% \begin{macro}{\textsw}
+% \begin{macro}{\textssc}
%
% \changes{v3.4c}{2019/12/17}{Macro added}
% \begin{macrocode}
diff --git a/macros/latex/base/ltfssaxes.dtx b/macros/latex/base/ltfssaxes.dtx
index 6fefa5cee9..8b5014a4cc 100644
--- a/macros/latex/base/ltfssaxes.dtx
+++ b/macros/latex/base/ltfssaxes.dtx
@@ -28,14 +28,14 @@
% \fi
% \iffalse
%%% From File: ltfssaxes.dtx
-%% Copyright (C) 1999-2020 Frank Mittelbach
+%% Copyright (C) 2019-2020 Frank Mittelbach
%
%<*driver>
% \fi
%
%
\ProvidesFile{ltfssaxes.dtx}
- [2023/10/30 v1.0i LaTeX Kernel (NFSS Axes handing)]
+ [2024/02/08 v1.0i LaTeX Kernel (NFSS Axes handing)]
% \iffalse
\documentclass{ltxdoc}
\begin{document}
@@ -1087,7 +1087,7 @@
%
% Shapes are also split in two axes (though it could be more if
% that is desirable), essentially building in an ``sc''
-% axis).
+% axis.
%
% \begin{macrocode}
%<*2ekernel|latexrelease>
@@ -1118,7 +1118,7 @@
% resets everything and \texttt{up} changes italic or slanted to
% upright and \texttt{ulc} undoes small caps.
%
-% So we now offer \cs{normalshape} (using \cs{shapedefault} which
+% So we now offer \cs{normalshape} (using \cs{shapedefault}) which
% is normally the same as calling both \cs{ulcshape} and
% \cs{upshape}, only more efficient.
%
@@ -1494,7 +1494,7 @@
% provide. So its redefinitions for the various shape commands,
% such as \cs{itshape} should no longer happen. We therefore force
% the standard definitions at \cs{AtBeginDocument} (later when this
-% is defined. Once
+% is defined). Once
% \texttt{fontaxes} is no longer doing such redefinitions that could
% be taken out again.
%
diff --git a/macros/latex/base/ltfssbas.dtx b/macros/latex/base/ltfssbas.dtx
index eaea328dac..df02a5749a 100644
--- a/macros/latex/base/ltfssbas.dtx
+++ b/macros/latex/base/ltfssbas.dtx
@@ -35,7 +35,7 @@
%
%
\ProvidesFile{ltfssbas.dtx}
- [2023/10/21 v3.2l LaTeX Kernel (NFSS Basic Macros)]
+ [2024/02/08 v3.2l LaTeX Kernel (NFSS Basic Macros)]
% \iffalse
\documentclass{ltxdoc}
\begin{document}
@@ -962,7 +962,7 @@
% case, however, we also need the value of |\baselineskip|. As the
% first argument to |\set@fontsize| we pass the current value of
% |\baselinestretch|. This will either match the internal value (in
-% which case nothing changes, or it will be an updated value due to
+% which case nothing changes) or it will be an updated value due to
% a user change of that macro using |\renewcommand|. If we would
% pass the internal |\f@linespread| such a change would be
% effectively overwritten by a size change.
diff --git a/macros/latex/base/ltfssini.dtx b/macros/latex/base/ltfssini.dtx
index 273ed4babd..255abe03f3 100644
--- a/macros/latex/base/ltfssini.dtx
+++ b/macros/latex/base/ltfssini.dtx
@@ -36,7 +36,7 @@
%
%
\ProvidesFile{ltfssini.dtx}
- [2021/09/10 v3.2i LaTeX Kernel (NFSS Initialisation)]
+ [2024/02/08 v3.2i LaTeX Kernel (NFSS Initialisation)]
% \iffalse
\documentclass{ltxdoc}
\begin{document}
@@ -864,7 +864,7 @@
%
% 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
+% (i.e., via \cs{def} or \cs{renewcommand}). In that case we reset
% all meta family defaults so that the document behaves like it was
% the case before the new mechanism was introduced.
% \changes{v3.1k}{2020/03/19}{Support legacy use of \cs{bfdefault}
@@ -885,7 +885,7 @@
\let\bfdefault@previous\bfdefault
% \end{macrocode}
% And we reset the meta family defaults (\cs{bfdef@ult} is an
-% expanded version of \cs{bfdefault}.
+% expanded version of \cs{bfdefault}).
% \begin{macrocode}
\let\bfseries@rm\bfdef@ult
\let\bfseries@sf\bfdef@ult
@@ -1661,8 +1661,8 @@
% \begin{macrocode}
\def\emfontdeclare@clist{#2,#1}%
% \end{macrocode}
-% Then we execute current declaration. Appending |\selectfont| means one
-% can write just |\fontshape{it}}| and that works then too.
+% Then we execute the current declaration. Appending |\selectfont| means one
+% can write just |\fontshape{it}| and that works then too.
% \begin{macrocode}
% \typeout{Use: \detokenize{#1}}%
#1\selectfont
diff --git a/macros/latex/base/ltfsstrc.dtx b/macros/latex/base/ltfsstrc.dtx
index f5dc2ad589..4f0e43021a 100644
--- a/macros/latex/base/ltfsstrc.dtx
+++ b/macros/latex/base/ltfsstrc.dtx
@@ -37,7 +37,7 @@
%<package> [2020/12/22 v3.0n Standard LaTeX package (font tracing)]
% \fi
% \ProvidesFile{ltfsstrc.dtx}
-% [2021/04/26 v3.0o LaTeX Kernel (NFSS tracing)]
+% [2024/02/08 v3.0o LaTeX Kernel (NFSS tracing)]
%
% \iffalse
%<+checkmem>\CHECKMEM
@@ -125,7 +125,7 @@
%
% \item[debugshow] In addition to \texttt{infoshow} show also
% changing of math fonts as far as possible (this option can produce a
-% large amount of output.
+% large amount of output).
%
% \item[loading] Show the name of external fonts when they are
% loaded. This option shows only ``newly'' loaded fonts not those
@@ -489,8 +489,8 @@
\let\f@shape@saved\f@shape
\let\f@series@saved\f@series
% \end{macrocode}
-% The we run the delayed adjustments (which is using the
-% \cs{..@without@substitution} commands
+% Then we run the delayed adjustments (which use the
+% \cs{..@without@substitution} commands):
% \begin{macrocode}
\delayed@f@adjustment
% \end{macrocode}
@@ -863,14 +863,15 @@
%
% \TeX{} uses the math fonts that are current when the end of a
% formula is reached. If we don't want to keep font setups local to
-% every formula (which would result in an enormous overhead, we have
+% every formula (which would result in an enormous overhead), we have
% to be careful not to end up with the wrong setup in case formulas
% are nested, e.g., we need to be able to handle
% \begin{verbatim}
% $ a=b+c \mbox{ \small for all $b$ and $c\in Z$}$
%\end{verbatim}
% Here the inner formulae |b| and |c\in Z| are typeset in |\small| but
-% we have to return to |\normalsize| before we reach the closing |$|
+% we have to return to |\normalsize| before we reach the
+% closing |$| \iffalse$\fi
% of the outer formula.
%
% This is handled in the following way:
@@ -1042,8 +1043,8 @@
% If so we first call the `=' macro (i.e.\ argument three) to set
% up special things for the selected math group. Then we call
% |\mathgroup| to select the group given by argument two and
-% finally we place |#1| (i.e.\ the argument of the \meta{math
-% alphabet identifier} at the end. This part of the code is
+% finally we place |#1| (i.e., the argument of the \meta{math
+% alphabet identifier}) at the end. This part of the code is
% surrounded by two commands which behave like |\begingroup|
% and |\endgroup| if we want \meta{math alphabet identifier}s
% but will expand into |\@empty| if we want simply switches to
@@ -1081,7 +1082,7 @@
% \begin{macro}{\math@egroup}
% \changes{v1.0q}{1990/07/07}{Tracing code added.} If the
% \texttt{margid} option is in force (which can be tested by
-% looking at the definition of |\math@bgroup| we change the
+% looking at the definition of |\math@bgroup|) we change the
% |\math@egroup| command a bit to display the current \meta{math
% group number} after it closes the scope of \meta{math alphabet}
% with |\endgroup|.
@@ -1385,7 +1386,7 @@
% It looks for font ranges with font size functions. It's operation
% is rather simple: it discards everything up to the next size
% specification and passes this on to |\is@range| for inspection.
-% The specification (parameter |#2| is inserted again, in case
+% The specification (parameter |#2|) is inserted again, in case
% it is needed later.
% \begin{macrocode}
\def\extract@rangefontinfo#1<#2>{%
@@ -1402,7 +1403,7 @@
%
% From the way |\is@range| is called inside |\extract@rangefontinfo|
% we see that |#2| is the character |>| if the size specification
-% found is a simple one (as it does not contain a |-| character.
+% found is a simple one (that does not contain a |-| character).
% This is checked easily enough and |\extract@rangefontinfo|
% called again. Note that the extra tokens inserted after the
% |\@nil| in the call to |\is@range| appear at the beginning of
diff --git a/macros/latex/base/lthooks-code.pdf b/macros/latex/base/lthooks-code.pdf
index 66ed34cff6..b1700b92bc 100644
--- a/macros/latex/base/lthooks-code.pdf
+++ b/macros/latex/base/lthooks-code.pdf
Binary files differ
diff --git a/macros/latex/base/lthooks-doc.pdf b/macros/latex/base/lthooks-doc.pdf
index 6a62d5fef3..dc25384519 100644
--- a/macros/latex/base/lthooks-doc.pdf
+++ b/macros/latex/base/lthooks-doc.pdf
Binary files differ
diff --git a/macros/latex/base/lthooks.dtx b/macros/latex/base/lthooks.dtx
index 446cdaae06..d282ff841c 100644
--- a/macros/latex/base/lthooks.dtx
+++ b/macros/latex/base/lthooks.dtx
@@ -27,17 +27,16 @@
% \fi
%
% \iffalse
-%
%%% From File: lthooks.dtx
%
-% \begin{macrocode}
-\def\lthooksversion{v1.1f}
-\def\lthooksdate{2023/10/02}
-% \end{macrocode}
-%
%<*driver>
+% \fi
+\ProvidesFile{lthooks.dtx}
+ [2024/04/22 v1.1h LaTeX Kernel (hooks)]
+% \iffalse
+%
\documentclass{l3doc}
-
+\GetFileInfo{lthooks.dtx}
\providecommand\InternalDetectionOff{}
\providecommand\InternalDetectionOn{}
@@ -62,7 +61,7 @@
%
%
% \title{\LaTeX{}'s hook management\thanks{This module has version
-% \lthooksversion\ dated \lthooksdate, \copyright\ \LaTeX\
+% \fileversion\ dated \filedate, \copyright\ \LaTeX\
% Project.}}
%
% \author{Frank Mittelbach\thanks{Code improvements for speed and other goodies by Phelype Oleinik}}
@@ -160,7 +159,7 @@
% \end{function}
%
%
-% \begin{function}{\NewHookWithArguments}
+% \begin{function}[added=2023-06-01]{\NewHookWithArguments}
% \begin{syntax}
% \cs{NewHookWithArguments} \Arg{hook} \Arg{number}
% \end{syntax}
@@ -172,7 +171,7 @@
% the current package name. See section~\ref{sec:default-label}.
% \end{function}
%
-% \begin{function}{\NewReversedHookWithArguments}
+% \begin{function}[added=2023-06-01]{\NewReversedHookWithArguments}
% \begin{syntax}
% \cs{NewReversedHookWithArguments} \Arg{hook} \Arg{number}
% \end{syntax}
@@ -184,7 +183,7 @@
% the current package name. See section~\ref{sec:default-label}.
% \end{function}
%
-% \begin{function}{\NewMirroredHookPairWithArguments}
+% \begin{function}[added=2023-06-01]{\NewMirroredHookPairWithArguments}
% \begin{syntax}
% \cs{NewMirroredHookPairWithArguments} \Arg{hook-1} \Arg{hook-2} \Arg{number}
% \end{syntax}
@@ -234,9 +233,9 @@
% (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.
%
+% Note that this command does not undo the effect of \cs{DisableGenericHook}.
% See section~\ref{sec:generic-hooks} for a discussion of when this
% declaration is appropriate.
% \end{function}
@@ -264,7 +263,7 @@
% A leading |.| is treated literally.
% \end{function}
%
-% \begin{function}{\UseHookWithArguments}
+% \begin{function}[added=2023-06-01]{\UseHookWithArguments}
% \begin{syntax}
% \cs{UseHookWithArguments} \Arg{hook} \Arg{number} \Arg{arg_1} \ldots \Arg{arg_n}
% \end{syntax}
@@ -314,7 +313,7 @@
%
% \end{function}
%
-% \begin{function}{\UseOneTimeHookWithArguments}
+% \begin{function}[added=2023-06-01]{\UseOneTimeHookWithArguments}
% \begin{syntax}
% \cs{UseOneTimeHookWithArguments} \Arg{hook} \Arg{number} \Arg{arg_1} \ldots \Arg{arg_n}
% \end{syntax}
@@ -340,7 +339,7 @@
%
% \begin{function}{\AddToHook}
% \begin{syntax}
-% \cs{AddToHook} \Arg{hook}\oarg{label}\Arg{code}
+% \cs{AddToHook} \Arg{hook} \oarg{label} \Arg{code}
% \end{syntax}
% Adds \meta{code} to the \meta{hook} labeled by \meta{label}.
% When the optional argument \meta{label} is not provided, the
@@ -368,9 +367,9 @@
% See section~\ref{sec:default-label}.
% \end{function}
%
-% \begin{function}{\AddToHookWithArguments}
+% \begin{function}[added=2023-06-01]{\AddToHookWithArguments}
% \begin{syntax}
-% \cs{AddToHookWithArguments} \Arg{hook}\oarg{label}\Arg{code}
+% \cs{AddToHookWithArguments} \Arg{hook} \oarg{label} \Arg{code}
% \end{syntax}
% Works exactly like \cs{AddToHook}, except that the \meta{code} can
% access the arguments passed to the hook using \verb|#1|, \verb|#2|,
@@ -398,7 +397,7 @@
%
% \begin{function}{\RemoveFromHook}
% \begin{syntax}
-% \cs{RemoveFromHook} \Arg{hook}\oarg{label}
+% \cs{RemoveFromHook} \Arg{hook} \oarg{label}
% \end{syntax}
% Removes any code labeled by \meta{label} from the \meta{hook}.
% When the optional argument \meta{label} is not provided, the
@@ -459,7 +458,7 @@
%
% \begin{function}{\AddToHookNext}
% \begin{syntax}
-% \cs{AddToHookNext} \Arg{hook}\Arg{code}
+% \cs{AddToHookNext} \Arg{hook} \Arg{code}
% \end{syntax}
% Adds \meta{code} to the next invocation of the \meta{hook}.
% The code is executed after the normal hook code has finished and
@@ -505,9 +504,9 @@
% \end{function}\footnotetext{There is
% no mechanism to reorder such code chunks (or delete them).}
%
-% \begin{function}{\AddToHookNextWithArguments}
+% \begin{function}[added=2023-06-01]{\AddToHookNextWithArguments}
% \begin{syntax}
-% \cs{AddToHookNextWithArguments} \Arg{hook}\Arg{code}
+% \cs{AddToHookNextWithArguments} \Arg{hook} \Arg{code}
% \end{syntax}
% Works exactly like \cs{AddToHookNext}, but the \meta{code} can
% contain references to the arguments of the \meta{hook} as described
@@ -522,7 +521,7 @@
%
% \begin{function}{\ClearHookNext}
% \begin{syntax}
-% \cs{ClearHookNext}\Arg{hook}
+% \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
@@ -746,7 +745,7 @@
%
% \begin{function}{\DeclareHookRule}
% \begin{syntax}
-% \cs{DeclareHookRule} \Arg{hook}\Arg{label1}\Arg{relation}\Arg{label2}
+% \cs{DeclareHookRule} \Arg{hook} \Arg{label1} \Arg{relation} \Arg{label2}
% \end{syntax}
% Defines a relation between \meta{label1} and \meta{label2} for a
% given \meta{hook}. If \meta{hook} is \texttt{??} this defines a default
@@ -807,7 +806,7 @@
%
% \begin{function}{\ClearHookRule}
% \begin{syntax}
-% \cs{ClearHookRule}\Arg{hook}\Arg{label1}\Arg{label2}
+% \cs{ClearHookRule} \Arg{hook} \Arg{label1} \Arg{label2}
% \end{syntax}
% Syntactic sugar for saying that \meta{label1} and \meta{label2}
% are unrelated for the given \meta{hook}.
@@ -817,7 +816,7 @@
%
% \begin{function}{\DeclareDefaultHookRule}
% \begin{syntax}
-% \cs{DeclareDefaultHookRule}\Arg{label1}\Arg{relation}\Arg{label2}
+% \cs{DeclareDefaultHookRule} \Arg{label1} \Arg{relation} \Arg{label2}
% \end{syntax}
% This sets up a relation between \meta{label1} and \meta{label2}
% for all hooks unless overwritten by a specific rule for a hook.
@@ -1004,7 +1003,7 @@
%
% \begin{function}{\DebugHooksOn,\DebugHooksOff}
% \begin{syntax}
-% \cs{DebugHooksOn}
+% \cs{DebugHooksOn} \ldots\ \cs{DebugHooksOff}
% \end{syntax}
% Turn the debugging of hook code on or off. This displays most changes
% made to the hook data structures. The output is rather coarse and
@@ -1044,7 +1043,7 @@
% the current package name. See section~\ref{sec:default-label}.
% \end{function}
%
-% \begin{function}{
+% \begin{function}[added=2023-06-01]{
% \hook_new_with_args:nn,
% \hook_new_reversed_with_args:nn,
% \hook_new_pair_with_args:nnn
@@ -1100,9 +1099,14 @@
%
%
%
-% \begin{function}{\hook_use:n,\hook_use:nnw}
+% \begin{function}{\hook_use:n}
+% \begin{syntax}
+% ~~\cs{hook_use:n} \Arg{hook}
+% \end{syntax}
+% \end{function}
+% \vskip-1.2\baselineskip
+% \begin{function}[added=2023-06-01]{\hook_use:nnw}
% \begin{syntax}
-% \cs{hook_use:n} \Arg{hook}
% \cs{hook_use:nnw} \Arg{hook} \Arg{number} \Arg{arg_1} \ldots \Arg{arg_n}
% \end{syntax}
% Executes the \Arg{hook} code followed (if set up) by the code for next
@@ -1118,9 +1122,14 @@
% A leading |.| is treated literally.
% \end{function}
%
-% \begin{function}{\hook_use_once:n,\hook_use_once:nnw}
+% \begin{function}{\hook_use_once:n}
% \begin{syntax}
% \cs{hook_use_once:n} \Arg{hook}
+% \end{syntax}
+% \end{function}
+% \vskip-1.2\baselineskip
+% \begin{function}[added=2023-06-01]{\hook_use_once:nnw}
+% \begin{syntax}
% \cs{hook_use_once:nnw} \Arg{hook} \Arg{number} \Arg{arg_1} \ldots \Arg{arg_n}
% \end{syntax}
% Changes the \Arg{hook} status so that from now on any addition to
@@ -1139,10 +1148,16 @@
%
% \begin{function}{
% \hook_gput_code:nnn,
+% }
+% \begin{syntax}
+% ~~~~~~~~~\cs{hook_gput_code:nnn} \Arg{hook} \Arg{label} \Arg{code}
+% \end{syntax}
+% \end{function}
+% \vskip -1.2\baselineskip
+% \begin{function}[added=2023-06-01]{
% \hook_gput_code_with_args:nnn
% }
% \begin{syntax}
-% \cs{hook_gput_code:nnn} \Arg{hook} \Arg{label} \Arg{code}
% \cs{hook_gput_code_with_args:nnn} \Arg{hook} \Arg{label} \Arg{code}
% \end{syntax}
% Adds a chunk of \meta{code} to the \meta{hook} labeled
@@ -1168,10 +1183,17 @@
%
% \begin{function}{
% \hook_gput_next_code:nn,
+% }
+% \begin{syntax}
+% ~~~~~~~~~~~~~\cs{hook_gput_next_code:nn} \Arg{hook} \Arg{code}
+% \end{syntax}
+% \end{function}
+% \vskip-1.2\baselineskip
+% \begin{function}[added=2023-06-01]{
% \hook_gput_next_code_with_args:nn,
% }
% \begin{syntax}
-% \cs{hook_gput_next_code:nn} \Arg{hook} \Arg{code}
+% \cs{hook_gput_next_code_with_args:nn} \Arg{hook} \Arg{code}
% \end{syntax}
% Adds a chunk of \meta{code} for use only in the next invocation of the
% \meta{hook}. Once used it is gone.
@@ -1183,6 +1205,7 @@
% In that case, if an actual parameter token should be added to the
% code, it should be doubled.
%
+% \end{function}
% This is simpler than \cs{hook_gput_code:nnn}, the code is simply
% appended to the hook in the order of declaration at the very end,
% i.e., after all standard code for the hook got executed.
@@ -1191,7 +1214,6 @@
%
% The \meta{hook} can be specified using the dot-syntax to denote
% the current package name. See section~\ref{sec:default-label}.
-% \end{function}
%
%
% \begin{function}{\hook_gclear_next_code:n}
@@ -1527,7 +1549,7 @@
% \hook{cmd},
% \hook{env},
% \hook{file},
-% \hook{include}
+% \hook{include},
% \hook{package}, and
% \hook{class},
% and all these are available out of the box: you only have to
@@ -1862,15 +1884,17 @@
% \item[\hook{env/\meta{env}/begin}]
%
% This hook is executed as part of \cs{begin} directly in front
-% of the code specific to the environment start (e.g., the
-% second argument of \cs{newenvironment}). Its scope is the
-% environment body.
+% of the code specific to the environment start (e.g.,
+% the third argument of \cs{NewDocumentEnvironment} and
+% the second argument of \cs{newenvironment}).
+% Its scope is the environment body.
%
% \item[\hook{env/\meta{env}/end}]
%
% This hook is executed as part of \cs{end} directly in front of the
-% code specific to the end of the environment (e.g., the third
-% argument of \cs{newenvironment}).
+% code specific to the end of the environment (e.g.,
+% the forth argument of \cs{NewDocumentEnvironment} and
+% the third argument of \cs{newenvironment}).
%
% \item[\hook{env/\meta{env}/after}]
%
@@ -2701,7 +2725,7 @@
% \hook_new:n,
% \hook_new_with_args:nn
% }
-% \begin{macro}{@@_new:nn}
+% \begin{macro}{\@@_new:nn}
% The \cs{hook_new:n} declaration declares a new hook and expects
% the hook \meta{name} as its argument, e.g.,
% \hook{begindocument}.
@@ -3509,7 +3533,8 @@
\msg_error:nnnnn { hooks } { set-top-level }
{ for } { SetDefaultHookLabel } {#1}
}
- { \exp_args:Nx \@@_set_default_label:n { \@@_make_name:n {#1} } }
+ { \exp_args:Nx
+ \@@_set_default_label:n { \@@_make_name:n {#1} } }
}
\cs_new_protected:Npn \@@_set_default_label:n #1
{
@@ -3722,7 +3747,8 @@
%<latexrelease>\IncludeInRelease{2020/10/01}{\hook_gput_code:nnn}
%<latexrelease> {Providing~hooks}
%<latexrelease>\cs_gset_protected:Npn \hook_gput_code:nnn #1 #2
-%<latexrelease> { \@@_normalize_hook_args:Nnn \@@_gput_code:nnn {#1} {#2} }
+%<latexrelease> { \@@_normalize_hook_args:Nnn
+%<latexrelease> \@@_gput_code:nnn {#1} {#2} }
%<latexrelease>\cs_gset_protected:Npn \@@_gput_code:nnn #1 #2 #3
%<latexrelease> {
%<latexrelease> \@@_if_execute_immediately:nTF {#1}
@@ -3736,7 +3762,8 @@
%<latexrelease> {
%<latexrelease> \@@_if_disabled:nTF {#1}
%<latexrelease> { \msg_error:nnn { hooks } { hook-disabled } {#1} }
-%<latexrelease> { \@@_try_declaring_generic_hook:nnn {#1} {#2} {#3} }
+%<latexrelease> { \@@_try_declaring_generic_hook:nnn
+%<latexrelease> {#1} {#2} {#3} }
%<latexrelease> }
%<latexrelease> }
%<latexrelease> }
@@ -3748,7 +3775,8 @@
%<latexrelease> \on@line\space <-~ \tl_to_str:n{#3}} }
%<latexrelease> \str_if_eq:nnTF {#2} { top-level }
%<latexrelease> {
-%<latexrelease> \str_if_eq:eeTF { top-level } { \@@_currname_or_default: }
+%<latexrelease> \str_if_eq:eeTF { top-level }
+%<latexrelease> { \@@_currname_or_default: }
%<latexrelease> {
%<latexrelease> \@@_init_structure:n {#1}
%<latexrelease> \@@_tl_gput_right:cn { @@_toplevel~#1 } {#3}
@@ -3756,7 +3784,8 @@
%<latexrelease> { \msg_error:nnn { hooks } { misused-top-level } {#1} }
%<latexrelease> }
%<latexrelease> {
-%<latexrelease> \prop_get:cnNTF { g_@@_#1_code_prop } {#2} \l_@@_return_tl
+%<latexrelease> \prop_get:cnNTF
+%<latexrelease> { g_@@_#1_code_prop } {#2} \l_@@_return_tl
%<latexrelease> {
%<latexrelease> \prop_gput:cno { g_@@_#1_code_prop } {#2}
%<latexrelease> { \l_@@_return_tl #3 }
@@ -3840,7 +3869,8 @@
% \changes{v1.1d}{2023/05/21}
% {Changes to allow support arguments in cmd hooks (cmd-args).}
% \begin{macrocode}
-%<latexrelease>\IncludeInRelease{2023/06/01}{\@@_try_declaring_generic_hook:nnn}
+%<latexrelease>\IncludeInRelease{2023/06/01}
+%<latexrelease> {\@@_try_declaring_generic_hook:nnn}
%<latexrelease> {Hooks~with~args}
\cs_new_protected:Npn \@@_try_declaring_generic_hook:nnn #1
{
@@ -3857,31 +3887,38 @@
{#1}
}
%<latexrelease>\EndIncludeInRelease
-%<latexrelease>\IncludeInRelease{2021/11/15}{\@@_try_declaring_generic_hook:nnn}
+%<latexrelease>\IncludeInRelease{2021/11/15}
+%<latexrelease> {\@@_try_declaring_generic_hook:nnn}
%<latexrelease> {Standardise~generic~hook~names}
%<latexrelease>\cs_gset_protected:Npn \@@_try_declaring_generic_hook:nnn #1
%<latexrelease> {
-%<latexrelease> \@@_try_declaring_generic_hook:wnTF #1 / / / \scan_stop: {#1}
+%<latexrelease> \@@_try_declaring_generic_hook:wnTF #1 / / / \scan_stop:
+%<latexrelease> {#1}
%<latexrelease> \hook_gput_code:nnn
%<latexrelease> \@@_gput_undeclared_hook:nnn
%<latexrelease> {#1}
%<latexrelease> }
-%<latexrelease>\cs_gset_protected:Npn \@@_try_declaring_generic_next_hook:nn #1
+%<latexrelease>\cs_gset_protected:Npn
+%<latexrelease> \@@_try_declaring_generic_next_hook:nn #1
%<latexrelease> {
-%<latexrelease> \@@_try_declaring_generic_hook:wnTF #1 / / / \scan_stop: {#1}
+%<latexrelease> \@@_try_declaring_generic_hook:wnTF #1 / / / \scan_stop:
+%<latexrelease> {#1}
%<latexrelease> \hook_gput_next_code:nn
%<latexrelease> \@@_gput_next_do:nn
%<latexrelease> {#1}
%<latexrelease> }
%<latexrelease>\EndIncludeInRelease
-%<latexrelease>\IncludeInRelease{2020/10/01}{\@@_try_declaring_generic_hook:nnn}
+%<latexrelease>\IncludeInRelease{2020/10/01}
+%<latexrelease> {\@@_try_declaring_generic_hook:nnn}
%<latexrelease> {Standardise~generic~hook~names}
-%<latexrelease>\cs_new_protected:Npn \@@_try_declaring_generic_hook:nnn #1
+%<latexrelease>\cs_new_protected:Npn
+%<latexrelease> \@@_try_declaring_generic_hook:nnn #1
%<latexrelease> {
%<latexrelease> \@@_try_declaring_generic_hook:nNNnn {#1}
%<latexrelease> \hook_gput_code:nnn \@@_gput_undeclared_hook:nnn
%<latexrelease> }
-%<latexrelease>\cs_new_protected:Npn \@@_try_declaring_generic_next_hook:nn #1
+%<latexrelease>\cs_new_protected:Npn
+%<latexrelease> \@@_try_declaring_generic_next_hook:nn #1
%<latexrelease> {
%<latexrelease> \@@_try_declaring_generic_hook:nNNnn {#1}
%<latexrelease> \hook_gput_next_code:nn \@@_gput_next_do:nn
@@ -3904,12 +3941,15 @@
%
% \changes{v1.0s}{2021/09/28}
% {Correct usage of older \cs{@@_if_file_hook:wTF} (gh/675)}
+% \changes{v1.1h}{2024/01/24}
+% {Correct usage of older \cs{@@_if_file_hook:wTF} (gh/1243)}
% \begin{macrocode}
%<latexrelease>\cs_new_protected:Npn \@@_try_declaring_generic_hook:nNNnn #1
%<latexrelease> {
-%<latexrelease> \@@_if_file_hook:wTF #1 / \s_@@_mark
+%<latexrelease> \@@_if_file_hook:wTF #1 / / \s_@@_mark
%<latexrelease> {
-%<latexrelease> \exp_args:Ne \@@_try_declaring_generic_hook_split:nNNnn
+%<latexrelease> \exp_args:Ne
+%<latexrelease> \@@_try_declaring_generic_hook_split:nNNnn
%<latexrelease> { \exp_args:Ne \@@_file_hook_normalize:n {#1} }
%<latexrelease> }
%<latexrelease> { \@@_try_declaring_generic_hook_split:nNNnn {#1} }
@@ -3917,9 +3957,11 @@
% \end{macrocode}
%
% \begin{macrocode}
-%<latexrelease>\cs_new_protected:Npn \@@_try_declaring_generic_hook_split:nNNnn #1 #2 #3
+%<latexrelease>\cs_new_protected:Npn
+%<latexrelease> \@@_try_declaring_generic_hook_split:nNNnn #1 #2 #3
%<latexrelease> {
-%<latexrelease> \@@_try_declaring_generic_hook:wnTF #1 / / / \scan_stop: {#1}
+%<latexrelease> \@@_try_declaring_generic_hook:wnTF #1 / / / \scan_stop:
+%<latexrelease> {#1}
%<latexrelease> { #2 }
%<latexrelease> { #3 } {#1}
%<latexrelease> }
@@ -3931,9 +3973,11 @@
% \changes{v1.1a}{2023/04/06}
% {Changes to add hook arguments (hook-args).}
% \begin{macrocode}
-%<latexrelease>\IncludeInRelease{2023/06/01}{\@@_try_declaring_generic_hook:wn}
+%<latexrelease>\IncludeInRelease{2023/06/01}
+%<latexrelease> {\@@_try_declaring_generic_hook:wn}
%<latexrelease> {Hooks~with~args}
-\prg_new_protected_conditional:Npnn \@@_try_declaring_generic_hook:wn
+\prg_new_protected_conditional:Npnn
+ \@@_try_declaring_generic_hook:wn
#1 / #2 / #3 / #4 \scan_stop: #5 { TF }
{
\@@_if_generic:nTF {#5}
@@ -4052,9 +4096,11 @@
% \end{macro}
%
% \begin{macrocode}
-%<latexrelease>\IncludeInRelease{2021/11/15}{\@@_try_declaring_generic_hook:wn}
+%<latexrelease>\IncludeInRelease{2021/11/15}
+%<latexrelease> {\@@_try_declaring_generic_hook:wn}
%<latexrelease> {Standardise~generic~hook~names}
-%<latexrelease>\prg_new_protected_conditional:Npnn \@@_try_declaring_generic_hook:wn
+%<latexrelease>\prg_new_protected_conditional:Npnn
+%<latexrelease> \@@_try_declaring_generic_hook:wn
%<latexrelease> #1 / #2 / #3 / #4 \scan_stop: #5 { TF }
%<latexrelease> {
%<latexrelease> \@@_if_generic:nTF {#5}
@@ -4083,9 +4129,11 @@
% \end{macrocode}
%
% \begin{macrocode}
-%<latexrelease>\IncludeInRelease{2021/06/01}{\@@_try_declaring_generic_hook:wn}
+%<latexrelease>\IncludeInRelease{2021/06/01}
+%<latexrelease> {\@@_try_declaring_generic_hook:wn}
%<latexrelease> {Support~cmd~hooks}
-%<latexrelease>\prg_new_protected_conditional:Npnn \@@_try_declaring_generic_hook:wn
+%<latexrelease>\prg_new_protected_conditional:Npnn
+%<latexrelease> \@@_try_declaring_generic_hook:wn
%<latexrelease> #1 / #2 / #3 / #4 \scan_stop: #5 { TF }
%<latexrelease> {
%<latexrelease> \tl_if_empty:nTF {#2}
@@ -4099,10 +4147,12 @@
%<latexrelease> { \@@_try_put_cmd_hook:n {#5} }
%<latexrelease> \@@_make_usable:n {#5}
%<latexrelease> }
-%<latexrelease> \prop_if_in:NnTF \c_@@_generics_reversed_ii_prop {#2}
+%<latexrelease> \prop_if_in:NnTF
+%<latexrelease> \c_@@_generics_reversed_ii_prop {#2}
%<latexrelease> { \tl_gset:cn { g_@@_#5_reversed_tl } { - } }
%<latexrelease> {
-%<latexrelease> \prop_if_in:NnT \c_@@_generics_reversed_iii_prop {#3}
+%<latexrelease> \prop_if_in:NnT
+%<latexrelease> \c_@@_generics_reversed_iii_prop {#3}
%<latexrelease> { \tl_gset:cn { g_@@_#5_reversed_tl } { - } }
%<latexrelease> }
%<latexrelease> \prg_return_true:
@@ -4114,9 +4164,11 @@
% \end{macrocode}
%
% \begin{macrocode}
-%<latexrelease>\IncludeInRelease{2020/10/01}{\@@_try_declaring_generic_hook:wn}
+%<latexrelease>\IncludeInRelease{2020/10/01}
+%<latexrelease> {\@@_try_declaring_generic_hook:wn}
%<latexrelease> {Support~cmd~hooks}
-%<latexrelease>\prg_new_protected_conditional:Npnn \@@_try_declaring_generic_hook:wn
+%<latexrelease>\prg_new_protected_conditional:Npnn
+%<latexrelease> \@@_try_declaring_generic_hook:wn
%<latexrelease> #1 / #2 / #3 / #4 \scan_stop: #5 { TF }
%<latexrelease> {
%<latexrelease> \tl_if_empty:nTF {#2}
@@ -4125,10 +4177,12 @@
%<latexrelease> \prop_if_in:NnTF \c_@@_generics_prop {#1}
%<latexrelease> {
%<latexrelease> \@@_if_declared:nF {#5} { \hook_new:n {#5} }
-%<latexrelease> \prop_if_in:NnTF \c_@@_generics_reversed_ii_prop {#2}
+%<latexrelease> \prop_if_in:NnTF
+%<latexrelease> \c_@@_generics_reversed_ii_prop {#2}
%<latexrelease> { \tl_gset:cn { g_@@_#5_reversed_tl } { - } }
%<latexrelease> {
-%<latexrelease> \prop_if_in:NnT \c_@@_generics_reversed_iii_prop {#3}
+%<latexrelease> \prop_if_in:NnT
+%<latexrelease> \c_@@_generics_reversed_iii_prop {#3}
%<latexrelease> { \tl_gset:cn { g_@@_#5_reversed_tl } { - } }
%<latexrelease> }
%<latexrelease> \prg_return_true:
@@ -4204,11 +4258,11 @@
% \changes{v1.0h}{2021/01/07}{Assume hook name has at least three
% nonempty parts (gh/464)}
% \begin{macrocode}
-%<latexrelease>\cs_new:Npn \@@_strip_double_slash:w #1/#2/#3 // #4 \s_@@_mark
+%<latexrelease>\cs_new:Npn \@@_strip_double_slash:w #1/#2/#3//#4\s_@@_mark
%<latexrelease> {
%<latexrelease> \tl_if_empty:nTF {#4}
%<latexrelease> { #1/#2/#3 }
-%<latexrelease> { \@@_strip_double_slash:w #1/#2/#3 / #4 \s_@@_mark }
+%<latexrelease> { \@@_strip_double_slash:w #1/#2/#3 /#4\s_@@_mark }
%<latexrelease> }
%<latexrelease>\EndIncludeInRelease
% \end{macrocode}
@@ -4287,9 +4341,12 @@
% \begin{macrocode}
%<latexrelease>\IncludeInRelease{2020/10/01}{\c_@@_generics_reversed_ii_prop}
%<latexrelease> {Standardise~generic~hook~names}
-%<latexrelease>\prop_const_from_keyval:Nn \c_@@_generics_reversed_ii_prop {after=,end=}
-%<latexrelease>\prop_const_from_keyval:Nn \c_@@_generics_reversed_iii_prop {after=}
-%<latexrelease>\prop_const_from_keyval:Nn \c_@@_generics_file_prop {before=,after=}
+%<latexrelease>\prop_const_from_keyval:Nn
+%<latexrelease> \c_@@_generics_reversed_ii_prop {after=,end=}
+%<latexrelease>\prop_const_from_keyval:Nn
+%<latexrelease> \c_@@_generics_reversed_iii_prop {after=}
+%<latexrelease>\prop_const_from_keyval:Nn
+%<latexrelease> \c_@@_generics_file_prop {before=,after=}
%<latexrelease>\EndIncludeInRelease
% \end{macrocode}
% \end{macro}
@@ -4369,7 +4426,8 @@
\str_if_eq:nnTF {#2} { top-level }
{ \@@_toplevel_gset:nn {#1} { } }
{
- \prop_gpop:cnNF { g_@@_#1_code_prop } {#2} \l_@@_return_tl
+ \prop_gpop:cnNF { g_@@_#1_code_prop }
+ {#2} \l_@@_return_tl
{ \msg_warning:nnnn { hooks } { cannot-remove } {#1} {#2} }
}
}
@@ -4387,7 +4445,8 @@
\@@_if_deprecated_generic:nTF {#1}
{
\@@_deprecated_generic_warn:n {#1}
- \@@_do_deprecated_generic:Nn \@@_gremove_code:nn {#1} {#2}
+ \@@_do_deprecated_generic:Nn
+ \@@_gremove_code:nn {#1} {#2}
}
{ \msg_warning:nnnn { hooks } { cannot-remove } {#1} {#2} }
}
@@ -4412,8 +4471,10 @@
%<latexrelease> \str_if_eq:nnTF {#2} { top-level }
%<latexrelease> { \@@_tl_gclear:c { @@_toplevel~#1 } }
%<latexrelease> {
-%<latexrelease> \prop_gpop:cnNF { g_@@_#1_code_prop } {#2} \l_@@_return_tl
-%<latexrelease> { \msg_warning:nnnn { hooks } { cannot-remove } {#1} {#2} }
+%<latexrelease> \prop_gpop:cnNF { g_@@_#1_code_prop }
+%<latexrelease> {#2} \l_@@_return_tl
+%<latexrelease> { \msg_warning:nnnn { hooks } { cannot-remove }
+%<latexrelease> {#1} {#2} }
%<latexrelease> }
%<latexrelease> }
%<latexrelease> \@@_if_usable:nT {#1}
@@ -4423,9 +4484,11 @@
%<latexrelease> \@@_if_deprecated_generic:nTF {#1}
%<latexrelease> {
%<latexrelease> \@@_deprecated_generic_warn:n {#1}
-%<latexrelease> \@@_do_deprecated_generic:Nn \@@_gremove_code:nn {#1} {#2}
+%<latexrelease> \@@_do_deprecated_generic:Nn
+%<latexrelease> \@@_gremove_code:nn {#1} {#2}
%<latexrelease> }
-%<latexrelease> { \msg_warning:nnnn { hooks } { cannot-remove } {#1} {#2} }
+%<latexrelease> { \msg_warning:nnnn { hooks } { cannot-remove }
+%<latexrelease> {#1} {#2} }
%<latexrelease> }
%<latexrelease> }
%<latexrelease>\EndIncludeInRelease
@@ -4467,7 +4530,8 @@
{#1} {#2}
}
\cs_new_protected:Npn \@@_cs_gput_right_fast:nnn #1 #2 #3
- { \cs_gset:cpx { @@#1~#2 } { \exp_not:v { @@#1~#2 } \exp_not:n {#3} } }
+ { \cs_gset:cpx { @@#1~#2 }
+ { \exp_not:v { @@#1~#2 } \exp_not:n {#3} } }
\cs_new_protected:Npn \@@_cs_gput_right_slow:nnn #1 #2 #3
{
% \end{macrocode}
@@ -4693,7 +4757,8 @@
% \begin{macrocode}
\exp_last_unbraced:NNf
\cs_set:Npn \@@_tmp:w { \@@_parameter:n {#1} } { }
- \tl_set:Ne \l_@@_tmpa_tl { \@@_braced_cs_parameter:n { @@_tmp:w } }
+ \tl_set:Ne \l_@@_tmpa_tl
+ { \@@_braced_cs_parameter:n { @@_tmp:w } }
% \end{macrocode}
% Now this function does the fun part. It is meant to be used with
% \cs{prop_map_function:NN}, taking a label name in \verb|##1| and the
@@ -5069,8 +5134,8 @@
%<latexrelease> \@@_if_deprecated_generic:nT {#1}
%<latexrelease> {
%<latexrelease> \@@_deprecated_generic_warn:n {#1}
-%<latexrelease> \@@_do_deprecated_generic:Nn \@@_gset_rule:nnnn {#1}
-%<latexrelease> {#2} {#3} {#4}
+%<latexrelease> \@@_do_deprecated_generic:Nn \@@_gset_rule:nnnn
+%<latexrelease> {#1} {#2} {#3} {#4}
%<latexrelease> \exp_after:wN \use_none:nnnnnnnnn \use_none:n
%<latexrelease> }
%<latexrelease> \@@_init_structure:n {#1}
@@ -5110,7 +5175,8 @@
% \begin{macrocode}
\cs_new_protected:Npn \@@_rule_before_gset:nnn #1#2#3
{
- \@@_tl_gset:cx { g_@@_#1_rule_ \@@_label_pair:nn {#2} {#3} _tl }
+ \@@_tl_gset:cx
+ { g_@@_#1_rule_ \@@_label_pair:nn {#2} {#3} _tl }
{ \@@_label_ordered:nnTF {#2} {#3} { < } { > } }
}
\cs_new_eq:cN { @@_rule_<_gset:nnn } \@@_rule_before_gset:nnn
@@ -5119,7 +5185,8 @@
% \begin{macrocode}
\cs_new_protected:Npn \@@_rule_after_gset:nnn #1#2#3
{
- \@@_tl_gset:cx { g_@@_#1_rule_ \@@_label_pair:nn {#3} {#2} _tl }
+ \@@_tl_gset:cx
+ { g_@@_#1_rule_ \@@_label_pair:nn {#3} {#2} _tl }
{ \@@_label_ordered:nnTF {#3} {#2} { < } { > } }
}
\cs_new_eq:cN { @@_rule_>_gset:nnn } \@@_rule_after_gset:nnn
@@ -5132,7 +5199,8 @@
% \begin{macrocode}
\cs_new_protected:Npn \@@_rule_voids_gset:nnn #1#2#3
{
- \@@_tl_gset:cx { g_@@_#1_rule_ \@@_label_pair:nn {#2} {#3} _tl }
+ \@@_tl_gset:cx
+ { g_@@_#1_rule_ \@@_label_pair:nn {#2} {#3} _tl }
{ \@@_label_ordered:nnTF {#2} {#3} { -> } { <- } }
}
% \end{macrocode}
@@ -5146,11 +5214,15 @@
% together in hook |#1|.
% \begin{macrocode}
\cs_new_protected:cpn { @@_rule_incompatible-error_gset:nnn } #1#2#3
- { \@@_tl_gset:cn { g_@@_#1_rule_ \@@_label_pair:nn {#2} {#3} _tl }
- { xE } }
+ { \@@_tl_gset:cn
+ { g_@@_#1_rule_ \@@_label_pair:nn {#2} {#3} _tl }
+ { xE }
+ }
\cs_new_protected:cpn { @@_rule_incompatible-warning_gset:nnn } #1#2#3
- { \@@_tl_gset:cn { g_@@_#1_rule_ \@@_label_pair:nn {#2} {#3} _tl }
- { xW } }
+ { \@@_tl_gset:cn
+ { g_@@_#1_rule_ \@@_label_pair:nn {#2} {#3} _tl }
+ { xW }
+ }
% \end{macrocode}
% \end{macro}
%
@@ -5268,7 +5340,7 @@
}
% \end{macrocode}
% After all hooks are initialized we change the ``use'' to just
-% call the hook code and not initialize it (as it was done in the
+% call the hook code and not initialize it (as this was already done in the
% preamble.
% \begin{macrocode}
\@@_post_initialization_defs:
@@ -5281,7 +5353,8 @@
%<latexrelease> {Hooks~with~args}
%<latexrelease>\cs_gset_protected:Npn \@@_initialize_all:
%<latexrelease> {
-%<latexrelease> \cs_gset_eq:NN \@@_update_hook_code:n \@@_initialize_hook_code:n
+%<latexrelease> \cs_gset_eq:NN \@@_update_hook_code:n
+%<latexrelease> \@@_initialize_hook_code:n
%<latexrelease> \@@_debug:n { \prop_gclear:N \g_@@_used_prop }
%<latexrelease> \seq_map_inline:Nn \g_@@_all_seq
%<latexrelease> { \@@_update_hook_code:n {##1} }
@@ -5291,7 +5364,8 @@
%<latexrelease> \prop_map_inline:Nn \g_@@_used_prop
%<latexrelease> {
%<latexrelease> \iow_term:x
-%<latexrelease> { ^^J ~ ##1 ~ -> ~ \cs_replacement_spec:c { @@~##1 } ~ }
+%<latexrelease> { ^^J ~ ##1 ~ -> ~
+%<latexrelease> \cs_replacement_spec:c { @@~##1 } ~ }
%<latexrelease> }
%<latexrelease> }
%<latexrelease> \cs_gset_eq:NN \hook_use:n \@@_use_initialized:n
@@ -5350,8 +5424,10 @@
% after the \verb|_next| and \verb|_toplevel| macros, so that the
% arguments passed to the hook are forwarded to them.
% \begin{macrocode}
- \exp_not:c { @@_toplevel~#1 } \@@_braced_parameter:n {#1}
- \exp_not:c { @@_next~#1 } \@@_braced_parameter:n {#1}
+ \exp_not:c { @@_toplevel~#1 }
+ \@@_braced_parameter:n {#1}
+ \exp_not:c { @@_next~#1 }
+ \@@_braced_parameter:n {#1}
}
}
{
@@ -5400,7 +5476,8 @@
%<latexrelease>\cs_gset_protected:Npn \@@_initialize_hook_code:n #1
%<latexrelease> {
%<latexrelease> \@@_debug:n
-%<latexrelease> { \iow_term:x { ^^J Update~code~for~hook~'#1' \on@line :^^J } }
+%<latexrelease> { \iow_term:x { ^^J Update~code~for~hook~'#1'
+%<latexrelease> \on@line :^^J } }
%<latexrelease> \@@_include_legacy_code_chunk:n {#1}
%<latexrelease> \@@_if_usable:nT {#1}
%<latexrelease> {
@@ -5414,15 +5491,21 @@
%<latexrelease> }
%<latexrelease> {
%<latexrelease> \@@_if_reversed:nTF {#1}
-%<latexrelease> { \cs_set_eq:NN \@@_tl_gput:Nn \@@_tl_gput_left:Nn
-%<latexrelease> \cs_set_eq:NN \@@_clist_gput:NV \clist_gput_left:NV }
-%<latexrelease> { \cs_set_eq:NN \@@_tl_gput:Nn \@@_tl_gput_right:Nn
-%<latexrelease> \cs_set_eq:NN \@@_clist_gput:NV \clist_gput_right:NV }
-%<latexrelease> \prop_set_eq:Nc \l_@@_work_prop { g_@@_#1_code_prop }
+%<latexrelease> { \cs_set_eq:NN \@@_tl_gput:Nn
+%<latexrelease> \@@_tl_gput_left:Nn
+%<latexrelease> \cs_set_eq:NN \@@_clist_gput:NV
+%<latexrelease> \clist_gput_left:NV }
+%<latexrelease> { \cs_set_eq:NN \@@_tl_gput:Nn
+%<latexrelease> \@@_tl_gput_right:Nn
+%<latexrelease> \cs_set_eq:NN \@@_clist_gput:NV
+%<latexrelease> \clist_gput_right:NV }
+%<latexrelease> \prop_set_eq:Nc \l_@@_work_prop
+%<latexrelease> { g_@@_#1_code_prop }
%<latexrelease> \@@_initialize_single:ccn
%<latexrelease> { @@~#1 } { g_@@_#1_labels_clist } {#1}
%<latexrelease> \@@_debug:n
-%<latexrelease> { \exp_args:NNx \prop_gput:Nnn \g_@@_used_prop {#1} { } }
+%<latexrelease> { \exp_args:NNx \prop_gput:Nnn \g_@@_used_prop
+%<latexrelease> {#1} { } }
%<latexrelease> }
%<latexrelease> }
%<latexrelease> }
@@ -5621,7 +5704,8 @@
\int_compare:nNnT
{ \cs:w \@@_tl_csname:n {##1} \cs_end: } = 0
{
- \tl_set:cn { \@@_tl_csname:n { \l_@@_rear_tl } } {##1}
+ \tl_set:cn
+ { \@@_tl_csname:n { \l_@@_rear_tl } } {##1}
\tl_set:Nn \l_@@_rear_tl {##1}
}
}
@@ -5703,42 +5787,50 @@
%<latexrelease> {#3}
%<latexrelease> }
%<latexrelease> }
-%<latexrelease> \@@_debug:n { \@@_debug_label_data:N \l_@@_work_prop }
+%<latexrelease> \@@_debug:n
+%<latexrelease> { \@@_debug_label_data:N \l_@@_work_prop }
%<latexrelease> \tl_set:Nn \l_@@_rear_tl { 0 }
%<latexrelease> \tl_set:cn { \@@_tl_csname:n { 0 } } { 0 }
%<latexrelease> \seq_map_inline:Nn \l_@@_labels_seq
%<latexrelease> {
-%<latexrelease> \int_compare:nNnT { \cs:w \@@_tl_csname:n {##1} \cs_end: } = 0
-%<latexrelease> {
-%<latexrelease> \tl_set:cn { \@@_tl_csname:n { \l_@@_rear_tl } }{##1}
-%<latexrelease> \tl_set:Nn \l_@@_rear_tl {##1}
-%<latexrelease> }
+%<latexrelease> \int_compare:nNnT
+%<latexrelease> { \cs:w \@@_tl_csname:n {##1} \cs_end: } = 0
+%<latexrelease> {
+%<latexrelease> \tl_set:cn { \@@_tl_csname:n
+%<latexrelease> { \l_@@_rear_tl } } {##1}
+%<latexrelease> \tl_set:Nn \l_@@_rear_tl {##1}
+%<latexrelease> }
%<latexrelease> }
%<latexrelease> \tl_set_eq:Nc \l_@@_front_tl { \@@_tl_csname:n { 0 } }
%<latexrelease> \@@_tl_gclear:N #1
%<latexrelease> \clist_gclear:N #2
-%<latexrelease> \bool_while_do:nn { ! \str_if_eq_p:Vn \l_@@_front_tl { 0 } }
+%<latexrelease> \bool_while_do:nn
+%<latexrelease> { ! \str_if_eq_p:Vn \l_@@_front_tl { 0 } }
%<latexrelease> {
%<latexrelease> \int_decr:N \l_@@_labels_int
-%<latexrelease> \prop_get:NVN \l_@@_work_prop \l_@@_front_tl \l_@@_return_tl
+%<latexrelease> \prop_get:NVN \l_@@_work_prop
+%<latexrelease> \l_@@_front_tl \l_@@_return_tl
%<latexrelease> \exp_args:NNV \@@_tl_gput:Nn #1 \l_@@_return_tl
%<latexrelease> \@@_clist_gput:NV #2 \l_@@_front_tl
-%<latexrelease> \@@_debug:n{ \iow_term:x{Handled~ code~ for~ \l_@@_front_tl} }
-%<latexrelease> \seq_map_inline:cn { \@@_seq_csname:n { \l_@@_front_tl } }
+%<latexrelease> \@@_debug:n{ \iow_term:x
+%<latexrelease> {Handled~ code~ for~ \l_@@_front_tl} }
+%<latexrelease> \seq_map_inline:cn
+%<latexrelease> { \@@_seq_csname:n { \l_@@_front_tl } }
%<latexrelease> {
%<latexrelease> \tl_set:cx { \@@_tl_csname:n {##1} }
-%<latexrelease> { \int_eval:n
-%<latexrelease> { \cs:w \@@_tl_csname:n {##1} \cs_end: - 1 }
-%<latexrelease> }
+%<latexrelease> { \int_eval:n
+%<latexrelease> { \cs:w \@@_tl_csname:n {##1} \cs_end: - 1 }
+%<latexrelease> }
%<latexrelease> \int_compare:nNnT
-%<latexrelease> { \cs:w \@@_tl_csname:n {##1} \cs_end: } = 0
-%<latexrelease> {
-%<latexrelease> \tl_set:cn { \@@_tl_csname:n { \l_@@_rear_tl } } {##1}
-%<latexrelease> \tl_set:Nn \l_@@_rear_tl {##1}
-%<latexrelease> }
+%<latexrelease> { \cs:w \@@_tl_csname:n {##1} \cs_end: } = 0
+%<latexrelease> {
+%<latexrelease> \tl_set:cn { \@@_tl_csname:n
+%<latexrelease> { \l_@@_rear_tl } } {##1}
+%<latexrelease> \tl_set:Nn \l_@@_rear_tl {##1}
+%<latexrelease> }
%<latexrelease> }
%<latexrelease> \tl_set_eq:Nc \l_@@_front_tl
-%<latexrelease> { \@@_tl_csname:n { \l_@@_front_tl } }
+%<latexrelease> { \@@_tl_csname:n { \l_@@_front_tl } }
%<latexrelease> }
%<latexrelease> \int_compare:nNnF \l_@@_labels_int = 0
%<latexrelease> {
@@ -5747,7 +5839,8 @@
%<latexrelease> \@@_debug_label_data:N \l_@@_work_prop
%<latexrelease> \iow_term:x{====================}
%<latexrelease> }
-%<latexrelease> \exp_args:NNo \@@_tl_gput:Nn #1 { \cs:w @@_toplevel~#3 \cs_end: }
+%<latexrelease> \exp_args:NNo \@@_tl_gput:Nn #1
+%<latexrelease> { \cs:w @@_toplevel~#3 \cs_end: }
%<latexrelease> \@@_tl_gput_right:No #1 { \cs:w @@_next~#3 \cs_end: }
%<latexrelease> }
%<latexrelease>\cs_generate_variant:Nn \@@_tl_gput_right:Nn { No }
@@ -6008,6 +6101,8 @@
%
% \changes{v1.1a}{2023/04/06}
% {Changes to add hook arguments (hook-args).}
+% \changes{v1.1g}{2024/01/03}
+% {Fix expansion of \cs{@@_print_args:nn} argument (gh/1221).}
% \begin{macrocode}
%<latexrelease>\IncludeInRelease{2023/06/01}{\@@_log:nN}
%<latexrelease> {Hooks~with~args}
@@ -6027,7 +6122,7 @@
hook~'#1'
\@@_if_disabled:nF {#1}
{
- \exp_args:Nf \@@_print_args:nn {#1}
+ \exp_args:Nne \@@_print_args:nn {#1}
{
\int_eval:n
{ \str_count:e { \@@_parameter:n {#1} } / 3 }
@@ -6164,7 +6259,8 @@
%<latexrelease> }
%<latexrelease> \@@_preamble_hook:n {#1}
%<latexrelease> \@@_log_cmd:x
-%<latexrelease> { ^^J ->~The~ \@@_if_generic:nT {#1} { generic~ } hook~'#1': }
+%<latexrelease> { ^^J ->~The~ \@@_if_generic:nT
+%<latexrelease> {#1} { generic~ } hook~'#1': }
%<latexrelease> \@@_if_usable:nF {#1}
%<latexrelease> { \@@_log_line:x { The~hook~is~not~declared. } }
%<latexrelease> \@@_if_disabled:nT {#1}
@@ -6177,26 +6273,30 @@
%<latexrelease> { \@@_log_line_indent:x { --- } }
%<latexrelease> {
%<latexrelease> \prop_map_inline:cn { g_@@_#1_code_prop }
-%<latexrelease> { \@@_log_line_indent:x { ##1~->~\tl_to_str:n {##2} } }
+%<latexrelease> { \@@_log_line_indent:x
+%<latexrelease> { ##1~->~\tl_to_str:n {##2} } }
%<latexrelease> }
%<latexrelease> \@@_log_line:x
%<latexrelease> {
%<latexrelease> Document-level~(top-level)~code
%<latexrelease> \@@_if_usable:nT {#1}
-%<latexrelease> { ~(executed~\@@_if_reversed:nTF {#1} {first} {last} ) } :
+%<latexrelease> { ~(executed~
+%<latexrelease> \@@_if_reversed:nTF {#1} {first} {last} ) } :
%<latexrelease> }
%<latexrelease> \@@_log_line_indent:x
%<latexrelease> {
%<latexrelease> \tl_if_empty:cTF { @@_toplevel~#1 }
%<latexrelease> { --- }
-%<latexrelease> { -> ~ \exp_args:Nv \tl_to_str:n { @@_toplevel~#1 } }
+%<latexrelease> { -> ~ \exp_args:Nv \tl_to_str:n
+%<latexrelease> { @@_toplevel~#1 } }
%<latexrelease> }
%<latexrelease> \@@_log_line:x { Extra~code~for~next~invocation: }
%<latexrelease> \@@_log_line_indent:x
%<latexrelease> {
%<latexrelease> \tl_if_empty:cTF { @@_next~#1 }
%<latexrelease> { --- }
-%<latexrelease> { ->~ \exp_args:Nv \@@_log_next_code:n { @@_next~#1 } }
+%<latexrelease> { ->~ \exp_args:Nv \@@_log_next_code:n
+%<latexrelease> { @@_next~#1 } }
%<latexrelease> }
%<latexrelease> \@@_log_line:x { Rules: }
%<latexrelease> \bool_set_true:N \l_@@_tmpa_bool
@@ -6220,7 +6320,8 @@
%<latexrelease> {
%<latexrelease> Execution~order
%<latexrelease> \bool_if:NTF \l_@@_tmpa_bool
-%<latexrelease> { \@@_if_reversed:nT {#1} { ~(after~reversal) } }
+%<latexrelease> { \@@_if_reversed:nT
+%<latexrelease> {#1}{ ~(after~reversal) } }
%<latexrelease> { ~(after~
%<latexrelease> \@@_if_reversed:nT {#1} { reversal~and~ }
%<latexrelease> applying~rules)
@@ -6231,16 +6332,19 @@
%<latexrelease> \@spaces
%<latexrelease> \clist_if_empty:cTF { g_@@_#1_labels_clist }
%<latexrelease> { --- }
-%<latexrelease> { \clist_use:cn { g_@@_#1_labels_clist } { ,~ } }
+%<latexrelease> { \clist_use:cn
+%<latexrelease> { g_@@_#1_labels_clist } { ,~ } }
%<latexrelease> }
%<latexrelease> }
%<latexrelease> {
%<latexrelease> \@@_log_line:x { Execution~order: }
%<latexrelease> #2
%<latexrelease> {
-%<latexrelease> \@spaces Not~set~because~the~hook~ \@@_if_usable:nTF {#1}
+%<latexrelease> \@spaces Not~set~because~the~hook~
+%<latexrelease> \@@_if_usable:nTF {#1}
%<latexrelease> { code~pool~is~empty }
-%<latexrelease> { is~\@@_if_disabled:nTF {#1} {disabled} {undeclared} }
+%<latexrelease> { is~\@@_if_disabled:nTF
+%<latexrelease> {#1} {disabled} {undeclared} }
%<latexrelease> }
%<latexrelease> }
%<latexrelease> }
@@ -6388,7 +6492,8 @@
%<latexrelease>\IncludeInRelease{2020/10/01}{\hook_gput_next_code:nn}
%<latexrelease> {Hooks~with~args}
%<latexrelease>\cs_gset_protected:Npn \hook_gput_next_code:nn #1
-%<latexrelease> { \@@_normalize_hook_args:Nn \@@_gput_next_code:nn {#1} }
+%<latexrelease> { \@@_normalize_hook_args:Nn
+%<latexrelease> \@@_gput_next_code:nn {#1} }
%<latexrelease>\cs_gset_protected:Npn \hook_gput_next_code_with_args:nn #1 #2 { }
%<latexrelease>\EndIncludeInRelease
% \end{macrocode}
@@ -6580,7 +6685,8 @@
%<latexrelease> \fi:
%<latexrelease> \cs:w @@~#1 \@@_use_end:
%<latexrelease> }
-%<latexrelease>\cs_new:Npn \@@_use_undefined:w #1 #2 @@~#3 \@@_use_end:
+%<latexrelease>\cs_new:Npn \@@_use_undefined:w
+%<latexrelease> #1 #2 @@~#3 \@@_use_end:
%<latexrelease> {
%<latexrelease> #1 % fi
%<latexrelease> \@@_use:wn #3 / \s_@@_mark {#3}
@@ -6680,15 +6786,18 @@
%
% \changes{v1.0s}{2021/09/28}
% {Correct usage of older \cs{@@_if_file_hook:wTF} (gh/675)}
+% \changes{v1.1h}{2024/01/24}
+% {Correct usage of older \cs{@@_if_file_hook:wTF} (gh/1243)}
% \begin{macrocode}
%<latexrelease>\cs_new_protected:Npn \@@_try_file_hook:n #1
%<latexrelease> {
-%<latexrelease> \@@_if_file_hook:wTF #1 / \s_@@_mark
+%<latexrelease> \@@_if_file_hook:wTF #1 / / \s_@@_mark
%<latexrelease> {
%<latexrelease> \exp_args:Ne \@@_if_usable_use:n
%<latexrelease> { \exp_args:Ne \@@_file_hook_normalize:n {#1} }
%<latexrelease> }
-%<latexrelease> { \@@_if_usable_use:n {#1} } % file/ generic hook (e.g. file/before)
+%<latexrelease> { \@@_if_usable_use:n {#1} }
+%<latexrelease> % file/ generic hook (e.g. file/before)
%<latexrelease> }
% \end{macrocode}
%
@@ -6726,12 +6835,14 @@
\cs_new_protected:Npn \hook_use_once:n #1
{
\@@_if_execute_immediately:nF {#1}
- { \@@_normalize_hook_args:Nn \@@_use_once:nn { \use:n {#1} } { 0 } }
+ { \@@_normalize_hook_args:Nn \@@_use_once:nn
+ { \use:n {#1} } { 0 } }
}
\cs_new_protected:Npn \hook_use_once:nnw #1 #2
{
\@@_if_execute_immediately:nF {#1}
- { \@@_normalize_hook_args:Nn \@@_use_once:nn { \use:n {#1} } {#2} }
+ { \@@_normalize_hook_args:Nn \@@_use_once:nn
+ { \use:n {#1} } {#2} }
}
%<latexrelease>\EndIncludeInRelease
% \end{macrocode}
@@ -6743,7 +6854,8 @@
%<latexrelease>\cs_gset_protected:Npn \hook_use_once:n #1
%<latexrelease> {
%<latexrelease> \@@_if_execute_immediately:nF {#1}
-%<latexrelease> { \@@_normalize_hook_args:Nn \@@_use_once:n { \use:n {#1} } }
+%<latexrelease> { \@@_normalize_hook_args:Nn \@@_use_once:n
+%<latexrelease> { \use:n {#1} } }
%<latexrelease> }
%<latexrelease>\cs_gset:Npn \hook_use_once:nnw #1 #2
%<latexrelease> { \use:c { use_none: \prg_replicate:nn {#2} { n } } }
@@ -6768,7 +6880,8 @@
% along with the next execution code.
% \begin{macrocode}
\@@_replacing_args_false:
- \@@_cs_gput_right:nnn { _next } {#1} { \@@_use_once_clear:n {#1} }
+ \@@_cs_gput_right:nnn { _next } {#1}
+ { \@@_use_once_clear:n {#1} }
\@@_replacing_args_reset:
\@@_if_usable:nTF {#1}
{ \@@_use_initialized:n {#1} }
@@ -7215,7 +7328,8 @@
{ 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_generic:n~or~\iow_char:N\\DisableGenericHook,~so~
+ with~\iow_char:N\\hook_disable_generic:n~or~
+ \iow_char:N\\DisableGenericHook,~so~
it~cannot~have~code~added~to~it.
}
% \end{macrocode}
@@ -7383,7 +7497,7 @@
%<latexrelease> {Hooks~with~args}
%<latexrelease>\cs_new_protected:Npn \NewHookWithArguments #1 #2 { }
%<latexrelease>\cs_new_protected:Npn \NewReversedHookWithArguments #1 #2 { }
-%<latexrelease>\cs_new_protected:Npn \NewMirroredHookPairWithArguments #1 #2 #3 { }
+%<latexrelease>\cs_new_protected:Npn \NewMirroredHookPairWithArguments #1 #2 #3{}
%<latexrelease>\EndIncludeInRelease
% \end{macrocode}
% \end{macro}
@@ -7835,7 +7949,8 @@
%<latexrelease> \exp_args:No \exp_not:o
%<latexrelease> {
%<latexrelease> \cs:w @@#1~#2 \exp_last_unbraced:Ne \cs_end:
-%<latexrelease> { \@@_braced_cs_parameter:n { @@#1~#2 } }
+%<latexrelease> { \@@_braced_cs_parameter:n
+%<latexrelease> { @@#1~#2 } }
%<latexrelease> }
%<latexrelease> }
%<latexrelease> }
diff --git a/macros/latex/base/ltkeys.dtx b/macros/latex/base/ltkeys.dtx
index da8340ea9d..34a0ab4b47 100644
--- a/macros/latex/base/ltkeys.dtx
+++ b/macros/latex/base/ltkeys.dtx
@@ -100,7 +100,7 @@
% \texttt{second-name} can be given anywhere, and will save its value in
% \cs{@mypkg@other@name}.
%
-% Keys created \emph{before} the use of \cs{ProcessKeyOptions}act as
+% Keys created \emph{before} the use of \cs{ProcessKeyOptions} act as
% package options.
% \end{function}
%
diff --git a/macros/latex/base/ltluatex.dtx b/macros/latex/base/ltluatex.dtx
index c310ac8ecf..a15019dcd5 100644
--- a/macros/latex/base/ltluatex.dtx
+++ b/macros/latex/base/ltluatex.dtx
@@ -23,16 +23,22 @@
%<tex> \ProvidesFile\undefined\begingroup\def\ProvidesFile
%<tex> #1#2[#3]{\endgroup\immediate\write-1{File: #1 #3}}
%<tex>\fi
-%<plain>\ProvidesFile{ltluatex.tex}%
-%<*driver>
+%<*dtx>
\ProvidesFile{ltluatex.dtx}
-%</driver>
-%<*tex>
-[2023/08/03 v1.2c
-%</tex>
-%<plain> LuaTeX support for plain TeX (core)
-%<*tex>
+%</dtx>
+%<plain>\ProvidesFile{ltluatex.tex}
+%<*plain>
+% \fi
+% \ProvidesFile{ltluatex.dtx}
+[2024/02/11 v1.2c
+% LaTeX Kernel (LuaTeX support)^^A
+%\iffalse
+%<plain> LuaTeX support for plain TeX (core)%
+%\fi
]
+% \iffalse
+%</plain>
+%<*tex>
\edef\etatcatcode{\the\catcode`\@}
\catcode`\@=11
%</tex>
@@ -541,9 +547,9 @@
\csname globbox\endcsname
% \end{macrocode}
%
-% Define|\e@alloc| as in latex (the existing macros in |etex.src|
+% Define|\e@alloc| as in \LaTeX{} (the existing macros in |etex.src| are
% hard to extend to further register types as they assume specific
-% 26x and 27x count range. For compatibility the existing register
+% 26x and 27x count range). For compatibility the existing register
% allocation is not changed.
%
% \begin{macrocode}
diff --git a/macros/latex/base/ltluatex.pdf b/macros/latex/base/ltluatex.pdf
index 9955fcf749..c20801f252 100644
--- a/macros/latex/base/ltluatex.pdf
+++ b/macros/latex/base/ltluatex.pdf
Binary files differ
diff --git a/macros/latex/base/ltmarks-code.pdf b/macros/latex/base/ltmarks-code.pdf
index 4aecd33f1e..47cc1dc6a3 100644
--- a/macros/latex/base/ltmarks-code.pdf
+++ b/macros/latex/base/ltmarks-code.pdf
Binary files differ
diff --git a/macros/latex/base/ltmarks-doc.pdf b/macros/latex/base/ltmarks-doc.pdf
index 141e3acdab..3ec5e19be0 100644
--- a/macros/latex/base/ltmarks-doc.pdf
+++ b/macros/latex/base/ltmarks-doc.pdf
Binary files differ
diff --git a/macros/latex/base/ltmarks.dtx b/macros/latex/base/ltmarks.dtx
index f826856484..a9f3bb0184 100644
--- a/macros/latex/base/ltmarks.dtx
+++ b/macros/latex/base/ltmarks.dtx
@@ -14,21 +14,14 @@
%
%%% From File: ltmarks.dtx
%
-% \begin{macrocode}
-\def\ltmarksversion{v1.0d}
-\def\ltmarksdate{2022/06/01}
-% \end{macrocode}
%<*driver>
+% \fi
+\ProvidesFile{ltmarks.dtx}
+ [2024/05/31 v1.0g LaTeX Kernel (Marks)]
+% \iffalse
+%
\documentclass{l3doc}
-
-%\usepackage{ltmarks}
-
-% Fixing footnotes in functions and variables: this should be in l3doc!
-
-\newcommand\fixfootnote[2]{\footnotemark
- \AddToHookNext{env/#1/after}{\footnotetext{#2}}}
-\AddToHook{env/function/begin}{\def\footnote{\fixfootnote{function}}}
-\AddToHook{env/variable/begin}{\def\footnote{\fixfootnote{variable}}}
+\GetFileInfo{ltmarks.dtx}
\EnableCrossrefs
\CodelineIndex
@@ -45,7 +38,7 @@
%
%
% \title{The \texttt{ltmarks.dtx} code\thanks{This file has version
-% \ltmarksversion\ dated \ltmarksdate, \copyright\ \LaTeX\
+% \fileversion\ dated \filedate, \copyright\ \LaTeX\
% Project.}}
% \author{^^A
% Frank Mittelbach, \LaTeX{} Project\thanks
@@ -156,7 +149,7 @@
% \begin{function}{\InsertMark,\mark_insert:nn}
% \begin{syntax}
% \cs{InsertMark} \Arg{class} \Arg{text}
-% \cs{mark_insert:nn} \Arg{class} \Arg{text}
+% \cs{mark_insert:nn} \Arg{class} \Arg{text}
% \end{syntax}
% Adds a mark to the current galley for the \meta{class}, containing the
% \meta{text}.
@@ -291,6 +284,11 @@
% The \meta{pos\textsubscript{\itshape i}} argument can be either
% \texttt{top}, \texttt{first}, or \texttt{last}.
%
+% Important to note is that the comparison is not with respect to
+% the textual content of the marks but whether or not they
+% originated from the same \cs{InsertMark} command (or the L3 layer
+% version \cs{mark_insert:nn}).
+%
% If you wish to compare marks across different regions or across
% different classes, you have to do it using the generic test only
% available in the L3 programming layer or do it manually, i.e.,
@@ -299,6 +297,8 @@
% \emph{true}; if a declared and an undeclared mark class is used
% it is always \emph{false}.}
%
+% \subsection{Use cases for conditionals}
+%
% However, the basic version is enough for the following typical use cases:
% \begin{description}
% \item[Test for at most one mark of class \texttt{myclass} on current
@@ -353,7 +353,7 @@
% \begin{function}{\DebugMarksOn,\DebugMarksOff,
% \mark_debug_on:,\mark_debug_off:}
% \begin{syntax}
-% \cs{DebugMarksOn} ... \cs{DebugMarksOff}
+% \cs{DebugMarksOn} \ldots\ \cs{DebugMarksOff}
% \end{syntax}
%
% Commands to turn the debugging of mark code on or off. The
@@ -397,8 +397,8 @@
%
% \begin{function}{\markboth, \markright}
% \begin{syntax}
-% \cs{markboth} \Arg{left} \Arg{right}
-% \cs{markright} \Arg{right}
+% \cs{markboth} \Arg{left} \Arg{right}
+% \cs{markright} \Arg{right}
% \end{syntax}
% \LaTeXe{} uses two marks which aren't fully independent. A
% \enquote{left} mark generated by the first argument of \cs{markboth}
@@ -610,9 +610,9 @@
% marks. It too is called as part of \cs{@opcol}.
% \end{function}
%
-% \begin{function}{\@@_update_structure:nn}
+% \begin{function}{\@@_update_structure_from_material:nn}
% \begin{syntax}
-% \cs{@@_update_structure:nn} \Arg{region} \Arg{material with marks}
+% \cs{@@_update_structure_from_material:nn} \Arg{region} \Arg{material with marks}
% \end{syntax}
% Helper function that inspects the marks
% inside the second argument and assigns new mark values based on
@@ -627,8 +627,8 @@
% \texttt{page} and \texttt{column} because only they have
% \texttt{previous-...} counterparts.
%
-% Another important part to keep in mind is that marks are only
-% recognized if they appear on top-level, e.g., if we want to
+% Another important aspect to keep in mind is that marks are recognized
+% only if they appear on the top level, e.g., if we want to
% process material stored in boxes we need to put it unboxed (using
% \cs{unvcopy} etc.)\ into the second argument.
% \end{function}
@@ -642,7 +642,7 @@
% Helper function that copies all mark values in the \meta{source}
% region to \meta{alias}, i.e., make the structures identical. Used
% to update the \texttt{previous-...} structures inside
-% \cs{@@_update_structure:nn} and \texttt{first-column} and
+% \cs{@@_update_structure_from_material:nn} and \texttt{first-column} and
% \texttt{last-column} structures inside
% \cs{@@_update_singlecol_structures:} or
% \cs{@@_update_dblcol_structures:}.
@@ -650,7 +650,6 @@
%
%
%
-%
% \begin{function}{\@@_update_structure_to_err:n}
% \begin{syntax}
% \cs{@@_update_structure_to_err:n} \Arg{region}
@@ -662,6 +661,37 @@
% \end{function}
%
%
+% \begin{function}{\@@_get_marks_for_reinsertion:nNN}
+% \begin{syntax}
+% \cs{@@_get_marks_for_reinsertion:nNN} \Arg{source}
+% \qquad \meta{token-list-var for collecting first marks}
+% \qquad \meta{token-list-var for collecting last marks}
+% \end{syntax}
+% Helper function for extracting marks that would otherwise get
+% lost, for example when they are hidden inside a box. This helper
+% does not update mark structures and can therefore be used outside
+% the output routine as well.
+%
+% It collect all the top-level marks from inside the \meta{source}
+% and adds suitable \cs{mark_insert:nn} in the two token
+% lists. These token lists can then be executed at the right place
+% to reinsert the marks, e.g., directly after the box. This is, for
+% example, used by \pkg{multicol} when a short balanced
+% \env{multicols} is returned to the galley for typesetting.
+%
+% If the \meta{source} consists of a single vertical box (plus
+% possibly followed by some glue but nothing else) then the box is
+% unpacked and the top-level marks are collected from its
+% content. However, if it is not a vertical box or there are are
+% other data then nothing is unpacked and you have to do the
+% unpacking yourself to get at the marks inside.
+%
+% It is quite likely that one only needs a single token list for
+% returning the \cs{mark_insert:nn} statements. If that is the case
+% this command may change to take only two arguments.
+% \end{function}
+%
+%
%
% ^^A \end{documentation}
%
@@ -703,12 +733,13 @@
%
%
% \begin{macro}{\mark_new_class:n,\@@_new_class:nn}
+%
% A mark class is created by initializing a number of data
-% structures. First, we get a register number to refer to the mark class.
-% The new mark class is then added to the \cs{g_@@_classes_seq}
-% sequence to be able to easily loop over all classes. Finally a
-% number of top-level global token lists are declared that hold
-% various versions of the mark for access.
+% structures. First, we get a register number to refer to the mark
+% class. The new mark class is then added to the
+% \cs{g_@@_classes_seq} sequence to be able to easily loop over all
+% classes. Finally a number of top-level global token lists are
+% declared that hold various versions of the mark for access.
% \begin{macrocode}
\cs_new_protected:Npn \mark_new_class:n #1
{
@@ -774,6 +805,32 @@
\tl_new:c { g_@@_last-column_top_ #1 _tl }
\tl_new:c { g_@@_last-column_first_ #1 _tl }
\tl_new:c { g_@@_last-column_last_ #1 _tl }
+% \end{macrocode}
+% All marks will have an identication at the beginning of the form
+% \cs{@@_id:n}\texttt\{\meta{number}\texttt\} and therefore the
+% initial empty values should have that too, so that data extraction
+% is going to be uniform.
+% \changes{v1.0g}{2024/05/31}{Initialize all marks with an id, use 0
+% when a new class is made (gh/1359)}
+% \begin{macrocode}
+ \tl_set:cn { g_@@_page_top_ #1 _tl }{ \@@_id:n{0} }
+ \tl_set:cn { g_@@_page_first_ #1 _tl }{ \@@_id:n{0} }
+ \tl_set:cn { g_@@_page_last_ #1 _tl }{ \@@_id:n{0} }
+ \tl_set:cn { g_@@_previous-page_top_ #1 _tl }{ \@@_id:n{0} }
+ \tl_set:cn { g_@@_previous-page_first_ #1 _tl }{ \@@_id:n{0} }
+ \tl_set:cn { g_@@_previous-page_last_ #1 _tl }{ \@@_id:n{0} }
+ \tl_set:cn { g_@@_column_top_ #1 _tl }{ \@@_id:n{0} }
+ \tl_set:cn { g_@@_column_first_ #1 _tl }{ \@@_id:n{0} }
+ \tl_set:cn { g_@@_column_last_ #1 _tl }{ \@@_id:n{0} }
+ \tl_set:cn { g_@@_previous-column_top_ #1 _tl }{ \@@_id:n{0} }
+ \tl_set:cn { g_@@_previous-column_first_ #1 _tl }{ \@@_id:n{0} }
+ \tl_set:cn { g_@@_previous-column_last_ #1 _tl }{ \@@_id:n{0} }
+ \tl_set:cn { g_@@_first-column_top_ #1 _tl }{ \@@_id:n{0} }
+ \tl_set:cn { g_@@_first-column_first_ #1 _tl }{ \@@_id:n{0} }
+ \tl_set:cn { g_@@_first-column_last_ #1 _tl }{ \@@_id:n{0} }
+ \tl_set:cn { g_@@_last-column_top_ #1 _tl }{ \@@_id:n{0} }
+ \tl_set:cn { g_@@_last-column_first_ #1 _tl }{ \@@_id:n{0} }
+ \tl_set:cn { g_@@_last-column_last_ #1 _tl }{ \@@_id:n{0} }
}
% \end{macrocode}
% \end{macro}
@@ -784,57 +841,74 @@
% \subsection{Updating mark structures}
%
%
-% \begin{macro}{\l_@@_box,\g_@@_tmp_tl,\g_@@_new_top_tl}
-% For some operations we need a temporary private box and two
+% \begin{macro}{\l_@@_box,\l_@@_ii_box,\g_@@_tmp_tl,\g_@@_new_top_tl}
+% For some operations we need two temporary private boxes and two
% private global token lists.
% \begin{macrocode}
\box_new:N \l_@@_box
+\box_new:N \l_@@_ii_box
\tl_new:N \g_@@_tmp_tl
\tl_new:N \g_@@_new_top_tl
% \end{macrocode}
% \end{macro}
%
%
-% \begin{macro}{\@@_update_structure:nn}
-%
-% This function updates the mark structures. The first argument is
-% the region to update and second argument receives the material
-% that holds the marks. Out of this material we extract the first
-% and last marks for all classes (if there are any) to do the
-% assignments.
%
+% \begin{macro}{\@@_extract_and_handle_marks:nn}
+% \changes{v1.0e}{2024/01/29}{Macro added}
+%
+% This is the main macro to extract and handle marks inside some
+% vertical material. It is used by
+% \cs{@@_update_structure_from_material:nn} (for updating the mark
+% structure for a region based on the marks found) and by
+% \cs{@@_get_marks_for_reinsertion:nNN} (for extracting marks from
+% some material and prepare for reinserting them later (e.g., out
+% of a box that is placed as a box into the main galley).
% \begin{macrocode}
-\cs_new_protected:Npn \@@_update_structure:nn #1#2
- {
+\cs_new_protected:Npn \@@_extract_and_handle_marks:nn #1#2 {
% \end{macrocode}
-% First thing we do is copying the current structure to
-% \texttt{previous-...}; this leaves the current structure
-% untouched so we can update it class by class (which is necessary).
+% This macro expects code to handle extracted marks in its first argument and
+% vertical material (not boxed or just consisting of a single
+% vertical box) as its second. It
+% extracts top-level mark information from \verb/#2/, stores them
+% as split marks and then calls
+% \verb/#1/ to make use of this information.
+%
+% If it finds a forced break in the material it removes it and then
+% restarts the attempt without it.
+%
+% We start with a group to keep most changes local.
% \begin{macrocode}
- \@@_update_structure_alias:nn { previous-#1 } {#1}
+ \group_begin:
% \end{macrocode}
+%
% Getting the first and last marks out of the material in \verb=#2=
-% is done by putting the material in a box and then doing a
-% split operation to the maximum size possible (which hopefully
-% means all of the content).\footnote{We could verify this, maybe we
-% should.} Because this is an action only for the sake of getting
-% at the mark values we don't want any underfull
-% box warnings so we turn those (locally) off.
+% is done by putting the material in a box and then doing a split
+% operation to the maximum size possible (which hopefully gets us
+% all of the content).\footnote{With normal column material cut
+% from the main galley we should always get all material in one go,
+% but in certain situations, for example, in a \pkg{multicols}
+% environment that contains some \cs{columnbreak}s a single split
+% operation will not be enough. Thus, this is something we need to
+% handle.} Because this action is used only to get the mark
+% values, we don't want any underfull box warnings so we (locally)
+% turn those off.
+%
% \begin{macrocode}
- \group_begin:
\dim_set_eq:NN \tex_splitmaxdepth:D \c_max_dim
\int_set_eq:NN \tex_vbadness:D \c_max_int
\dim_set_eq:NN \tex_vfuzz:D \c_max_dim
% \end{macrocode}
-% There is a further complication: if the region contains infinite
+%
+% There is a further complication: if the material contains infinite
% shrinking glue then a \tn{vsplit} operation will balk with a
-% low-level error. Now pages or columns, which are our main concern here, can't
-% have such infinite shrinkage if they are cut straight from the
-% galley, however the use of \tn{enlargethispage} actually does add
-% some at the very bottom (and also wraps the whole page into a box
-% by itself, so if we leave it this way then a) we get this error
-% and b) we don't see any marks because they are hidden one level
-% down).
+% low-level error. Now pages or columns, which are our main concern
+% here, can't have such infinite shrinkage if they are cut straight
+% from the galley, however the use of \tn{enlargethispage} actually
+% does add some at the very bottom (and also wraps the whole page
+% into a box by itself, so if we leave it this way then a) we get
+% this error and b) we don't see any marks because they are hidden
+% one level down).
%
% Another possible issue are packages or user code that place stray
% \tn{vbox}es directly into the main galley (an example is
@@ -842,93 +916,236 @@
% boxes end up as the last item on the page we should not unpack
% them.
%
-% We therefore do an \tn{unskip} to get rid of that glue if present and
-% also check if we have then a \tn{vbox} as the last item and if so
-% unpack that too, but only under certain conditions, see
-% below. All this is temporary, just for getting the
-% marks out, so it doesn't affect the final page production.
-%
-% In fact, we go one step further and set the box to a large
-% negative height possible and afterwards take a look at the
-% reported badness: if it is zero we know that there has still been
-% infinite shrinkage in the box so that we can't do a
-% \tn{vsplit}. If that is the case we generate an error message and
-% bypass extracting the marks. We use only half of \cs{c_max_dim}
-% because otherwise \TeX{} will report an overfull vbox despite our
-% setting of \cs{tex_vfuzz:D}. This test will not find existing
-% infinite shrinkage in all cases, e.g., if there are several glues
-% that cancel each other, but it is the best we can do.
-% \begin{macrocode}
- \vbox_set_to_ht:Nnn \l_@@_box { -.5\c_max_dim }
- {
- #2
- \tex_unskip:D
- \box_set_to_last:N \l_@@_box
+% All these issues need to be handled, which is done in
+% \cs{@@_prepare_and_extract:nn}.
+%
+% \begin{macrocode}
+ \@@_prepare_and_extract:nn {#1} {#2}
+% \end{macrocode}
+% Once all mark classes have been processed, the data structures are
+% updated and we can close the group, which undoes our local
+% changes and retains only the global ones.
+% \begin{macrocode}
+ \group_end:
+ }
+% \end{macrocode}
+% \end{macro}
+%
+%
+% \begin{macro}{\@@_prepare_and_extract:nn}
+%
+% This macro does the dirty work. It is not directly integrated in
+% \cs{@@_extract_and_handle_marks:nn} because we may have to call
+% it recursively if we find forced breaks.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_prepare_and_extract:nn #1#2 {
+% \end{macrocode}
+%
+% To handle the \cs{enlargethispage} case we do an \tn{unskip} to
+% get rid of any glue that is present at the very end of the material
+% and also check if we have then a \tn{vbox} as the last item and
+% if so unpack that too, but only under certain conditions, see
+% below. All this is temporary done in a group, just for getting
+% the marks out, so it doesn't affect the final page production.
+%
+% \begin{macrocode}
+ \vbox_set:Nn \l_@@_box
+ {
+ #2
+ \tex_unskip:D
+ \box_set_to_last:N \l_@@_box
% \end{macrocode}
% After having removed the last box from the current list (if there
-% was one)
-% we check if the list is now empty. If not, the the last box is
-% definitely not the one from \tn{enlargethispage} and so we can
-% and should leave it alone. Otherwise we check if this last box is
-% a \tn{vbox}.
+% was one) we check whether the vertical list is now empty. If not,
+% then the last box is definitely not the one from
+% \tn{enlargethispage} and so we can, and should, leave it
+% alone. Otherwise we check if this last box is a \tn{vbox}.
% \changes{v1.0d}{2022/06/01}{Extend the logic for detecting the marks
% in the box (gh/836)}
% \begin{macrocode}
- \int_compare:nNnT \tex_lastnodetype:D < 0
- {
- \box_if_vertical:NT \l_@@_box
- {
-% \end{macrocode}
-% If it is we do a further test and reset the \cs{l_@@_box}
-% to check if it contains infinitely shrinkable glue.
-% \begin{macrocode}
- \vbox_set_to_ht:Nnn \l_@@_box { -.5\c_max_dim }
- {
- \vbox_unpack:N \l_@@_box
- \tex_kern:D \c_zero_dim % ensure that box
- % is not empty
- }
+ \int_compare:nNnT \tex_lastnodetype:D < 0
+ {
+ \box_if_vertical:NT \l_@@_box
% \end{macrocode}
-% If not, then we unpack it, if yes we still ignore it for the process of
-% mark extraction. We do not generate an error though, because in all
-% likelihood this is an ordinary box like a marginal that does
-% contain something like \tn{vss}.
+% If it is, we unpack the box.
% \begin{macrocode}
- \int_compare:nNnT \tex_badness:D > 0
- { \vbox_unpack:N \l_@@_box }
- }
- }
+ { \vbox_unpack:N \l_@@_box }
+ }
% \end{macrocode}
% If it wasn't a vbox, it was either an hbox or there was no box.
% Given that we are only interested in the marks we don't need put
-% it back in that case. However, we have to make sure that the
-% outer box under construction
-% is not totally empty (which it might have been from the start, or
-% now), because \TeX{} does not report a badness for empty boxes
-% and that means our test would incorrectly conclude that we have
-% infinite shrinking glue. A simple \tn{kern} is enough to avoid
-% this (the same was already done above).
-% \begin{macrocode}
- \tex_kern:D \c_zero_dim
- }
- \int_compare:nNnTF \tex_badness:D > 0
+% it back in that case.
+% \begin{macrocode}
+ }
% \end{macrocode}
-% If the box had no infinite shrinkage (or rather if our test
-% didn't show any) we vsplit it. Note that it
-% doesn't matter that we set it to this strange size first. If there
-% was infinite shrinkage after all, we end up with a low-level
-% \TeX{} error, but if there is, it is a coding error and needs
-% correcting.
+% We are now ready to \cs{vsplit} the box to get at the marks. If
+% the box contains some infinite negative glue the \TeX{} will
+% produce an error complaining about it but it will correctly find
+% the the split marks. Given that we can't prevent that error, we
+% hide it from the user and ensure that \TeX{} doesn't stop. The
+% error message still shows in the log, but even that is mitigated
+% as best as possible---see the definition of
+% \cs{@@_vbox_set_split_to_maxdimen:NN} for the tricks employed.
% \begin{macrocode}
- {
- \vbox_set_split_to_ht:NNn \l_@@_box \l_@@_box \c_max_dim
+ \@@_vbox_set_split_to_maxdimen:NN \l_@@_ii_box \l_@@_box
+% \end{macrocode}
+% After splitting we check if there is anything left in
+% \cs{l_@@_box}. If not then the above split has set some split marks
+% that we can then use to finish the extraction:
+% \begin{macrocode}
+ \box_if_empty:NTF \l_@@_box
+ { #1 }
+% \end{macrocode}
+% If we have a remainder after the split then this means that there
+% was some forced break in the material. We get rid of that by
+% combining the content of the two boxes and restart.
+% \begin{macrocode}
+ {
+%<*trace>
+ \@@_debug:n { \iow_term:x
+ { Marks:~ mark~ extraction~needs~ recursion~
+ \msg_line_context: } }
+%</trace>
+ \@@_prepare_and_extract:nn {#1}
+ { \vbox_unpack:N \l_@@_ii_box
+ \vbox_unpack:N \l_@@_box }
+ }
+}
+% \end{macrocode}
+% \end{macro}
+%
+%
+% \begin{macro}{\@@_vbox_set_split_to_maxdimen:NN}
+%
+% Split a box to get at its marks without pausing even if \TeX{} is
+% producing an error message because of infinite negative glue in
+% the box. If there is such an error we ensure that it only shows
+% up in the log but not on the terminal.
+%
+% The nice low-level hack by DPC records in the \texttt{.log} that a glue
+% shrinkage error is harmless.
+%
+% We disguise \cs{c_max_dim} in an odd looking csname, which then
+% shows up as part of the display of an error message if that error
+% happens. This csname forms part of the error diplay so what
+% you get is something like
+%\begin{verbatim}
+% ! Infinite glue shrinkage found in box being split.
+% <argument> Infinite shrink error above ignored !
+% l. ... }
+%\end{verbatim}
+% which hopefully makes it clear that the error is harmless and
+% and should be ignored by the reader of the \texttt{.log}.
+% \begin{macrocode}
+\cs_set_eq:cN {Infinite~shrink~error~above~ignored~!}\c_max_dim
+% \end{macrocode}
+%
+% The whole definition of \cs{@@_vbox_set_split_to_maxdimen:NN}
+% below is fully expanded, so we have to use a lot of
+% \cs{exp_not:N} commands to prevent expansion where necessary.
+% \begin{macrocode}
+\cs_new_protected:Npx \@@_vbox_set_split_to_maxdimen:NN #1#2 {
+% \end{macrocode}
+% We start by saving the current interaction and escape char settings.
+% \begin{macrocode}
+ \tl_set:Ne \exp_not:N \l_@@_saved_parameters_tl
+ {
+ \tex_interactionmode:D
+ \exp_not:N \int_use:N \tex_interactionmode:D \scan_stop:
+ \tex_escapechar:D
+ \exp_not:N \int_use:N \tex_escapechar:D \scan_stop:
+ }
+% \end{macrocode}
+% Then we change them so that no escape char is printed in the
+% error message (accounts for the missing backslash in front of
+% \verb/Infinite shrink .../) and we set the interaction to
+% \cs{nonstopmode} so that the the error (if any) just goes into
+% the \texttt{.log} file and \TeX{} doesn't stop at that point.
+% \begin{macrocode}
+ \tex_escapechar:D -1 \scan_stop:
+ \tex_interactionmode:D 0 \scan_stop:
+% \end{macrocode}
+% Then we do the splitting of the box to \cs{c_max_dim} to get at
+% the marks. This may generate the error we are worried about,
+% i.e., if the box contains infinite negative glue. However, \TeX{}
+% makes this glue finite and continues, which means we get our split
+% marks which is really all we care about.
+% \begin{macrocode}
+ \tex_setbox:D #1 \tex_vsplit:D #2 to
+% \end{macrocode}
+% The \cs{use:n} may seem pointless, and it is to some extent, but
+% we need it to get our disguised \cs{c_max_dim} displayed
+% properly as part of the error message if there is one. Without
+% it, the display would show only part of what we want it to show
+% (try it).
+% \begin{macrocode}
+ \exp_not:N \use:n {
+ \use:c{Infinite~shrink~error~above~ignored~!}
+ }
+% \end{macrocode}
+% Finally, we change the escape char and the interaction mode back
+% to what it was before:
+% \begin{macrocode}
+ \exp_not:N \l_@@_saved_parameters_tl
+}
+% \end{macrocode}
+% \end{macro}
+%
+%
+%
+% \begin{macro}{\l_@@_saved_parameters_tl}
+% The temporary variable used for resetting escape char and
+% interaction mode.
+% \begin{macrocode}
+\tl_new:N \l_@@_saved_parameters_tl
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_update_structure_from_material:nn}
+%
+% \changes{v1.0e}{2024/01/29}{Macro renamed}
+%
+% This function updates the mark structures of a region. The first
+% argument is the region to update and second argument receives the
+% material that holds the marks. Out of this material we extract
+% the first and last marks for all classes (if there are any) to do
+% the assignments.
+%
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_update_structure_from_material:nn #1#2 {
+ \@@_extract_and_handle_marks:nn
+% \end{macrocode}
+%
+% Once the marks can be extracted we update the structure from the
+% split marks (code in \cs{@@_update_structure_from_splitmarks:n}).
+% \begin{macrocode}
+ { \@@_update_structure_from_splitmarks:n {#1} }
+ { #2 }
+}
+% \end{macrocode}
+% \end{macro}
+%
+%
+%
+% \begin{macro}{\@@_update_structure_from_splitmarks:n}
+% This macro is called after we have done a \cs{tex_vsplit:D}
+% operation and the mark data is in the split marks.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_update_structure_from_splitmarks:n #1 {
+% \end{macrocode}
+%
+% The first thing we do is to copy the current region structure to
+% \texttt{previous-...}; this leaves the current structure
+% untouched so we can update it class by class (which is necessary).
+% \begin{macrocode}
+ \@@_update_structure_alias:nn { previous-#1 } {#1}
% \end{macrocode}
% After this action we can get first and last marks of the various
% classes through \cs{tex_splitfirstmarks:D} and
% \cs{tex_splitbotmarks:D}. So now we loop over all classes stored in
% \cs{g_@@_classes_seq}.
% \begin{macrocode}
- \seq_map_inline:Nn \g_@@_classes_seq
+ \seq_map_inline:Nn \g_@@_classes_seq
{
% \end{macrocode}
% First action: get the last mark from the previous region, i.e.,
@@ -950,14 +1167,14 @@
\tl_gset:No \g_@@_tmp_tl
{ \tex_splitbotmarks:D \use:c { c_@@_class_##1_mark } }
% \end{macrocode}
-% If this mark doesn't exist then obviously first mark does
-% neither, so both become the last mark from the previous region. We
+% If this mark doesn't exist then obviously neither does the first mark,
+% so both become the last mark from the previous region. We
% have to be a little careful here: something like
% \verb=\mark_insert:nn{foo}{}= adds an \enquote{empty} mark that should
% not be confused with no mark at all. But no mark in our material
% will result in \cs{g_@@_tmp_tl} being fully empty. This is why we
% have to make sure that \enquote{empty} from \cs{mark_insert:nn} only
-% appears to be empty but fails the next test (see below how this
+% appears to be empty when typeset but fails the next test (see below how this
% is done).
% \begin{macrocode}
\tl_if_empty:NTF \g_@@_tmp_tl
@@ -987,29 +1204,144 @@
}
}
}
- }
+}
% \end{macrocode}
-% If the badness was zero (we actually tested for${}>0$ but it
-% can't get negative) then we had infinite shrinkage, so we report
-% that and set all marks to the value the last mark had before.
+% \end{macro}
+%
+%
+%
+% \begin{macro}{\@@_get_marks_for_reinsertion:nNN}
+%
+% This function extracts the marks from the material in the first
+% argument but it does not update any the mark structures. Instead,
+% it collects the marks in the token lists given as the second and
+% third argument, in such a way that they can be reinserted by just
+% executing the token lists.\footnote{It is probably enough to
+% collect everything in a single token list as long as we put the
+% first marks first and the last marks last). But for extra
+% flexibility, I currently use 2 token lists. This might change when it is
+% really clear that this is never needed.}
+%
% \begin{macrocode}
- {
- \msg_error:nnn { mark } { infinite-shrinkage } {#1}
- \seq_map_inline:Nn \g_@@_classes_seq
+\cs_new_protected:Npn \@@_get_marks_for_reinsertion:nNN #1#2#3 {
+% \end{macrocode}
+% First we clear the temporary token lists as we haven't seen any marks yet.
+% \begin{macrocode}
+ \tl_clear:N \g_@@_first_marks_tl
+ \tl_clear:N \g_@@_last_marks_tl
+% \end{macrocode}
+% Then we extract all top-level marks, thereby filling the token lists
+% with suitable \cs{mark_insert:nn} calls.
+% \begin{macrocode}
+ \@@_extract_and_handle_marks:nn
+% \end{macrocode}
+% The first argument holds the code for fill the token lists and
+% the second is the material we extract from.
+% \begin{macrocode}
+ \@@_get_from_splitmarks:
+ { #1 }
+% \end{macrocode}
+%
+% Finally, we copy the updated (or not updated) temporary token
+% lists to the two that have been supplied when the function was
+% called. By convention \enquote{get} operations return their
+% values in local variables and \cs{@@_extract_and_handle_marks:nn}
+% runs in a group, which is why we have to use global temporary
+% variables for collecting.
+% \begin{macrocode}
+ \tl_set_eq:NN #2 \g_@@_first_marks_tl
+ \tl_set_eq:NN #3 \g_@@_last_marks_tl
+}
+% \end{macrocode}
+% \end{macro}
+%
+%
+% \begin{macro}{\@@_get_from_splitmarks:}
+% This function is called after we have done a \cs{vsplit} to
+% update the split marks. It loops through all mark classes to find
+% out if there are marks for this class and if so updates the
+% global tls used for collecting.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_get_from_splitmarks: {
+ \seq_map_inline:Nn \g_@@_classes_seq
{
- \tl_gset_eq:cc { g_@@_#1_top_ ##1_tl }
- { g_@@_#1_last_ ##1_tl }
- \tl_gset_eq:cc { g_@@_#1_first_##1_tl }
- { g_@@_#1_last_ ##1_tl }
+% \end{macrocode}
+% First we to get the last mark for the current class from the
+% material supplied.
+% \begin{macrocode}
+ \tl_gset:No \g_@@_tmp_tl
+ { \tex_splitbotmarks:D \use:c { c_@@_class_##1_mark } }
+% \end{macrocode}
+%
+% If this mark doesn't exist then obviously first mark doesn't
+% either, so we do nothing (other than issuing some debugging
+% info).
+
+% We have to be a little careful here: something like
+% \verb=\mark_insert:nn{foo}{}= adds an \enquote{empty} mark that
+% we should not confuse with the case where there is no mark at
+% all.
+%
+% When there is no mark at all we get a truly empty
+% \cs{g_@@_tmp_tl} as a result. This is why we have to make sure
+% that an \enquote{empty} mark generated with \cs{mark_insert:nn}
+% only appears to be empty when it is typeset, but fails the next
+% test (see below how this is done).
+% \begin{macrocode}
+ \tl_if_empty:NTF \g_@@_tmp_tl
+ {
+%<*trace>
+ \@@_debug:n { \iow_term:x { Marks:~no~ marks~
+ for~ class~ '##1'~\msg_line_context: } }
+%</trace>
+ }
+% \end{macrocode}
+%
+% If it wasn't empty, i.e., if it had a real value then we use this
+% value for our new last mark instead. This means we put an
+% appropriate \cs{mark_insert:nn} statement into
+% \cs{g_@@_last_marks_tl}.
+% \begin{macrocode}
+ {
+%<*trace>
+ \@@_debug:n { \iow_term:x { Marks:~ extract~ last~
+ mark~ for~ class~ '##1'~ =~ \g_@@_tmp_tl } }
+%</trace>
+ \tl_gput_right:Ne \g_@@_last_marks_tl
+ { \mark_insert:nn {##1} { \g_@@_tmp_tl } }
+% \end{macrocode}
+% Because we had a last mark we also have a first mark (which might
+% be the same, but might not be), so we pick that up and add it to
+% the \cs{g_@@_first_marks_tl} token list. This explains why we
+% first checked for the last mark because that makes the processing
+% faster in case there is none.
+% \begin{macrocode}
+%<*trace>
+ \@@_debug:n { \iow_term:x { Marks:~ extract~ first~
+ mark~ for~ class~ '##1'~ =~
+ \tex_splitfirstmarks:D
+ \use:c { c_@@_class_##1_mark }
+ } }
+%</trace>
+ \tl_gput_right:Ne \g_@@_first_marks_tl
+ { \mark_insert:nn {##1}
+ {
+ \tex_splitfirstmarks:D
+ \use:c { c_@@_class_##1_mark }
+ }
+ }
+ }
}
- }
+}
% \end{macrocode}
-% Once all mark classes have been processed the data structures are
-% updated and we can close the group which undoes our local
-% changes and retains only the global ones.
+% \end{macro}
+%
+%
+% \begin{macro}{\g_@@_first_marks_tl,\g_@@_last_marks_tl}
+% These are two global temporary variables used in the code above.
% \begin{macrocode}
- \group_end:
- }
+\tl_new:N \g_@@_first_marks_tl
+\tl_new:N \g_@@_last_marks_tl
% \end{macrocode}
% \end{macro}
%
@@ -1098,7 +1430,18 @@
% \begin{macrocode}
\@kernel@before@insertmark
\hook_use:n { insertmark }
- \unrestored@protected@xdef \g_@@_tmp_tl {#2}
+ \unrestored@protected@xdef \g_@@_tmp_tl
+ {
+% \end{macrocode}
+% To ensure that marks are unique we insert a hidden sequence
+% marker at the beginning of the content of the mark containing the
+% sequence number of the mark.
+% \changes{v1.0f}{2024/05/30}{Use sequence marker to make all marks
+% unique on nearby regions (gh/1359)}
+% \begin{macrocode}
+ \@@_id:n{ \int_use:N\g_@@_int }
+ #2
+ }
%<*trace>
\@@_debug:n{ \iow_term:x { Marks:~ set~#1~<-~
'\tl_to_str:V \g_@@_tmp_tl' ~ \msg_line_context: } }
@@ -1111,9 +1454,11 @@
% becomes empty, but not immediately; otherwise we just put
% \cs{g_@@_tmp_tl} in.
% \begin{macrocode}
- \tl_if_empty:NTF \g_@@_tmp_tl
- { \exp_not:n { \prg_do_nothing: } }
- { \exp_not:o { \g_@@_tmp_tl } }
+% this is no longer needed with 1.0f
+% \tl_if_empty:NTF \g_@@_tmp_tl
+% { \exp_not:n { \prg_do_nothing: } }
+% { \exp_not:o { \g_@@_tmp_tl } }
+ \exp_not:o { \g_@@_tmp_tl }
}
\group_end:
% \end{macrocode}
@@ -1135,15 +1480,43 @@
% \end{macro}
%
%
+% \begin{macro}{\@@_id:n}
+% A hidden marker is placed into every mark added by
+% \cs{mark_insert:nn}. It will will not show up in the output but
+% its argument (a counter value that is incremented) makes all
+% marks unique so the test for \enquote{equal} is not fooled by two
+% different marks having the same mark text.
+% \changes{v1.0f}{2024/05/30}{Use sequence marker to make all marks
+% unique on nearby regions (gh/1359)}
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_id:n #1 { }
+% \end{macrocode}
+% \end{macro}
+%
+%
% \begin{macro}[int]{\@kernel@before@insertmark}
% \begin{macro}{insertmark}
% By default \cs{label}, \cs{index}, and \cs{glossary} do nothing
% when the mark is inserted.
% \begin{macrocode}
+\int_new:N \g_@@_int
\cs_new:Npn \@kernel@before@insertmark {
\cs_set_eq:NN \label \scan_stop:
\cs_set_eq:NN \index \scan_stop:
\cs_set_eq:NN \glossary \scan_stop:
+% \end{macrocode}
+% We count each mark and use that to place a hidden marker in front
+% of the mark text. To ensure that there is no overflow (very
+% unlikely but you never know) we restart every 100000 marks. Thus,
+% if somebody puts more than that number of marks on a single page
+% you could construct a scenario in which that approach fails.
+% \changes{v1.0f}{2024/05/30}{Use sequence marker to make all marks
+% unique on nearby regions (gh/1359)}
+% \begin{macrocode}
+ \int_compare:nNnTF \g_@@_int < {99999}
+ { \int_gincr:N \g_@@_int }
+ { \int_gzero:N \g_@@_int }
+
}
% \end{macrocode}
% The public hook to augment the setup.
@@ -1158,15 +1531,25 @@
% To retrieve the first, last or top region mark, we grab the
% appropriate value stored in the corresponding token list variable
% and pass its contents back. These functions should be used only
-% in output routines after \cs{@@_update_structure:nn} has acted,
+% in output routines and only after \cs{@@_update_structure_from_material:nn} has acted,
% otherwise their value will be wrong.
%
% If used with an unknown class or region they generate an error
% (fairly low-level because we are in an expandable context).
+%
+% Each mark starts with an id and while the id does not print it is
+% nevertheless better to remove it when returning the mark, so that
+% downstream manipulation of the data doesn't have to deal with it.
+% \changes{v1.0g}{2024/05/31}{Remove the id when returning the mark value (gh/1359)}
% \begin{macrocode}
-\cs_new:Npn \mark_use_first:nn #1#2 { \exp_not:v { g_@@_#1_first_#2_tl } }
-\cs_new:Npn \mark_use_last:nn #1#2 { \exp_not:v { g_@@_#1_last_#2_tl } }
-\cs_new:Npn \mark_use_top:nn #1#2 { \exp_not:v { g_@@_#1_top_#2_tl } }
+\cs_new:Npn \mark_use_first:nn #1#2 { \@@_use:v { g_@@_#1_first_#2_tl } }
+\cs_new:Npn \mark_use_last:nn #1#2 { \@@_use:v { g_@@_#1_last_#2_tl } }
+\cs_new:Npn \mark_use_top:nn #1#2 { \@@_use:v { g_@@_#1_top_#2_tl } }
+% \end{macrocode}
+% This is what the \cs{use_none:nn} accomplishes.
+% \begin{macrocode}
+\cs_new:Npn \@@_use:n #1 { \exp_not:o { \use_none:nn #1 } }
+\cs_generate_variant:Nn \@@_use:n { v }
% \end{macrocode}
% \end{macro}
%
@@ -1207,7 +1590,7 @@
%
% \subsection{Messages}
%
-% Mark errors are LaTeX kernel errors:
+% Mark errors are \LaTeX{} kernel errors:
% \changes{v1.0d}{2022/06/01}{Marks are kernel errors}
% \begin{macrocode}
\prop_gput:Nnn \g_msg_module_type_prop { mark } { LaTeX }
@@ -1247,17 +1630,7 @@
}
% \end{macrocode}
%
-% \begin{macrocode}
-\msg_new:nnnn { mark } { infinite-shrinkage }
- { Infinite~shrinkage~found~in~'#1'. }
- {
- \c__msg_coding_error_text_tl
- The~mark~region~'#1'~contains~some~infinite~negative~glue~
- allowing~it~to~shrink~to~an~arbitrary~size.~
- This~makes~it~impossible~to~split~the~region~apart~to~
- get~at~its~marks.~They~are~lost.
- }
-% \end{macrocode}
+%
%
%
%
@@ -1358,7 +1731,7 @@
%
%
% \begin{macro}{\@@_status:n}
-% Show all mark class values across all regions.
+% Show a snapshot of all mark class values across all regions.
% \begin{macrocode}
\cs_new_protected:Npn \@@_status:n #1
{
@@ -1370,6 +1743,22 @@
% \end{macro}
%
%
+% \begin{macro}{\ShowMarksAt}
+% \changes{v1.0e}{2024/01/29}{Macro added}
+% Debugging helper that displays a snapshot of all known mark
+% structures. The argument is a text string that is
+% displayed to help identifying when the snapshot was made.
+%
+% This may not stay like this (or at all), which is why it isn't
+% yet documented as an official command.
+% \begin{macrocode}
+\cs_new_protected:Npn \ShowMarksAt #1 {
+%<*trace>
+ \@@_debug:n { \@@_status:n {#1} }
+%</trace>
+}
+% \end{macrocode}
+% \end{macro}
%
%
% \subsection{Designer-level interfaces}
@@ -1425,9 +1814,9 @@
%
%
%
-% \section{\LaTeXe{} integration}
+% \section{\LaTeXe{} integration}
%
-% \subsection{Core \LaTeXe{} integration}
+% \subsection{Core \LaTeXe{} integration}
%
% \begin{macro}{\@@_update_singlecol_structures:}
% This command updates the mark structures if we are producing a
@@ -1445,11 +1834,11 @@
% \begin{macrocode}
\box_if_vertical:NTF \@outputbox
{
- \@@_update_structure:nn {page}
+ \@@_update_structure_from_material:nn {page}
{ \vbox_unpack:N \@outputbox }
}
{
- \@@_update_structure:nn {page}
+ \@@_update_structure_from_material:nn {page}
{ \hbox_unpack:N \@outputbox }
}
% \end{macrocode}
@@ -1489,11 +1878,11 @@
% \begin{macrocode}
\box_if_vertical:NTF \@outputbox
{
- \@@_update_structure:nn {column}
+ \@@_update_structure_from_material:nn {column}
{ \vbox_unpack:N \@outputbox }
}
{
- \@@_update_structure:nn {column}
+ \@@_update_structure_from_material:nn {column}
{ \hbox_unpack:N \@outputbox }
}
% \end{macrocode}
@@ -1538,6 +1927,12 @@
% \begin{macrocode}
\seq_map_inline:Nn \g_@@_classes_seq
{
+% \end{macrocode}
+% The \texttt{previous-page} updates need to come before the
+% updates for \texttt{page} region because otherwise the values
+% to copy are already overwritten.
+% necessary values.
+% \begin{macrocode}
\tl_gset_eq:cc { g_@@_previous-page_top_ ##1 _tl }
{ g_@@_page_top_ ##1 _tl }
\tl_gset_eq:cc { g_@@_previous-page_first_ ##1 _tl }
@@ -1545,16 +1940,48 @@
\tl_gset_eq:cc { g_@@_previous-page_last_ ##1 _tl }
{ g_@@_page_last_ ##1 _tl }
% \end{macrocode}
-% The \texttt{page} updates need to come after the corresponding
-% updates for \texttt{previous-page} otherwise we loose the
-% necessary value.
+% To update the \texttt{top} we only have to copy what is in
+% \texttt{first-column}:
% \begin{macrocode}
\tl_gset_eq:cc { g_@@_page_top_ ##1 _tl }
{ g_@@_first-column_top_ ##1 _tl }
- \tl_gset_eq:cc { g_@@_ page_first_ ##1 _tl }
- { g_@@_first-column_first_ ##1 _tl }
- \tl_gset_eq:cc { g_@@_page_last_ ##1 _tl }
- { g_@@_last-column_last_ ##1 _tl }
+
+% \end{macrocode}
+% Updating the \texttt{first} mark for the \texttt{page} region is
+% more complicated. We first have to find out of there is any mark
+% in the first column (this can be done by comparing the \texttt{top} and
+% the \texttt{first} mark of of that region).
+% \changes{v1.0f}{2024/05/30}{Correct logic for first mark in page
+% region if first column contains no marks (gh/1359)}
+% \begin{macrocode}
+ \tl_if_eq:ccTF { g__@@_first-column_top_ ##1 _tl }
+ { g__@@_first-column_first_ ##1 _tl }
+ {
+% \end{macrocode}
+% If there is no mark in the first column we copy the first mark of
+% the last column. If that doesn't contain a mark we still get the
+% right result because the first mark is then equal to the top mark.
+% \begin{macrocode}
+ \tl_gset_eq:cc { g_@@_page_first_ ##1 _tl }
+ { g_@@_last-column_first_ ##1 _tl }
+ }
+ {
+% \end{macrocode}
+% On the other hand, if there is a mark in the first column we copy
+% over the \texttt{first} mark from that column.
+% \begin{macrocode}
+ \tl_gset_eq:cc { g_@@_page_first_ ##1 _tl }
+ { g_@@_first-column_first_ ##1 _tl }
+ }
+% \end{macrocode}
+% The logic for the \texttt{last} page mark is again simple, we can
+% just copy the value in the \texttt{last} mark of the last column.
+% If that column doesn't contain any marks, then the value in
+% \texttt{last} will be automatically the same as the \texttt{last}
+% from the first column.
+% \begin{macrocode}
+ \tl_gset_eq:cc { g_@@_page_last_ ##1 _tl }
+ { g_@@_last-column_last_ ##1 _tl }
}
}
%<*trace>
@@ -1583,17 +2010,26 @@
%<@@=>
% \end{macrocode}
%
-% \begin{macro}[int]{\@expl@@@mark@update@singlecol@structures@@,
-% \@expl@@@mark@update@dblcol@structures@@}
+% \begin{macro}[int]{\@expl@@@mark@update@singlecol@structures@@}
% \begin{macrocode}
\cs_new_eq:NN \@expl@@@mark@update@singlecol@structures@@
\__mark_update_singlecol_structures:
+% \end{macrocode}
+% \end{macro}
+%
+%
+%
+% \begin{macro}[int]{\@expl@@@mark@update@dblcol@structures@@}
+% \begin{macrocode}
\cs_new_eq:NN \@expl@@@mark@update@dblcol@structures@@
\__mark_update_dblcol_structures:
% \end{macrocode}
% \end{macro}
%
-% \subsection{Other \LaTeXe{} output routines}
+%
+%
+%
+% \subsection{Other \LaTeXe{} output routines}
%
% This section will cover \pkg{multicol} and other packages altering
% or providing their own output routine. Not done yet.
@@ -1601,6 +2037,9 @@
%
%
%
+% \subsection{Rollback information}
+%
+%
% \begin{macrocode}
%<latexrelease>\IncludeInRelease{0000/00/00}{ltmarks}%
%<latexrelease> {Undo~Marks~handling}
@@ -1609,7 +2048,7 @@
% We keep the interface commands around even if we roll back in
% case they are used in packages that don't roll back. Not likely
% to do a lot of good, but then there is not much we can do, but
-% this at least then doesn't give errors.
+% this at least they won't give unknown csname errors.
% \begin{macrocode}
%<latexrelease>\DeclareRobustCommand \NewMarkClass[1]{}
%<latexrelease>\DeclareRobustCommand \InsertMark[2]{}
diff --git a/macros/latex/base/ltmeta.dtx b/macros/latex/base/ltmeta.dtx
index 30da4016fb..cc3e62811d 100644
--- a/macros/latex/base/ltmeta.dtx
+++ b/macros/latex/base/ltmeta.dtx
@@ -13,20 +13,14 @@
%
%
%%% From File: ltmeta.dtx
-%
-% \begin{macrocode}
-\def\ltmetaversion{v1.0b}
-\def\ltmetadate{2022/05/18}
-% \end{macrocode}
%<*driver>
+% \fi
+\ProvidesFile{ltmeta.dtx}
+ [2024/05/16 v1.0b LaTeX Kernel (Document Metadata)]
+% \iffalse
+%
\documentclass{l3doc}
-
-% Fixing footnotes in functions and variables: this should be in l3doc!
-
-\newcommand\fixfootnote[2]{\footnotemark
- \AddToHookNext{env/#1/after}{\footnotetext{#2}}}
-\AddToHook{env/function/begin}{\def\footnote{\fixfootnote{function}}}
-\AddToHook{env/variable/begin}{\def\footnote{\fixfootnote{variable}}}
+\GetFileInfo{ltmeta.dtx}
\EnableCrossrefs
\CodelineIndex
@@ -43,7 +37,7 @@
%
%
% \title{The \texttt{ltmeta.dtx} code\thanks{This file has version
-% \ltmetaversion\ dated \ltmetadate, \copyright\ \LaTeX\
+% \fileversion\ dated \filedate, \copyright\ \LaTeX\
% Project.}}
% \author{Frank Mittelbach}
%
diff --git a/macros/latex/base/ltmiscen.dtx b/macros/latex/base/ltmiscen.dtx
index 9706f27203..accdac24b2 100644
--- a/macros/latex/base/ltmiscen.dtx
+++ b/macros/latex/base/ltmiscen.dtx
@@ -32,7 +32,7 @@
%<*driver>
% \fi
\ProvidesFile{ltmiscen.dtx}
- [2023/09/13 v1.2c LaTeX Kernel (Misc. Environments)]
+ [2024/02/08 v1.2c LaTeX Kernel (Misc. Environments)]
% \iffalse
\documentclass{ltxdoc}
\GetFileInfo{ltmiscen.dtx}
@@ -509,8 +509,8 @@
% endings are converted to spaces by \TeX{} during that process.
%
% However, especially the \texttt{.toc} file might be read in L-R mode
-% (in cases the \cs{tableofcontents} attempts to put, say a list of
-% sub-sections as a paragraph. In that case the newlines after a line
+% (in cases the \cs{tableofcontents} attempts to put, say, a list of
+% sub-sections as a paragraph). In that case the newlines after a line
% like
% \begin{verbatim}
% \contentsline {subsubsection}{\numberline {1.1.1}A C-head}{2}
@@ -520,9 +520,9 @@
%
% That could be fixed by reading in the file using
% \cs{endlinechar}\texttt{=-1} but that has the danger that it drops
-% some valid endlines that should be converted to spaces (for example
+% some valid endlines that should be converted to spaces (for example,
% when the user edited the TOC and then used \cs{nofiles} to preserve
-% it.
+% it).
%
% So the approach taken instead is this:
% \begin{itemize}
@@ -1604,7 +1604,7 @@
% ``\verb=!~!foo='' in the output.
% To avoid this scenario we check if \verb=#1= has the character
% code of a space, if so we recurse otherwise we call \cs{@@sverb}
-% (which is the original definition of \cs{@sverb}.
+% (which is the original definition of \cs{@sverb}).
% \changes{v1.1u}{2020/04/22}{Drop spaces before \cs{verb} delimiter (gh/327)}
% \begin{macrocode}
\def\@sverb#1{\if\noexpand#1 \expandafter\@sverb\else\@@sverb{#1}\fi}
diff --git a/macros/latex/base/ltnews.pdf b/macros/latex/base/ltnews.pdf
index d9318b5c30..49b79e34d3 100644
--- a/macros/latex/base/ltnews.pdf
+++ b/macros/latex/base/ltnews.pdf
Binary files differ
diff --git a/macros/latex/base/ltnews.tex b/macros/latex/base/ltnews.tex
index 05e37223e2..d4a6d274ae 100644
--- a/macros/latex/base/ltnews.tex
+++ b/macros/latex/base/ltnews.tex
@@ -40,7 +40,7 @@
\ProvidesFile{ltnews.tex}%
[2022/06/10 v1.4e Master file for ltnews*.tex (LaTeX Project)]
-\providecommand*{\lastissue}{38}
+\providecommand*{\lastissue}{39}
\InputIfFileExists{ltnews-lastissue.cfg}{}{}
diff --git a/macros/latex/base/ltnews01.pdf b/macros/latex/base/ltnews01.pdf
index bb1c3479ae..7b770a65c0 100644
--- a/macros/latex/base/ltnews01.pdf
+++ b/macros/latex/base/ltnews01.pdf
Binary files differ
diff --git a/macros/latex/base/ltnews02.pdf b/macros/latex/base/ltnews02.pdf
index fceaba3de6..7866b8eeeb 100644
--- a/macros/latex/base/ltnews02.pdf
+++ b/macros/latex/base/ltnews02.pdf
Binary files differ
diff --git a/macros/latex/base/ltnews03.pdf b/macros/latex/base/ltnews03.pdf
index 5b15e3eb7c..60ba50f32f 100644
--- a/macros/latex/base/ltnews03.pdf
+++ b/macros/latex/base/ltnews03.pdf
Binary files differ
diff --git a/macros/latex/base/ltnews04.pdf b/macros/latex/base/ltnews04.pdf
index 366704a89d..1d3becc2bc 100644
--- a/macros/latex/base/ltnews04.pdf
+++ b/macros/latex/base/ltnews04.pdf
Binary files differ
diff --git a/macros/latex/base/ltnews05.pdf b/macros/latex/base/ltnews05.pdf
index 85bee898ce..4073a53b74 100644
--- a/macros/latex/base/ltnews05.pdf
+++ b/macros/latex/base/ltnews05.pdf
Binary files differ
diff --git a/macros/latex/base/ltnews06.pdf b/macros/latex/base/ltnews06.pdf
index f3aec4acdf..4d8803f831 100644
--- a/macros/latex/base/ltnews06.pdf
+++ b/macros/latex/base/ltnews06.pdf
Binary files differ
diff --git a/macros/latex/base/ltnews07.pdf b/macros/latex/base/ltnews07.pdf
index d30e8d184e..798590a76b 100644
--- a/macros/latex/base/ltnews07.pdf
+++ b/macros/latex/base/ltnews07.pdf
Binary files differ
diff --git a/macros/latex/base/ltnews08.pdf b/macros/latex/base/ltnews08.pdf
index b1c0c2b522..d622376dbb 100644
--- a/macros/latex/base/ltnews08.pdf
+++ b/macros/latex/base/ltnews08.pdf
Binary files differ
diff --git a/macros/latex/base/ltnews09.pdf b/macros/latex/base/ltnews09.pdf
index 0050844b8c..543079562d 100644
--- a/macros/latex/base/ltnews09.pdf
+++ b/macros/latex/base/ltnews09.pdf
Binary files differ
diff --git a/macros/latex/base/ltnews10.pdf b/macros/latex/base/ltnews10.pdf
index 2adda73502..34503b1c0b 100644
--- a/macros/latex/base/ltnews10.pdf
+++ b/macros/latex/base/ltnews10.pdf
Binary files differ
diff --git a/macros/latex/base/ltnews11.pdf b/macros/latex/base/ltnews11.pdf
index 23fcd19b29..e49ea664ac 100644
--- a/macros/latex/base/ltnews11.pdf
+++ b/macros/latex/base/ltnews11.pdf
Binary files differ
diff --git a/macros/latex/base/ltnews12.pdf b/macros/latex/base/ltnews12.pdf
index d0c4c1f192..1f540b699e 100644
--- a/macros/latex/base/ltnews12.pdf
+++ b/macros/latex/base/ltnews12.pdf
Binary files differ
diff --git a/macros/latex/base/ltnews13.pdf b/macros/latex/base/ltnews13.pdf
index bdeb853315..2dca33b57f 100644
--- a/macros/latex/base/ltnews13.pdf
+++ b/macros/latex/base/ltnews13.pdf
Binary files differ
diff --git a/macros/latex/base/ltnews14.pdf b/macros/latex/base/ltnews14.pdf
index 78bd35261a..f7aff8a10b 100644
--- a/macros/latex/base/ltnews14.pdf
+++ b/macros/latex/base/ltnews14.pdf
Binary files differ
diff --git a/macros/latex/base/ltnews15.pdf b/macros/latex/base/ltnews15.pdf
index 532518b849..a63ae6d288 100644
--- a/macros/latex/base/ltnews15.pdf
+++ b/macros/latex/base/ltnews15.pdf
Binary files differ
diff --git a/macros/latex/base/ltnews16.pdf b/macros/latex/base/ltnews16.pdf
index 283472da94..f5756e4633 100644
--- a/macros/latex/base/ltnews16.pdf
+++ b/macros/latex/base/ltnews16.pdf
Binary files differ
diff --git a/macros/latex/base/ltnews17.pdf b/macros/latex/base/ltnews17.pdf
index 4407a451db..0de538362b 100644
--- a/macros/latex/base/ltnews17.pdf
+++ b/macros/latex/base/ltnews17.pdf
Binary files differ
diff --git a/macros/latex/base/ltnews18.pdf b/macros/latex/base/ltnews18.pdf
index f03865e055..a4d531a1d9 100644
--- a/macros/latex/base/ltnews18.pdf
+++ b/macros/latex/base/ltnews18.pdf
Binary files differ
diff --git a/macros/latex/base/ltnews19.pdf b/macros/latex/base/ltnews19.pdf
index 82fb604409..04a090a73c 100644
--- a/macros/latex/base/ltnews19.pdf
+++ b/macros/latex/base/ltnews19.pdf
Binary files differ
diff --git a/macros/latex/base/ltnews20.pdf b/macros/latex/base/ltnews20.pdf
index d0cf9a25b2..60154a2351 100644
--- a/macros/latex/base/ltnews20.pdf
+++ b/macros/latex/base/ltnews20.pdf
Binary files differ
diff --git a/macros/latex/base/ltnews21.pdf b/macros/latex/base/ltnews21.pdf
index cb04e771a5..3f46daa1c2 100644
--- a/macros/latex/base/ltnews21.pdf
+++ b/macros/latex/base/ltnews21.pdf
Binary files differ
diff --git a/macros/latex/base/ltnews22.pdf b/macros/latex/base/ltnews22.pdf
index 574c6a7e90..69285c673e 100644
--- a/macros/latex/base/ltnews22.pdf
+++ b/macros/latex/base/ltnews22.pdf
Binary files differ
diff --git a/macros/latex/base/ltnews23.pdf b/macros/latex/base/ltnews23.pdf
index 302f42d7de..ca26eeda60 100644
--- a/macros/latex/base/ltnews23.pdf
+++ b/macros/latex/base/ltnews23.pdf
Binary files differ
diff --git a/macros/latex/base/ltnews24.pdf b/macros/latex/base/ltnews24.pdf
index 3880b4f29a..8fac501b4b 100644
--- a/macros/latex/base/ltnews24.pdf
+++ b/macros/latex/base/ltnews24.pdf
Binary files differ
diff --git a/macros/latex/base/ltnews25.pdf b/macros/latex/base/ltnews25.pdf
index a3fbc572ab..ccb7249d8b 100644
--- a/macros/latex/base/ltnews25.pdf
+++ b/macros/latex/base/ltnews25.pdf
Binary files differ
diff --git a/macros/latex/base/ltnews26.pdf b/macros/latex/base/ltnews26.pdf
index d11dcd2b70..0e3ddf34a9 100644
--- a/macros/latex/base/ltnews26.pdf
+++ b/macros/latex/base/ltnews26.pdf
Binary files differ
diff --git a/macros/latex/base/ltnews27.pdf b/macros/latex/base/ltnews27.pdf
index 3012fa054b..e9896c50f0 100644
--- a/macros/latex/base/ltnews27.pdf
+++ b/macros/latex/base/ltnews27.pdf
Binary files differ
diff --git a/macros/latex/base/ltnews28.pdf b/macros/latex/base/ltnews28.pdf
index 1569168804..c832553e0e 100644
--- a/macros/latex/base/ltnews28.pdf
+++ b/macros/latex/base/ltnews28.pdf
Binary files differ
diff --git a/macros/latex/base/ltnews28.tex b/macros/latex/base/ltnews28.tex
index fec5c5c6c9..de4ecfa00a 100644
--- a/macros/latex/base/ltnews28.tex
+++ b/macros/latex/base/ltnews28.tex
@@ -126,7 +126,7 @@ happened. For example, the German word ``Gr\"o\ss e'' (height) entered on a
German keyboard could show up as ``Gr\v T\`ae'' on a different
computer using a different encoding by default.
-So in summmary the situation wasn't at all good and it was clear in
+So in summary the situation wasn't at all good and it was clear in
the early nineties that \LaTeXe{} (that was being developed to provide
a \LaTeX{} version usable across the world) had to provide a solution
to this issue.
@@ -318,7 +318,7 @@ As a result some parts of the columns did overprint each other.
The fix required a redesign of the output routines used by
\pkg{multicol} and while it ``should'' be transparent in other cases
-(and all tests in the regession test suite came out fine) there is the
+(and all tests in the regression test suite came out fine) there is the
off-chance that code that hooked into internals of \pkg{multicol}
needs adjustment.
diff --git a/macros/latex/base/ltnews29.pdf b/macros/latex/base/ltnews29.pdf
index 61b0c8dfcf..bedf1ed031 100644
--- a/macros/latex/base/ltnews29.pdf
+++ b/macros/latex/base/ltnews29.pdf
Binary files differ
diff --git a/macros/latex/base/ltnews30.pdf b/macros/latex/base/ltnews30.pdf
index dd58858990..86e45a1eea 100644
--- a/macros/latex/base/ltnews30.pdf
+++ b/macros/latex/base/ltnews30.pdf
Binary files differ
diff --git a/macros/latex/base/ltnews31.pdf b/macros/latex/base/ltnews31.pdf
index cf7f452958..ac6729dbba 100644
--- a/macros/latex/base/ltnews31.pdf
+++ b/macros/latex/base/ltnews31.pdf
Binary files differ
diff --git a/macros/latex/base/ltnews31.tex b/macros/latex/base/ltnews31.tex
index 194791cff5..c1b81e52be 100644
--- a/macros/latex/base/ltnews31.tex
+++ b/macros/latex/base/ltnews31.tex
@@ -552,8 +552,8 @@ This was corrected.
\subsection{Ensure that \cs{textbackslash} remains robust}
In the last release we made most document-level commands robust, but
-\cs{textbackslash} became fragile again\\
-whenever \cs{raggedright} or similar typesetting\\
+\cs{textbackslash} became fragile again
+whenever \cs{raggedright} or similar typesetting
was used. This has been fixed.
%
\githubissue{203}
diff --git a/macros/latex/base/ltnews32.pdf b/macros/latex/base/ltnews32.pdf
index f52cd24444..7691d3824f 100644
--- a/macros/latex/base/ltnews32.pdf
+++ b/macros/latex/base/ltnews32.pdf
Binary files differ
diff --git a/macros/latex/base/ltnews33.pdf b/macros/latex/base/ltnews33.pdf
index 795e30a114..fd08812bc4 100644
--- a/macros/latex/base/ltnews33.pdf
+++ b/macros/latex/base/ltnews33.pdf
Binary files differ
diff --git a/macros/latex/base/ltnews34.pdf b/macros/latex/base/ltnews34.pdf
index e431c49cf7..6c7817a0d7 100644
--- a/macros/latex/base/ltnews34.pdf
+++ b/macros/latex/base/ltnews34.pdf
Binary files differ
diff --git a/macros/latex/base/ltnews35.pdf b/macros/latex/base/ltnews35.pdf
index a5ff443519..77c334f482 100644
--- a/macros/latex/base/ltnews35.pdf
+++ b/macros/latex/base/ltnews35.pdf
Binary files differ
diff --git a/macros/latex/base/ltnews35.tex b/macros/latex/base/ltnews35.tex
index 8f0c9d6ae3..d8c985b813 100644
--- a/macros/latex/base/ltnews35.tex
+++ b/macros/latex/base/ltnews35.tex
@@ -547,7 +547,7 @@ enabling \cs{obeyspaces} within a %
quote environment.
\end{quote}
Thus, if you are keen to use the plain \TeX{} trick, you need to say
-\cs{let}\cs{obeyedlines}\texttt{=}\cs{cr} now.
+\cs{let}\cs{obeyedline}\texttt{=}\cs{cr} now.
%
\githubissue{367}
diff --git a/macros/latex/base/ltnews36.pdf b/macros/latex/base/ltnews36.pdf
index 7ec209184d..de30185937 100644
--- a/macros/latex/base/ltnews36.pdf
+++ b/macros/latex/base/ltnews36.pdf
Binary files differ
diff --git a/macros/latex/base/ltnews37.pdf b/macros/latex/base/ltnews37.pdf
index 3d0f317f93..9e5ae8a9d1 100644
--- a/macros/latex/base/ltnews37.pdf
+++ b/macros/latex/base/ltnews37.pdf
Binary files differ
diff --git a/macros/latex/base/ltnews38.pdf b/macros/latex/base/ltnews38.pdf
index 699f313049..81bb4d3b5c 100644
--- a/macros/latex/base/ltnews38.pdf
+++ b/macros/latex/base/ltnews38.pdf
Binary files differ
diff --git a/macros/latex/base/ltnews38.tex b/macros/latex/base/ltnews38.tex
index 04ffe1a0ed..bf485de239 100644
--- a/macros/latex/base/ltnews38.tex
+++ b/macros/latex/base/ltnews38.tex
@@ -177,7 +177,7 @@ and \pkg{biblatex}.
For now activation is done through the line
\begin{verbatim}
\DocumentMetadata
- {testphase={phase-III,math,tabular}}
+ {testphase={phase-III,math,table}}
\end{verbatim}
The math and the tabular support are not yet incorporated into
\texttt{phase-III} but need their own activation, so that we can
diff --git a/macros/latex/base/ltnews39.pdf b/macros/latex/base/ltnews39.pdf
new file mode 100644
index 0000000000..7b4f627bb8
--- /dev/null
+++ b/macros/latex/base/ltnews39.pdf
Binary files differ
diff --git a/macros/latex/base/ltnews39.tex b/macros/latex/base/ltnews39.tex
new file mode 100644
index 0000000000..1ac9c9e54c
--- /dev/null
+++ b/macros/latex/base/ltnews39.tex
@@ -0,0 +1,893 @@
+% \iffalse meta-comment
+%
+% Copyright 2024
+% The LaTeX Project and any individual authors listed elsewhere
+% in this file.
+%
+% This file is part of the LaTeX base system.
+% -——————————————
+%
+% It may be distributed and/or modified under the
+% conditions of the LaTeX Project Public License, either version 1.3c
+% of this license or (at your option) any later version.
+% The latest version of this license is in
+% https://www.latex-project.org/lppl.txt
+% and version 1.3c or later is part of all distributions of LaTeX
+% version 2008 or later.
+%
+% This file has the LPPL maintenance status "maintained".
+%
+% The list of all files belonging to the LaTeX base distribution is
+% given in the file `manifest.txt'. See also `legal.txt' for additional
+% information.
+%
+% The list of derived (unpacked) files belonging to the distribution
+% and covered by LPPL is defined by the unpacking scripts (with
+% extension .ins) which are part of the distribution.
+%
+% \fi
+% Filename: ltnews39.tex
+%
+% This is issue 39 of LaTeX News.
+
+\NeedsTeXFormat{LaTeX2e}[2020-02-02]
+
+\documentclass{ltnews}
+
+%% Maybe needed only for Chris' inadequate system:
+\providecommand\Dash {\unskip \textemdash}
+
+%% NOTE: Chris' preferred hyphens!
+%% \showhyphens{parameters}
+%% \hyphenation{because}
+
+\usepackage[T1]{fontenc}
+
+\usepackage{lmodern,url,hologo}
+
+\usepackage{csquotes}
+\usepackage{multicol}
+\usepackage{color}
+
+\providecommand\hook[1]{\texttt{#1}}
+
+\providecommand\meta[1]{$\langle$\textrm{\itshape#1}$\rangle$}
+\providecommand\option[1]{\texttt{#1}}
+\providecommand\env[1]{\texttt{#1}}
+\providecommand\Arg[1]{\texttt\{\meta{#1}\texttt\}}
+
+
+\providecommand\eTeX{\hologo{eTeX}}
+\providecommand\XeTeX{\hologo{XeTeX}}
+\providecommand\LuaTeX{\hologo{LuaTeX}}
+\providecommand\pdfTeX{\hologo{pdfTeX}}
+\providecommand\MiKTeX{\hologo{MiKTeX}}
+\providecommand\CTAN{\textsc{ctan}}
+\providecommand\TL{\TeX\,Live}
+
+
+\providecommand\githubissue[2][]{\ifhmode\unskip\fi
+ \quad\penalty500\strut\nobreak\hfill
+ \mbox{\small\slshape(%
+ \href{https://github.com/latex3/latex2e/issues/\getfirstgithubissue#2 \relax}%
+ {github issue#1 #2}%
+ )}%
+ \par\smallskip}
+%% But Chris has to mostly disable \href for his TEXPAD app:
+%% \def\href #1#2{#2} % Only For Chris' deficient TeX engine
+
+% simple solution right now (just link to the first issue if there are more)
+\def\getfirstgithubissue#1 #2\relax{#1}
+
+\providecommand\sxissue[1]{\ifhmode\unskip
+ \else
+ % githubissue preceding
+ \vskip-\smallskipamount
+ \vskip-\parskip
+ \fi
+ \quad\penalty500\strut\nobreak\hfill
+ \mbox{\small\slshape(\url{https://tex.stackexchange.com/#1})}\par}
+
+\providecommand\gnatsissue[2]{\ifhmode\unskip\fi
+ \quad\penalty500\strut\nobreak\hfill
+ \mbox{\small\slshape(%
+ \href{https://www.latex-project.org/cgi-bin/ltxbugs2html?pr=#1\%2F\getfirstgithubissue#2 \relax}%
+ {gnats issue #1/#2}%
+ )}%
+ \par}
+
+\let\cls\pkg
+\providecommand\env[1]{\texttt{#1}}
+\providecommand\acro[1]{\textsc{#1}}
+
+\vbadness=1400 % accept slightly empty columns
+
+
+\let\finalpagebreak\pagebreak % for TUB (if they use it)
+\let\finalvspace\vspace % for document layout fixes
+
+\makeatletter
+% maybe not the greatest design but normally we wouldn't have subsubsections
+\renewcommand{\subsubsection}{%
+ \@startsection {subsubsection}{2}{0pt}{1.5ex \@plus 1ex \@minus .2ex}%
+ {-1em}{\@subheadingfont\colonize}%
+}
+\providecommand\colonize[1]{#1:}
+\makeatother
+
+
+% Undo ltnews's \verbatim@font with active < and >
+\makeatletter
+\def\verbatim@font{\normalsize\ttfamily}
+\makeatother
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+\providecommand\tubcommand[1]{}
+\tubcommand{\input{tubltmac}}
+
+\publicationmonth{June}
+%\publicationyear{2024 --- DRAFT version for upcoming release}
+\publicationyear{2024}
+
+\publicationissue{39}
+
+\begin{document}
+
+\tubcommand{\addtolength\textheight{4.2pc}} % only for TUB
+
+\maketitle
+{\hyphenpenalty=10000 \exhyphenpenalty=10000 \spaceskip=3.33pt \hbadness=10000
+\tableofcontents}
+
+\setlength\rightskip{0pt plus 3em}
+
+\medskip
+
+\section{Introduction}
+
+The \LaTeX{} Project team remains strongly focused on producing
+automatically tagged PDF output for accessibility and reuse. At the
+beginning of 2024 the ISO PDF/UA-2 and the WTPDF (well-tagged PDF)
+standards were released and we are glad to be able to report that it
+is now possible to use \LaTeX{} to automatically produce documents
+that conform to these new standards.\footnote{At the present time we
+are still in a trial/prototype phase in which only a limited set of
+document classes and packages are supported. Over the next releases
+we expect to gradually lift these restrictions and eventually provide
+the full functionality as part of the core distribution, rather than
+through \texttt{latex-lab} modules.} A sample collection of such
+documents ranging from classical texts, such as the Bible, to recent
+technical papers submitted to arXiv.org can be found at
+\url{https://github.com/latex3/tagging-project/discussions/72}.
+
+In February Ulrike and Frank presented the current project status
+during the 5th International Workshop on \enquote{Digitization and
+ E-Inclusion in Mathematics and Science 2024} (DEIMS 2024) at Nihon
+University, Tokyo, Japan; see~\cite{39:deims}.
+
+
+\section{News from the \enquote{\LaTeX{} Tagged PDF} project}
+
+In the previous \LaTeX{} News~\cite{39:ltnews38} we announced some prototype
+support for tagged tabulars. Some of the necessary code has
+now been moved from \texttt{latex-lab} to the corresponding packages
+(using sockets and plugs) and to the \LaTeX{} kernel (for those parts
+that are also necessary for other aspects of tagging).
+
+The kernel code specific to tagging is implemented in the file
+\texttt{lttagging.dtx}. For now it contains \cs{UseTaggingSocket}, a
+special invocation command for sockets that are specific to
+tagging. This enables us to also provide \cs{SuspendTagging} and
+\cs{ResumeTagging}, i.e., a very efficient way to temporarily disable
+the whole tagging process. This is, for example, necessary if some
+code is doing trial typesetting. In that case the trials should not
+generate tagging structures\Dash only the finally-chosen version
+should. Thus, \pkg{tabularx}, for example, stops the tagging while
+doing its trials to figure out the correct column widths to use, and
+then re-enables tagging when the table is finally typeset.
+
+Over time, \texttt{lttagging.dtx} will hold more general tagging code
+as appropriate. For now it is only documented as part of
+\texttt{source2e.pdf} but long term we will provide a separate guide
+for tagging, which will then also include the information currently
+found in various other places, e.g., \texttt{tagpdf.pdf}.
+
+We also added support for a few missing commands
+described in Leslie Lamport's \emph{\LaTeX{}
+Manual}~\cite{39:Lamport}: If \texttt{phase-III} is used
+the \cs{marginpar} command will be properly tagged (depending on
+the PDF version) as an \texttt{Aside} or a \texttt{Note} structure.
+In the standard classes \cs{maketitle} will be tagged if the additional
+testphase module \texttt{title} is used.
+
+The \texttt{math} module has been extended and now includes
+options to attach MathML files to the structures.
+First tests with a PDF reader and screen reader that support
+associated files look very promising. Examples of PDF files tagged with the
+new method can be found at
+\url{https://github.com/latex3/tagging-project/discussions/72}.
+
+At last various small bugs and problems reported at
+\url{https://github.com/latex3/tagging-project}
+have been fixed.
+Such feedback is very valuable,
+so we hope to see you there and thank you for
+any contribution, whether it is an issue or a post on a discussion
+thread.
+
+
+
+\section{Enhancements to the new mark mechanism}
+
+In June 2022 we introduced a new mark mechanism~\cite[p.~76]{39:ltnews} that allows keeping track of multiple
+independent marks. It also properly supports top marks, something that wasn't
+reliably possible with \LaTeX{} before.
+
+There was, however, one limitation: to retrieve the marks from the
+page data it was necessary to \cs{vsplit} that data artificially so
+that \TeX{} would produce split marks that the mechanism could then
+use. Unfortunately, \TeX{} gets very upset if it finds infinite
+negative glue (e.g., from \cs{vss}) within this data. This is not
+totally surprising because such glue would allow splitting off any
+amount of material as such glue would hide its size. \TeX{}
+therefore responds with an error message if it find such glue while
+doing a \cs{vsplit} operation (and it does so even if a later glue
+item cancels the infinite glue).
+
+To account for this, the code in 2022 attempted to detect this
+situation beforehand and if so did not do any splitting but, of
+course, it would then also not extract any mark information.
+
+In this release the approach has been changed and we always do a
+\cs{vsplit} operation and thus always get the right mark data
+extracted. While it is not possible to avoid upsetting \TeX{} in case
+we have infinite negative glue present, it is possible to hide this
+(more or less) from the user.\footnote{A note to \pkg{l3build} users
+that make use of its testing capabilities: the new mechanism
+temporarily changes \cs{interactionmode} and, for implementation
+reasons in \TeX{}, that results in extra newlines in the \texttt{.log}
+file, so instead of seeing \texttt{[1] [2]} you will see each on
+separate lines. This means that test files might show differences of
+that nature, once the code is active, and must therefore be
+regenerated as necessary.} With the new code \TeX{} will neither stop
+nor show anything on the terminal. What we can't do, though, is
+avoid an error being written to the log file, but to make it clear
+that this error is harmless and should be ignored we have arranged the
+code so that the error message, if it is issued, takes the following
+format:
+\begingroup
+\makeatletter
+\def\verbatim@font{%
+ \small\ttfamily}
+\makeatother
+\begin{verbatim}
+! Infinite glue shrinkage found in box being split.
+<argument> Infinite shrink error above ignored !
+l. ... }
+\end{verbatim}
+Not perfect (especially the somewhat unmotivated \texttt{<argument>}),
+but you can only do so much when error messages and their texts are
+hard-wired in the engine.
+
+\endgroup
+
+So why all this? There are two reasons: we do not lose marks in edge
+cases any more, and perhaps more importantly we are now also reliably
+able to extract marks from arbitrarily boxed data, something that
+wasn't possible at all before. This is necessary, for example, to
+support extended marks in \env{multicols} environments or extract them
+from floats, marginpars, etc.\tubcommand{\looseness-1}
+
+Details about the implementation can be found in \texttt{texdoc
+ ltmarks-code} or in the shorter \texttt{texdoc ltmarks-doc} (which
+only describes the general concepts and the command interfaces).
+
+
+\section{Providing \pkg{xtemplate} in the format}
+
+In \LaTeX{} News~32, we described the move of one long-term experimental idea
+into the kernel: the package \pkg{xparse}, which was integrated as \pkg{ltcmd}.
+With this edition, we move another long-term development idea to stable status:
+\emph{templates}.
+
+In this context, templates are a mechanism to abstract out various elements
+of a document (such as \enquote{sectioning}) in such a way that different
+implementations can be interchanged,
+%% CAR added text: --- FMi: but it is wrong
+%% variations of the document markup can be accommodated,
+and design decisions can be implemented efficiently and controllably.
+
+In contrast to \pkg{ltcmd}, which provides a mechanism that many document
+authors will exploit routinely, templates are a more specialised tool. We
+anticipate that they will be used by a small number of programmers, providing
+generic ideas that will then be used within document classes. Most document
+authors will therefore likely directly encounter templates only rarely.
+We anticipate though that they will be \emph{using} templates provided
+by the team or others.
+
+%% CAR added this paragraph: FMi: doesn't belong in ltnews
+%We shall continue to develop these generic ideas and interfaces in various ways: for example, to support the varied document markup possibilities
+%provided in \pkg{ltcmd} and elsewhere.
+
+The template system requires three separate ideas
+\begin{itemize}
+ \item Template \emph{type}: the \enquote{thing} we are using templates
+ for, such as \enquote{sectioning} or \enquote{enumerated-list}
+ \item A template: a combination of code and keys that can be used
+ to implement a type. Here for example we might have
+ \enquote{standard-\LaTeX{}-sectioning} as a template for
+ \enquote{sectioning}
+ \item One or more \emph{instances}: a specific use case of a template
+ where (some) keys are set to known values. We might for example see
+ \enquote{\LaTeX{}-section}, \enquote{\LaTeX{}-subsection}, etc.
+\end{itemize}
+
+As part of the move from the experimental \pkg{xtemplate} to kernel integration,
+the team have revisited the commands provided. The stable set now comprises
+\begin{itemize}
+\item \cs{NewTemplateType}
+\item \cs{DeclareTemplateInterface}
+\item \cs{DeclareTemplateCode}
+\item \cs{DeclareTemplateCopy}
+\item \cs{EditTemplateDefault}
+\item \cs{UseTemplate}
+\item \cs{DeclareInstance}
+\item \cs{DeclareInstanceCopy}
+\item \cs{EditInstance}
+\item \cs{UseInstance}
+\item \cs{IfInstanceExistsTF} and variants
+\end{itemize}
+
+To support existing package authors, we have released an updated version of
+\pkg{xtemplate} which will work smoothly with the new kernel-level code. The
+existing commands provided in \pkg{xtemplate} will continue to work, but
+we encourage programmers to move to the set above.
+
+
+\section{New or improved commands}
+
+\subsection{\pkg{doc}:\ Provide \cs{ProvideDocElement}}
+
+In addition to
+\cs{NewDocElement} and \cs{RenewDocElement} we now also offer a
+\cs{ProvideDocElement} declaration that does nothing unless the doc
+element could be declared with \cs{NewDocElement}. This can be useful
+if documentation files are processed both individually and
+combined.
+
+
+\subsection{\pkg{doc}:\ Better support for \pkg{upquote}}
+
+In \LaTeX{} News~37~\cite{39:ltnews37} we wrote that support for the
+\pkg{upquote} package was added to the \pkg{doc} package, but back
+then this was added only for \cs{verb} and the \env{verbatim}
+environments. However,
+in a typical \texttt{.dtx} file, most of the code will be in the body
+of some \env{macrocode} or \env{macrocode*} environments, and neither
+of these was affected by adding \pkg{upquote}.
+We have now updated \pkg{doc} so that
+\pkg{upquote} alters the quote characters in these environments as
+well.
+%
+\githubissue{1230}
+
+\subsection[\pkg{ifthen}:\ Allow active characters in comparisons]
+ {\pkg{ifthen}:\ Guard against active characters in comparisons}
+The \cs{ifthenelse} command now ensures that \verb|<|, \verb|=| and
+\verb|>| are safe
+in numeric tests, even if they have been made active
+(typically by \pkg{babel} language shorthands).
+%
+\githubissue{756}
+
+\subsection%[New conditionals: \cs{IfClassAtLeastT}, etc.]
+ {New conditionals:\ \cs{IfClassAtLeastT} and friends}
+
+Around 2020 we added a number of conditionals with CamelCase names, i.e.,
+%
+\cs{IfClassAtLeastTF},
+\cs{IfClassLoadedTF},
+\cs{IfClassLoadedWithOptionsFF},
+\cs{IfFormatAtLeastTF},
+\cs{IfPackageAtLeastTF},
+\cs{IfPackageLoadedTF}, and
+\cs{IfPackageLoadedWithOptionsTF}
+%
+to help arranging conditional code that depends on the release of a
+particular class, package or format. However, we only provided the
+\texttt{TF} commands and not also the \texttt{T} and \texttt{F}
+variants. This has now been changed.
+
+In 2023 we introduced \cs{IfFileAtLeastTF} but we did not also provide
+\cs{IfFileLoadedTF} at the same time. This conditional and its
+\texttt{T} and \texttt{F} variants have now also been added. Remember
+that one can only test for files that contain a \cs{ProvidesFile}
+line.
+%
+We did the same for the conditionals \cs{IfLabelExistsTF} and
+\cs{IfPropertyExistsTF}, also introduced in 2023.\footnote{By mistake they
+were initially introduced under the names \cs{IfLabelExistTF} and
+\cs{IfPropertyExistTF}; we corrected that at the same time. This is a
+breaking change, but the commands have been used so far only in
+kernel code.}
+%
+\githubissue[s]{1222 1262}
+
+
+\section{Code improvements}
+
+\subsection{Load packages only at the top level}
+
+Classes and packages must be loaded only by using the commands
+\cs{documentclass} and \cs{usepackage} or the class interface commands
+such as \cs{LoadClass} or \cs{RequirePackageWithOptions}; moreover,
+all of these must always be used at the top level, and not inside a
+group of any type (for example, within an environment).
+Previously \LaTeX\ did not check this,
+which would often lead to low level errors later on if package declarations
+were reverted when a group ended.
+\LaTeX\ now checks the group level and an error is thrown
+if the class or package is loaded in a group.
+%
+\githubissue{1185}
+
+\subsection{Keep track of lost glyphs}
+
+A while ago we changed the \LaTeX{} default value for
+\cs{tracinglostchars} from \texttt{1} to \texttt{2} so that missing
+glyphs generate at least a warning, but we forgot to make the same
+change to \cs{tracingnone}. Thus, when issuing that command \LaTeX{}
+stopped generating warnings about missing glyphs. This has now been
+corrected.
+%
+\githubissue{549}
+
+\subsection{Improve \pkg{fontenc} error message}
+
+If the \pkg{fontenc} package is asked to load a font encoding for which it
+doesn't find a suitable \texttt{.def} file then it generates an error
+message indicating that the encoding name might be misspelled. That
+is, of course, one of the possible causes, but another one is that the
+installation is missing a necessary support package, e.g., that no
+support for Cyrillic fonts has been installed. The error message text
+has therefore been extended to explain the issue more generally.
+%
+\githubissue{1102}
+
+
+\subsection{Warn if counter names are problematic}
+
+In the past it was possible to declare, for example,
+\verb/\newcounter{index}/ with the side-effect that this defines
+\cs{theindex}, even though \LaTeX{} has a \env{theindex} environment
+that then got clobbered by the declaration.
+%
+This has now been changed: if \cs{the}\meta{counter} is already
+defined it is not altered, but instead a warning message is displayed.
+%
+\githubissue{823}
+
+\subsection{Extended information in \cs{listfiles}}
+
+The \cs{listfiles} command provides useful information when finding issues
+related to variation in package versions. However, this has to date relied on
+the information in the \cs{ProvidesPackage} line, or similar: that can be
+misleading if for example a file has been edited locally. We have now extended
+\cs{listfiles} to take an optional argument which can include the MD5
+hash and size of each file in the \texttt{.log}. Thus for
+example you can use
+\begin{verbatim}
+\listfiles[hashes,sizes]
+\end{verbatim}
+to get both the file sizes and file hashes in the \texttt{.log} as well as
+the standard release information.
+%
+\githubissue{945}
+
+\subsection{Optimize creation of simple document commands}
+
+Creating document commands using declarations such as \cs{NewDocumentCommand}, etc., provides a very
+flexible way of grabbing arguments. When the document command only takes simple
+mandatory arguments, this has to-date added an overhead that could be avoided.
+We have now refined the internal code path such that \enquote{simple} document
+commands avoid almost any overhead at point-of-use, making the results
+essentially as efficient as using \cs{newcommand} for low-level \TeX{}
+constructs. Note that as \cs{NewDocumentCommand} makes engine-robust commands,
+the direct equivalent to \cs{newcommand} is \cs{NewExpandableDocumentCommand}.
+%
+\githubissue{1189}
+
+\subsection{\texorpdfstring{\raggedright}{}Handling of end-of-lines in \texttt{+v} arguments of \cs{NewDocumentCommand} and friends}
+
+The \texttt{+v} argument type provided by declarations such as \cs{NewDocumentCommand}, etc., allows
+grabbing of multiple lines of text in a verbatim-like argument. Almost always,
+the result of this grabbing will be used in a typesetting context. Previously,
+the end-of-line characters were stored literally as category code~12
+(\enquote{other}) \verb|^^M| tokens. However, these are difficult to work with
+in general. We have now revised this behavior, such that end-of-line characters
+are converted to the \cs{obeyedline} command when parsed by \texttt{+v}-type
+arguments.
+This change may require adjustments to the source of some documents, but the
+enhanced ability of users and programmers to exploit the \texttt{+v}-type
+argument means we believe it is necessary.
+
+\subsection{Declaring appropriate sub-encodings for \texttt{TS1} symbol fonts}
+
+In 2020 we incorporated support for the \texttt{TS1} symbol encoding
+directly into the kernel and in this way removed the need to load the
+\pkg{textcomp} package~\cite{39:ltnews31} to make commands such as
+\cs{texteuro} available.
+
+There is, however, a big problem with this \texttt{TS1} symbol
+encoding: only very few fonts provide every glyph that is supposed
+to be part of \texttt{TS1}. This means that changing font families
+might result in certain symbols becoming unavailable. This can be a
+major disaster if, for example,
+the symbol \cs{texteuro} (\texteuro) or \cs{textohm} (\textohm)
+no longer gets printed in your document, just because you altered the
+text font family.
+
+To mitigate this problem, in 2020 we also introduced the declaration
+\cs{DeclareEncodingSubset}. This declaration is supposed to be used in
+font definition files for the \texttt{TS1} encoding to specify which
+subset (we have defined 10 common ones) a specific font implements. If
+such a declaration is used then missing symbols are automatically
+taken from a fallback font.
+
+%% CAR -- this paragraph maybe needs more substantial rewording ??
+While this is not perfect, it is the best
+you can do other than painstakingly checking that your document
+%% CAR: was "painstrickenly" -- should be a word, but!!
+uses only glyphs that the font supports
+and, if necessary, switching to a different font or avoiding the
+missing symbols. See also the discussion in \cite{39:ltnews33}.
+
+To jumpstart the process we also added declarations to the \LaTeX{}
+kernel for most of the fonts found in \TL{} at the time\Dash with
+the assumption that such declarations would over time be superseded by
+declarations in the \texttt{.fd} files. Unfortunately, this hasn't
+happened yet (or not often) and so many of the initial declarations
+went stale: several fonts got new glyphs added to them (so their
+sub-encoding should have been changed but didn't); others (mainly due
+to license issues) changed the family name and thus our declarations
+became useless and the renamed fonts (now without a declaration) ended
+up in the default sub-encoding that offers only a few glyphs;
+yet others such as CharisSIL (which triggered the GitHub issue) were
+simply not around at the time.
+
+We have, therefore, again attempted to provide the (currently) correct
+declarations, but it is obvious that this is not a workable
+process. As we do not maintain the fonts we do not have the
+information that something has changed, and to regularly check the
+ever growing font support bundles is simply not possible. It is
+therefore very important that maintainers of font packages not only
+provide \texttt{.fd} files but also add such a declaration to every
+\texttt{TS1...fd} font definition file that they distribute.
+
+To simplify this process, we now provide a simple \LaTeX{} file
+(\texttt{checkencodingsubset.tex}) for determining the correct (safe)
+sub-encoding. If run, it asks for a font family and then outputs its
+findings, for example, for \texttt{AlgolRevived-TLF} you will get:
+\tubcommand{\begin{small}}
+\begin{verbatim}
+-----------------------------------------
+Testing font family AlgolRevived-TLF
+(currently TS1-sub-encoding 9)
+-----------------------------------------
+Some glyphs are missing from sub-encoding 8:
+ ==> \textcelsius (137) is missing
+ ==> \texttwosuperior (178) is missing
+ ==> \textthreesuperior (179) is missing
+ ==> \textonesuperior (185) is missing
+Some glyphs are missing from sub-encoding 7:
+ ==> \texteuro (191) is missing
+All glyphs between sub-encoding 6 and 7 exist
+All glyphs between sub-encoding 5 and 6 exist
+All glyphs between sub-encoding 4 and 5 exist
+Some glyphs are missing from sub-encoding 3:
+ ==> \textwon (142) is missing
+All glyphs between sub-encoding 2 and 3 exist
+Some glyphs are missing from sub-encoding 1:
+ ==> \textmho (77) is missing
+ ==> \textpertenthousand (152) is missing
+All glyphs between sub-encoding 0 and 1 exist
+All glyphs in core exist
+-----------------------------------------
+TS1 encoding subset for AlgolRevived-TLF (ok)
+Use sub-encoding 9
+-----------------------------------------
+\end{verbatim}
+\tubcommand{\end{small}\noindent}%
+This output is meant for human consumption, e.g., you see which glyphs
+are missing and why a certain sub-encoding is suggested, but it is not
+that hard to use it in a script and extract the suggested sub-encoding
+by grepping for the line starting with \texttt{Use sub-encoding}.
+
+Of course, this check will only work if the missing glyphs are really
+missing: some fonts placed \enquote{tofu}\footnote{Little squares to
+indicate a missing symbol.} into such slots and in this case it looks
+to \TeX{} as if the glyph is provided. For example, for the old
+Palatino fonts (family \texttt{ppl}) it would report
+\begin{verbatim}
+-----------------------------------------
+TS1 encoding subset for ppl (bad)
+Use sub-encoding 0 (not 5)
+-----------------------------------------
+\end{verbatim}
+thus it claims that
+all glyphs are provided, while in reality more than twenty are missing
+and sub-encoding 5, as declared in the kernel, is in fact correct.
+%
+\githubissue{1257}
+
+
+\subsection{Behavior when loading \pkg{textcomp} without options}
+
+When incorporating the \pkg{textcomp} package into the \LaTeX{} kernel, in
+the February 2020 release~\cite{39:ltnews31}, the default type of its package messages was changed from package info (\texttt{Package textcomp Info})
+to \LaTeX{} kernel info (\texttt{LaTeX Info}). But if \pkg{textcomp}
+was loaded without options, the message type got restored to package info.
+This restoration has now been canceled.
+
+Note that loading \pkg{textcomp} with one of the options \option{error},
+\option{warn}, or \option{info} still changes the message
+type to an error, warning, or info message from the \pkg{textcomp} package.
+%
+\githubissue{1333}
+
+
+\subsection{Rollback improvements}
+
+When requesting a rollback of the \LaTeX{} kernel and/or packages,
+several packages produced the error \enquote{Suspicious rollback date}
+because their rollback section contained only data about recent
+releases even if the package, such as \pkg{array}, was available since
+the first release of \LaTeXe{} in 1994. We now suppress this error and
+load the first release that is still part of the distribution (and
+hope for the best). This change was implemented for the packages
+\pkg{amsmath},
+\pkg{array},
+\pkg{doc},
+\pkg{graphics},
+\pkg{longtable},
+\pkg{multicol},
+\pkg{showkeys},
+\pkg{textcomp}, and
+\pkg{varioref}.
+%
+\githubissue{1333}
+
+
+
+\section{Documentation improvements}
+
+\subsection{Further updates to the guides}
+
+We reported about the updated versions of \texttt{usrguide} and
+\texttt{clsguide} in \LaTeX{} News~37~\cite{39:ltnews37}. We have now
+revised \texttt{fntguide} as well to reflect the changes and macros
+added to the kernel over the last years of development. Note that the
+file name hasn't changed and there is no \texttt{fntguide-historic}.
+
+\section{Bug fixes}
+
+\subsection{Fix inconsistent expansion of the package option list}
+
+\LaTeX{} applies one-step expansion to the raw option list of packages
+and classes, so that constructions such as
+\begin{verbatim}
+ \def\myoptions{opt1,opt2}
+ \usepackage[\myoptions]{foo}
+\end{verbatim}
+are supported.
+%% CAR Rewritten sentence:
+But if a package declares its options using the new
+key/value approach~\cite{39:ltnews35} and it gets loaded a second time,
+then its raw option list will not be expanded and so an error might be raised.
+This has now been corrected.
+%
+\githubissue{1298}
+
+\subsection{Fix logic for first mark (page region)}
+
+In the new mark mechanism introduced in June 2022~\cite{39:ltnews35} the result of
+\cs{FirstMark} on a two-column page was incorrect if the first column
+contained no marks. In that case it should have returned the first
+mark of the second column but didn't.
+This has now been corrected.
+
+Documents using \cs{leftmark} are not effected, because that command is still
+using the old mechanism for now.
+%
+\githubissue{1359}
+
+
+\subsection{Struts at the end of footnotes or \texttt{p} columns}
+
+To produce consistent spacing in footnotes and tabular
+\texttt{p}-cells \LaTeX{} adds a strut at the beginning and end of
+the content.
+%% CAR Rewritten sentences:
+%% It assumed, however, that the footnote or tabular cell ended in
+%% horizontal mode and until now added the struts unconditionally. As a
+%% result, with vertical material at the end of the material this strut
+%% started a new paragraph consisting of a single line with just the
+%% strut inside.
+This assumed, however, that the content of the footnote or tabular cell ended in
+horizontal mode and so, until now, these struts were unconditionally added;
+as a result, if this content ended with vertical material then this strut
+started a new paragraph consisting of a single line with just the
+strut in it. This has finally been corrected and now the placement
+logic for the strut changes when vertical mode is detected.
+
+\emph{(First seen in a bug report for \pkg{footmisc} in combination with
+\pkg{bigfoot})}
+
+
+
+\section{Changes to packages in the \pkg{amsmath} category}
+
+\subsection{\pkg{amsmath}:\ Correct equation tag placement}
+
+If there is not enough space to place an equation tag on the same line
+as the equation then \pkg{amsmath} calculates a suitable offset and it
+places the tag above (or below) the equation. In the case of the
+\env{gather} environment this offset was not reset at the end, with
+the result that it also got applied to any following environment,
+resulting in incorrect spacing in certain situations. This has now
+been corrected.
+%
+\githubissue{1289}
+
+
+
+%\section{Changes to packages in the \pkg{graphics} category}
+
+\section{Changes to packages in the \pkg{tools} category}
+
+\subsection{\pkg{array}, \pkg{longtable}, \pkg{tabularx}:\ Support tagging}
+
+%% CAR Rewritten sentences
+These three packages have been extended so they can now, on request,
+produce tagged tabular. This is done by adding a number of sockets (see
+\cite{39:ltnews38}) that, by default, do nothing; but when tagged PDF
+is requested they get equipped with appropriate plugs.
+
+In the previous \LaTeX{} release this was handled in \texttt{latex-lab}, by
+patching the packages when tagging was requested.
+
+
+\subsection{\pkg{array}:\ No \cs{unskip} in math cells}
+
+Math cells in the standard \env{array} environment of the kernel are
+not subject to space removal at the right end of the cell, i.e., explicit
+spaces from \cs{hspace} or \verb*|\ |, etc.\ are honored
+(normal spaces are automatically ignored in math). In the \pkg{array}
+package all spaces got removed by calling \cs{unskip} unconditionally,
+regardless of the type of cell.
+This difference in behavior has now been removed by correcting the processing of
+math cells in \pkg{array}.
+%
+\githubissue{1323}
+
+
+\subsection{\pkg{verbatim}:\ \cs{verb} showed visible spaces}
+
+A recent change in the kernel was not reflected in the \pkg{verbatim}
+package, with the result that \cs{verb} showed visible spaces
+(\verb*/ /) after the package was loaded. This has already been corrected
+in a hotfix for the November 2023 release.
+%
+\githubissue{1160}
+
+\subsection{\pkg{verbatim}:\ Support tabs in \cs{verbatiminput*}}
+
+Mimicking the November 2023 kernel update that allowed \cs{verb*}
+to mark tabs as spaces, the \pkg{verbatim} package
+has now been updated so that \cs{verbatiminput*} also marks tabs as spaces.
+\githubissue{1245}
+
+
+\subsection{\pkg{multicol}:\ \cs{columnbreak} interferes with mark mechanism}
+
+The \pkg{multicol} package has to keep track of marks (from
+\cs{markright} or \cs{markboth}) as part of its output routine code
+and can't rely on \LaTeX{} handling that automatically. It does so by
+artificially splitting page data with \cs{vsplit} to extract the mark
+data. With the introduction of \cs{columnbreak} that code failed
+sometimes, because it was not seeing any mark that followed such a
+forced column break.
+
+This has now been corrected, but there is further work to do, because
+as of now \pkg{multicol} does not yet handle marks using the new mark
+mechanism\Dash see the discussion at the beginning of the newsletter.
+%
+\githubissue{1130}
+
+\subsection{\pkg{showkeys}:\ Allow \cs{newline} in \pkg{amsthm} to work}
+%
+Previously \pkg{showkeys} added an extra box layer which disabled the \cs{newline}
+of \pkg{amsthm} theorem styles. This extra box has now been avoided.
+%
+\githubissue{1123}
+
+\subsection{\pkg{xr}:\ Support links and properties}
+%
+The \pkg{xr} package implements a system for eXternal References.
+The \pkg{xr-hyper} package (in the \pkg{hyperref} bundle)
+extended this to also support links to external documents.
+%% CAR: Rewritten sentences:
+Using last year's extension of the \cs{label} command, which unified
+the label syntax of \LaTeX{} and \pkg{hyperref},
+it became possible to merge the two packages and thus make
+\pkg{xr-hyper} obsolete.
+With this change it is also possible to refer to properties
+that are stored in external documents using \cs{RecordProperties}.
+%
+\githubissue{1180}
+
+\section{Changes to files in the \pkg{cyrillic} category}
+
+\subsection{Correct definition of \cs{k}}
+
+Ages ago, the encoding-specific definitions for various accent
+commands were changed to guard against altering some parameter values
+non-locally by mistake. For some reason the definition for \cs{k} in
+the Cyrillic encodings \texttt{T2A}, \texttt{T2B}, and \texttt{T2C}
+didn't get this treatment. This oversight has now been corrected.
+%
+\githubissue{1148}
+
+
+\tubcommand{\newpage}
+\begin{thebibliography}{9}\frenchspacing
+
+%\fontsize{9.3}{11.3}\selectfont
+
+
+\bibitem{39:Lamport}
+Leslie Lamport.
+\newblock \emph{{\LaTeX}: {A} Document Preparation System: User's Guide and Reference
+ Manual}.
+\newblock \mbox{Addison}-Wesley, Reading, MA, USA, 2nd edition, 1994.
+\newblock ISBN 0-201-52983-1.
+\newblock Reprinted with corrections in 1996.
+
+\bibitem{39:ltnews} \LaTeX{} Project Team.
+ \emph{\LaTeXe{} news 1--39}. June, 2024.
+ \url{https://latex-project.org/news/latex2e-news/ltnews.pdf}
+
+\bibitem{39:ltnews31} \LaTeX{} Project Team.
+ \emph{\LaTeXe{} news 31}. February, 2020.
+ \url{https://latex-project.org/news/latex2e-news/ltnews31.pdf}
+
+\bibitem{39:ltnews33} \LaTeX{} Project Team.
+ \emph{\LaTeXe{} news 33}. June 2021.\\
+ \url{https://latex-project.org/news/latex2e-news/ltnews33.pdf}
+
+\bibitem{39:ltnews35} \LaTeX{} Project Team.
+ \emph{\LaTeXe{} news 35}. June 2022.\\
+ \url{https://latex-project.org/news/latex2e-news/ltnews35.pdf}
+
+\bibitem{39:ltnews37} \LaTeX{} Project Team.
+ \emph{\LaTeXe{} news 37}. June 2023.\\
+ \url{https://latex-project.org/news/latex2e-news/ltnews37.pdf}
+
+\bibitem{39:ltnews38} \LaTeX{} Project Team.
+ \emph{\LaTeXe{} news 38}. November 2023.
+ \url{https://latex-project.org/news/latex2e-news/ltnews38.pdf}
+
+\bibitem{39:deims} Frank Mittelbach and Ulrike Fischer.
+ \emph{Enhancing \LaTeX{} to automatically produce
+ tagged and accessible PDF}. \textsl{TUGboat} 45:1, 2024.
+ \url{https://latex-project.org/publications/indexbyyear/2024/}
+
+ %\bibitem{39:blueprint} Frank Mittelbach and Chris Rowley.
+% \emph{\LaTeX{} Tagged PDF \Dash A blueprint for a large project}.\\
+% \url{https://latex-project.org/publications/indexbyyear/2020/}
+
+\end{thebibliography}
+
+\end{document}
+
diff --git a/macros/latex/base/ltoutenc.dtx b/macros/latex/base/ltoutenc.dtx
index e7d48e4ba2..c18ff01446 100644
--- a/macros/latex/base/ltoutenc.dtx
+++ b/macros/latex/base/ltoutenc.dtx
@@ -44,7 +44,7 @@
%<*driver>
% \fi
\ProvidesFile{ltoutenc.dtx}
- [2022/05/27 v2.0z LaTeX Kernel (font encodings)]
+ [2024/02/08 v2.1a LaTeX Kernel (font encodings)]
% \iffalse
\documentclass{ltxdoc}
\GetFileInfo{ltoutenc.dtx}
@@ -383,10 +383,10 @@
% other encodings, so there are some optimizations provided:
% \begin{quote}
% |\DeclareTextSymbolDefault{|^^A
-% \meta{command}|}|^^A
+% \meta{command}|}{|^^A
% \meta{encoding}|}|\\
% |\DeclareTextAccentDefault{|^^A
-% \meta{command}|}|^^A
+% \meta{command}|}{|^^A
% \meta{encoding}|}|
% \end{quote}
% are short for:
@@ -840,7 +840,7 @@
% interfere between accent and base character. Therefore we need to
% avoid that (they are some hidden inside \cs{maybe@load@fontshape}).
% As we don't have to load the fontshape in this case
-% (as that happened in the box above if necessary, we simply
+% (as that already happened in the box above, if necessary), we simply
% disable that part of the code temporarily.
% We also ignore \cs{ignorespaces} which has the same issue and may
% show up as part of \cs{normalfont} if that is used.
@@ -3659,10 +3659,10 @@
\let\encodingdefault\CurrentOption
% \end{macrocode}
% From 2020/02/02 release onward we only load the encoding files if
-% they haven't be loaded already. To check this we look if
-% \verb=\T@=\textit{encoding} is already defined. If not we load
+% they haven't be loaded already. To check this we look at whether
+% \verb=\T@=\textit{encoding} is already defined. If not, we load it later
% (indicated by setting the switch
-% \texttt{@tempswa} to true and we always load if we run in an older
+% \texttt{@tempswa} to true) and we always load if we are using an older
% format (or rather in a rollback situation).
% \changes{v2.0m}{2020/01/25}{Load each encoding file only once (gh/255)}
% \begin{macrocode}
@@ -3677,6 +3677,7 @@
\if@tempswa
% \end{macrocode}
%
+% \changes{v2.1a}{2023/11/07}{Add more explanation to error message (gh/1102)}
% \begin{macrocode}
\edef\reserved@f{%
\lowercase{\def\noexpand\reserved@f{\CurrentOption enc.def}}}%
@@ -3685,7 +3686,11 @@
{}{\PackageError{fontenc}%
{Encoding file `\reserved@f' not found.%
\MessageBreak
- You might have misspelt the name of the encoding}%
+ You might have misspelled the name of the encoding
+ \MessageBreak
+ or a required support package (e.g., cyrillic) is
+ \MessageBreak
+ missing in your installation}%
{Necessary code for this encoding was not
loaded.\MessageBreak
Thus calling the encoding later on will
@@ -3723,8 +3728,8 @@
% \end{macrocode}
%
% We select the new font encoding default (i.e., the last encoding
-% specified in the option list. But this encoding may not work with
-% the current |\f@shape|, e.g., \texttt{LY1} is not defined for
+% specified in the option list). But this encoding may not work with
+% the current |\f@shape|: e.g., \texttt{LY1} is not defined for
% \texttt{cmr} and therefore packages switching to \texttt{LY1}
% usually also change \cs{rmdefault}. But that only applies at
% |\begin{document}| so we get a spurious warning if we use what
diff --git a/macros/latex/base/ltoutput.dtx b/macros/latex/base/ltoutput.dtx
index b067ef5ecb..f0c1bf830b 100644
--- a/macros/latex/base/ltoutput.dtx
+++ b/macros/latex/base/ltoutput.dtx
@@ -37,7 +37,7 @@
%<*driver>
% \fi
\ProvidesFile{ltoutput.dtx}
- [2023/05/26 v1.4j LaTeX Kernel (Output Routine)]
+ [2024/03/16 v1.4j LaTeX Kernel (Output Routine)]
% \iffalse
\documentclass{ltxdoc}
\GetFileInfo{ltoutput.dtx}
@@ -847,7 +847,7 @@
% \begin{macro}{\if@firstcolumn}
% \begin{macro}{\if@twocolumn}
% \begin{macro}{\if@twoside}
-% \begin{macro}{\if@reversemarginpar}
+% \begin{macro}{\if@reversemargin}
% \begin{macro}{\if@mparswitch}
% \begin{macro}{\col@number}
% \changes{v1.0n}{1994/04/30}{Added \cs{col@number}}
diff --git a/macros/latex/base/ltpara-code.pdf b/macros/latex/base/ltpara-code.pdf
index 645fb8f851..f6fc884a68 100644
--- a/macros/latex/base/ltpara-code.pdf
+++ b/macros/latex/base/ltpara-code.pdf
Binary files differ
diff --git a/macros/latex/base/ltpara-doc.pdf b/macros/latex/base/ltpara-doc.pdf
index 7895499693..2fcf71bf44 100644
--- a/macros/latex/base/ltpara-doc.pdf
+++ b/macros/latex/base/ltpara-doc.pdf
Binary files differ
diff --git a/macros/latex/base/ltpara.dtx b/macros/latex/base/ltpara.dtx
index f76352fb91..f102d68e0d 100644
--- a/macros/latex/base/ltpara.dtx
+++ b/macros/latex/base/ltpara.dtx
@@ -14,21 +14,14 @@
%
%%% From File: ltpara.dtx
%
-% \begin{macrocode}
-\def\ltparaversion{v1.0l}
-\def\ltparadate{2023/01/30}
-% \end{macrocode}
%<*driver>
+% \fi
+\ProvidesFile{ltpara.dtx}
+ [2024/05/16 v1.0m LaTeX Kernel (paragraph hooks)]
+% \iffalse
+%
\documentclass{l3doc}
-
-%\usepackage{ltpara}
-
-% Fixing footnotes in functions and variables: this should be in l3doc!
-
-\newcommand\fixfootnote[2]{\footnotemark
- \AddToHookNext{env/#1/after}{\footnotetext{#2}}}
-\AddToHook{env/function/begin}{\def\footnote{\fixfootnote{function}}}
-\AddToHook{env/variable/begin}{\def\footnote{\fixfootnote{variable}}}
+\GetFileInfo{ltpara.dtx}
\EnableCrossrefs
\CodelineIndex
@@ -45,7 +38,7 @@
%
%
% \title{The \texttt{ltpara.dtx} code\thanks{This file has version
-% \ltparaversion\ dated \ltparadate, \copyright\ \LaTeX\
+% \fileversion\ dated \filedate, \copyright\ \LaTeX\
% Project.}}
% \author{Frank Mittelbach}
%
@@ -811,9 +804,11 @@
\hook_use:n {para/begin}
% \end{macrocode}
% If we aren't in horizontal mode any longer the hooks above misbehaved.
+% \changes{v1.0m}{2023/11/16}{Correct error message: hook
+% left horizontal not vertical mode (gh/1182)}
% \begin{macrocode}
\if_mode_horizontal: \else:
- \msg_error:nnnn { hooks }{ para-mode }{begin}{vertical} \fi:
+ \msg_error:nnnn { hooks }{ para-mode }{begin}{horizontal} \fi:
% \end{macrocode}
% Finally we reinsert the indentation box (unless suppressed) and
% then call \cs{everypar} the way legacy \LaTeX\ code expects it.
@@ -845,7 +840,7 @@
%<latexrelease> \@kernel@before@para@begin
%<latexrelease> \hook_use:n {para/begin}
%<latexrelease> \if_mode_horizontal: \else:
-%<latexrelease> \msg_error:nnnn { hooks }{ para-mode }{begin}{vertical} \fi:
+%<latexrelease> \msg_error:nnnn { hooks }{ para-mode }{begin}{horizontal} \fi:
%<latexrelease> \@@_handle_indent:
%<latexrelease>}
% \end{macrocode}
@@ -1261,7 +1256,7 @@
% redo the \cs{everypar} setting from the kernel, otherwise that
% gets lost (as it happens before that file is loaded).
% \begin{macrocode}
-\everypar{\@nodocument} %% To get an error if text appears before the
+\everypar{\@nodocument} %% To get an error if text appears before the \document
% \end{macrocode}
%
%
diff --git a/macros/latex/base/ltplain.dtx b/macros/latex/base/ltplain.dtx
index 3773373562..a628b954d9 100644
--- a/macros/latex/base/ltplain.dtx
+++ b/macros/latex/base/ltplain.dtx
@@ -32,7 +32,7 @@
%<*driver>
% \fi
\ProvidesFile{ltplain.dtx}
- [2023/10/21 v2.3i LaTeX Kernel (Plain TeX)]
+ [2024/02/08 v2.3j LaTeX Kernel (Plain TeX)]
% \iffalse
\documentclass{ltxdoc}
\GetFileInfo{ltplain.dtx}
@@ -1241,11 +1241,11 @@
%<latexrelease>\IncludeInRelease{2022/06/01}{\obeylines}%
%<latexrelease> {Add a redirection to obeylines and obeyspaces}%
% \end{macrocode}
-% If the active |^^M| escapes, e.g. into a \cs{write} (which is
-% effectively in a different context) we don't want the definition
+% If the active |^^M| escapes, e.g., into a \cs{write} (which is
+% effectively in a different context) then we don't want the definition
% from \cs{obeylines} but rather a simple \cs{par} (in fact even
% the primitive one, not the \LaTeX{} version \cs{para\_end:} which
-% is only defined later.
+% is only defined later).
%
% \begin{macrocode}
\begingroup
@@ -1263,7 +1263,7 @@
% line ending characters and in that mode \TeX{} discards
% everything from that point onwards to the real end of the line so
% it works like a comment --- pretty strange really (and I think
-% due to the fact the the original pascal compiler could have some
+% due to the fact that the original pascal compiler could have some
% garbage showing up after the normal line ending character. Thus
% we really have to make sure that any closing braces is not one
% the same line as an |^^M|, because otherwise it would get dropped
@@ -1293,7 +1293,7 @@
% one that is current when \cs{obeylines} act.
%
% There is a small subtlety here: in an \cs{edef} the active |^^M| stayed
-% put (because it was equal to to the primitive \cs{par}), now
+% put (because it was equal to the primitive \cs{par}), now
% \cs{obeyedline} expands and you get what it contains, i.e., in that
% case \cs{par}, into the \cs{edef} or \cs{mark} unless we use
% \cs{protected} on it.
@@ -1813,7 +1813,13 @@
\tracinggroups\z@
\tracingparagraphs\z@
\tracingmacros\z@
- \tracinglostchars\@ne
+% \end{macrocode}
+% None really means go back to the \LaTeX{} ``default'' and for
+% \cs{tracinglostchars} this should therefore be 2 these days.
+% \changes{v2.3j}{2023/11/07}{Set \cs{tracinglostchars} to 2 in
+% \cs{tracingnone} (gh/549)}
+% \begin{macrocode}
+ \tracinglostchars\tw@
\tracingpages\z@
\tracingstats\z@
}%
diff --git a/macros/latex/base/ltproperties-code.pdf b/macros/latex/base/ltproperties-code.pdf
index 58b2001964..65ed0c2337 100644
--- a/macros/latex/base/ltproperties-code.pdf
+++ b/macros/latex/base/ltproperties-code.pdf
Binary files differ
diff --git a/macros/latex/base/ltproperties-doc.pdf b/macros/latex/base/ltproperties-doc.pdf
index 7fff51f06a..bcf80a571f 100644
--- a/macros/latex/base/ltproperties-doc.pdf
+++ b/macros/latex/base/ltproperties-doc.pdf
Binary files differ
diff --git a/macros/latex/base/ltproperties.dtx b/macros/latex/base/ltproperties.dtx
index 40c50cd20a..0fd8f22e0e 100644
--- a/macros/latex/base/ltproperties.dtx
+++ b/macros/latex/base/ltproperties.dtx
@@ -1,8 +1,8 @@
% \iffalse meta-comment
%
-%% File: ltproperties.dtx
+% File: ltproperties.dtx
%
-% Copyright (C) 2021-2023 The LaTeX Project
+% Copyright (C) 2023-2024 The LaTeX Project
%
% It may be distributed and/or modified under the conditions of the
% LaTeX Project Public License (LPPL), either version 1.3c of this
@@ -21,13 +21,21 @@
% https://github.com/latex3/latex2e
%
% for those people who are interested.
-% \begin{macrocode}
-\def\ltpropertiesversion{1.0c}
-\def\ltpropertiesdate{2023-10-15}
-% \end{macrocode}
-
-%<*driver>
+%
+% \fi
+%
+% \iffalse
+%%% From File: ltproperties.dtx
+%
+%<*driver>
+% \fi
+\ProvidesFile{ltproperties.dtx}
+ [2024/04/17 v1.0e LaTeX Kernel (Properties)]
+% \iffalse
+%
\documentclass[full]{l3doc}
+\GetFileInfo{ltproperties.dtx}
+
\EnableCrossrefs
\CodelineIndex
\begin{document}
@@ -39,7 +47,7 @@
% \title{^^A
% Recording and cross-referencing document properties^^A
% \thanks{This module has version
-% \ltpropertiesversion\ dated \ltpropertiesdate, \copyright\ The \LaTeX\
+% \fileversion\ dated \filedate, \copyright\ The \LaTeX\
% Project.}
% }
%
@@ -157,8 +165,8 @@
%
% \begin{function}{\property_new:nnnn,\property_gset:nnnn}
% \begin{syntax}
-% \cs{property_new:nnnn} \Arg{property} \Arg{setpoint} \Arg{default} \Arg{code}
-% \cs{property_gset:nnnn} \Arg{property}\Arg{setpoint} \Arg{default} \Arg{code}
+% \cs{property_new:nnnn} \Arg{property} \Arg{setpoint} \Arg{default} \Arg{code}
+% \cs{property_gset:nnnn} \Arg{property} \Arg{setpoint} \Arg{default} \Arg{code}
% \end{syntax}
% \LaTeXe-interface: see \cs{NewProperty}, \cs{SetProperty}.\\
% Sets the \meta{property} to have the \meta{default} specified, and at the
@@ -180,7 +188,7 @@
% \property_record:nn, \property_record:nV, \property_record:ee
% }
% \begin{syntax}
-% \cs{property_record:nN} \Arg{label} \Arg{clist var}
+% \cs{property_record:nN} \Arg{label} \meta{clist var}
% \cs{property_record:nn} \Arg{label} \Arg{clist}
% \end{syntax}
% \LaTeXe{}-interface: see \cs{RecordProperties}.\\
@@ -266,7 +274,7 @@
% \cs{property_if_exist_p:n} \Arg{property}
% \cs{property_if_exist:nTF} \Arg{property} \Arg{true code} \Arg{false code}
% \end{syntax}
-% \LaTeXe{}-interface: \cs{IfPropertyExistTF}.\\
+% \LaTeXe{}-interface: \cs{IfPropertyExistsTF}.\\
% Tests if the \meta{property} has been declared.
% \end{function}
%
@@ -275,7 +283,7 @@
% \cs{property_if_recorded_p:n} \Arg{label}
% \cs{property_if_recorded:nTF} \Arg{label} \Arg{true code} \Arg{false code}
% \end{syntax}
-% \LaTeXe{}-interface: \cs{IfLabelExistTF}\\
+% \LaTeXe{}-interface: \cs{IfLabelExistsTF}\\
% Tests if the \meta{label} is known. This is also true if the label has been
% set with the standard \cs{label} command.
% \end{function}
@@ -307,8 +315,8 @@
%
% \begin{function}{\NewProperty,\SetProperty}
% \begin{syntax}
-% \cs{NewProperty} \Arg{property} \Arg{setpoint} \Arg{default} \Arg{code}
-% \cs{SetProperty} \Arg{property} \Arg{setpoint} \Arg{default} \Arg{code}
+% \cs{NewProperty} \Arg{property} \Arg{setpoint} \Arg{default} \Arg{code}
+% \cs{SetProperty} \Arg{property} \Arg{setpoint} \Arg{default} \Arg{code}
% \end{syntax}
% Sets the \meta{property} to have the \meta{default} specified, and at the
% \meta{setpoint} (either |now| or |shipout|) to write the result of the
@@ -329,7 +337,7 @@
% of properties. Also similar to the standard \cs{label} command, the command is surrounded
% by an \cs{@bsphack}/\cs{@esphack} pair to preserve spacing.
% \end{function}
-
+%
% \begin{function}[EXP]{\RefProperty}
% \begin{syntax}
% \cs{RefProperty} \oarg{local default} \Arg{label} \Arg{property}
@@ -340,16 +348,16 @@
% If \Arg{property} has not been declared an error is issued.
% \end{function}
%
-% \begin{function}{\IfPropertyExistTF}
+% \begin{function}{\IfPropertyExistsTF,\IfPropertyExistsT,\IfPropertyExistsF}
% \begin{syntax}
-% \cs{IfPropertyExistTF} \Arg{property} \Arg{true code} \Arg{false code}
+% \cs{IfPropertyExistsTF} \Arg{property} \Arg{true code} \Arg{false code}
% \end{syntax}
% Tests if the \meta{property} has been declared.
% \end{function}
%
-% \begin{function}{\IfLabelExistTF}
+% \begin{function}{\IfLabelExistsTF,\IfLabelExistsT,\IfLabelExistsF}
% \begin{syntax}
-% \cs{IfLabelExistTF} \Arg{label} \Arg{true code} \Arg{false code}
+% \cs{IfLabelExistsTF} \Arg{label} \Arg{true code} \Arg{false code}
% \end{syntax}
% Tests if the \meta{label} has been recorded. This is also true if a label
% has been set with the standard \cs{label} command.
@@ -361,7 +369,7 @@
% \end{syntax}
% Tests if the label and a value of the \meta{property} for the \meta{label} are both known.
% \end{function}
-
+%
% \begin{function}{\RefUndefinedWarn}
% \begin{syntax}
% \cs{RefUndefinedWarn} \Arg{label} \Arg{property}
@@ -551,6 +559,7 @@
% later too. That is all pretty easy using \pkg{expl3}: we accept a stray
% comma at the end of the list as that is easier to deal with than trying
% to tidy up, and there is no real downside.
+% \changes{v1.0d}{2024-01-17}{Use \cs{protected@write}}%
% \begin{macrocode}
\cs_new_protected:Npn \property_record:nN #1#2
{ \property_record:nV {#1} #2 }
@@ -561,7 +570,7 @@
{
\legacy_if:nT { @filesw }
{
- \iow_shipout_x:Nx \@auxout
+ \protected@write \@auxout {}
{
\token_to_str:N \new@label@record
{#1}
@@ -737,9 +746,13 @@
% \end{macrocode}
% \end{macro}
%
-% \begin{macro}{IfPropertyExistTF}
+% \begin{macro}{\IfPropertyExistsTF,\IfPropertyExistsT,\IfPropertyExistsF}
+% \changes{v1.0e}{2024-04-17}{Renamed \cs{IfPropertyExistTF} to
+% \cs{IfPropertyExistsTF} (gh/1262)}
% \begin{macrocode}
-\cs_new_eq:NN \IfPropertyExistTF \property_if_exist:eTF
+\cs_new_eq:NN \IfPropertyExistsTF \property_if_exist:eTF
+\cs_new:Npn \IfPropertyExistsT #1#2 {\property_if_exist:eTF {#1}{#2}{} }
+\cs_new:Npn \IfPropertyExistsF #1 {\property_if_exist:eTF {#1}{} }
% \end{macrocode}
% \end{macro}
%
@@ -762,9 +775,13 @@
% \end{macrocode}
% \end{macro}
%
-% \begin{macro}{\IfLabelExistTF}
+% \begin{macro}{\IfLabelExistsTF,\IfLabelExistsT,\IfLabelExistsF}
+% \changes{v1.0e}{2024-04-17}{Renamed \cs{IfLabelExistTF} to
+% \cs{IfLabelExistsTF} (gh/1262)}
% \begin{macrocode}
-\cs_new_eq:NN \IfLabelExistTF \property_if_recorded:eTF
+\cs_new_eq:NN \IfLabelExistsTF \property_if_recorded:eTF
+\cs_new:Npn \IfLabelExistsT #1#2 {\property_if_exist:eTF {#1}{#2}{} }
+\cs_new:Npn \IfLabelExistsF #1 {\property_if_exist:eTF {#1}{} }
% \end{macrocode}
% \end{macro}
%
@@ -938,8 +955,8 @@
%<latexrelease>\let \RefProperty \@undefined
%<latexrelease>\let \RefUndefinedWarn \@undefined
%<latexrelease>
-%<latexrelease>\let \IfPropertyExistTF \@undefined
-%<latexrelease>\let \IfLabelExistTF \@undefined
+%<latexrelease>\let \IfPropertyExistsTF \@undefined
+%<latexrelease>\let \IfLabelExistsTF \@undefined
%<latexrelease>\let \IfPropertyRecordedTF \@undefined
%<latexrelease>
%<latexrelease>\let\new@label@record \@undefined
diff --git a/macros/latex/base/ltsect.dtx b/macros/latex/base/ltsect.dtx
index 4560704463..21aeda32e0 100644
--- a/macros/latex/base/ltsect.dtx
+++ b/macros/latex/base/ltsect.dtx
@@ -31,7 +31,7 @@
%%% From File: ltsect.dtx
%<*driver>
% \fi
-\ProvidesFile{ltsect.dtx}[2021/07/28 v1.1f LaTeX Kernel (Sectioning)]
+\ProvidesFile{ltsect.dtx}[2024/03/25 v1.1f LaTeX Kernel (Sectioning)]
% \iffalse
\documentclass{ltxdoc}
\GetFileInfo{ltsect.dtx}
@@ -835,13 +835,13 @@
% \begin{macro}{\contentsline}
% 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
-% example, might be produced by:
+% It will appear in the |.toc| or other file.
+% For example, the entry for subsection 1.4.3 in the table of contents,
+% might be produced by:
%
% \begin{verbatim}
% \contentsline{subsection}
-% {\makebox{30pt}[r]{1.4.3} Gnats and Gnus}{22}
+% {\numberline{1.4.3}Gnats and Gnus}{22}{}
% \end{verbatim}
%
% The |\protect| command causes command sequences to be written
diff --git a/macros/latex/base/ltshipout-code.pdf b/macros/latex/base/ltshipout-code.pdf
index 1a2a6592f3..7597895a00 100644
--- a/macros/latex/base/ltshipout-code.pdf
+++ b/macros/latex/base/ltshipout-code.pdf
Binary files differ
diff --git a/macros/latex/base/ltshipout-doc.pdf b/macros/latex/base/ltshipout-doc.pdf
index cef55100da..abd32adce9 100644
--- a/macros/latex/base/ltshipout-doc.pdf
+++ b/macros/latex/base/ltshipout-doc.pdf
Binary files differ
diff --git a/macros/latex/base/ltshipout.dtx b/macros/latex/base/ltshipout.dtx
index aaeba15ea7..0c9113ce93 100644
--- a/macros/latex/base/ltshipout.dtx
+++ b/macros/latex/base/ltshipout.dtx
@@ -31,30 +31,14 @@
%
%%% From File: ltshipout.dtx
%
-% \begin{macrocode}
-\providecommand\ltshipoutversion{v1.0n}
-\providecommand\ltshipoutdate{2022/11/08}
-% \end{macrocode}
-%
%<*driver>
-
+% \fi
+\ProvidesFile{ltshipout.dtx}
+ [2024/02/11 v1.0n LaTeX Kernel (Shipout)]
+% \iffalse
+%
\documentclass{l3doc}
-
-% bug fix fo l3doc.cls
-\ExplSyntaxOn
-\cs_set_protected:Npn \__codedoc_macro_typeset_one:nN #1#2
- {
- \vbox_set:Nn \l__codedoc_macro_box
- {
- \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
- }
-\ExplSyntaxOff
+\GetFileInfo{ltshipout.dtx}
\providecommand\InternalDetectionOff{}
\providecommand\InternalDetectionOn{}
@@ -76,7 +60,7 @@
%
%
% \title{The \texttt{ltshipout} documentation\thanks{This file has version
-% \ltshipoutversion\ dated \ltshipoutdate, \copyright\ \LaTeX\
+% \fileversion\ dated \filedate, \copyright\ \LaTeX\
% Project.}}
%
% \author{Frank Mittelbach, \LaTeX{} Project Team}
@@ -859,7 +843,7 @@
%
% \changes{v1.0d}{2020/11/23}{Check for both kernel and user hook (gh/431)}
% \changes{v1.0f}{2021/01/08}{Added another kernel hook for more
-% flexibility (cf \texttt{https://github.com/pgf-tikz/pgf/issues/960}}
+% flexibility (cf.\ \texttt{https://github.com/pgf-tikz/pgf/issues/960}}
% \begin{macrocode}
\bool_lazy_and:nnF
{ \hook_if_empty_p:n {shipout/background} }
diff --git a/macros/latex/base/ltsockets-code.pdf b/macros/latex/base/ltsockets-code.pdf
index 922adb45cd..8b4a7e33ee 100644
--- a/macros/latex/base/ltsockets-code.pdf
+++ b/macros/latex/base/ltsockets-code.pdf
Binary files differ
diff --git a/macros/latex/base/ltsockets-doc.pdf b/macros/latex/base/ltsockets-doc.pdf
index 9b0dcfe601..b405a2472f 100644
--- a/macros/latex/base/ltsockets-doc.pdf
+++ b/macros/latex/base/ltsockets-doc.pdf
Binary files differ
diff --git a/macros/latex/base/ltsockets.dtx b/macros/latex/base/ltsockets.dtx
index 909792a4f5..243963f7bc 100644
--- a/macros/latex/base/ltsockets.dtx
+++ b/macros/latex/base/ltsockets.dtx
@@ -30,14 +30,14 @@
%
%%% From File: ltsockets.dtx
%
-% \begin{macrocode}
-\def\ltsocketsversion{0.9a}
-\def\ltsocketsdate{2023-08-21}
-% \end{macrocode}
+%<*driver>
+% \fi
+\ProvidesFile{ltsockets.dtx}
+ [2024/02/11 v0.9a LaTeX Kernel (Sockets)]
+% \iffalse
%
-%<*driver>
\documentclass{l3doc}
-
+\GetFileInfo{ltsockets.dtx}
\providecommand\InternalDetectionOff{}
\providecommand\InternalDetectionOn{}
@@ -55,7 +55,7 @@
%
%
% \title{\LaTeX{}'s socket management\thanks{This module has version
-% \ltsocketsversion\ dated \ltsocketsdate, \copyright\ \LaTeX\
+% \fileversion\ dated \filedate, \copyright\ \LaTeX\
% Project.}}
%
% \author{Frank Mittelbach}
@@ -530,8 +530,8 @@
%
% \begin{function}{\NewSocket,\socket_new:nn}
% \begin{syntax}
-% \cs{NewSocket} \Arg{socket-name}\Arg{number-of-inputs}
-% \cs{socket_new:nn}\Arg{socket-name}\Arg{number-of-inputs}
+% \cs{NewSocket} \Arg{socket-name} \Arg{number-of-inputs}
+% \cs{socket_new:nn} \Arg{socket-name} \Arg{number-of-inputs}
% \end{syntax}
% Declares a new socket with name \meta{socket-name} having
% \meta{number-of-inputs} inputs. There is automatically a
@@ -563,9 +563,9 @@
%
% \begin{function}{\NewSocketPlug,\socket_new_plug:nnn,\socket_set_plug:nnn}
% \begin{syntax}
-% \cs{NewSocketPlug} \Arg{socket-name}\Arg{socket-plug-name}\Arg{code}
-% \cs{socket_new_plug:nnn}\Arg{socket-name}\Arg{socket-plug-name}\Arg{code}
-% \cs{socket_set_plug:nnn}\Arg{socket-name}\Arg{socket-plug-name}\Arg{code}
+% \cs{NewSocketPlug} \Arg{socket-name} \Arg{socket-plug-name} \Arg{code}
+% \cs{socket_new_plug:nnn} \Arg{socket-name} \Arg{socket-plug-name} \Arg{code}
+% \cs{socket_set_plug:nnn} \Arg{socket-name} \Arg{socket-plug-name} \Arg{code}
% \end{syntax}
% Declares a new plug for socket \meta{socket-name} that runs
% \meta{code} when executing. It complains if the plug was already
@@ -582,8 +582,8 @@
%
% \begin{function}{\AssignSocketPlug,\socket_assign_plug:nn}
% \begin{syntax}
-% \cs{AssignSocketPlug} \Arg{socket-name}\Arg{socket-plug-name}
-% \cs{socket_assign_plug:nn}\Arg{socket-name}\Arg{socket-plug-name}
+% \cs{AssignSocketPlug} \Arg{socket-name} \Arg{socket-plug-name}
+% \cs{socket_assign_plug:nn} \Arg{socket-name} \Arg{socket-plug-name}
% \end{syntax}
% Assigns the plug \meta{socket-plug-name} to the socket
% \meta{socket-name}. It errors if either socket or plug is not
@@ -595,8 +595,8 @@
%
% \begin{function}{\UseSocket,\socket_use:nw,\socket_use:n,\socket_use:nn,\socket_use:nnn,\socket_use:nnnn}
% \begin{syntax}
-% \cs{UseSocket} \Arg{socket-name}
-% \cs{socket_use:nnn}\Arg{socket-name} \Arg{socket-arg\textsubscript{1}} \Arg{socket-arg\textsubscript{2}}
+% \cs{UseSocket} \Arg{socket-name}
+% \cs{socket_use:nnn} \Arg{socket-name} \Arg{socket-arg\textsubscript{1}} \Arg{socket-arg\textsubscript{2}}
% \end{syntax}
% Executes the socket \meta{socket-name} by retrieving the
% \meta{code} of the current plug assigned to the socket. This is
@@ -619,8 +619,8 @@
%
% \begin{function}{\ShowSocket,\LogSocket,\socket_show:n,\socket_log:n}
% \begin{syntax}
-% \cs{ShowSocket} \Arg{socket-name}
-% \cs{socket_show:n}\Arg{socket-name}
+% \cs{ShowSocket} \Arg{socket-name}
+% \cs{socket_show:n} \Arg{socket-name}
% \end{syntax}
% Displays information about the socket \meta{socket-name} and its
% state then stops and waits for further instructions --- at the
diff --git a/macros/latex/base/ltspace.dtx b/macros/latex/base/ltspace.dtx
index 73941d4815..206e4f3885 100644
--- a/macros/latex/base/ltspace.dtx
+++ b/macros/latex/base/ltspace.dtx
@@ -32,7 +32,7 @@
%<*driver>
% \fi
\ProvidesFile{ltspace.dtx}
- [2023/10/26 v1.3r LaTeX Kernel (spacing)]
+ [2024/02/08 v1.3r LaTeX Kernel (spacing)]
% \iffalse
\documentclass{ltxdoc}
\GetFileInfo{ltspace.dtx}
@@ -568,7 +568,7 @@
% \changes{LaTeX2e}{1993/12/08}
% {Command reimplemented; late birthday present for Chris}
% \changes{LaTeX2e}{1993/12/08}{Command reimplemented}
-% \changes{LaTeX2e}{1993/12/16}{Corrected optimisation :-)}
+% \changes{LaTeX2e}{1993/12/16}{Corrected optimisation}
% |\@bsphack| and |\@esphack|
% used by macros such as |\index| and
% |\begin{@float}| \ldots |\end{@float}|
@@ -1156,8 +1156,8 @@
% \subsection{Horizontal space (and breaks)}
%
% \begin{macro}{\nobreakdashes}
-% \changes{v1.3}{2004/02/04}{(Macro added}
-% \changes{v1.3a}{2004/02/15}{(Added spacefactor setting}
+% \changes{v1.3}{2004/02/04}{Macro added}
+% \changes{v1.3a}{2004/02/15}{Added spacefactor setting}
% This idea is borrowed from the \textsf{amsmath} package but
% here we define a robust command.
%
@@ -1194,7 +1194,7 @@
% \end{macro}
%
% \begin{macro}{\nobreakspace}
-% \changes{v1.2k}{1995/12/04}{(Macro added}
+% \changes{v1.2k}{1995/12/04}{Macro added}
% \changes{v1.3r}{2023/10/26}{Protected definition for tilde}
% \begin{macro}{\@xobeysp}
% \changes{v1.2t}{1996/09/28}{Moved from ltmiscen.dtx and redefined to
@@ -1209,7 +1209,7 @@
%
% The braces in the definition of |~| are needed to ensure that a
% following space is preserved when reading to/from internal files.
-% \changes{v1.2l}{1995/12/04}{(braces added to definition of tilde}
+% \changes{v1.2l}{1995/12/04}{braces added to definition of tilde}
%
% We need to keep \cs{@xobeysp} as it is widely used; so here it is
% let to the non-robust command \cs{nobreakspace }.
diff --git a/macros/latex/base/lttagging.dtx b/macros/latex/base/lttagging.dtx
new file mode 100644
index 0000000000..585479df21
--- /dev/null
+++ b/macros/latex/base/lttagging.dtx
@@ -0,0 +1,775 @@
+% \iffalse meta-comment
+%
+% Copyright (C) 2023-2024
+% The LaTeX Project and any individual authors listed elsewhere
+% in this file.
+%
+% This file is part of the LaTeX base system.
+% -------------------------------------------
+%
+% It may be distributed and/or modified under the
+% conditions of the LaTeX Project Public License, either version 1.3c
+% of this license or (at your option) any later version.
+% The latest version of this license is in
+% https://www.latex-project.org/lppl.txt
+% and version 1.3c or later is part of all distributions of LaTeX
+% version 2008 or later.
+%
+% This file has the LPPL maintenance status "maintained".
+%
+% The list of all files belonging to the LaTeX base distribution is
+% given in the file `manifest.txt'. See also `legal.txt' for additional
+% information.
+%
+% The list of derived (unpacked) files belonging to the distribution
+% and covered by LPPL is defined by the unpacking scripts (with
+% extension .ins) which are part of the distribution.
+%
+% \fi
+%
+% \iffalse
+%%% From File: lttagging.dtx
+%
+%<*driver>
+% \fi
+\ProvidesFile{lttagging.dtx}
+ [2023/12/19 v1.0a LaTeX Kernel (tagging support)]
+% \iffalse
+\documentclass{l3doc}
+\GetFileInfo{lttagging.dtx}
+\title{\filename}
+\date{\filedate}
+\author{\LaTeX{} project}
+
+\begin{document}
+% \MaintainedByLaTeXTeam{latex} % should be added again the moment
+ % it is supported by l3doc
+ \maketitle
+ \DocInput{\filename}
+\end{document}
+%</driver>
+% \fi
+%
+% \providecommand\env[1]{\texttt{#1}}
+%
+% \providecommand\hook[1]{\texttt{#1\DescribeHook[noprint]{#1}}}
+% \providecommand\socket[1]{\texttt{#1\DescribeSocket[noprint]{#1}}}
+% \providecommand\plug[1]{\texttt{#1\DescribePlug[noprint]{#1}}}
+%
+% \let\ProvideDocElement\NewDocElement
+%
+% \ProvideDocElement[printtype=\textit{socket},idxtype=socket,idxgroup=Sockets]{Socket}{socketdecl}
+% \ProvideDocElement[printtype=\textit{hook},idxtype=hook,idxgroup=Hooks]{Hook}{hookdecl}
+% \ProvideDocElement[printtype=\textit{plug},idxtype=plug,idxgroup=Plugs]{Plug}{plugdecl}
+%
+%
+% \section{}
+%
+%
+%
+% \MaybeStop{}
+%
+% \begin{macrocode}
+%<*2ekernel|latexrelease>
+% \end{macrocode}
+%
+% \begin{macrocode}
+\ExplSyntaxOn
+% \end{macrocode}
+%
+%
+% \section{General support for tagged output}
+%
+% \DescribeMacro\SuspendTagging
+% \DescribeMacro\ResumeTagging
+%
+% The are places in code where it is import top stop any tagging
+% activities, e.g., when we are doing trial typesetting that it is
+% done several times. In such a case one must tag only the final
+% version that is actually used, otherwise tagging structures are
+% allowed which then do not end up in the PDF and confuse the
+% mechanism. For this we have two commands that can be used in
+% packages: \cs{SuspendTagging} and \cs{ResumeTagging}. They are
+% available as part of the \LaTeX{} kernel, so that they can be
+% safely used in packages whether or not tagging is requested .They
+% both take string argument that is used for debugging to easily
+% identify why tagging was suspended or restarted, for example, in
+% \pkg{tabularx} you find \verb=\SuspendTagging{tabularx}=. By default
+% they two commands do nothing.
+%
+% TODO: the corresponding L3 layer commands should also have a dummy
+% definition in the kernel!
+%
+% \DescribeMacro\UseTaggingSocket
+% \DescribeMacro\tag_socket_use:n
+% \DescribeMacro\tag_socket_use:nn
+% To support tagging in packages we use sockets with names starting
+% with \texttt{tagsupport/}. Usually, these sockets have exactly two
+% plugs defined:
+% \plug{noop} (when no tagging is requested or tagging is not wanted
+% for some reason) and a second plug that enables the tagging. There
+% may be more, e.g., tagging with special debugging, etc., but right
+% now it is usually just on or off.
+%
+% Given that we sometimes have to suspend tagging, it would be fairly
+% inefficient to put different plugs into these sockets whenever that
+% happens. We therefore offer \cs{UseTaggingSocket} which is like
+% \cs{UseSocket} except that the socket name is specified without
+% \texttt{tagsupport/}, i.e.,
+% \begin{quote}
+% \verb=\UseTaggingSocket{foo}= $\to$
+% \verb=\UseSocket{tagsupport/foo}=
+% \end{quote}
+% Beside being slightly shorter, the big advantage is that this way
+% we can change \cs{UseTaggingSocket} to do nothing when tagging is
+% suspended with \cs{SuspendTagging} instead of changing the plugs of
+% the tagging support sockets back and forth.
+%
+% It is possible to use the tagging support sockets with
+% \cs{UseSocket} directly, but in this case the socket remains active
+% if \cs{SuspendTagging} is in force. There my be reasons for doing
+% that but in general we expect to always use \cs{UseTaggingSocket}.
+%
+% The L3 programming layer versions \cs{tag_socket_use:n} and
+% \cs{tag_socket_use:nn} are slightly more efficient than
+% \cs{UseTaggingSocket} because they do not have to determine how
+% many arguments the socket takes when disabling it, so in code that
+% is using the L3 programming layer we recommend to use them instead
+% of the CamelCase command.
+%
+%
+%
+% \begin{macro}{\SuspendTagging,\ResumeTagging}
+%
+% In the kernel, these two commands get dummy definitions so that
+% they can be used without harm in packages. The real definition is
+% used when tagging gets enabled.
+% \begin{macrocode}
+\cs_new_eq:NN \SuspendTagging \use_none:n
+\cs_new_eq:NN \ResumeTagging \use_none:n
+% \end{macrocode}
+%
+% A simplified version of this defnition should move to
+% \pkg{tagpdf} and dropped here, eventually.
+% \begin{macrocode}
+\AddToHook{begindocument/before}{
+ \cs_if_exist:NT \tag_stop:n
+ {
+ \cs_set:Npn \SuspendTagging #1 {
+% \end{macrocode}%
+% This stops tagging and also disables all tagging sockets so we are done.
+% \begin{macrocode}
+ \tag_stop:n {#1}
+ }
+% \end{macrocode}
+%
+% \begin{macrocode}
+ \cs_set:Npn \ResumeTagging #1 { \tag_start:n {#1} }
+ }
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\tag_socket_use:n,
+% \tag_socket_use:nn,
+% \UseTaggingSocket,
+% }
+% Again this is not the final definition for the kernel; it is just
+% a version to get going while some parts of the kernel support are
+% still missing.
+% \begin{macrocode}
+\AddToHook{begindocument}[kernel]{
+ \cs_if_exist:NF \tag_if_active:T
+ {
+ \prg_new_conditional:Npnn \tag_if_active: { p , T , TF, F }
+ { \prg_return_false: }
+ }
+}
+% \end{macrocode}
+%
+% Dummy definitions in the kernel.
+% These definitions will get updated in \pkg{tagpdf}.
+% \begin{macrocode}
+\cs_new_protected:Npn \tag_socket_use:n #1 { }
+\cs_new_protected:Npn \tag_socket_use:nn #1#2 { }
+% \end{macrocode}
+% The default in the kernel is just to get rid of the argument:
+% \begin{macrocode}
+\cs_new_protected:Npn \UseTaggingSocket #1 {
+ \int_case:nnF
+ { \int_use:c { c__socket_tagsupport/#1_args_int } }
+ {
+ 0 \prg_do_nothing:
+ 1 \use_none:n
+ 2 \use_none:nn
+% \end{macrocode}
+% We do not expect tagging sockets with more than one or two
+% arguments, so for now we only provide those.
+% \begin{macrocode}
+ }
+ \ERRORusetaggingsocket % that should get a proper error message
+}
+\ExplSyntaxOff
+% \end{macrocode}
+%
+% \end{macro}
+%
+%
+%
+%
+%
+%
+% \subsection{Tagging support for table/tabular packages}
+%
+% The code uses a number of sockets to inject the tagging
+% commands. These can be easily set to a noop-plug in case the
+% automated tagging is not wanted.
+%
+% \begin{socketdecl}{tagsupport/tbl/cell/begin,
+% tagsupport/tbl/cell/end,
+% tagsupport/tbl/pcell/end,
+% tagsupport/tbl/pcell/end,
+% tagsupport/tbl/row/begin,
+% tagsupport/tbl/row/end,
+% }
+% At first sockets for the begin and end of cells and table rows:
+% \begin{macrocode}
+\NewSocket{tagsupport/tbl/cell/begin}{0}
+\NewSocket{tagsupport/tbl/cell/end}{0}
+% \end{macrocode}
+%
+% \begin{macrocode}
+\NewSocket{tagsupport/tbl/row/begin}{0}
+\NewSocket{tagsupport/tbl/row/end}{0}
+% \end{macrocode}
+% Multi-line cells have their own sockets (as they start out in
+% vertical mode and need different treatment).
+% \begin{macrocode}
+\NewSocket{tagsupport/tbl/pcell/begin}{0}
+\NewSocket{tagsupport/tbl/pcell/end}{0}
+% \end{macrocode}
+% \end{socketdecl}
+%
+% \begin{socketdecl}{tagsupport/tbl/init}
+% This socket should be at the begin of the table, inside a group.
+% It is used for settings such as disabling para-tagging inside the
+% table. This socket
+% can perhaps be merged later into the begin-sockets.
+% \begin{macrocode}
+\NewSocket{tagsupport/tbl/init}{0}
+% \end{macrocode}
+% \end{socketdecl}
+%
+%
+% \begin{socketdecl}{tagsupport/tbl/finalize}
+% To fine tune the structure (change cells to header cells, remove
+% unwanted structures, move a foot to the end, etc.). We also need a
+% socket that is executed at the end of the table but \emph{before}
+% all the variables are restored to the outer or default values.
+% The code in the socket can make assignments, but probably
+% shouldn't do typesetting and not write whatsits.
+% \begin{macrocode}
+\NewSocket{tagsupport/tbl/finalize}{0}
+% \end{macrocode}
+% \end{socketdecl}
+%
+
+
+% \begin{socketdecl}{tagsupport/tbl/colspan}
+% This socket is used to manage spanning cells, e.g., a
+% \cs{multicolumn}. It expects one argument (the number of cells
+% spanned) and if tagging is enabled set appropriate tag attributes
+% in the background. We probably need a similar socket for row
+% spans eventually.
+% \begin{macrocode}
+\NewSocket{tagsupport/tbl/colspan}{1}
+% \end{macrocode}
+% \end{socketdecl}
+%
+
+
+% \begin{socketdecl}{tagsupport/tbl/hmode/begin,
+% tagsupport/tbl/hmode/end,
+% tagsupport/tbl/vmode/begin,
+% tagsupport/tbl/vmode/end
+% }
+%
+% These sockets are used in the begin and end code of environments,
+% to allow a fast enabling and disabling of the tagging. We
+% distinguish between tables that can be used inside paragraphs and
+% standalone tables such as \env{longtable} that are always in
+% vertical mode.
+% \begin{macrocode}
+\NewSocket{tagsupport/tbl/hmode/begin}{0}
+\NewSocket{tagsupport/tbl/hmode/end}{0}
+\NewSocket{tagsupport/tbl/vmode/begin}{0}
+\NewSocket{tagsupport/tbl/vmode/end}{0}
+% \end{macrocode}
+% \end{socketdecl}
+%
+%
+%
+% \begin{socketdecl}{tagsupport/tbl/longtable/init,
+% tagsupport/tbl/longtable/finalize}
+% \env{longtable} needs its own sockets to fine tune the structure.
+% Simply switching the plug in the previous socket interferes with
+% enabling/disabling the tagging.
+% \begin{macrocode}
+\NewSocket{tagsupport/tbl/longtable/init}{0}
+\NewSocket{tagsupport/tbl/longtable/finalize}{0}
+% \end{macrocode}
+% \end{socketdecl}
+%
+% \begin{socketdecl}{tagsupport/tbl/longtable/head,
+% tagsupport/tbl/longtable/foot}
+% Header and footer boxes need special handling because they are repeatedly
+% used.
+% \begin{macrocode}
+\NewSocket{tagsupport/tbl/longtable/head}{0}
+\NewSocket{tagsupport/tbl/longtable/foot}{0}
+% \end{macrocode}
+% \end{socketdecl}
+%
+%
+%
+%
+%
+% \section{For lttab.dtx parked here for now}
+%
+%
+% \begin{macrocode}
+%<@@=tbl>
+\ExplSyntaxOn
+% \end{macrocode}
+%
+%
+% \subsection{Variables for row, column and span counting}
+%
+% This part needs a decision on names for various integer registers
+% as well as a decision if those should be also made available for
+% \LaTeXe{}-style packages in form of 2e names and or as
+% non-internals for the L3 programming layer.
+%
+% At the moment they are all internal but this probably has to change.
+%
+% \begin{macro}{
+% \g_@@_col_int,
+% \g_@@_row_int,
+% \g_@@_span_tl,
+% \g_@@_table_cols_tl}
+%
+% \cs{g_@@_row_int} holds the current row number in the table. The
+% value \texttt{0} means we haven't yet processed the table
+% preamble (or in case of longtable are just in front of the next
+% chunk to be processed). It is incremented by every \cs{cr}
+% including the one ending the table preamble.
+%
+% TODO: due to the gymnastics needed inside the longtable code the
+% row counter is directly exposed there rather than hidden by
+% interfaces. This needs changing when it is decided how to manage
+% these counters.
+%
+% \cs{g_@@_col_int} holds the current column number. The value
+% \texttt{0} means we have not yet started the table or just finished a table row
+% (with \verb=\\= typically); any other positive value means we
+% are currently typesetting a cell in that column in some row
+% (denoted by the \cs{g_@@_row_int}).
+%
+% In a \cs{multicolumn} it holds the column number of the first
+% spanned column and \cs{g_@@_span_tl} the info how many cells are
+% spanned.
+%
+% \cs{g_@@_span_tl} is normally \texttt{1} except in a
+% \cs{multicolumn} cell.
+% \begin{macrocode}
+\int_new:N \g_@@_col_int
+\int_new:N \g_@@_row_int
+\tl_new:N \g_@@_span_tl
+\tl_new:N \g_@@_table_cols_tl
+
+\tl_gset:Nn \g_@@_span_tl {1}
+\tl_gset:Nn \g_@@_table_cols_tl {0} % indicates outer level
+% \end{macrocode}
+% \end{macro}
+%
+%
+% \begin{macro}{\l_@@_saved_col_tl,\l_@@_saved_row_tl,
+% \l_@@_saved_span_tl,\l_@@_saved_table_cols_tl}
+%
+% Saving the outer values if we are nesting tables is necessary (as
+% the above variables are globally altered). For this we always use
+% token lists because they don't change and we do not need to blow
+% additional integer registers.
+% \begin{macrocode}
+\tl_new:N \l_@@_saved_col_tl
+\tl_new:N \l_@@_saved_row_tl
+\tl_new:N \l_@@_saved_span_tl
+\tl_new:N \l_@@_saved_table_cols_tl
+
+\tl_set:Nn \l_@@_saved_col_tl{0}
+\tl_set:Nn \l_@@_saved_row_tl{0}
+\tl_set:Nn \l_@@_saved_span_tl{1}
+\tl_set:Nn \l_@@_saved_table_cols_tl{0} % indicates outer level
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\g_@@_missingcells_int}
+% This will contain the number of missing cells in a row:
+% \begin{macrocode}
+\int_new:N \g_@@_missing_cells_int
+% \end{macrocode}
+% \end{macro}
+%
+%
+%
+%
+%
+% \subsection{Tracing/debugging}
+%
+% \begin{macro}{\DebugTablesOn,\DebugTablesOff}
+%
+% \begin{macrocode}
+\def\DebugTablesOn{
+ \cs_set_eq:NN \@@_trace:n \typeout
+}
+\def\DebugTablesOff{
+ \cs_set_eq:NN \@@_trace:n \use_none:n
+}
+% \end{macrocode}
+%
+% \begin{macrocode}
+\cs_new_eq:NN \@@_trace:n \use_none:n
+% \end{macrocode}
+% \end{macro}
+%
+%
+%
+% \subsection{Interface commands}
+%
+% All interface commands for the cell number determination have to be
+% public on some level because they are needed in other packages as
+% well, e.g., longtable. We may or may not also want to provide 2e
+% style names for them.
+%
+% \begin{macro}{\tbl_update_cell_data:}
+% Updating cell data in columns after the first means we have to
+% increment the \cs{g_@@_col_int} by the span count of the previous
+% cell (in case it was a \cs{multicolumn}) and then reset the
+% \cs{g_@@_span_tl} to one (as the default).
+% \begin{macrocode}
+\cs_new_protected:Npn \tbl_update_cell_data: {
+ \int_gadd:Nn \g_@@_col_int { \g_@@_span_tl }
+ \tl_gset:Nn \g_@@_span_tl {1}
+}
+% \end{macrocode}
+% \end{macro}
+%
+%
+%
+% \begin{macro}{\tbl_count_table_cols:}
+% Current implementation of \cs{@mkpream} uses the scratch counter
+% \cs{count@} to keep track of the number of toks registers it needs
+% (2 per column), but this can't be used as it counts also
+% insertions made with \verb+!{}+ and \verb+@{}+.
+% So similar as does longtable for \cs{LT@cols} we count the
+% numbers of ampersands instead.
+% \begin{macrocode}
+\cs_new:Npn \tbl_count_table_cols: {
+ \seq_set_split:NnV\l_@@_tmpa_seq {&}\@preamble
+ \tl_gset:Ne \g_@@_table_cols_tl { \seq_count:N \l_@@_tmpa_seq }
+ \@@_trace:n { ==>~ Table~ has~ \g_@@_table_cols_tl \space columns }
+}
+% \end{macrocode}
+% \end{macro}
+%
+%
+% \begin{macro}{\l_@@_tmpa_seq}
+%
+% \begin{macrocode}
+\seq_new:N \l_@@_tmpa_seq
+% \end{macrocode}
+% \end{macro}
+%
+%
+%
+% \begin{macro}{\tbl_count_missing_cells:n}
+%
+% We might have the situation that some table package has not
+% implemented the \cs{tbl_count_table_cols:} in which case
+% \cs{g_@@_table_cols_tl} would always be zero and we would get an
+% error below when we try to determine the missing cells, so bypass
+% that calculation if we aren't doing tagging (there the packages
+% should have the proper code added). Recall that this is code,
+% that is called by \verb=\\= and an old table packagee might rely
+% on whatever the \LaTeX{} kernel offers here.
+% \begin{macrocode}
+\cs_new:Npn \tbl_count_missing_cells:n #1 {
+ \tag_if_active:T {
+ \int_compare:nNnT \g_@@_col_int > 0
+ {
+ \int_gset:Nn \g_@@_missing_cells_int
+ {
+ \g_@@_table_cols_tl
+ - \g_@@_col_int
+ - \g_@@_span_tl
+ + 1
+ }
+ \int_compare:nNnT \g_@@_missing_cells_int < 0 \ERRORmissingcells % should not happen
+ \@@_trace:n{==>~
+ (#1)~
+ This~ row~ needs~
+ \int_use:N \g_@@_missing_cells_int \space
+ additional~ cell(s)
+ }
+ }
+ }
+}
+% \end{macrocode}
+% \end{macro}
+%
+%
+% \begin{macro}{\tbl_save_outer_table_cols:}
+%
+% \begin{macrocode}
+\cs_new_protected:Npn \tbl_save_outer_table_cols: {
+ \tl_set_eq:NN \l_@@_saved_table_cols_tl \g_@@_table_cols_tl
+}
+% \end{macrocode}
+% \end{macro}
+%
+%
+% \begin{macro}{\tbl_init_cell_data_for_table:}
+%
+% \begin{macrocode}
+\cs_new_protected:Npn \tbl_init_cell_data_for_table: {
+ \tl_set:No \l_@@_saved_col_tl {\int_use:N \g_@@_col_int }
+ \tl_set:No \l_@@_saved_row_tl {\int_use:N \g_@@_row_int }
+ \tl_set_eq:NN \l_@@_saved_span_tl \g_@@_span_tl
+%
+ \@@_trace:n { ==>~ saved~cell~data:~
+ \l_@@_saved_row_tl,
+ \l_@@_saved_col_tl,
+ \l_@@_saved_span_tl \space
+ (
+ \int_compare:nNnTF \l_@@_saved_table_cols_tl = 0
+ { outer~ level }
+ { max:~ \l_@@_saved_table_cols_tl }
+ )
+ }
+% \end{macrocode}
+% These are the initial values when starting a table:
+% \begin{macrocode}
+ \int_gzero:N \g_@@_row_int
+ \int_gzero:N \g_@@_col_int
+ \tl_gset:Nn \g_@@_span_tl {1}
+}
+% \end{macrocode}
+% \end{macro}
+%
+%
+%
+%
+% \begin{macro}{\tbl_update_cell_data_for_next_row:}
+% \begin{macrocode}
+\cs_new_protected:Npn \tbl_update_cell_data_for_next_row: {
+ \int_gincr:N \g_@@_row_int % this row about to start
+ \int_gzero:N \g_@@_col_int % we are before first col
+}
+% \end{macrocode}
+% \end{macro}
+%
+%
+% \begin{macro}{\tbl_init_cell_data_for_row:}
+% If we start processing a cell in the first column we set
+% \cs{g_@@_col_int} to \texttt{1} as we are no longer "at" but "in"
+% the first column. We also set \cs{g_@@_span_tl} to its default
+% value (not spanning cells).
+% \begin{macrocode}
+\cs_new_protected:Npn \tbl_init_cell_data_for_row: {
+ \int_gset:Nn \g_@@_col_int {1}
+ \tl_gset:Nn \g_@@_span_tl {1}
+}
+% \end{macrocode}
+% \end{macro}
+%
+%
+% \begin{macro}{\tbl_if_row_was_started:T,
+% \tbl_if_row_was_started:TF}
+% We use \cs{g_@@_col_int} equal zero to indicate that we are just
+% after a TR (i.e.n between rows or at the very beginning of the
+% table). Using the row
+% count is not so good as longtable may split the table in chunks.
+%
+% These conditionals have to be expandable (i.e., unprotected) as
+% they are sometimes executed when \TeX{} is scanning inside a table.
+% \begin{macrocode}
+\cs_new:Npn \tbl_if_row_was_started:T {
+ \int_compare:nNnT \g_@@_col_int > 0
+}
+\cs_new:Npn \tbl_if_row_was_started:TF {
+ \int_compare:nNnTF \g_@@_col_int > 0
+}
+% \end{macrocode}
+% \end{macro}
+%
+%
+%
+% \begin{macro}{\tbl_gzero_row_count:,\tbl_gincr_row_count:,\tbl_gdecr_row_count:}
+% This here is basically a temporary interface. What it will be in
+% the end depends on what we decide concerning exposing row and
+% column counters, if they stay internal we need something like
+% this here (perhaps using \texttt{gincr} etc, or perhaps some
+% other names in the first place).
+% \begin{macrocode}
+\cs_new_protected:Npn \tbl_gzero_row_count: {
+ \int_gzero:N \g_@@_row_int
+}
+\cs_new_protected:Npn \tbl_gincr_row_count: {
+ \int_gincr:N \g_@@_row_int
+}
+\cs_new_protected:Npn \tbl_gdecr_row_count: {
+ \int_gdecr:N \g_@@_row_int
+}
+% \end{macrocode}
+% \end{macro}
+%
+%
+% \begin{macro}{\tbl_inbetween_rows:}
+% Again name is not really brilliant so far.
+% \begin{macrocode}
+\cs_new_protected:Npn \tbl_inbetween_rows: {
+ \int_gzero:N \g_@@_col_int
+}
+% \end{macrocode}
+% \end{macro}
+%
+%
+%
+%
+%
+%
+% \begin{macro}{\tbl_restore_outer_cell_data:}
+%
+% \begin{macrocode}
+\cs_new_protected:Npn \tbl_restore_outer_cell_data: {
+ \int_gset:Nn \g_@@_col_int { \l_@@_saved_col_tl }
+ \int_gset:Nn \g_@@_row_int { \l_@@_saved_row_tl }
+ \tl_gset_eq:NN \g_@@_span_tl \l_@@_saved_span_tl
+ \tl_gset_eq:NN \g_@@_table_cols_tl \l_@@_saved_table_cols_tl
+ \@@_trace:n { ==>~ restored~cell~data:~
+ \int_use:N \g_@@_row_int,
+ \int_use:N \g_@@_col_int,
+ \l_@@_saved_span_tl \space
+ (
+ \int_compare:nNnTF \g_@@_table_cols_tl = 0
+ { outer~ level }
+ { max:~ \g_@@_table_cols_tl }
+ )
+ }
+}
+% \end{macrocode}
+% \end{macro}
+%
+%
+%
+% \begin{macro}{\tbl_update_multicolumn_cell_data:n}
+% This macro updates \cs{g_@@_col_int} and \cs{g_@@_span_tl} inside
+% a \cs{multicolumn} and possibly calls the tagging socket
+% \texttt{tbl/row/begin}.
+% \begin{macrocode}
+\cs_new_protected:Npn \tbl_update_multicolumn_cell_data:n #1 {
+% \end{macrocode}
+% We execute socket for tagging only if this \cs{multicolumn}
+% replaces the preamble of the first column. In that case we also have
+% to set \cs{g_@@_col_int} to 1 because this is no longer done in the
+% preamble for the cell either.
+% \begin{macrocode}
+ \int_compare:nNnTF \g_@@_col_int = 0
+ {
+ \UseTaggingSocket{tbl/row/begin}
+ \int_gset:Nn \g_@@_col_int {1}
+ }
+% \end{macrocode}
+% If we are in a later column we use \cs{g_@@_span_tl} from the
+% previous column to update.
+% \begin{macrocode}
+ {
+ \int_gadd:Nn \g_@@_col_int { \g_@@_span_tl }
+ }
+% \end{macrocode}
+% Then we set the span value so that it can be use in the next column.
+% \begin{macrocode}
+ \tl_gset:Nn \g_@@_span_tl {#1}
+}
+% \end{macrocode}
+% \end{macro}
+%
+%
+%
+% \begin{macro}{\tbl_crcr:n}
+% This macro is used instead of the usual \cs{crcr} at the end of a
+% table. It is deliberately defined without protection because it
+% may get expanded by the scanning mechanism of low-level \TeX{}
+% after a final \cs{cr} (aka \verb=\\=) in the table. In that case
+% it shouldn't stop the expansion and the conditional inside will
+% be false, thus it just vanishes without doing anything. If there
+% are missing cells (in which case we also haven't see \cs{cr} yet)
+% the macro \cs{tbl_count_missing_cells:n} is executed and
+% then the row is finished with a final \cs{cr}.
+% \begin{macrocode}
+\cs_new:Npn \tbl_crcr:n #1 {
+ \int_compare:nNnT \g_@@_col_int > 0
+ {
+ \tbl_count_missing_cells:n {#1}
+ \cr
+ }
+}
+% \end{macrocode}
+% \end{macro}
+%
+%
+%
+% \begin{macrocode}
+\ExplSyntaxOff
+%<@@=>
+% \end{macrocode}
+%
+% This is needed for \pkg{longtable} because \cs{refstepcounter} is
+% setting up a target when \pkg{hyperref} is loaded and we don't
+% want that in \pkg{longtable}.
+%
+% TODO: move to right .dtx file
+% \begin{macrocode}
+\let\@kernel@refstepcounter\refstepcounter
+% \end{macrocode}
+% Prevent longtable patching by hyperref until hyperref does so automatically:
+% \begin{macrocode}
+\def\hyper@nopatch@longtable{}
+% \end{macrocode}
+%
+%
+% Should there be a module?
+%
+% \begin{macrocode}
+%<latexrelease>\NewModuleRelease{2024/06/01}{lttagging}
+%<latexrelease> {Tagging support}
+% \end{macrocode}
+%
+%
+%
+%
+% \begin{macrocode}
+%<latexrelease>\IncludeInRelease{0000/00/00}{lttagging}%
+%<latexrelease> {Undo tagging support}
+%<latexrelease>
+%<latexrelease>
+%<latexrelease>
+%<latexrelease>\EndModuleRelease
+% \end{macrocode}
+%
+% \begin{macrocode}
+%</2ekernel|latexrelease>
+% \end{macrocode}
+%
+% \Finale
+%
diff --git a/macros/latex/base/lttemplates.dtx b/macros/latex/base/lttemplates.dtx
new file mode 100644
index 0000000000..7192359e72
--- /dev/null
+++ b/macros/latex/base/lttemplates.dtx
@@ -0,0 +1,2634 @@
+% \iffalse meta-comment
+%
+% Copyright (C) 1999 Frank Mittelbach, Chris Rowley, David Carlisle
+% Copyright (C) 2004-2010 Frank Mittelbach, The LaTeX Project
+% Copyright (C) 2011-2024
+% The LaTeX Project and any individual authors listed elsewhere
+% in this file.
+%
+% This file is part of the LaTeX base system.
+% -------------------------------------------
+%
+% It may be distributed and/or modified under the
+% conditions of the LaTeX Project Public License, either version 1.3c
+% of this license or (at your option) any later version.
+% The latest version of this license is in
+% https://www.latex-project.org/lppl.txt
+% and version 1.3c or later is part of all distributions of LaTeX
+% version 2008 or later.
+%
+% This file has the LPPL maintenance status "maintained".
+%
+% The list of all files belonging to the LaTeX base distribution is
+% given in the file `manifest.txt'. See also `legal.txt' for additional
+% information.
+%
+% The list of derived (unpacked) files belonging to the distribution
+% and covered by LPPL is defined by the unpacking scripts (with
+% extension .ins) which are part of the distribution.
+%
+% \fi
+%
+% \iffalse
+%
+%%% From File: lttemplates.dtx
+%
+%<*driver>
+% \fi
+\ProvidesFile{lttemplates.dtx}
+ [2024-04-17 v1.0c LaTeX Kernel (Prototype document functions)]
+% \iffalse
+\documentclass{l3doc}
+\GetFileInfo{lttemplates.dtx}
+\begin{document}
+ \DocInput{lttemplates.dtx}
+\end{document}
+%</driver>
+% \fi
+%
+% \title{The \texttt{lttemplates.dtx} code\thanks{This file has version
+% \fileversion\ dated \filedate, \copyright\ \LaTeX\
+% Project.}}
+% \author{^^A
+% Frank Mittelbach, Chris Rowley, David Carlisle, \LaTeX{} Project\thanks
+% {^^A
+% E-mail:
+% \href{mailto:latex-team@latex-project.org}
+% {latex-team@latex-project.org}^^A
+% }^^A
+% }
+%
+% \maketitle
+%
+% \section{Introduction}
+%
+% There are three broad \enquote{layers} between putting down ideas into
+% a source file and ending up with a typeset document. These layers of
+% document writing are
+% \begin{enumerate}
+% \item authoring of the text with mark-up;
+% \item document layout design;
+% \item implementation (with \TeX{} programming) of the design.
+% \end{enumerate}
+% We write the text as an author, and we see the visual output of the design
+% after the document is generated; the \TeX{} implementation in the middle is
+% the glue between the two.
+%
+% \LaTeX{}'s greatest success has been to standardise a system of mark-up that
+% balances the trade-off between ease of reading and ease of writing to suit
+% almost all forms of technical writing. It's
+% other original strength was a good background in typographical design; while
+% the standard \LaTeXe{} classes look somewhat dated now in terms of their
+% visual design, their typography is generally sound (barring the occasional
+% minor faults).
+%
+% However, \LaTeXe{} has always lacked a standard approach to customising
+% the visual design of a document. Changing the looks of the standard classes
+% involved either:
+% \begin{itemize}
+% \item Creating a new version of the implementation code of the class and
+% editing it.
+% \item Loading one of the many packages to customise certain elements of
+% the standard classes.
+% \item Loading a completely different document class, such as
+% \textsf{KOMA-Script} or \textsf{memoir}, that allows easy customisation.
+% \end{itemize}
+% All three of these approaches have their drawbacks and learning curves.
+%
+% The idea behind \pkg{lttemplates} is to cleanly separate the three layers
+% introduced at the beginning of this section, so that document authors who
+% are not programmers can easily change the design of their documents.
+% \pkg{lttemplates} also makes it easier for \LaTeX{} programmers to provide
+% their own customisations on top of a pre-existing class.
+%
+% \section{What is a document?}
+%
+% Besides the textual content of the words themselves, the source file
+% of a document contains mark-up elements that add structure to the
+% document. These elements include sectional divisions, figure/table
+% captions, lists of various sorts, theorems/proofs, and so on.
+% The list will be different for every document that can be written.
+%
+% Each element can be represented logically without worrying about the
+% formatting, with mark-up such as \cs{section}, \cs{caption},
+% |\begin{enumerate}| and so on. The output of each one of these
+% document elements will be a typeset representation of the information
+% marked up, and the visual arrangement and design of these elements
+% can vary widely in producing a variety of desired outcomes.
+%
+% For each type of document element, there may be design variations that
+% contain the same sort of information but present it in slightly
+% different ways. For example, the difference between a numbered and an
+% unnumbered section, \cs{section} and |\section*|, or the difference
+% between an itemised list or an enumerated list.
+%
+% There are three distinct layers in the definition of
+% \enquote{a document} at this level
+% \begin{enumerate}
+% \item semantic elements such as the ideas of sections and lists;
+% \item a set of design solutions for representing these elements
+% visually;
+% \item specific variations for these designs that represent the
+% elements in the document.
+% \end{enumerate}
+% In the parlance of the template system, these are called types,
+% templates, and instances, and they are discussed below in sections
+% \ref{sec:types}, \ref{sec:templates}, and~\ref{sec:instances},
+% respectively.
+%
+% \section {Types, templates, and instances}
+%
+% By formally declaring documents to be composed of mark-up elements
+% grouped into types, which are interpreted and typeset with a set of
+% templates, each of which has one or more instances with which to
+% compose each and every semantic unit of the text, we can cleanly
+% separate the components of document construction.
+%
+% All of the structures provided by the template system are global,
+% and do not respect \TeX{} grouping.
+%
+% \section{Template types}
+% \label{sec:types}
+%
+% An \emph{template type} (sometimes just \enquote{type}) is an
+% abstract idea of a document element that takes a fixed number of
+% arguments corresponding to the information from the document author
+% that it is representing. A sectioning type, for example, might take
+% three inputs: \enquote{title}, \enquote{short title}, and
+% \enquote{label}.
+%
+% Any given document class will define which types are to be
+% used in the document, and any template of a given type can be
+% used to generate an instance for the type. (Of course, different
+% templates will produce different typeset representations, but the
+% underlying content will be the same.)
+%
+% \begin{function}{\NewTemplateType}
+% \begin{syntax}
+% \cs{NewTemplateType} \Arg{template type} \Arg{no. of args}
+% \end{syntax}
+% This function defines an \meta{template type} taking
+% \meta{number of arguments}, where the \meta{type} is an
+% abstraction as discussed above. For example,
+% \begin{verbatim}
+% \NewTemplateType{sectioning}{3}
+% \end{verbatim}
+% creates a type \enquote{sectioning}, where each use of that
+% type will need three arguments.
+% \end{function}
+%
+% \section{Templates}
+% \label{sec:templates}
+%
+% A \emph{template} is a generalised design solution for representing
+% the information of a specified type. Templates that do the same
+% thing, but in different ways, are grouped together by their type
+% and given separate names. There are two important parts to a template:
+% \begin{itemize}
+% \item the parameters it takes to vary the design it is producing;
+% \item the implementation of the design.
+% \end{itemize}
+% As a document author or designer does not care about the
+% implementation but rather only the interface to the template, these two
+% aspects of the template definition are split into two independent
+% declarations, \cs{DeclareTemplateInterface} and
+% \cs{DeclareTemplateCode}.
+%
+% \begin{function}{\DeclareTemplateInterface}
+% \begin{syntax}
+% \cs{DeclareTemplateInterface}
+% ~~\Arg{type} \Arg{template} \Arg{no.~of args}
+% ~~\Arg{key list}
+% \end{syntax}
+% A \meta{template} interface is declared for a particular
+% \meta{type}, where the \meta{number of arguments} must
+% agree with the type declaration. The interface itself is
+% defined by the \meta{key list}, which is itself a key--value list
+% taking a specialized format:
+% \begin{quotation}
+% \obeylines
+% \noindent
+% \meta{key1}~":"~\meta{key type1}~","
+% \meta{key2}~":"~\meta{key type2}~","
+% \meta{key3}~":"~\meta{key type3}~"="~\meta{default3}~","
+% \meta{key4}~":"~\meta{key type4}~"="~\meta{default4}~","
+% \ldots
+% \end{quotation}
+% Each \meta{key} name should consist of \textsc{ascii} characters,
+% with the exception of |,|, |=| and \verb*| |. The recommended form
+% for key names is to use lower case letters, with dashes to separate
+% out different parts. Spaces are ignored in key names, so they can be
+% included or missed out at will. Each \meta{key} must have a
+% \meta{key type}, which defined the type of input that the \meta{key}
+% requires. A full list of key types is given in
+% Table~\ref{tab:key-types}. Each key may have a \meta{default}
+% value, which will be used in by the template if the \meta{key} is
+% not set explicitly. The \meta{default} should be of the correct
+% form to be accepted by the \meta{key type} of the \meta{key}: this
+% is not checked by the code. Expressions for numerical values are
+% evaluated when the template is used, thus for example values given
+% in terms of |em| or |ex| will be set respecting the prevailing font.
+% \end{function}
+%
+% \begin{table}
+% \centering
+% \begin{tabular}{>{\ttfamily}ll}
+% \toprule
+% \multicolumn{1}{l}{Key-type} & Description of input \\
+% \midrule
+% boolean & \texttt{true} or \texttt{false} \\
+% choice\Arg{choices}
+% & A list of pre-defined \meta{choices} \\
+% commalist & A comma-separated list \\
+% function\Arg{$N$}
+% & A function definition with $N$ arguments
+% ($N$ from $0$ to $9$) \\
+% instance\Arg{name}
+% & An instance of type \meta{name} \\
+% integer & An integer or integer expression \\
+% length & A fixed length \\
+% muskip & A math length with shrink and stretch components \\
+% real & A real (floating point) value \\
+% skip & A length with shrink and stretch components \\
+% tokenlist & A token list: any text or commands \\
+% \bottomrule
+% \end{tabular}
+% \caption{Key-types for defining template interfaces with
+% \cs{DeclareTemplateInterface}.}
+% \label{tab:key-types}
+% \end{table}
+%
+% \begin{function}{\KeyValue}
+% \begin{syntax}
+% \cs{KeyValue} \Arg{key name}
+% \end{syntax}
+% There are occasions where the default (or value) for one key
+% should be taken from another. The \cs{KeyValue} function can be
+% used to transfer this information without needing to know the
+% internal implementation of the key:
+% \begin{verbatim}
+% \DeclareTemplateInterface { type } { template } { no. of args }
+% {
+% key-name-1 : key-type = value ,
+% key-name-2 : key-type = \KeyValue { key-name-1 },
+% ...
+% }
+% \end{verbatim}
+% \end{function}
+%
+% \begin{function}{\DeclareTemplateCode}
+% \begin{syntax}
+% \cs{DeclareTemplateCode}
+% ~~\Arg{type} \Arg{template} \Arg{no.~of args}
+% ~~\Arg{key bindings} \Arg{code}
+% \end{syntax}
+% The relationship between a templates keys and the internal
+% implementation is created using the \cs{DeclareTemplateCode}
+% function. As with \cs{DeclareTemplateInterface}, the
+% \meta{template} name is given along with the \meta{type}
+% and \meta{number of arguments} required. The \meta{key bindings}
+% argument is a key--value list which specifies the relationship
+% between each \meta{key} of the template interface with an
+% underlying\meta{variable}.
+%
+% \begin{quotation}
+% \obeylines
+% \noindent
+% \meta{key1}~"="~\meta{variable1},
+% \meta{key2}~"="~\meta{variable2},
+% \meta{key3}~"="~global~\meta{variable3},
+% \meta{key4}~"="~global~\meta{variable4},
+% \ldots
+% \end{quotation}
+% With the exception of the choice, code and function key types,
+% the \meta{variable} here should be the name of an existing
+% \LaTeX3 register. As illustrated, the key word \enquote{global}
+% may be included in the listing to indicate that the \meta{variable}
+% should be assigned globally. A full list of variable bindings is
+% given in Table~\ref{tab:key-vars}.
+%
+% The \meta{code} argument of \cs{DeclareTemplateCode} is used
+% as the replacement text for the template when it is used, either
+% directly or as an instance. This may therefore accept arguments
+% |#1|, |#2|, \emph{etc}.~as detailed by the \meta{number of arguments}
+% taken by the type.
+% \end{function}
+%
+% \begin{table}
+% \centering
+% \begin{tabular}{>{\ttfamily}ll}
+% \toprule
+% \multicolumn{1}{l}{Key-type} & Description of binding \\
+% \midrule
+% \ & Boolean variable, \emph{e.g}.~\cs{l_tmpa_bool} \\
+% choice
+% & List of choice implementations
+% (see Section~\ref{sec:choices-key}) \\
+% commalist & Comma list, \emph{e.g}.~\cs{l_tmpa_clist} \\
+% function
+% & Function taking $N$ arguments, \emph{e.g}.~\cs{use_i:nn} \\
+% instance \\
+% integer & Integer variable, \emph{e.g}.~\cs{l_tmpa_int} \\
+% length & Dimension variable, \emph{e.g}.~\cs{l_tmpa_dim} \\
+% muskip & Muskip variable, \emph{e.g}.~\cs{l_tmpa_muskip} \\
+% real & Floating-point variable, \emph{e.g}.~\cs{l_tmpa_fp} \\
+% skip & Skip variable, \emph{e.g}.~\cs{l_tmpa_skip} \\
+% tokenlist & Token list variable, \emph{e.g}.~\cs{l_tmpa_tl} \\
+% \bottomrule
+% \end{tabular}
+% \caption{Bindings required for different key types when defining
+% template implementations with \cs{DeclareTemplateCode}. Apart
+% from \texttt{code}, \texttt{choice} and \texttt{function}
+% all of these accept the key word \texttt{global} to carry
+% out a global assignment.}
+% \label{tab:key-vars}
+% \end{table}
+%
+% \begin{function}{\AssignTemplateKeys}
+% \begin{syntax}
+% \cs{AssignTemplateKeys}
+% \end{syntax}
+% In the final argument of \cs{DeclareTemplateCode} the assignment of
+% keys defined by the template may be delayed by including the command
+% \cs{AssignTemplateKeys}. If this is \emph{not} present, keys are assigned
+% immediately before the template code. If \cs{AssignTemplateKeys} is
+% present, assignment is delayed until this point. Note that the
+% command must be \emph{directly} present in the code, not placed
+% within a nested command/macro.
+% \end{function}
+%
+% \begin{function}{\DeclareTemplateCopy}
+% \begin{syntax}
+% \cs{DeclareTemplateCopy}
+% ~~\Arg{type} \Arg{template2} \Arg{template1}
+% \end{syntax}
+% Copies \meta{template1} of \meta{type} to a new name \meta{template2}:
+% the copy can then be edited independent of teh original.
+% \end{function}
+%
+% \section{Multiple choices}
+% \label{sec:choices-key}
+%
+% The \texttt{choice} key type implements multiple choice input. At the
+% interface level, only the list of valid choices is needed:
+% \begin{verbatim}
+% \DeclareTemplateInterface { foo } { bar } { 0 }
+% { key-name : choice { A, B, C } }
+% \end{verbatim}
+% where the choices are given as a comma-list (which must therefore
+% be wrapped in braces). A default value can also be given:
+% \begin{verbatim}
+% \DeclareTemplateInterface { foo } { bar } { 0 }
+% { key-name : choice { A, B, C } = A }
+% \end{verbatim}
+%
+% At the implementation level, each choice is associated with code,
+% using a nested key--value list.
+% \begin{verbatim}
+% \DeclareTemplateCode { foo } { bar } { 0 }
+% {
+% key-name =
+% {
+% A = Code-A ,
+% B = Code-B ,
+% C = Code-C
+% }
+% }
+% { ... }
+% \end{verbatim}
+% The two choice lists should match, but in the implementation a
+% special \texttt{unknown} choice is also available. This can be used
+% to ignore values and implement an \enquote{else} branch:
+% \begin{verbatim}
+% \DeclareTemplateCode { foo } { bar } { 0 }
+% {
+% key-name =
+% {
+% A = Code-A ,
+% B = Code-B ,
+% C = Code-C ,
+% unknown = Else-code
+% }
+% }
+% { ... }
+% \end{verbatim}
+% The \texttt{unknown} entry must be the last one given, and should
+% \emph{not} be listed in the interface part of the template.
+%
+% For keys which accept the values \texttt{true} and \texttt{false}
+% both the boolean and choice key types can be used. As template
+% interfaces are intended to prompt clarity at the design level, the
+% boolean key type should be favoured, with the choice type reserved
+% for keys which take arbitrary values.
+%
+% \section{Instances}
+% \label{sec:instances}
+%
+% After a template is defined it still needs to be put to use. The
+% parameters that it expects need to be defined before it can be used in
+% a document. Every time a template has parameters given to it, an
+% \emph{instance} is created, and this is the code that ends up in the
+% document to perform the typesetting of whatever pieces of information
+% are input into it.
+%
+% For example, a template might say \enquote{here is a section with or
+% without a number that might be centred or left aligned and print its
+% contents in a certain font of a certain size, with a bit of a gap
+% before and after it} whereas an instance declares \enquote{this is a
+% section with a number, which is centred and set in $12\,\text{pt}$
+% italic with a $10\,\text{pt}$ skip before and a
+% $12\,\text{pt}$ skip after it}. Therefore, an instance is just a
+% frozen version of a template with specific settings as chosen by the
+% designer.
+%
+% \begin{function}{\DeclareInstance}
+% \begin{syntax}
+% \cs{DeclareInstance}
+% ~~\Arg{type} \Arg{instance} \Arg{template} \Arg{parameters}
+% \end{syntax}
+% This function uses a \meta{template} for an \meta{type}
+% to create an \meta{instance}. The \meta{instance} will be set
+% up using the \meta{parameters}, which will set some of the
+% \meta{keys} in the \meta{template}.
+%
+% As a practical example, consider a type for document sections
+% (which might include chapters, parts, sections, \emph{etc}.), which
+% is called \texttt{sectioning}. One possible template for this
+% type might be called \texttt{basic}, and one instance of this
+% template would be a numbered section. The instance declaration might
+% read:
+% \begin{verbatim}
+% \DeclareInstance { sectioning } { section-num } { basic }
+% {
+% numbered = true ,
+% justification = center ,
+% font =\normalsize\itshape ,
+% before-skip = 10pt ,
+% after-skip = 12pt ,
+% }
+% \end{verbatim}
+% Of course, the key names here are entirely imaginary, but illustrate
+% the general idea of fixing some settings.
+% \end{function}
+%
+% \begin{function}{\IfInstanceExistsT, \IfInstanceExisstF, \IfInstanceExistsTF}
+% \begin{syntax}
+% \cs{IfInstanceExistsTF} \Arg{type} \Arg{instance} \Arg{true code} \Arg{false code}
+% \end{syntax}
+% Tests if the named \meta{instance} of a \meta{type} exists, and
+% then inserts the appropriate code into the input stream.
+% \end{function}
+%
+% \begin{function}{\DeclareInstanceCopy}
+% \begin{syntax}
+% \cs{DeclareInstanceCopy}
+% ~~\Arg{type} \Arg{instance2} \Arg{instance1}
+% \end{syntax}
+% Copies the \meta{values} for \meta{instance1} for an
+% \meta{type} to \meta{instance2}.
+% \end{function}
+%
+% \section{Document interface}
+%
+% After the instances have been chosen, document commands must be
+% declared to use those instances in the document. \cs{UseInstance}
+% calls instances directly, and this command should be used internally
+% in document-level mark-up.
+%
+% \begin{function}{\UseInstance}
+% \begin{syntax}
+% \cs{UseInstance}
+% ~~\Arg{type} \Arg{instance} \meta{arguments}
+% \end{syntax}
+% Uses an \meta{instance} of the \meta{type}, which will require
+% \meta{arguments} as determined by the number specified for the
+% \meta{type}. The \meta{instance} must have been declared
+% before it can be used, otherwise an error is raised.
+% \end{function}
+%
+% \begin{function}{\UseTemplate}
+% \begin{syntax}
+% \cs{UseTemplate} \Arg{type} \Arg{template}
+% ~~\Arg{settings} \meta{arguments}
+% \end{syntax}
+% Uses the \meta{template} of the specified \meta{type},
+% applying the \meta{settings} and absorbing \meta{arguments} as
+% detailed by the \meta{type} declaration. This in effect
+% is the same as creating an instance using \cs{DeclareInstance}
+% and immediately using it with \cs{UseInstance}, but without the
+% instance having any further existence. It is therefore useful where
+% a template needs to be used once.
+%
+% This function can also be used as the argument to \texttt{instance}
+% key types:
+% \begin{verbatim}
+% \DeclareInstance { type } { template } { instance }
+% {
+% instance-key =
+% \UseTemplate { type2 } { template2 } { <settings> }
+% }
+% \end{verbatim}
+% \end{function}
+%
+% \section{Changing existing definitions}
+%
+% Template parameters may be assigned specific defaults for instances
+% to use if the instance declaration doesn't explicit set those
+% parameters. In some cases, the document designer will wish to edit
+% these defaults to allow them to \enquote{cascade} to the instances.
+% The alternative would be to set each parameter identically for each
+% instance declaration, a tedious and error-prone process.
+%
+% \begin{function}{\EditTemplateDefaults}
+% \begin{syntax}
+% \cs{EditTemplateDefaults}
+% ~~\Arg{type} \Arg{template} \Arg{new defaults}
+% \end{syntax}
+% Edits the \meta{defaults} for a \meta{template} for an
+% \meta{type}. The \meta{new defaults}, given as a key--value
+% list, replace the existing defaults for the \meta{template}. This
+% means that the change will apply to instances declared after the
+% editing, but that instances which have already been created are
+% unaffected.
+% \end{function}
+%
+% \begin{function}{\EditInstance}
+% \begin{syntax}
+% \cs{EditInstance}
+% ~~\Arg{type} \Arg{instance} \Arg{new values}
+% \end{syntax}
+% Edits the \meta{values} for an \meta{instance} for an
+% \meta{type}. The \meta{new values}, given as a key--value
+% list, replace the existing values for the \meta{instance}. This
+% function is complementary to \cs{EditTemplateDefaults}:
+% \cs{EditInstance} changes a single instance while leaving the
+% template untouched.
+% \end{function}
+%
+% \section{\emph{Ad hoc} adjustment of templates}
+%
+% \begin{function}{\SetTemplateKeys}
+% \begin{syntax}
+% \cs{SetTemplateKeys} \Arg{type} \Arg{template} \Arg{keyvals}
+% \end{syntax}
+% At point of use it may be useful to apply changed to individual instances.
+% This is supported as each template key is made available for adjustment
+% using \cs{SetTemplateKeys}.
+% \end{function}
+%
+% For example, after
+% \begin{verbatim}
+% \NewTypeType{MyObj}{0}
+% \DeclareTemplateInterface{MyObj}{TemplateA}{0}
+% {
+% akey: tokenlist ,
+% bkey: function{2}
+% }
+% \DeclareTemplateCode{MyObj}{TemplateA}{0}
+% {
+% akey = SomeTokens ,
+% bkey = \func:nn ,
+% }
+% \end{verbatim}
+% the template keys could be adjusted in an \emph{ad hoc} fashion using
+% \begin{verbatim}
+% \SetTemplateKeys{MyObj}{TemplateA}
+% {
+% akey = OtherTokens ,
+% bkey = \AltFunc:nn
+% }
+% \end{verbatim}
+%
+% \section{Getting information about templates and instances}
+%
+% \begin{function}{\ShowInstanceValues}
+% \begin{syntax}
+% \cs{ShowInstanceValues} \Arg{type} \Arg{instance}
+% \end{syntax}
+% Shows the \meta{values} for an \meta{instance} of the given
+% \meta{type} at the terminal.
+% \end{function}
+%
+% \begin{function}{\ShowTemplateCode}
+% \begin{syntax}
+% \cs{ShowTemplateCode} \Arg{type} \Arg{template}
+% \end{syntax}
+% Shows the \meta{code} of a \meta{template} for an \meta{type}
+% in the terminal.
+% \end{function}
+%
+% \begin{function}{\ShowTemplateDefaults}
+% \begin{syntax}
+% \cs{ShowTemplateDefaults} \Arg{type} \Arg{template}
+% \end{syntax}
+% Shows the \meta{default} values of a \meta{template} for an
+% \meta{type} in the terminal.
+% \end{function}
+%
+% \begin{function}{\ShowTemplateInterface}
+% \begin{syntax}
+% \cs{ShowTemplateInterface} \Arg{type} \Arg{template}
+% \end{syntax}
+% Shows the \meta{keys} and associated \meta{key types} of a
+% \meta{template} for an \meta{type} in the terminal.
+% \end{function}
+%
+% \begin{function}{\ShowTemplateVariables}
+% \begin{syntax}
+% \cs{ShowTemplateVariables} \Arg{type} \Arg{template}
+% \end{syntax}
+% Shows the \meta{variables} and associated \meta{keys} of a
+% \meta{template} for an \meta{type} in the terminal. Note that
+% \texttt{code} and \texttt{choice} keys do not map directly to variables
+% but to arbitrary code. For \texttt{choice} keys, each valid choice
+% is shown as a separate entry in the list, with the key name and choice
+% separated by a space, for example
+% \begin{verbatim}
+% Template 'example' of type 'example' has variable mapping:
+% > demo unknown => \def \demo {?}
+% > demo c => \def \demo {c}
+% > demo b => \def \demo {b}
+% > demo a => \def \demo {a}.
+% \end{verbatim}
+% would be shown for a choice key \texttt{demo} with valid choices
+% \texttt{a}, \texttt{b} and \texttt{c}, plus code for an \texttt{unknown}
+% branch.
+% \end{function}
+%
+% \MaybeStop{\setlength\IndexMin{200pt}\PrintIndex}
+%
+% \section{The implementation}
+%
+% \begin{macrocode}
+%<@@=template>
+% \end{macrocode}
+%
+% \begin{macrocode}
+%<*2ekernel>
+\message{templates,}
+%</2ekernel>
+% \end{macrocode}
+%
+% \begin{macrocode}
+%<*2ekernel|latexrelease>
+% \end{macrocode}
+%
+% \begin{macrocode}
+\ExplSyntaxOn
+% \end{macrocode}
+%
+% \begin{macrocode}
+%<latexrelease>\NewModuleRelease{2024/06/01}{lttemplates}
+%<latexrelease> {Prototype~document~commands}%
+% \end{macrocode}
+%
+% \subsection{Variables and constants}
+%
+% \begin{variable}
+% {
+% \c_@@_code_root_tl ,
+% \c_@@_defaults_root_tl ,
+% \c_@@_instances_root_tl ,
+% \c_@@_keytypes_root_tl ,
+% \c_@@_key_order_root_tl ,
+% \c_@@_restrict_root_tl ,
+% \c_@@_values_root_tl ,
+% \c_@@_vars_root_tl
+% }
+% So that literal values are kept to a minimum.
+% \begin{macrocode}
+\tl_const:Nn \c_@@_code_root_tl { template~code~>~ }
+\tl_const:Nn \c_@@_defaults_root_tl { template~defaults~>~ }
+\tl_const:Nn \c_@@_instances_root_tl { template~instance~>~ }
+\tl_const:Nn \c_@@_keytypes_root_tl { template~key~types~>~ }
+\tl_const:Nn \c_@@_key_order_root_tl { template~key~order~>~ }
+\tl_const:Nn \c_@@_values_root_tl { template~values~>~ }
+\tl_const:Nn \c_@@_vars_root_tl { template~vars~>~ }
+% \end{macrocode}
+% \end{variable}
+%
+% \begin{variable}{\c_@@_keytypes_arg_seq}
+% A list of keytypes which also need additional data (an argument),
+% used to parse the keytype correctly.
+% \begin{macrocode}
+\seq_const_from_clist:Nn \c_@@_keytypes_arg_seq
+ { choice , function , instance }
+% \end{macrocode}
+% \end{variable}
+%
+% \begin{variable}{\g_@@_type_prop}
+% For storing types and the associated number of arguments.
+% \begin{macrocode}
+\prop_new:N \g_@@_type_prop
+% \end{macrocode}
+% \end{variable}
+%
+% \begin{variable}{\l_@@_assignments_tl}
+% When creating an instance, the assigned values are collected here.
+% \begin{macrocode}
+\tl_new:N \l_@@_assignments_tl
+% \end{macrocode}
+% \end{variable}
+%
+% \begin{macro}{\l_@@_default_tl}
+% The default value for a key is recovered here from the property list
+% in which it is stored.
+% \begin{macrocode}
+\tl_new:N \l_@@_default_tl
+% \end{macrocode}
+%\ end{macro}
+%
+% \begin{variable}{\l_@@_error_bool}
+% A flag for errors to be carried forward.
+% \begin{macrocode}
+\bool_new:N \l_@@_error_bool
+% \end{macrocode}
+% \end{variable}
+%
+% \begin{variable}{\l_@@_global_bool}
+% Used to indicate that assignments should be global.
+% \begin{macrocode}
+\bool_new:N \l_@@_global_bool
+% \end{macrocode}
+% \end{variable}
+%
+% \begin{variable}
+% {
+% \l_@@_key_name_tl ,
+% \l_@@_keytype_tl ,
+% \l_@@_keytype_arg_tl ,
+% \l_@@_value_tl ,
+% \l_@@_var_tl
+% }
+% When defining each key in a template, the name and type of the key
+% need to be separated and stored. Any argument needed by the
+% keytype is also stored separately.
+% \begin{macrocode}
+\tl_new:N \l_@@_key_name_tl
+\tl_new:N \l_@@_keytype_tl
+\tl_new:N \l_@@_keytype_arg_tl
+\tl_new:N \l_@@_value_tl
+\tl_new:N \l_@@_var_tl
+% \end{macrocode}
+% \end{variable}
+%
+% \begin{variable}
+% {
+% \l_@@_keytypes_prop ,
+% \l_@@_key_order_seq ,
+% \l_@@_values_prop ,
+% \l_@@_vars_prop
+% }
+% To avoid needing too many difficult-to-follow csname assignments,
+% various scratch token registers are used to build up data, which is
+% then transferred
+% \begin{macrocode}
+\prop_new:N \l_@@_keytypes_prop
+\seq_new:N \l_@@_key_order_seq
+\prop_new:N \l_@@_values_prop
+\prop_new:N \l_@@_vars_prop
+% \end{macrocode}
+% \end{variable}
+%
+% \begin{variable}
+% {
+% \l_@@_tmp_clist ,
+% \l_@@_tmp_dim ,
+% \l_@@_tmp_int ,
+% \l_@@_tmp_muskip ,
+% \l_@@_tmp_skip ,
+% \l_@@_tmp_tl
+% }
+% Scratch space.
+% \begin{macrocode}
+\clist_new:N \l_@@_tmp_clist
+\dim_new:N \l_@@_tmp_dim
+\int_new:N \l_@@_tmp_int
+\muskip_new:N \l_@@_tmp_muskip
+\skip_new:N \l_@@_tmp_skip
+\tl_new:N \l_@@_tmp_tl
+% \end{macrocode}
+% \end{variable}
+%
+% \begin{variable}{\s_@@_mark, \s_@@_stop}
+% Internal scan marks.
+% \begin{macrocode}
+\scan_new:N \s_@@_mark
+\scan_new:N \s_@@_stop
+% \end{macrocode}
+% \end{variable}
+%
+% \begin{variable}{\q_@@_nil}
+% Internal quarks.
+% \begin{macrocode}
+\quark_new:N \q_@@_nil
+% \end{macrocode}
+% \end{variable}
+%
+% \begin{macro}[pTF]{\@@_quark_if_nil:n}
+% Branching quark conditional.
+% \begin{macrocode}
+\__kernel_quark_new_conditional:Nn \@@_quark_if_nil:N { F }
+% \end{macrocode}
+% \end{macro}
+%
+% \subsection{Testing existence and validity}
+%
+% There are a number of checks needed for either the existence of
+% a type, template or instance. There are also some for the
+% validity of a particular call. All of these are collected up here.
+%
+% \begin{macro}{\@@_execute_if_arg_agree:nnT}
+% A test agreement between the number of arguments for the template
+% type and that specified when creating a template. This is not done as a
+% separate conditional for efficiency and better error message
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_execute_if_arg_agree:nnT #1#2#3
+ {
+ \prop_get:NnN \g_@@_type_prop {#1} \l_@@_tmp_tl
+ \int_compare:nNnTF {#2} = \l_@@_tmp_tl
+ {#3}
+ {
+ \msg_error:nneee { template } { argument-number-mismatch }
+ {#1} { \l_@@_tmp_tl } {#2}
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_execute_if_code_exist:nnT}
+% A template is only fully declared if the code has been set up,
+% which can be checked by looking for the template function itself.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_execute_if_code_exist:nnT #1#2#3
+ {
+ \cs_if_exist:cTF { \c_@@_code_root_tl #1 / #2 }
+ {#3}
+ { \msg_error:nnnn { template } { no-template-code } {#1} {#2} }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}
+% {\@@_execute_if_keytype_exist:nT, \@@_execute_if_keytype_exist:VT}
+% The test for valid keytypes looks for a function to set up the key,
+% which is part of the \enquote{code} side of the template definition.
+% This avoids having different lists for the two parts of the process.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_execute_if_keytype_exist:nT #1#2
+ {
+ \cs_if_exist:cTF { @@_store_value_ #1 :n }
+ {#2}
+ { \msg_error:nnn { template } { unknown-keytype } {#1} }
+ }
+\cs_generate_variant:Nn \@@_execute_if_keytype_exist:nT { V }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_execute_if_type_exist:nT}
+% To check that a particular type is valid.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_execute_if_type_exist:nT #1#2
+ {
+ \prop_if_in:NnTF \g_@@_type_prop {#1}
+ {#2}
+ { \msg_error:nnn { template } { unknown-type } {#1} }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_execute_if_keys_exist:nnT}
+% To check that the keys for a template have been set up before trying
+% to create any code, a simple check for the correctly-named keytype
+% property list.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_if_keys_exist:nnT #1#2#3
+ {
+ \cs_if_exist:cTF { \c_@@_keytypes_root_tl #1 / #2 }
+ {#3}
+ { \msg_error:nnnn { template } { unknown-template } {#1} {#2} }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[TF]{\@@_if_key_value:n, \@@_if_key_value:V}
+% Tests for the first token in a string being \cs{KeyValue}.
+% \begin{macrocode}
+\prg_new_conditional:Npnn \@@_if_key_value:n #1 { T , F , TF }
+ {
+ \str_if_eq:noTF { \KeyValue } { \tl_head:w #1 \q_nil \q_stop }
+ \prg_return_true:
+ \prg_return_false:
+ }
+\prg_generate_conditional_variant:Nnn \@@_if_key_value:n { V } { T , F , TF }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[TF]{\@@_if_instance_exist:nn}
+% Testing for an instance
+% \begin{macrocode}
+\prg_new_conditional:Npnn \@@_if_instance_exist:nn #1#2 { T, F, TF }
+ {
+ \cs_if_exist:cTF { \c_@@_instances_root_tl #1 / #2 }
+ \prg_return_true:
+ \prg_return_false:
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_if_use_template:nTF}
+% Tests for the first token in a string being \cs{UseTemplate}.
+% \begin{macrocode}
+\prg_new_conditional:Npnn \@@_if_use_template:n #1 { TF }
+ {
+ \str_if_eq:noTF { \UseTemplate } { \tl_head:w #1 \q_nil \q_stop }
+ \prg_return_true:
+ \prg_return_false:
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \subsection{Saving and recovering property lists}
+%
+% The various property lists for templates have to be shuffled in
+% and out of storage.
+%
+% \begin{macro}
+% {
+% \@@_store_defaults:nn ,
+% \@@_store_keytypes:nn ,
+% \@@_store_values:nn ,
+% \@@_store_vars:nn
+% }
+% The defaults and keytypes are transferred from the scratch property
+% lists to the \enquote{proper} lists for the template being created.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_store_defaults:nn #1#2
+ {
+ \debug_suspend:
+ \prop_gclear_new:c { \c_@@_defaults_root_tl #1 / #2 }
+ \prop_gset_eq:cN { \c_@@_defaults_root_tl #1 / #2 }
+ \l_@@_values_prop
+ \debug_resume:
+ }
+\cs_new_protected:Npn \@@_store_keytypes:nn #1#2
+ {
+ \debug_suspend:
+ \prop_if_exist:cTF { \c_@@_keytypes_root_tl #1 / #2 }
+ {
+ \msg_info:nnnn { template } { declare-template-interface } {#1} {#2}
+ \prop_gclear:c { \c_@@_keytypes_root_tl #1 / #2 }
+ }
+ { \prop_new:c { \c_@@_keytypes_root_tl #1 / #2 } }
+ \prop_gset_eq:cN { \c_@@_keytypes_root_tl #1 / #2 }
+ \l_@@_keytypes_prop
+ \seq_gclear_new:c { \c_@@_key_order_root_tl #1 / #2 }
+ \seq_gset_eq:cN { \c_@@_key_order_root_tl #1 / #2 }
+ \l_@@_key_order_seq
+ \debug_resume:
+ }
+\cs_new_protected:Npn \@@_store_values:nn #1#2
+ {
+ \debug_suspend:
+ \prop_clear_new:c { \c_@@_values_root_tl #1 / #2 }
+ \prop_set_eq:cN { \c_@@_values_root_tl #1 / #2 }
+ \l_@@_values_prop
+ \debug_resume:
+ }
+\cs_new_protected:Npn \@@_store_vars:nn #1#2
+ {
+ \debug_suspend:
+ \prop_gclear_new:c { \c_@@_vars_root_tl #1 / #2 }
+ \prop_gset_eq:cN { \c_@@_vars_root_tl #1 / #2 }
+ \l_@@_vars_prop
+ \debug_resume:
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}
+% {
+% \@@_recover_defaults:nn ,
+% \@@_recover_keytypes:nn ,
+% \@@_recover_values:nn ,
+% \@@_recover_vars:nn
+% }
+% Recovering the stored data for a template is rather less complex
+% than storing it. All that happens is the data is transferred from
+% the permanent to the scratch storage. However, we need to check the
+% scratch storage does exist.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_recover_defaults:nn #1#2
+ {
+ \prop_if_exist:cTF
+ { \c_@@_defaults_root_tl #1 / #2 }
+ {
+ \prop_set_eq:Nc \l_@@_values_prop
+ { \c_@@_defaults_root_tl #1 / #2 }
+ }
+ { \prop_clear:N \l_@@_values_prop }
+ }
+\cs_new_protected:Npn \@@_recover_keytypes:nn #1#2
+ {
+ \prop_if_exist:cTF
+ { \c_@@_keytypes_root_tl #1 / #2 }
+ {
+ \prop_set_eq:Nc \l_@@_keytypes_prop
+ { \c_@@_keytypes_root_tl #1 / #2 }
+ }
+ { \prop_clear:N \l_@@_keytypes_prop }
+ \seq_if_exist:cTF { \c_@@_key_order_root_tl #1 / #2 }
+ {
+ \seq_set_eq:Nc \l_@@_key_order_seq
+ { \c_@@_key_order_root_tl #1 / #2 }
+ }
+ { \seq_clear:N \l_@@_key_order_seq }
+ }
+\cs_new_protected:Npn \@@_recover_values:nn #1#2
+ {
+ \prop_if_exist:cTF
+ { \c_@@_values_root_tl #1 / #2 }
+ {
+ \prop_set_eq:Nc \l_@@_values_prop
+ { \c_@@_values_root_tl #1 / #2 }
+ }
+ { \prop_clear:N \l_@@_values_prop }
+ }
+\cs_new_protected:Npn \@@_recover_vars:nn #1#2
+ {
+ \prop_if_exist:cTF
+ { \c_@@_vars_root_tl #1 / #2 }
+ {
+ \prop_set_eq:Nc \l_@@_vars_prop
+ { \c_@@_vars_root_tl #1 / #2 }
+ }
+ { \prop_clear:N \l_@@_vars_prop }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \subsection{Creating new template types}
+%
+% \begin{macro}{\@@_define_type:nn, \@@_declare_type:nn}
+% Although the type is the \enquote{top level} of the template
+% system, it is actually very easy to implement. All that happens is that
+% the number of arguments required is recorded, indexed by the name of the
+% type.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_define_type:nn #1#2
+ {
+ \prop_if_in:NnTF \g_@@_type_prop {#1}
+ { \msg_error:nnn { template } { type-already-defined } {#1} }
+ { \@@_declare_type:nn {#1} {#2} }
+ }
+\cs_new_protected:Npn \@@_declare_type:nn #1#2
+ {
+ \int_set:Nn \l_@@_tmp_int {#2}
+ \int_compare:nTF { 0 <= \l_@@_tmp_int <= 9 }
+ {
+ \msg_info:nnnV { template } { declare-type }
+ {#1} \l_@@_tmp_int
+ \prop_gput:NnV \g_@@_type_prop {#1}
+ \l_@@_tmp_int
+ }
+ {
+ \msg_error:nnnV { template } { bad-number-of-arguments }
+ {#1} \l_@@_tmp_int
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \subsection{Design part of template declaration}
+%
+% The \enquote{design} part of a template declaration defines the general
+% behaviour of each key, and possibly a default value. However, it does
+% not include the implementation. This means that what happens here is
+% the two properties are saved to appropriate lists, which can then
+% be used later to recover the information when implementing the keys.
+%
+% \begin{macro}{\@@_declare_template_keys:nnnn}
+% The main function for the \enquote{design} part of creating a template
+% starts by checking that the type exists and that the number of
+% arguments required agree. If that is all fine, then the two storage
+% areas for defaults and keytypes are initialised. The mechanism is then
+% set up for the \pkg{l3keys} module to actually parse the keys.
+% Finally, the code hands of to the storage routine to save the parsed
+% information properly.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_declare_template_keys:nnnn #1#2#3#4
+ {
+ \@@_execute_if_type_exist:nT {#1}
+ {
+ \@@_execute_if_arg_agree:nnT {#1} {#3}
+ {
+ \prop_clear:N \l_@@_values_prop
+ \prop_clear:N \l_@@_keytypes_prop
+ \seq_clear:N \l_@@_key_order_seq
+ \keyval_parse:NNn
+ \@@_parse_keys_elt:n \@@_parse_keys_elt:nn {#4}
+ \@@_store_defaults:nn {#1} {#2}
+ \@@_store_keytypes:nn {#1} {#2}
+ }
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_parse_keys_elt:n}
+% \begin{macro}{\@@_parse_keys_elt_aux:n}
+% \begin{macro}{\@@_parse_keys_elt_aux:}
+% Processing the key part of the key--value pair is always carried out
+% using this function, even if a value was found. First, the key name
+% is separated from the keytype, and if necessary the keytype is
+% separated into two parts. This information is then used to check that
+% the keytype is valid, before storing the keytype (plus argument if
+% necessary) as a property of the key name. The key name is also stored
+% (in braces) in the token list to record the order the keys are defined
+% in.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_parse_keys_elt:n #1
+ {
+ \@@_split_keytype:n {#1}
+ \bool_if:NF \l_@@_error_bool
+ {
+ \@@_execute_if_keytype_exist:VT \l_@@_keytype_tl
+ {
+ \seq_map_function:NN \c_@@_keytypes_arg_seq
+ \@@_parse_keys_elt_aux:n
+ \bool_if:NF \l_@@_error_bool
+ {
+ \seq_if_in:NoTF \l_@@_key_order_seq
+ \l_@@_key_name_tl
+ {
+ \msg_error:nnV { template } { duplicate-key-interface }
+ \l_@@_key_name_tl
+ }
+ { \@@_parse_keys_elt_aux: }
+ }
+ }
+ }
+ }
+\cs_new_protected:Npn \@@_parse_keys_elt_aux:n #1
+ {
+ \str_if_eq:VnT \l_@@_keytype_tl {#1}
+ {
+ \tl_if_empty:NT \l_@@_keytype_arg_tl
+ {
+ \msg_error:nnn { template } { keytype-requires-argument } {#1}
+ \bool_set_true:N \l_@@_error_bool
+ \seq_map_break:
+ }
+ }
+ }
+\cs_new_protected:Npn \@@_parse_keys_elt_aux:
+ {
+ \tl_set:Ne \l_@@_tmp_tl
+ {
+ \l_@@_keytype_tl
+ \tl_if_empty:NF \l_@@_keytype_arg_tl
+ { { \l_@@_keytype_arg_tl } }
+ }
+ \prop_put:NVV \l_@@_keytypes_prop \l_@@_key_name_tl
+ \l_@@_tmp_tl
+ \seq_put_right:NV \l_@@_key_order_seq \l_@@_key_name_tl
+ \str_if_eq:VnT \l_@@_keytype_tl { choice }
+ {
+ \clist_if_in:NnT \l_@@_keytype_arg_tl { unknown }
+ { \msg_error:nn { template } { choice-unknown-reserved } }
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\@@_parse_keys_elt:nn}
+% For keys which have a default, the keytype and key name are first
+% separated out by the \cs{@@_parse_keys_elt:n}
+% routine, before storing the default value in the scratch property list.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_parse_keys_elt:nn #1#2
+ {
+ \@@_parse_keys_elt:n {#1}
+ \use:c { @@_store_value_ \l_@@_keytype_tl :n } {#2}
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_split_keytype:n}
+% \begin{macro}{\@@_split_keytype_aux:w}
+% The keytype and key name should be separated by |:|. As the
+% definition might be given inside or outside of a code block,
+% the category code of colons is standardised. After
+% that, the standard delimited argument method is used to separate the
+% two parts.
+% \begin{macrocode}
+\cs_new_protected:Npe \@@_split_keytype:n #1
+ {
+ \exp_not:N \bool_set_false:N \exp_not:N \l_@@_error_bool
+ \tl_set:Nn \exp_not:N \l_@@_tmp_tl {#1}
+ \tl_replace_all:Nnn \exp_not:N \l_@@_tmp_tl { : } { \token_to_str:N : }
+ \tl_if_in:VnTF \exp_not:N \l_@@_tmp_tl { \token_to_str:N : }
+ {
+ \exp_not:n
+ {
+ \tl_clear:N \l_@@_key_name_tl
+ \exp_after:wN \@@_split_keytype_aux:w
+ \l_@@_tmp_tl \s_@@_stop
+ }
+ }
+ {
+ \exp_not:N \bool_set_true:N \exp_not:N \l_@@_error_bool
+ \msg_error:nnn { template } { missing-keytype } {#1}
+ }
+ }
+\use:e
+ {
+ \cs_new_protected:Npn \exp_not:N \@@_split_keytype_aux:w
+ #1 \token_to_str:N : #2 \s_@@_stop
+ {
+ \tl_put_right:Ne \exp_not:N \l_@@_key_name_tl
+ {
+ \exp_not:N \tl_trim_spaces:e
+ { \exp_not:N \tl_to_str:n {#1} }
+ }
+ \tl_if_in:nnTF {#2} { \token_to_str:N : }
+ {
+ \tl_put_right:Nn \exp_not:N \l_@@_key_name_tl
+ { \token_to_str:N : }
+ \exp_not:N \@@_split_keytype_aux:w #2 \s_@@_stop
+ }
+ {
+ \exp_not:N \tl_if_empty:NTF \exp_not:N \l_@@_key_name_tl
+ {
+ \msg_error:nnn { template } { empty-key-name }
+ { \token_to_str:N : #2 }
+ }
+ { \exp_not:N \@@_split_keytype_arg:n {#2} }
+ }
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\@@_split_keytype_arg:n, \@@_split_keytype_arg:V}
+% \begin{macro}{\@@_split_keytype_arg_aux:n}
+% \begin{macro}{\@@_split_keytype_arg_aux:w}
+% The second stage of sorting out the keytype is to check for an
+% argument. As there is no convenient delimiting token to look for,
+% a check is made instead for each possible text value for the keytype.
+% To keep things faster, this only involves the keytypes that need an
+% argument. If a match is made, then a check is also needed to see that
+% it is at the start of the keytype information. All being well, the
+% split can then be applied. Any non-matching keytypes are assumed to
+% be \enquote{correct} as given, and are left alone (this is checked by
+% other code).
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_split_keytype_arg:n #1
+ {
+ \tl_set:Ne \l_@@_keytype_tl { \tl_trim_spaces:n {#1} }
+ \tl_clear:N \l_@@_keytype_arg_tl
+ \cs_set_protected:Npn \@@_split_keytype_arg_aux:n ##1
+ {
+ \tl_if_in:nnT {#1} {##1}
+ {
+ \cs_set:Npn \@@_split_keytype_arg_aux:w
+ ####1 ##1 ####2 \s_@@_stop
+ {
+ \tl_if_blank:nT {####1}
+ {
+ \tl_set:Ne \l_@@_keytype_tl
+ { \tl_trim_spaces:n {##1} }
+ \tl_if_blank:nF {####2}
+ {
+ \tl_set:Ne \l_@@_keytype_arg_tl
+ { \use:n ####2 }
+ }
+ \seq_map_break:
+ }
+ }
+ \@@_split_keytype_arg_aux:w #1 \s_@@_stop
+ }
+ }
+ \seq_map_function:NN \c_@@_keytypes_arg_seq
+ \@@_split_keytype_arg_aux:n
+ }
+\cs_generate_variant:Nn \@@_split_keytype_arg:n { V }
+\cs_new:Npn \@@_split_keytype_arg_aux:n #1 { }
+\cs_new:Npn \@@_split_keytype_arg_aux:w #1 \s_@@_stop { }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \subsubsection{Storing values}
+%
+% As \pkg{lttemplates} pre-processes key values for efficiency reasons,
+% there is a need to convert the values given as defaults into
+% \enquote{ready to use} data. The same general idea is true when an instance
+% is declared. However, assignments are not made until an instance is
+% used, and so there has to be some intermediate storage. Furthermore,
+% the ability to delay evaluation of results is needed. To achieve these
+% aims, a series of \enquote{process and store} functions are defined here.
+%
+% All of the information about the key (the key name and the keytype)
+% is already stored as variables. The same property list is always used
+% to store the data, meaning that the only argument required is the
+% value to be processed and potentially stored.
+%
+% \begin{macro}{\@@_store_value_boolean:n}
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_store_value_boolean:n #1
+ { \prop_put:Non \l_@@_values_prop \l_@@_key_name_tl {#1} }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_store_value:n, \@@_store_value_choice:n,
+% \@@_store_value_function:n, \@@_store_value_instance:n}
+% With no need to worry about delayed evaluation, these keytypes all
+% just store the input directly.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_store_value:n #1
+ { \prop_put:Non \l_@@_values_prop \l_@@_key_name_tl {#1} }
+\cs_new_eq:NN \@@_store_value_choice:n \@@_store_value:n
+\cs_new_eq:NN \@@_store_value_function:n \@@_store_value:n
+\cs_new_eq:NN \@@_store_value_instance:n \@@_store_value:n
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_store_value_aux:Nn, \@@_store_value_integer:n,
+% \@@_store_value_length:n, \@@_store_value_muskip:n,
+% \@@_store_value_real:n, \@@_store_value_skip:n,
+% \@@_store_value_tokenlist:n, \@@_store_value_commalist:n}
+% Storing values in \cs{l_@@_values_prop} is in most cases the same.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_store_value_aux:Nn #1#2
+ { \prop_put:Non \l_@@_values_prop \l_@@_key_name_tl {#2} }
+\cs_new_protected:Npn \@@_store_value_integer:n
+ { \@@_store_value_aux:Nn \int_eval:n }
+\cs_new_protected:Npn \@@_store_value_length:n
+ { \@@_store_value_aux:Nn \dim_eval:n }
+\cs_new_protected:Npn \@@_store_value_muskip:n
+ { \@@_store_value_aux:Nn \muskip_eval:n }
+\cs_new_protected:Npn \@@_store_value_real:n
+ { \@@_store_value_aux:Nn \fp_eval:n }
+\cs_new_protected:Npn \@@_store_value_skip:n
+ { \@@_store_value_aux:Nn \skip_eval:n }
+\cs_new_protected:Npn \@@_store_value_tokenlist:n
+ { \@@_store_value_aux:Nn \use:n }
+\cs_new_eq:NN \@@_store_value_commalist:n \@@_store_value_tokenlist:n
+% \end{macrocode}
+% \end{macro}
+%
+% \subsection{Implementation part of template declaration}
+%
+% \begin{macro}{\@@_declare_template_code:nnnnn}
+% \begin{macro}{\@@_declare_template_code:nnnn}
+% The main function for implementing a template starts with a couple of
+% simple checks to make sure that there are no obvious mistakes: the
+% number of arguments must agree and the template keys must have been
+% declared.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_declare_template_code:nnnnn #1#2#3#4#5
+ {
+ \@@_execute_if_type_exist:nT {#1}
+ {
+ \@@_execute_if_arg_agree:nnT {#1} {#3}
+ {
+ \@@_if_keys_exist:nnT {#1} {#2}
+ {
+ \@@_store_key_implementation:nnn {#1} {#2} {#4}
+ \regex_match:nnTF { \c { AssignTemplateKeys } } {#5}
+ { \@@_declare_template_code:nnnn {#1} {#2} {#3} {#5} }
+ {
+ \@@_declare_template_code:nnnn
+ {#1} {#2} {#3} { \AssignTemplateKeys #5 }
+ }
+ }
+ }
+ }
+ }
+\cs_new_protected:Npn \@@_declare_template_code:nnnn #1#2#3#4
+ {
+ \cs_if_exist:cT { \c_@@_code_root_tl #1 / #2 }
+ { \msg_info:nnnn { template } { declare-template-code } {#1} {#2} }
+ \cs_generate_from_arg_count:cNnn
+ { \c_@@_code_root_tl #1 / #2 }
+ \cs_gset_protected:Npn {#3} {#4}
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\@@_store_key_implementation:nnn}
+% Actually storing the implementation part of a template is quite easy
+% as it only requires the list of keys given to be turned into a
+% property list. There is also some error-checking to do, hence the need
+% to have the list of defined keytypes available. In certain cases
+% (when choices are involved) parsing the key results in changes to the
+% default values. That is why they are loaded and then saved again.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_store_key_implementation:nnn #1#2#3
+ {
+ \@@_recover_defaults:nn {#1} {#2}
+ \@@_recover_keytypes:nn {#1} {#2}
+ \prop_clear:N \l_@@_vars_prop
+ \keyval_parse:nnn
+ { \@@_parse_vars_elt:n } { \@@_parse_vars_elt:nnn { #1 / #2 } } {#3}
+ \@@_store_vars:nn {#1} {#2}
+ \prop_map_inline:Nn \l_@@_keytypes_prop
+ { \msg_error:nnnnn { template } { key-not-implemented } {##1} {#2} {#1} }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_parse_vars_elt:n}
+% At the implementation stage, every key must have a value given. So
+% this is an error function.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_parse_vars_elt:n #1
+ { \msg_error:nnn { template } { key-no-variable } {#1} }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_parse_vars_elt:nnn}
+% \begin{macro}{\@@_parse_vars_elt_aux:nn}
+% \begin{macro}{\@@_parse_vars_elt_aux:nw}
+% \begin{macro}{\@@_parse_vars_elt_aux:nnn, \@@_parse_vars_elt_aux:nne}
+% \begin{macro}{\@@_parse_vars_elt_key:nn}
+% The actual storage part here is very simple: the storage bin name
+% is placed into the property list. At the same time, a comparison is
+% made with the keytypes defined earlier: if there is a mismatch then
+% an error is raised.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_parse_vars_elt:nnn #1#2#3
+ {
+ \tl_set:Ne \l_@@_key_name_tl
+ { \tl_trim_spaces:e { \tl_to_str:n {#2} } }
+ \prop_get:NVNTF \l_@@_keytypes_prop
+ \l_@@_key_name_tl
+ \l_@@_keytype_tl
+ {
+ \@@_split_keytype_arg:V \l_@@_keytype_tl
+ \@@_parse_vars_elt_aux:nn {#1} {#3}
+ \prop_remove:NV \l_@@_keytypes_prop \l_@@_key_name_tl
+ }
+ { \msg_error:nnn { template } { unknown-key } {#2} }
+ }
+% \end{macrocode}
+% Split off any leading \texttt{global} and they look for the way to
+% implement.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_parse_vars_elt_aux:nn #1#2
+ {
+ \@@_parse_vars_elt_aux:nw {#1} #2 global global \s_@@_stop
+ }
+\cs_new_protected:Npn \@@_parse_vars_elt_aux:nw
+ #1#2 global #3 global #4 \s_@@_stop
+ {
+ \tl_if_blank:nTF {#4}
+ { \@@_parse_vars_elt_aux:nnn {#1} { } {#2} }
+ {
+ \tl_if_blank:nTF {#2}
+ {
+ \@@_parse_vars_elt_aux:nne
+ {#1} { global } { \tl_trim_spaces:n {#3} }
+ }
+ { \msg_error:nnn { template } { bad-variable } { #2 global #3 } }
+ }
+ }
+\cs_new_protected:Npn \@@_parse_vars_elt_aux:nnn #1#2#3
+ {
+ \str_case:VnF \l_@@_keytype_tl
+ {
+ { choice } { \@@_implement_choices:nn {#1} {#3} }
+ { function }
+ {
+ \cs_if_exist:NF #3
+ { \cs_new:Npn #3 { } }
+ \@@_parse_vars_elt_key:nn {#1}
+ {
+ .code:n =
+ {
+ \cs_generate_from_arg_count:NNnn
+ \exp_not:N #3
+ \exp_not:c
+ { cs_ \str_if_eq:nnT {#1} { global } { g } set:Npn }
+ { \exp_not:V \l_@@_keytype_arg_tl }
+ {##1}
+ }
+ }
+ \prop_put:NVn \l_@@_vars_prop
+ \l_@@_key_name_tl {#2#3}
+ }
+ { instance }
+ {
+ \@@_parse_vars_elt_key:nn {#1}
+ {
+ .code:n =
+ {
+ \exp_not:c
+ { cs_ \str_if_eq:nnT {#1} { global } { g } set:Npn }
+ \exp_not:N #3 { \UseInstance {##1} }
+ }
+ }
+ \prop_put:NVn \l_@@_vars_prop
+ \l_@@_key_name_tl {#2#3}
+ }
+ }
+ {
+ \tl_if_single:nTF {#3}
+ {
+ \cs_if_exist:NF #3
+ { \use:c { \@@_map_var_type: _new:N } #3 }
+ \@@_parse_vars_elt_key:nn {#1}
+ {
+ . \@@_map_var_type:
+ _ \str_if_eq:nnT {#1} { global } { g } set:N
+ = \exp_not:N #3
+ }
+ \prop_put:NVn \l_@@_vars_prop
+ \l_@@_key_name_tl {#2#3}
+ }
+ { \msg_error:nnn { template } { bad-variable } {#2#3} }
+ }
+ }
+\cs_generate_variant:Nn \@@_parse_vars_elt_aux:nnn { nne }
+\cs_new_protected:Npn \@@_parse_vars_elt_key:nn #1#2
+ {
+ \keys_define:ne { template / #1 }
+ { \l_@@_key_name_tl #2 }
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}[EXP]{\@@_map_var_type:}
+% Turn a \enquote{friendly} variable type into an \texttt{expl3} one.
+% \begin{macrocode}
+\cs_new:Npn \@@_map_var_type:
+ {
+ \str_case:Vn \l_@@_keytype_tl
+ {
+ { boolean } { bool }
+ { commalist } { clist }
+ { integer } { int }
+ { length } { dim }
+ { muskip } { muskip }
+ { real } { fp }
+ { skip } { skip }
+ { tokenlist } { tl }
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_implement_choices:nn}
+% \begin{macro}{\@@_implement_choices_default:}
+% Implementing choices requires a second key--value loop. So after a
+% little set-up, the standard parser is called.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_implement_choices:nn #1#2
+ {
+ \clist_set:NV \l_@@_tmp_clist \l_@@_keytype_arg_tl
+ \prop_put:NVn \l_@@_vars_prop \l_@@_key_name_tl { }
+ \keys_define:ne { template / #1 } { \l_@@_key_name_tl .choice: }
+ \keyval_parse:nnn
+ { \@@_implement_choice_elt:n }
+ { \@@_implement_choice_elt:nnn {#1} }
+ {#2}
+ \prop_get:NVNT \l_@@_values_prop \l_@@_key_name_tl
+ \l_@@_tmp_tl
+ { \@@_implement_choices_default: }
+ \clist_if_empty:NF \l_@@_tmp_clist
+ {
+ \clist_map_inline:Nn \l_@@_tmp_clist
+ { \msg_error:nnn { template } { choice-not-implemented } {##1} }
+ }
+ }
+% \end{macrocode}
+% A sanity check for the default value, so that an error is raised
+% now and not when converting to assignments.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_implement_choices_default:
+ {
+ \tl_set:Ne \l_@@_tmp_tl
+ { \l_@@_key_name_tl \c_space_tl \l_@@_tmp_tl }
+ \prop_if_in:NVF \l_@@_vars_prop \l_@@_tmp_tl
+ {
+ \tl_set:Ne \l_@@_tmp_tl
+ { \l_@@_key_name_tl \c_space_tl \l_@@_tmp_tl }
+ \prop_if_in:NVF \l_@@_vars_prop \l_@@_tmp_tl
+ {
+ \prop_get:NVN \l_@@_keytypes_prop \l_@@_key_name_tl
+ \l_@@_tmp_tl
+ \@@_split_keytype_arg:V \l_@@_tmp_tl
+ \prop_get:NVN \l_@@_values_prop \l_@@_key_name_tl
+ \l_@@_tmp_tl
+ \msg_error:nnVV { template } { unknown-default-choice }
+ \l_@@_key_name_tl
+ \l_@@_key_name_tl
+ }
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\@@_implement_choice_elt:nnn, \@@_implement_choice_elt_aux:nnn}
+% \begin{macro}{\@@_implement_choice_elt_aux:n}
+% \begin{macro}{\@@_implement_choice_elt:n}
+% The actual storage of the implementation of a choice is mainly about
+% error checking. The code here ensures that all choices have to have
+% been declared, apart from the special \texttt{unknown} choice, which
+% must come last. The code for each choice is stored along with the
+% key name in the variables property list.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_implement_choice_elt:nnn #1#2#3
+ {
+ \clist_if_empty:NTF \l_@@_tmp_clist
+ {
+ \str_if_eq:nnTF {#2} { unknown }
+ { \@@_implement_choice_elt_aux:nnn {#1} {#2} {#3} }
+ { \@@_implement_choice_elt_aux:n {#2} }
+ }
+ {
+ \clist_if_in:NnTF \l_@@_tmp_clist {#2}
+ {
+ \clist_remove_all:Nn \l_@@_tmp_clist {#2}
+ \@@_implement_choice_elt_aux:nnn {#1} {#2} {#3}
+ }
+ { \@@_implement_choice_elt_aux:n {#2} }
+ }
+ }
+\cs_new_protected:Npn \@@_implement_choice_elt_aux:n #1
+ {
+ \prop_get:NVN \l_@@_keytypes_prop \l_@@_key_name_tl
+ \l_@@_tmp_tl
+ \@@_split_keytype_arg:V \l_@@_tmp_tl
+ \msg_error:nnVn { template } { unknown-choice } \l_@@_key_name_tl {#1}
+ }
+\cs_new_protected:Npn \@@_implement_choice_elt_aux:nnn #1#2#3
+ {
+ \keys_define:ne { template / #1 }
+ { \l_@@_key_name_tl / #2 .code:n = { \exp_not:n {#3} } }
+ \tl_set:Ne \l_@@_tmp_tl
+ { \l_@@_key_name_tl \c_space_tl #2 }
+ \prop_put:NVn \l_@@_vars_prop \l_@@_tmp_tl {#3}
+ }
+\cs_new_protected:Npn \@@_implement_choice_elt:n #1
+ {
+ \msg_error:nnVn { template } { choice-requires-code }
+ \l_@@_key_name_tl {#1}
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \subsection{Editing template defaults}
+%
+% \begin{macro}{\@@_edit_defaults:nnn}
+% Editing the template defaults means getting the values back out
+% of the store, then parsing the list of new values before putting
+% the updated list back into storage.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_edit_defaults:nnn #1#2#3
+ {
+ \@@_if_keys_exist:nnT {#1} {#2}
+ {
+ \@@_recover_defaults:nn {#1} {#2}
+ \@@_parse_values:nnn {#1} {#2} {#3}
+ \@@_store_defaults:nn {#1} {#2}
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_parse_values:nnn}
+% The routine to parse values is the same for both editing a
+% template and setting up an instance. So the code here does only the
+% minimum necessary for reading the values.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_parse_values:nnn #1#2#3
+ {
+ \@@_recover_keytypes:nn {#1} {#2}
+ \keyval_parse:NNn
+ \@@_parse_values_elt:n \@@_parse_values_elt:nn {#3}
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_parse_values_elt:n}
+% Every key needs a value, so this is just an error routine.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_parse_values_elt:n #1
+ {
+ \bool_set_true:N \l_@@_error_bool
+ \msg_error:nnn { template } { key-no-value } {#1}
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_parse_values_elt:nn}
+% \begin{macro}{\@@_parse_values_elt_aux:n}
+% To store the value, find the keytype then call the saving function.
+% These need the current key name saved as \cs{l_@@_key_name_tl}.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_parse_values_elt:nn #1#2
+ {
+ \tl_set:Ne \l_@@_key_name_tl
+ { \tl_trim_spaces:e { \tl_to_str:n {#1} } }
+ \prop_get:NVNTF \l_@@_keytypes_prop \l_@@_key_name_tl
+ \l_@@_tmp_tl
+ { \@@_parse_values_elt_aux:n {#2} }
+ { \msg_error:nnV { template } { unknown-key } \l_@@_key_name_tl }
+ }
+\cs_new_protected:Npn \@@_parse_values_elt_aux:n #1
+ {
+ \@@_split_keytype_arg:V \l_@@_tmp_tl
+ \use:c { @@_store_value_ \l_@@_keytype_tl :n } {#1}
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\@@_template_set_eq:nnn}
+% To copy a template, each of the lists plus the code has to be copied
+% across. To keep this independent of the list storage system, it is
+% all done with two-part shuffles.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_template_set_eq:nnn #1#2#3
+ {
+ \@@_recover_defaults:nn {#1} {#3}
+ \@@_store_defaults:nn {#1} {#2}
+ \@@_recover_keytypes:nn {#1} {#3}
+ \@@_store_keytypes:nn {#1} {#2}
+ \@@_recover_vars:nn {#1} {#3}
+ \@@_store_vars:nn {#1} {#2}
+ \cs_if_exist:cT { \c_@@_code_root_tl #1 / #2 }
+ { \msg_info:nnnn { template } { declare-template-code } {#1} {#2} }
+ \cs_gset_eq:cc { \c_@@_code_root_tl #1 / #2 }
+ { \c_@@_code_root_tl #1 / #3 }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \subsection{Creating instances of templates}
+%
+% \begin{macro}
+% {
+% \@@_declare_instance:nnnn,
+% \@@_declare_instance_aux:nnnn
+% }
+% Making an instance has two distinct parts. First, the keys given are
+% parsed to transfer the values into the structured data format used
+% internally. This allows the default and given values to be combined
+% with no repetition. In the second step, the structured data is
+% converted to pre-defined variable assignments, and these are stored
+% in the function for the instance.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_declare_instance:nnnn #1#2#3#4
+ {
+ \@@_execute_if_code_exist:nnT {#1} {#2}
+ {
+ \@@_recover_defaults:nn {#1} {#2}
+ \@@_recover_vars:nn {#1} {#2}
+ \@@_declare_instance_aux:nnnn {#1} {#2} {#3} {#4}
+ }
+ }
+\cs_new_protected:Npn \@@_declare_instance_aux:nnnn #1#2#3#4
+ {
+ \bool_set_false:N \l_@@_error_bool
+ \@@_parse_values:nnn {#1} {#2} {#4}
+ \bool_if:NF \l_@@_error_bool
+ {
+ \prop_put:Nnn \l_@@_values_prop { from~template } {#2}
+ \@@_store_values:nn {#1} {#3}
+ \@@_convert_to_assignments:
+ \cs_if_exist:cT { \c_@@_instances_root_tl #1 / #3 }
+ { \msg_info:nnnn { template } { declare-instance } {#3} {#1} }
+ \cs_set_protected:cpe { \c_@@_instances_root_tl #1 / #3 }
+ {
+ \exp_not:N \@@_assignments_push:n
+ { \exp_not:V \l_@@_assignments_tl }
+ \exp_not:c { \c_@@_code_root_tl #1 / #2 }
+ }
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_instance_set_eq:nnn}
+% Copy--paste an instance.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_instance_set_eq:nnn #1#2#3
+ {
+ \@@_if_instance_exist:nnTF {#1} {#3}
+ {
+ \@@_recover_values:nn {#1} {#3}
+ \@@_store_values:nn {#1} {#2}
+ \cs_if_exist:cT { \c_@@_instances_root_tl #1 / #2 }
+ { \msg_info:nnnn { template } { declare-instance } {#2} {#1} }
+ \cs_set_eq:cc { \c_@@_instances_root_tl #1 / #2 }
+ { \c_@@_instances_root_tl #1 / #3 }
+ }
+ { \msg_error:nnnn { template } { unknown-instance } {#1} {#3} }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_edit_instance:nnn}
+% \begin{macro}
+% {\@@_edit_instance_aux:nnnnn, \@@_edit_instance_aux:nVnnn}
+% Editing an instance is almost identical to declaring one. The only
+% variation is the source of the values to use. When editing, they are
+% recovered from the previous instance run.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_edit_instance:nnn #1#2#3
+ {
+ \@@_if_instance_exist:nnTF {#1} {#2}
+ {
+ \@@_recover_values:nn {#1} {#2}
+ \prop_get:NnN \l_@@_values_prop { from~template }
+ \l_@@_tmp_tl
+ \@@_edit_instance_aux:nVnn
+ {#1} \l_@@_tmp_tl {#2} {#3}
+ }
+ { \msg_error:nnnn { template } { unknown-instance } {#1} {#2} }
+ }
+\cs_new_protected:Npn \@@_edit_instance_aux:nnnn #1#2#3#4
+ {
+ \@@_recover_vars:nn {#1} {#2}
+ \@@_declare_instance_aux:nnnn {#1} {#2} {#3} {#4}
+ }
+\cs_generate_variant:Nn \@@_edit_instance_aux:nnnn { nV }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\@@_convert_to_assignments:}
+% \begin{macro}{\@@_convert_to_assignments_aux:n}
+% \begin{macro}
+% {\@@_convert_to_assignments_aux:nn, \@@_convert_to_assignments_aux:nV}
+% The idea on converting to a set of assignments is to loop over each
+% key, so that the loop order follows the declaration order of the keys.
+% This is done using a sequence as property lists are not
+% \enquote{ordered}.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_convert_to_assignments:
+ {
+ \tl_clear:N \l_@@_assignments_tl
+ \seq_map_function:NN \l_@@_key_order_seq
+ \@@_convert_to_assignments_aux:n
+ }
+\cs_new_protected:Npn \@@_convert_to_assignments_aux:n #1
+ {
+ \prop_get:NnN \l_@@_keytypes_prop {#1} \l_@@_tmp_tl
+ \@@_convert_to_assignments_aux:nV {#1} \l_@@_tmp_tl
+ }
+% \end{macrocode}
+% The second auxiliary function actually does the work. The
+% arguments here are the key name (|#1|) and the keytype (|#2|).
+% From those, the value to assign and the name of the appropriate
+% variable are recovered. A bit of work is then needed to sort out
+% keytypes with arguments (for example instances), and to look for
+% global assignments. Once that is done, a hand-off can be made to the
+% handler for the relevant keytype.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_convert_to_assignments_aux:nn #1#2
+ {
+ \prop_get:NnNT \l_@@_values_prop {#1} \l_@@_value_tl
+ {
+ \prop_get:NnNTF \l_@@_vars_prop {#1} \l_@@_var_tl
+ {
+ \@@_split_keytype_arg:n {#2}
+ \str_if_eq:VnF \l_@@_keytype_tl { choice }
+ {
+ \str_if_eq:VnF \l_@@_keytype_tl { code }
+ { \@@_find_global: }
+ }
+ \tl_set:Nn \l_@@_key_name_tl {#1}
+ \cs_if_exist_use:cF { @@_assign_ \l_@@_keytype_tl : }
+ { \@@_assign_variable: }
+ }
+ { \msg_error:nnn { template } { unknown-attribute } {#1} }
+ }
+ }
+\cs_generate_variant:Nn \@@_convert_to_assignments_aux:nn { nV }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\@@_find_global:}
+% \begin{macro}{\@@_find_global_aux:w}
+% Global assignments should have the phrase |global| at the front.
+% This is pretty easy to find: no other error checking, though.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_find_global:
+ {
+ \bool_set_false:N \l_@@_global_bool
+ \tl_if_in:onT \l_@@_var_tl { global }
+ {
+ \exp_after:wN \@@_find_global_aux:w \l_@@_var_tl \s_@@_stop
+ }
+ }
+\cs_new_protected:Npn \@@_find_global_aux:w #1 global #2 \s_@@_stop
+ {
+ \tl_set:Nn \l_@@_var_tl {#2}
+ \bool_set_true:N \l_@@_global_bool
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \subsection{Using templates directly}
+%
+% \begin{macro}{\@@_use_template:nnn}
+% Directly use a template with a particular parameter setting.
+% This is also picked up if used in a nested fashion inside a parameter
+% list. The idea is essentially the same as creating an instance,
+% just with no saving of the result.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_use_template:nnn #1#2#3
+ {
+ \@@_execute_if_code_exist:nnT {#1} {#2}
+ {
+ \@@_recover_defaults:nn {#1} {#2}
+ \@@_recover_vars:nn {#1} {#2}
+ \@@_parse_values:nnn {#1} {#2} {#3}
+ \@@_convert_to_assignments:
+ \use:c { \c_@@_code_root_tl #1 / #2 }
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \subsection{Assigning values to variables}
+%
+% \begin{macro}{\@@_assign_boolean:}
+% \begin{macro}{\@@_assign_boolean_aux:n}
+% Setting a Boolean value is slightly different to everything else
+% as the value can be used to work out which \texttt{set} function to
+% call. As long as there is no need to recover things from another
+% variable, everything is pretty easy. If there is, then we need to allow
+% for the fact that the recovered value here will \emph{not} be expandable,
+% so needs to be converted to something that is.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_assign_boolean:
+ {
+ \bool_if:NTF \l_@@_global_bool
+ { \@@_assign_boolean_aux:n { bool_gset } }
+ { \@@_assign_boolean_aux:n { bool_set } }
+ }
+\cs_new_protected:Npn \@@_assign_boolean_aux:n #1
+ {
+ \@@_if_key_value:VTF \l_@@_value_tl
+ {
+ \@@_key_to_value:
+ \tl_put_right:Ne \l_@@_assignments_tl
+ {
+ \exp_not:c { #1 _eq:NN }
+ \exp_not:V \l_@@_var_tl
+ \exp_not:V \l_@@_value_tl
+ }
+ }
+ {
+ \tl_put_right:Ne \l_@@_assignments_tl
+ {
+ \exp_not:c { #1 _ \l_@@_value_tl :N }
+ \exp_not:V \l_@@_var_tl
+ }
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\@@_assign_choice:}
+% \begin{macro}
+% {\@@_assign_choice_aux:nF, \@@_assign_choice_aux:eF}
+% The idea here is to find either the choice as-given or else the
+% special |unknown| choice, and to copy the appropriate code across.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_assign_choice:
+ {
+ \@@_assign_choice_aux:eF
+ { \l_@@_key_name_tl \c_space_tl \l_@@_value_tl }
+ {
+ \@@_assign_choice_aux:eF
+ { \l_@@_key_name_tl \c_space_tl unknown }
+ {
+ \prop_get:NVN \l_@@_keytypes_prop \l_@@_key_name_tl
+ \l_@@_tmp_tl
+ \@@_split_keytype_arg:V \l_@@_tmp_tl
+ \msg_error:nnVV { template } { unknown-choice }
+ \l_@@_key_name_tl
+ \l_@@_value_tl
+ }
+ }
+ }
+\cs_new_protected:Npn \@@_assign_choice_aux:nF #1
+ {
+ \prop_get:NnNTF \l_@@_vars_prop {#1} \l_@@_tmp_tl
+ { \tl_put_right:NV \l_@@_assignments_tl \l_@@_tmp_tl }
+ }
+\cs_generate_variant:Nn \@@_assign_choice_aux:nF { e }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\@@_assign_function:}
+% \begin{macro}{\@@_assign_function_aux:N}
+% This looks a bit messy but is only actually one function.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_assign_function:
+ {
+ \bool_if:NTF \l_@@_global_bool
+ { \@@_assign_function_aux:N \cs_gset:Npn }
+ { \@@_assign_function_aux:N \cs_set:Npn }
+ }
+\cs_new_protected:Npn \@@_assign_function_aux:N #1
+ {
+ \tl_put_right:Ne \l_@@_assignments_tl
+ {
+ \cs_generate_from_arg_count:NNnn
+ \exp_not:V \l_@@_var_tl
+ \exp_not:N #1
+ { \exp_not:V \l_@@_keytype_arg_tl }
+ { \exp_not:V \l_@@_value_tl }
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\@@_assign_instance:}
+% \begin{macro}{\@@_assign_instance_aux:N}
+% Using an instance means adding the appropriate function creation to
+% the tl. No checks are made at this stage, so if the instance is
+% not valid then errors will arise later.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_assign_instance:
+ {
+ \bool_if:NTF \l_@@_global_bool
+ { \@@_assign_instance_aux:N \cs_gset_protected:Npn }
+ { \@@_assign_instance_aux:N \cs_set_protected:Npn }
+ }
+\cs_new_protected:Npn \@@_assign_instance_aux:N #1
+ {
+ \tl_put_right:Ne \l_@@_assignments_tl
+ {
+ \exp_not:N #1 \exp_not:V \l_@@_var_tl
+ {
+ \@@_use_instance:nn
+ { \exp_not:V \l_@@_keytype_arg_tl }
+ { \exp_not:V \l_@@_value_tl }
+ }
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\@@_assign_variable:}
+% \begin{macro}{\@@_assign_variable:N, \@@_assign_variable:c}
+% A general-purpose function for all of the other assignments.
+% As long as the value is not coming from another variable, the stored
+% value is simply transferred for output.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_assign_variable:
+ {
+ \@@_assign_variable:c
+ {
+ \@@_map_var_type: _
+ \bool_if:NT \l_@@_global_bool { g } set:Nn
+ }
+ }
+\cs_new_protected:Npn \@@_assign_variable:N #1
+ {
+ \@@_if_key_value:VT \l_@@_value_tl
+ { \@@_key_to_value: }
+ \tl_put_right:Ne \l_@@_assignments_tl
+ {
+ #1 \exp_not:V \l_@@_var_tl
+ { \exp_not:V \l_@@_value_tl }
+ }
+ }
+\cs_generate_variant:Nn \@@_assign_variable:N { c }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\@@_key_to_value:}
+% \begin{macro}{\@@_key_to_value_auxi:w}
+% \begin{macro}{\@@_key_to_value_auxii:w}
+% The idea here is to recover the attribute value of another key. To
+% do that, the marker is removed and a look up takes place. If this
+% is successful, then the name of the variable of the attribute is
+% returned. This assumes that the value will be used in context where
+% it will be converted to a value, for example when setting a number.
+% There is also a need to check in case the copied value happens to be
+% \texttt{global}.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_key_to_value:
+ { \exp_after:wN \@@_key_to_value_auxi:w \l_@@_value_tl }
+\cs_new_protected:Npn \@@_key_to_value_auxi:w \KeyValue #1
+ {
+ \tl_set:Ne \l_@@_tmp_tl { \tl_trim_spaces:e { \tl_to_str:n {#1} } }
+ \prop_get:NVNTF \l_@@_vars_prop \l_@@_tmp_tl
+ \l_@@_value_tl
+ {
+ \exp_after:wN \@@_key_to_value_auxii:w \l_@@_value_tl
+ \s_@@_mark global \q_@@_nil \s_@@_stop
+ }
+ { \msg_error:nnV { template } { unknown-attribute } \l_@@_tmp_tl }
+ }
+\cs_new_protected:Npn \@@_key_to_value_auxii:w #1 global #2#3 \s_@@_stop
+ {
+ \@@_quark_if_nil:NF #2
+ { \tl_set:Nn \l_@@_value_tl {#2} }
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \subsection{Using instances}
+%
+% \begin{macro}{\@@_use_instance:nn}
+% \begin{macro}{\@@_use_instance_aux:nNnnn}
+% \begin{macro}{\@@_use_instance_aux:nn}
+% Using an instance is just a question of finding the appropriate function.
+% If nothing is found, an error is raised. One complication is that
+% if the first token of argument |#2| is \cs{UseTemplate} then that
+% is also valid. There is an error-test to make sure that the
+% types agree, and if so the template is used directly.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_use_instance:nn #1#2
+ {
+ \@@_if_use_template:nTF {#2}
+ { \@@_use_instance_aux:nNnnn {#1} #2 }
+ { \@@_use_instance_aux:nn {#1} {#2} }
+ }
+\cs_new_protected:Npn \@@_use_instance_aux:nNnnn #1#2#3#4#5
+ {
+ \str_if_eq:nnTF {#1} {#3}
+ { \@@_use_template:nnn {#3} {#4} {#5} }
+ { \msg_error:nnnn { template } { type-mismatch } {#1} {#3} }
+}
+\cs_new_protected:Npn \@@_use_instance_aux:nn #1#2
+ {
+ \@@_if_instance_exist:nnTF {#1} {#2}
+ { \use:c { \c_@@_instances_root_tl #1 / #2 } }
+ { \msg_error:nnnn { template } { unknown-instance } {#1} {#2} }
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+%\subsection{Assignment manipulation}
+%
+% A few functions to transfer assignments about, as this is needed by
+% \cs{AssignTemplateKeys}.
+%
+% \begin{macro}{\@@_assignments_pop:}
+% To actually use the assignments.
+% \begin{macrocode}
+\cs_new:Npn \@@_assignments_pop: { \l_@@_assignments_tl }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_assignments_push:n}
+% Here, the assignments are stored for later use.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_assignments_push:n #1
+ { \tl_set:Nn \l_@@_assignments_tl {#1} }
+% \end{macrocode}
+% \end{macro}
+%
+% \subsection{Showing templates and instances}
+%
+% \begin{macro}{\@@_show_code:nn}
+% Showing the code for a template is just a translation of
+% \cs{cs_show:c}.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_show_code:nn #1#2
+ { \cs_show:c { \c_@@_code_root_tl #1 / #2 } }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}
+% {
+% \@@_show_defaults:nn,
+% \@@_show_keytypes:nn,
+% \@@_show_vars:nn
+% }
+% \begin{macro}{\@@_show:Nnnn}
+% A modified version of the property-list printing code, such that
+% the output refers to templates and instances rather than to the
+% underlying structures.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_show_defaults:nn #1#2
+ {
+ \@@_if_keys_exist:nnT {#1} {#2}
+ {
+ \@@_recover_defaults:nn {#1} {#2}
+ \@@_show:Nnnn \l_@@_values_prop
+ {#1} {#2} { default~values }
+ }
+ }
+\cs_new_protected:Npn \@@_show_keytypes:nn #1#2
+ {
+ \@@_if_keys_exist:nnT {#1} {#2}
+ {
+ \@@_recover_keytypes:nn {#1} {#2}
+ \@@_show:Nnnn \l_@@_keytypes_prop
+ {#1} {#2} { interface }
+ }
+ }
+\cs_new_protected:Npn \@@_show_vars:nn #1#2
+ {
+ \@@_execute_if_code_exist:nnT {#1} {#2}
+ {
+ \@@_recover_vars:nn {#1} {#2}
+ \@@_show:Nnnn \l_@@_vars_prop
+ {#1} {#2} { variable~mapping }
+ }
+ }
+\cs_new_protected:Npn \@@_show:Nnnn #1#2#3#4
+ {
+ \msg_show:nneeee { template } { show-attribute }
+ { \tl_to_str:n {#2} }
+ { \tl_to_str:n {#3} }
+ { \tl_to_str:n {#4} }
+ { \prop_map_function:NN #1 \msg_show_item_unbraced:nn }
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\@@_show_values:nn}
+% Instance values are a little more complex, as is the template to consider.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_show_values:nn #1#2
+ {
+ \@@_if_instance_exist:nnT {#1} {#2}
+ {
+ \@@_recover_values:nn {#1} {#2}
+ \msg_show:nneee { template } { show-values }
+ { \tl_to_str:n {#1} }
+ { \tl_to_str:n {#2} }
+ {
+ \prop_map_function:NN \l_@@_values_prop
+ \msg_show_item_unbraced:nn
+ }
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \subsection{Messages}
+%
+% The text for error messages: short and long text for all of them.
+% \begin{macrocode}
+\msg_new:nnnn { template } { argument-number-mismatch }
+ { Template~type~'#1'~takes~#2~argument(s). }
+ {
+ Templates~of~type~'#1'~require~#2~argument(s).\\
+ You~have~tried~to~make~a~template~for~'#1'~
+ with~#3~argument(s),~which~is~not~possible:~
+ the~number~of~arguments~must~agree.
+ }
+\msg_new:nnnn { template } { bad-number-of-arguments }
+ { Bad~number~of~arguments~for~template~type~'#1'. }
+ {
+ A~template~may~accept~between~0~and~9~arguments.\\
+ You~asked~to~use~#2~arguments:~this~is~not~supported.
+ }
+\msg_new:nnnn { template } { bad-variable }
+ { Incorrect~variable~description~'#1'. }
+ {
+ The~argument~'#1'~is~not~of~the~form \\
+ ~~'<variable>'\\
+ ~or~\\
+ ~~'global~<variable>'.\\
+ It~must~be~given~in~one~of~these~formats~to~be~used~in~a~template.
+ }
+\msg_new:nnnn { template } { choice-not-implemented }
+ { The~choice~'#1'~has~no~implementation. }
+ {
+ Each~choice~listed~in~the~interface~for~a~template~must~
+ have~an~implementation.
+ }
+\msg_new:nnnn { template } { choice-no-code }
+ { The~choice~'#1'~requires~implementation~details. }
+ {
+ When~creating~template~code~using~\DeclareTemplateCode,~
+ each~choice~name~must~have~an~associated~implementation.\\
+ This~should~be~given~after~a~'='~sign:~LaTeX~did~not~find~one.
+ }
+\msg_new:nnnn { template } { choice-requires-code }
+ { The~choice~'#2'~for~key~'#1'~requires~an~implementation. }
+ {
+ You~should~have~put:\\
+ \ \ #1~:~choice~{~#2 = <code> ~} \\
+ but~LaTeX~did~not~find~any~<code>.
+ }
+\msg_new:nnnn { template } { duplicate-key-interface }
+ { Key~'#1'~appears~twice~in~interface~definition~\msg_line_context:. }
+ {
+ Each~key~can~only~have~one~interface~declared~in~a~template.\\
+ LaTeX~found~two~interfaces~for~'#1'.
+ }
+\msg_new:nnnn { template } { keytype-requires-argument }
+ { The~key~type~'#1'~requires~an~argument~\msg_line_context:. }
+ {
+ You~should~have~put:\\
+ \ \ <key-name>~:~#1~{~<argument>~} \\
+ but~LaTeX~did~not~find~an~<argument>.
+ }
+\msg_new:nnnn { template } { invalid-keytype }
+ { The~key~'#1'~is~missing~a~key-type~\msg_line_context:. }
+ {
+ Each~key~in~a~template~requires~a~key-type,~given~in~the~form:\\
+ \ \ <key>~:~<key-type>\\
+ LaTeX~could~not~find~a~<key-type>~in~your~input.
+ }
+\msg_new:nnnn { template } { key-no-value }
+ { The~key~'#1'~has~no~value~\msg_line_context:. }
+ {
+ When~creating~an~instance~of~a~template~
+ every~key~listed~must~include~a~value:\\
+ \ \ <key>~=~<value>
+ }
+\msg_new:nnnn { template } { key-no-variable }
+ { The~key~'#1'~requires~implementation~details~\msg_line_context:. }
+ {
+ When~creating~template~code~using~\DeclareTemplateCode,~
+ each~key~name~must~have~an~associated~implementation.\\
+ This~should~be~given~after~a~'='~sign:~LaTeX~did~not~find~one.
+ }
+\msg_new:nnnn { template } { key-not-implemented }
+ { Key~'#1'~has~no~implementation~\msg_line_context:. }
+ {
+ The~definition~of~key~implementations~for~template~'#2'~
+ of~template~type~'#3'~does~not~include~any~details~for~key~'#1'.\\
+ The~key~was~declared~in~the~interface~definition,~
+ and~so~an~implementation~is~required.
+ }
+\msg_new:nnnn { template } { missing-keytype }
+ { The~key~'#1'~is~missing~a~key-type~\msg_line_context:. }
+ {
+ Key~interface~definitions~should~be~of~the~form\\
+ \ \ #1~:~<key-type>\\
+ but~LaTeX~could~not~find~a~<key-type>.
+ }
+\msg_new:nnnn { template } { no-template-code }
+ {
+ The~template~'#2'~of~type~'#1'~is~unknown~
+ or~has~no~implementation.
+ }
+ {
+ There~is~no~code~available~for~the~template~name~given.\\
+ This~should~be~given~using~\DeclareTemplateCode.
+ }
+\msg_new:nnnn { template } { type-already-defined }
+ { Template~type~'#1'~already~defined. }
+ {
+ You~have~used~\NewTemplateType~
+ with~a~template~type~that~has~already~been~defined.
+ }
+\msg_new:nnnn { template } { type-mismatch }
+ { Template~types~'#1'~and~'#2'~do~not~agree. }
+ {
+ You~are~trying~to~use~a~template~directly~with~\UseInstance
+ (or~a~similar~function),~but~the~template~types~do~not~match.
+ }
+\msg_new:nnnn { template } { unknown-attribute }
+ { The~template~attribute~'#1'~is~unknown. }
+ {
+ There~is~a~definition~in~the~current~template~reading\\
+ \ \ \token_to_str:N \KeyValue {~#1~} \\
+ but~there~is~no~key~called~'#1'.
+ }
+\msg_new:nnnn { template } { unknown-choice }
+ { The~choice~'#2'~was~not~declared~for~key~'#1'. }
+ {
+ The~key~'#1'~takes~a~fixed~list~of~choices~
+ and~this~list~does~not~include~'#2'.
+ }
+\msg_new:nnnn { template } { unknown-default-choice }
+ { The~default~choice~'#2'~was~not~declared~for~key~'#1'. }
+ {
+ The~key~'#1'~takes~a~fixed~list~of~choices~
+ and~this~list~does~not~include~'#2'.
+ }
+\msg_new:nnnn { template } { unknown-instance }
+ { The~instance~'#2'~of~type~'#1'~is~unknown. }
+ {
+ You~have~asked~to~use~an~instance~'#2',~
+ but~this~has~not~been~created.
+ }
+\msg_new:nnnn { template } { unknown-key }
+ { Unknown~template~key~'#1'. }
+ {
+ The~key~'#1'~was~not~declared~in~the~interface~
+ for~the~current~template.
+ }
+\msg_new:nnnn { template } { unknown-keytype }
+ { The~key-type~'#1'~is~unknown. }
+ {
+ Valid~key-types~are:\\
+ -~boolean;\\
+ -~choice;\\
+ -~commalist;\\
+ -~function;\\
+ -~instance;\\
+ -~integer;\\
+ -~length;\\
+ -~muskip;\\
+ -~real;\\
+ -~skip;\\
+ -~tokenlist.
+ }
+\msg_new:nnnn { template } { unknown-type }
+ { The~template~type~'#1'~is~unknown. }
+ {
+ A~template~type~needs~to~be~defined~with~\NewTemplateType
+ prior~to~using~it.
+ }
+\msg_new:nnnn { template } { unknown-template }
+ { The~template~'#2'~of~type~'#1'~is~unknown. }
+ {
+ No~interface~has~been~declared~for~a~template~
+ '#2'~of~template~type~'#1'.
+ }
+% \end{macrocode}
+%
+% Information messages only have text: more text should not be needed.
+% \begin{macrocode}
+\msg_new:nnn { template } { declare-instance }
+ { Declaring~instance~~'#1'~of~type~#2~\msg_line_context:. }
+\msg_new:nnn { template } { declare-template-code }
+ { Declaring~code~for~template~'#2'~of~template~type~'#1'~\msg_line_context:. }
+\msg_new:nnn { template } { declare-template-interface }
+ {
+ Declaring~interface~for~template~'#2'~of~template~type~'#1'~
+ \msg_line_context:.
+ }
+\msg_new:nnn { template } { declare-type }
+ { Declaring~template~type~'#1'~taking~#2~argument(s)~\msg_line_context:. }
+\msg_new:nnn { template } { show-attribute }
+ {
+ The~template~'#2'~of~type~'#1'~has~
+ \tl_if_empty:nTF {#4} { no~#3. } { #3 : #4 }
+ }
+\msg_new:nnn { template } { show-values }
+ {
+ The~instance~'#2'~of~type~'#1'~has~
+ \tl_if_empty:nTF {#3} { no~values. } { values: #3 }
+ }
+% \end{macrocode}
+%
+% Also add \pkg{template} to the \pkg{LaTeX} messages.
+% \begin{macrocode}
+\prop_gput:Nnn \g_msg_module_type_prop { template } { LaTeX }
+% \end{macrocode}
+%
+% \subsection{User functions}
+%
+% \begin{macro}{\NewTemplateType}
+% \begin{macro}{\DeclareTemplateInterface}
+% \begin{macro}{\DeclareTemplateCode}
+% \begin{macro}{\DeclareTemplateCopy}
+% \begin{macro}{\EditTemplateDefaults}
+% \begin{macro}{\UseTemplate}
+% \begin{macro}{\DeclareInstance}
+% \begin{macro}{\DeclareInstanceCopy}
+% \begin{macro}{\EditInstance}
+% \begin{macro}{\UseInstance}
+% All simple translations.
+% \begin{macrocode}
+\cs_new_protected:Npn \NewTemplateType #1#2
+ { \@@_define_type:nn {#1} {#2} }
+\cs_new_protected:Npn \DeclareTemplateInterface #1#2#3#4
+ { \@@_declare_template_keys:nnnn {#1} {#2} {#3} {#4} }
+\cs_new_protected:Npn \DeclareTemplateCode #1#2#3#4#5
+ { \@@_declare_template_code:nnnnn {#1} {#2} {#3} {#4} {#5} }
+\cs_new_protected:Npn \DeclareTemplateCopy #1#2#3
+ { \@@_template_set_eq:nnn {#1} {#2} {#3} }
+\cs_new_protected:Npn \EditTemplateDefaults #1#2#3
+ { \@@_edit_defaults:nnn {#1} {#2} {#3} }
+\cs_new_protected:Npn \UseTemplate #1#2#3
+ { \@@_use_template:nnn {#1} {#2} {#3} }
+\cs_new_protected:Npn \DeclareInstance #1#2#3#4
+ { \@@_declare_instance:nnnn {#1} {#3} {#2} {#4} }
+\cs_new_protected:Npn \DeclareInstanceCopy #1#2#3
+ { \@@_instance_set_eq:nnn {#1} {#2} {#3} }
+\cs_new_protected:Npn \EditInstance #1#2#3
+ { \@@_edit_instance:nnn {#1} {#2} {#3} }
+\cs_new_protected:Npn \UseInstance #1#2
+ { \@@_use_instance:nn {#1} {#2} }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\ShowTemplateCode}
+% \begin{macro}{\ShowTemplateDefaults}
+% \begin{macro}{\ShowTemplateInterface}
+% \begin{macro}{\ShowTemplateVariables}
+% \begin{macro}{\ShowInstanceValues}
+% The show functions are again just translation.
+% \begin{macrocode}
+\cs_new_protected:Npn \ShowTemplateCode #1#2
+ { \@@_show_code:nn {#1} {#2} }
+\cs_new_protected:Npn \ShowTemplateDefaults #1#2
+ { \@@_show_defaults:nn {#1} {#2} }
+\cs_new_protected:Npn \ShowTemplateInterface #1#2
+ { \@@_show_keytypes:nn {#1} {#2} }
+\cs_new_protected:Npn \ShowTemplateVariables #1#2
+ { \@@_show_vars:nn {#1} {#2} }
+\cs_new_protected:Npn \ShowInstanceValues #1#2
+ { \@@_show_values:nn {#1} {#2} }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\IfInstanceExistsT, \IfInstanceExistsF, \IfInstanceExistsTF}
+% \changes{2024-02-15}{v1.0b}{New macros}
+% \changes{2024-04-17}{v1.0c}{Use plural names}
+% More direct translation.
+% \begin{macrocode}
+\cs_new:Npn \IfInstanceExistsTF #1#2
+ { \@@_if_instance_exist:nnTF {#1} {#2} }
+\cs_new:Npn \IfInstanceExistsT #1#2
+ { \@@_if_instance_exist:nnT {#1} {#2} }
+\cs_new:Npn \IfInstanceExistsF #1#2
+ { \@@_if_instance_exist:nnF {#1} {#2} }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\KeyValue}
+% Simply dump the argument when executed: this should not happen.
+% \begin{macrocode}
+\cs_new_protected:Npn \KeyValue #1 {#1}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\AssignTemplateKeys}
+% A short call to use a token register by proxy.
+% \begin{macrocode}
+\cs_new_protected:Npn \AssignTemplateKeys { \@@_assignments_pop: }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\SetTemplateKeys}
+% A friendly wrapper
+% \begin{macrocode}
+\cs_new_protected:Npn \SetTemplateKeys #1#2#3
+ { \keys_set_known:nnN { template / #1 / #2 } {#3} \l_@@_tmp_clist }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macrocode}
+%<latexrelease>\IncludeInRelease{0000/00/00}{lttemplates}%
+%<latexrelease> {Prototype~document~commands}%
+%<latexrelease>
+%<latexrelease>\EndModuleRelease
+% \end{macrocode}
+%
+% \begin{macrocode}
+\ExplSyntaxOff
+% \end{macrocode}
+%
+% \begin{macrocode}
+%</2ekernel|latexrelease>
+% \end{macrocode}
+%
+% We need to stop DocStrip treating |@@| in a special way at this point.
+% \begin{macrocode}
+%<@@=>
+% \end{macrocode}
+%
+% \Finale \ No newline at end of file
diff --git a/macros/latex/base/lttextcomp.dtx b/macros/latex/base/lttextcomp.dtx
index 5de3797f79..7f247747d6 100644
--- a/macros/latex/base/lttextcomp.dtx
+++ b/macros/latex/base/lttextcomp.dtx
@@ -37,7 +37,7 @@
%
%
\ProvidesFile{lttextcomp.dtx}
- [2022/08/07 v1.0g LaTeX Kernel (text companion symbols)]
+ [2024/04/24 v1.1c LaTeX Kernel (text companion symbols)]
% \iffalse
\documentclass{ltxdoc}
\begin{document}
@@ -163,11 +163,12 @@
%
% \begin{macro}{\DeclareEncodingSubset}
%
-% The declaration takes 3 mandatory arguments: an \emph{encoding}
+% The declaration takes 3 mandatory arguments: an \emph{encoding}
% for which a subsetting is wanted (currently always \texttt{TS1},
% and most likely forever), the \emph{font family} for which we
-% declare the subset and finally the \emph{subset} number (between \texttt{0} (all
-% of the encoding is supported) and \texttt{9} many glyphs are missing.
+% declare the subset and finally the \emph{subset} number, with a value between
+% \texttt{0} (all of the encoding is supported) and \texttt{9} (many
+% glyphs are missing).
%
% For \texttt{TS1} the numbers have been chosen in a way that most
% fonts can be fairly correctly categorized, but the default
@@ -439,7 +440,7 @@
% \end{macrocode}
%
% And here are the other \texttt{TS1} glyphs that are implemented
-% by every font (or nearly every---a few are commented out and
+% by every font (or nearly every)---a few are commented out and
% moved to sub-encoding 9,
% because they aren't around in some fonts.
% \begin{macrocode}
@@ -950,6 +951,8 @@
% This first block contains the fonts that have been already
% supported by the \texttt{textcomp} package way back, i.e., the
% font families that have \TeX{} support since the mid-nineties.
+% \changes{v1.1a}{2024/01/27}{Adjusted/corrected TS1 sub-encoding
+% declarations for various families (gh/1257)}
% \begin{macrocode}
\DeclareEncodingSubset{TS1}{ccr} {0}
\DeclareEncodingSubset{TS1}{cmbr} {0}
@@ -981,16 +984,28 @@
\DeclareEncodingSubset{TS1}{lmss} {1}
\DeclareEncodingSubset{TS1}{lmssq} {1}
\DeclareEncodingSubset{TS1}{lmvtt} {1}
-\DeclareEncodingSubset{TS1}{lmtt} {1} % missing TM, SM and
- % pertenthousand for some reason
+% \end{macrocode}
+% The lmtt family is missing TM, SM, and perthousand for some
+% reason, so the first safe sub-encoding would be 2, but that is
+% then missing out a huge number of glyphs that are available, so
+% we claim it is sub-encoding 1 even if this can lead to missing glyphs.
+% \begin{macrocode}
+\DeclareEncodingSubset{TS1}{lmtt} {1} % missing TM, SM and pertenthousand
% \end{macrocode}
%
+% The next three families have been removed from TeX Live, but we
+% keep the definitions
% \begin{macrocode}
\DeclareEncodingSubset{TS1}{ptmx} {2}
\DeclareEncodingSubset{TS1}{ptmj} {2}
\DeclareEncodingSubset{TS1}{ul8} {2}
% \end{macrocode}
%
+% The next set are the early PostScript font implementations, these
+% days there are better alternatives, but \ldots. Note that, their
+% virtual fonts contain a lot of ``tofu'' in form of black squares,
+% thus they don't even give a missing character warning if you
+% select such a glyph. This is why they are set as sub-encoding 5.
% \begin{macrocode}
\DeclareEncodingSubset{TS1}{bch} {5} % tofu for blank, ohm
\DeclareEncodingSubset{TS1}{futj}{5} % tofu for blank, interrobang/down, ohm
@@ -1009,12 +1024,11 @@
\DeclareEncodingSubset{TS1}{ul9} {5} % tofu for blank, interrobang/down, ohm
% \end{macrocode}
%
+% The next set suffers from the same problem and they contain even
+% fewer real glyphs.
% \begin{macrocode}
\DeclareEncodingSubset{TS1}{dayroms}{6} % tofu for blank, interrobang/down, ohm
\DeclareEncodingSubset{TS1}{dayrom} {6} % tofu for blank, interrobang/down, ohm
-% \end{macrocode}
-%
-% \begin{macrocode}
\DeclareEncodingSubset{TS1}{augie}{8} % really only missing euro
\DeclareEncodingSubset{TS1}{put} {8}
\DeclareEncodingSubset{TS1}{uag} {8} % probably (currently broken distrib)
@@ -1024,6 +1038,7 @@
% \begin{macrocode}
\DeclareEncodingSubset{TS1}{zi4} {9}
% \end{macrocode}
+%
% LucidaBright (sold through TUG) probably not quite correct, I
% guess as I have the older fonts \ldots
% \begin{macrocode}
@@ -1041,44 +1056,72 @@
% Below are the newer fonts that have support files for
% \LaTeX{}. With very few exceptions the classifications are done
% so that all characters are correctly produced (either being
-% available in the font or substituted.
+% available in the font or substituted).
%
% There are a few fonts that contain ``tofu'' squares in places
% (instead of a real glyph) and in a few cases some really seldom
% needed chars are unavailable, i.e., produce missing glyphs (to
% avoid that a large number of available chars are unnecessarily
-% substituted.
+% substituted).
%
+% Encoding declarations for these font families shouldn't really be
+% in the kernel, but part of the \texttt{.fd} files for the
+% family. When we introduced the concept in 2021 we had some hope
+% that this would happen over time and that we could take the
+% declarations out---after all it is nearly impossible to maintain
+% it correctly in the kernel, given that fonts may get new glyphs
+% added (happened for several of them in the recent year) which is
+% something we wouldn't notice. However, so far this hasn't
+% happened, so in 2024, I went through the current set and adjusted
+% the declarations in several places.
+%
+% Next four are wrong and still need adjustment:
% \begin{macrocode}
\DeclareEncodingSubset{TS1}{lato-*} {0} % with a bunch of tofu inside
\DeclareEncodingSubset{TS1}{opensans-*} {0} % with a bunch of tofu inside
\DeclareEncodingSubset{TS1}{cantarell-*} {0} % with a bunch of tofu inside
-\DeclareEncodingSubset{TS1}{fbb-*} {0} % missing centoldstyle
+\DeclareEncodingSubset{TS1}{tli} {1} % with lots of tofu inside
% \end{macrocode}
%
% \begin{macrocode}
-\DeclareEncodingSubset{TS1}{tli} {1} % with lots of tofu inside
+\DeclareEncodingSubset{TS1}{fbb-*} {2} % missing centoldstyle
% \end{macrocode}
%
+%
% \begin{macrocode}
\DeclareEncodingSubset{TS1}{Alegreya-*} {2}
\DeclareEncodingSubset{TS1}{AlegreyaSans-*} {2}
+\DeclareEncodingSubset{TS1}{BaskervilleF-*} {2}
\DeclareEncodingSubset{TS1}{DejaVuSans-TLF} {2}
\DeclareEncodingSubset{TS1}{DejaVuSansCondensed-TLF} {2}
+% \end{macrocode}
+% Next one is missing \cs{textfractionsolidus} but is otherwise
+% completely sub-encoding 2 so we use that sub-encoding.
+% \begin{macrocode}
\DeclareEncodingSubset{TS1}{DejaVuSansMono-TLF} {2}
+% \end{macrocode}
+%
+% \begin{macrocode}
\DeclareEncodingSubset{TS1}{EBGaramond-*} {2}
+\DeclareEncodingSubset{TS1}{Merriwthr-OsF} {2}
+\DeclareEncodingSubset{TS1}{MerriwthrSans-OsF} {2}
+\DeclareEncodingSubset{TS1}{Montserrat-*} {2}
+\DeclareEncodingSubset{TS1}{MontserratAlternates-*} {2}
+\DeclareEncodingSubset{TS1}{NotoSansMono-TLF} {2}
+\DeclareEncodingSubset{TS1}{NotoSansMono-TOsF} {2}
\DeclareEncodingSubset{TS1}{Tempora-TLF} {2}
\DeclareEncodingSubset{TS1}{Tempora-TOsF} {2}
+\DeclareEncodingSubset{TS1}{XCharter-TLF} {2}
+\DeclareEncodingSubset{TS1}{XCharter-TOsF} {2}
+\DeclareEncodingSubset{TS1}{erewhon-*} {2}
% \end{macrocode}
%
% \begin{macrocode}
\DeclareEncodingSubset{TS1}{Arimo-TLF} {3}
-\DeclareEncodingSubset{TS1}{Carlito-*} {3}
-\DeclareEncodingSubset{TS1}{FiraSans-*} {3}
+\DeclareEncodingSubset{TS1}{Crlt-*} {3}
+\DeclareEncodingSubset{TS1}{IBMPlexMono-TLF} {3}
\DeclareEncodingSubset{TS1}{IBMPlexSans-TLF} {3}
-\DeclareEncodingSubset{TS1}{Merriweather-OsF} {3}
-\DeclareEncodingSubset{TS1}{Montserrat-*} {3}
-\DeclareEncodingSubset{TS1}{MontserratAlternates-*} {3}
+\DeclareEncodingSubset{TS1}{IBMPlexSerif-TLF} {3}
\DeclareEncodingSubset{TS1}{SourceCodePro-TLF} {3}
\DeclareEncodingSubset{TS1}{SourceCodePro-TOsF} {3}
\DeclareEncodingSubset{TS1}{SourceSansPro-*} {3}
@@ -1096,6 +1139,7 @@
\DeclareEncodingSubset{TS1}{CrimsonPro-*} {4}
\DeclareEncodingSubset{TS1}{FiraMono-TLF} {4}
\DeclareEncodingSubset{TS1}{FiraMono-TOsF} {4}
+\DeclareEncodingSubset{TS1}{FiraSans-*} {4}
\DeclareEncodingSubset{TS1}{Go-TLF} {4}
\DeclareEncodingSubset{TS1}{GoMono-TLF} {4}
\DeclareEncodingSubset{TS1}{InriaSans-*} {4}
@@ -1108,7 +1152,6 @@
\DeclareEncodingSubset{TS1}{LinguisticsPro-OsF} {4}
\DeclareEncodingSubset{TS1}{LinuxBiolinumT-*} {4}
\DeclareEncodingSubset{TS1}{LinuxLibertineT-*} {4}
-\DeclareEncodingSubset{TS1}{MerriweatherSans-OsF} {4}
\DeclareEncodingSubset{TS1}{MintSpirit-*} {4}
\DeclareEncodingSubset{TS1}{MintSpiritNoTwo-*} {4}
\DeclareEncodingSubset{TS1}{PTMono-TLF} {4}
@@ -1128,66 +1171,64 @@
% \end{macrocode}
%
% \begin{macrocode}
-\DeclareEncodingSubset{TS1}{Almendra-OsF} {5}
+\DeclareEncodingSubset{TS1}{Almndr-OsF} {5}
\DeclareEncodingSubset{TS1}{Baskervaldx-*} {5}
-\DeclareEncodingSubset{TS1}{BaskervilleF-*} {5}
-\DeclareEncodingSubset{TS1}{Bitter-TLF} {5}
+\DeclareEncodingSubset{TS1}{Bttr-TLF} {5}
\DeclareEncodingSubset{TS1}{Cinzel-LF} {5}
\DeclareEncodingSubset{TS1}{CinzelDecorative-LF} {5}
+\DeclareEncodingSubset{TS1}{Cochineal-*} {5}
\DeclareEncodingSubset{TS1}{DejaVuSerif-TLF} {5}
\DeclareEncodingSubset{TS1}{DejaVuSerifCondensed-TLF} {5}
\DeclareEncodingSubset{TS1}{GilliusADF-LF} {5}
\DeclareEncodingSubset{TS1}{GilliusADFCond-LF} {5}
\DeclareEncodingSubset{TS1}{GilliusADFNoTwo-LF} {5}
\DeclareEncodingSubset{TS1}{GilliusADFNoTwoCond-LF} {5}
-\DeclareEncodingSubset{TS1}{LobsterTwo-LF} {5}
\DeclareEncodingSubset{TS1}{OldStandard-TLF} {5}
-\DeclareEncodingSubset{TS1}{PlayfairDisplay-TLF} {5}
-\DeclareEncodingSubset{TS1}{PlayfairDisplay-TOsF} {5}
+\DeclareEncodingSubset{TS1}{PlyfrDisplay-TLF} {5}
+\DeclareEncodingSubset{TS1}{PlyfrDisplay-TOsF} {5}
\DeclareEncodingSubset{TS1}{TheanoDidot-TLF} {5}
\DeclareEncodingSubset{TS1}{TheanoDidot-TOsF} {5}
\DeclareEncodingSubset{TS1}{TheanoModern-TLF} {5}
\DeclareEncodingSubset{TS1}{TheanoModern-TOsF} {5}
\DeclareEncodingSubset{TS1}{TheanoOldStyle-TLF} {5}
\DeclareEncodingSubset{TS1}{TheanoOldStyle-TOsF} {5}
+\DeclareEncodingSubset{TS1}{charssil-TLF} {5}
% \end{macrocode}
%
% \begin{macrocode}
\DeclareEncodingSubset{TS1}{Crimson-TLF} {6}
-\DeclareEncodingSubset{TS1}{IBMPlexMono-TLF} {6}
-\DeclareEncodingSubset{TS1}{IBMPlexSerif-TLF} {6}
-\DeclareEncodingSubset{TS1}{LibertinusMono-TLF} {6}
\DeclareEncodingSubset{TS1}{LibertinusSerifDisplay-LF}{6}
\DeclareEncodingSubset{TS1}{LinuxLibertineDisplayT-*} {6}
\DeclareEncodingSubset{TS1}{LinuxLibertineMonoT-LF} {6}
\DeclareEncodingSubset{TS1}{LinuxLibertineMonoT-TLF} {6}
-\DeclareEncodingSubset{TS1}{Overlock-LF} {6}
+\DeclareEncodingSubset{TS1}{Ovrlck-LF} {6}
% \end{macrocode}
%
% \begin{macrocode}
+\DeclareEncodingSubset{TS1}{ComicNeue-TLF} {7}
+\DeclareEncodingSubset{TS1}{ComicNeueAngular-TLF} {7}
\DeclareEncodingSubset{TS1}{CormorantGaramond-*} {7}
\DeclareEncodingSubset{TS1}{Heuristica-TLF} {7}
\DeclareEncodingSubset{TS1}{Heuristica-TOsF} {7}
\DeclareEncodingSubset{TS1}{IMFELLEnglish-TLF} {7}
-\DeclareEncodingSubset{TS1}{LibreBaskerville-TLF} {7}
-\DeclareEncodingSubset{TS1}{LibreCaslon-*} {7}
-\DeclareEncodingSubset{TS1}{Marcellus-LF} {7}
+\DeclareEncodingSubset{TS1}{LibreBskrvl-TLF} {7}
+\DeclareEncodingSubset{TS1}{LibreCsln-*} {7}
+\DeclareEncodingSubset{TS1}{Lbstr-LF} {7}
+\DeclareEncodingSubset{TS1}{Mrcls-LF} {7}
+% \end{macrocode}
+% Strangely enough NotoSerif and NotoSans are sub-encoding 7 as
+% they are missing \cs{textminus} and several other glyphs. In
+% contrast the NotoSansMono is far more complete.
+% \begin{macrocode}
\DeclareEncodingSubset{TS1}{NotoSans-*} {7}
-\DeclareEncodingSubset{TS1}{NotoSansMono-TLF} {7}
-\DeclareEncodingSubset{TS1}{NotoSansMono-TOsF} {7}
\DeclareEncodingSubset{TS1}{NotoSerif-*} {7}
-\DeclareEncodingSubset{TS1}{Quattrocento-TLF} {7}
-\DeclareEncodingSubset{TS1}{QuattrocentoSans-TLF} {7}
-\DeclareEncodingSubset{TS1}{XCharter-TLF} {7}
-\DeclareEncodingSubset{TS1}{XCharter-TOsF} {7}
-\DeclareEncodingSubset{TS1}{erewhon-*} {7}
-\DeclareEncodingSubset{TS1}{ComicNeue-TLF} {7}
-\DeclareEncodingSubset{TS1}{ComicNeueAngular-TLF} {7}
-\DeclareEncodingSubset{TS1}{Forum-LF} {7} % the superiors are missing
+\DeclareEncodingSubset{TS1}{Quattro-LF} {7}
+\DeclareEncodingSubset{TS1}{QuattroSans-LF} {7}
+\DeclareEncodingSubset{TS1}{Frm-LF} {7} % the superiors are missing
% \end{macrocode}
%
% \begin{macrocode}
-\DeclareEncodingSubset{TS1}{Cochineal-*} {8}
+\DeclareEncodingSubset{TS1}{LibertinusMono-TLF} {8}
% \end{macrocode}
%
% \begin{macrocode}
@@ -1231,7 +1272,7 @@
%
% Here are new names for the legacy symbols that \LaTeX{} used to
% pick up from the \texttt{OMS} encoded fonts (and used for itemize
-% lists or footnote symbols.
+% lists or footnote symbols).
%
% We go the roundabout way via separate OMS declarations so that
%\begin{verbatim}
@@ -1481,20 +1522,22 @@
%
%
%
-%
% \section{The \texttt{textcomp} package}
%
%
+% For any rollback request before 2018-08-11 we make an attempt by
+% loading the 2018 version.
+% \changes{v2.1b}{2024/04/24}
+% {Load the 2018 version when rolling back prior to 2018-08-11
+% (gh/1333)}
% \begin{macrocode}
%<*TS1sty>
-\providecommand\DeclareRelease[3]{}
-\providecommand\DeclareCurrentRelease[2]{}
-
+\DeclareRelease{}{1997-12-01}{textcomp-2018-08-11.sty}
\DeclareRelease{}{2018-08-11}{textcomp-2018-08-11.sty}
\DeclareCurrentRelease{}{2020-02-02}
\ProvidesPackage{textcomp}
- [2020/02/02 v2.0n Standard LaTeX package]
+ [2024/04/24 v2.1b Standard LaTeX package]
% \end{macrocode}
%
% A precaution in case this is used without rebuilding the format.
@@ -1550,8 +1593,8 @@
}
% \end{macrocode}
%
+% \changes{v2.1a}{2024/04/22}{Drop default option \texttt{info} (gh/1333)}
% \begin{macrocode}
-\ExecuteOptions{info}
\ProcessOptions\relax
% \end{macrocode}
%
@@ -1706,7 +1749,7 @@
% The default is ``almostfull'' which means that old documents will
% work except that |\textcircled| and |\t| will use the kernel
% defaults (with the advantage that this also works if the current
-% font (as often the case) doesn't implement these glyphs.
+% font, as often the case, doesn't implement these glyphs).
%
% The ``force'' option simply sets the switch to true.
% \begin{macrocode}
@@ -2301,8 +2344,547 @@
% \begin{macrocode}
%</TS1oldsty>
% \end{macrocode}
+%
+%
+%
+%
+% \section{The \texttt{checkencodingsubset.tex} file}
+%
+% This is a simple file that asks for a name of a font family and
+% then displays information about the TS1 encoding for this family
+% and recommends the right encoding subset (to be used with
+% \cs{DeclareEncodingsubset}) for this family.
+% \changes{v1.1a}{2024/01/27}{Added check file for encoding subset}
+% \begin{macrocode}
+%<*TS1check>
+\Providesfile{checkencodingsubset.tex}
+ [2024/01/27 v0.5a Figure out safe TS1 encoding subsets]
+% \end{macrocode}
+%
+% \begin{macrocode}
+\let\typeoutdetails\typeout
+%\def\typeoutdetails#1{} % alternative definition used below
+% \end{macrocode}
+%
+% For the purpose of this check a glyph exists if the font slot is
+% occupied---too bad if that contains the wrong glyph or some tofu.
+% If it ``exists'' we return 0 otherwise 1. This way we can call
+% this macro several times in a row and obtain a number that is 0
+% if all glyphs are existing or greater than 0 if any of them is
+% missing.
+%
+% The second argument (holding the command name for a symbol) is
+% not used during these tests.
+% \begin{macrocode}
+\def\doesglyphexist#1#2{\iffontchar\testFont #1 0\else 1\relax \fi}
+% \end{macrocode}
+%
+% This macro also tests and outputs some information about the
+% symbol if it is missing. This time we make use of the second
+% argument.
+% \begin{macrocode}
+\def\glyphmissingdetails#1#2{\iffontchar\testFont #1 \else
+ \typeoutdetails{\space\space\space ==> \string#2 (#1) is missing}\fi}
+% \end{macrocode}
+%
+% \begin{macrocode}
+\newif\ifsafesubencodingfound
+\newif\ifcoremisses
+% \end{macrocode}
+%
+% Testing a group of symbols that belong to one sub-encoding. More
+% precisely, the symbols that become unavailable if you change from
+% sub-encoding $x$ (\texttt{\#2}) to $x+1$ (\texttt{\#3}). As far
+% as the code is concerned, the
+% symbols that are supposed to be always available (the core)
+% become available if we test the group \texttt{-1} and \texttt{0}.
+%
+% The first argument contains the testing code and is supposed to
+% return a single number greater or equal to zero.
+% \begin{macrocode}
+\def\testgroup#1#2#3{%
+ \ifnum 0 = #1%
+ \ifnum #2<0
+ \typeoutdetails{All glyphs in core exist}%
+ \else
+ \typeoutdetails{All glyphs between sub-encoding #2 and #3 exist}%
+ \fi
+ \else
+ \ifnum #2<0
+ \typeoutdetails{**********************************}%
+ \typeoutdetails{Some glyphs are missing from core:}%
+ \coremissestrue
+ \ifsafesubencodingfound \else
+ \def\subencodingresult{#2}%
+ \fi
+ \else
+ \typeoutdetails{Some glyphs are missing from sub-encoding #2:}%
+ \ifsafesubencodingfound \else
+ \def\subencodingresult{#3}%
+ \fi
+ \fi
+% \end{macrocode}
+% If some glyphs are missing, we rerun the test code but this time
+% using \cs{glyphmissingdetails}.
+% \begin{macrocode}
+ {\let\doesglyphexist \glyphmissingdetails #1}%
+% \end{macrocode}
+% And because we had misses we have definitely found the subset.
+% \begin{macrocode}
+ \safesubencodingfoundtrue
+ \fi
+}
+% \end{macrocode}
+%
+% The currently defined subset for the family is either stored in
+% \cs{TS1:\meta{family}} if it was declared, or it is the default
+% subset which is stored in \cs{TS1:?}.
+% \begin{macrocode}
+\def\currsubencoding#1{\csname TS1:\ifcsname TS1:#1\endcsname #1\else ?\fi\endcsname}
+% \end{macrocode}
+%
+% If a font family is not found when declaring it with
+% \cs{DeclareFixedFont} we end up with the following font. This can
+% then be used as a simple test if we failed loading the TS1 font.
+% \begin{macrocode}
+\DeclareFixedFont\cmrFont{TS1}{cmr}{m}{n}{10pt}
+% \end{macrocode}
+%
+% Check for all glyphs in all encoding subsets \ldots
+% \begin{macrocode}
+\def\testallgroups#1{%
+ \DeclareFixedFont\testFont{TS1}{#1}{m}{n}{10pt}%
+ \ifx\testFont\cmrFont
+ \typeout{***** Font family #1 not found ****}%
+ \else
+% \end{macrocode}
+% We haven't checked anything yet.
+% \begin{macrocode}
+ \safesubencodingfoundfalse
+ \coremissesfalse
+ \typeoutdetails{^^J-----------------------------------------}%
+ \typeoutdetails{Testing font family #1^^J(currently TS1-sub-encoding
+ \currsubencoding{#1})}%
+ \typeout{-----------------------------------------}%
+% \end{macrocode}
+% Then we start testing the groups beginning with the glyphs
+% between sub-encoding 8 and 9. If any of them is missing (checked
+% with \cs{doesglyphexist}) then we already know that 9 is the
+% correct answer.
+% \begin{macrocode}
+ \testgroup{%
+ \doesglyphexist{21}{\texttwelveudash}%
+ \doesglyphexist{22}{\textthreequartersemdash}%
+ \doesglyphexist{134}{\textbardbl}%
+ \doesglyphexist{137}{\textcelsius}%
+ \doesglyphexist{178}{\texttwosuperior}%
+ \doesglyphexist{179}{\textthreesuperior}%
+ \doesglyphexist{185}{\textonesuperior}%
+ }{8}{9}%
+% \end{macrocode}
+% Nevertheless we go on with further groups so that the output
+% lists all missing glyphs.
+% \begin{macrocode}
+ \testgroup{%
+ \doesglyphexist{32}{\textblank}%
+ \doesglyphexist{148}{\textinterrobang}%
+ \doesglyphexist{149}{\textinterrobangdown}%
+ \doesglyphexist{191}{\texteuro}%
+ }{7}{8}%
+ \testgroup{%
+ \doesglyphexist{47}{\textfractionsolidus}%
+ \doesglyphexist{61}{\textminus}%
+ \doesglyphexist{87}{\textohm}%
+ \doesglyphexist{181}{\textmu}%
+ }{6}{7}%
+ \testgroup{%
+ \doesglyphexist{140}{\textflorin}%
+ \doesglyphexist{164}{\textcurrency}%
+ }{5}{6}%
+ \testgroup{%
+ \doesglyphexist{155}{\textnumero}%
+ \doesglyphexist{157}{\textestimated}%
+ }{4}{5}%
+ \testgroup{%
+ \doesglyphexist{24}{\textleftarrow}%
+ \doesglyphexist{25}{\textrightarrow}%
+ \doesglyphexist{94}{\textuparrow}%
+ \doesglyphexist{95}{\textdownarrow}%
+ \doesglyphexist{141}{\textcolonmonetary}%
+ \doesglyphexist{142}{\textwon}%
+ \doesglyphexist{146}{\textlira}%
+ \doesglyphexist{150}{\textdong}%
+ }{3}{4}%
+ \testgroup{%
+ \doesglyphexist{60}{\textlangle}%
+ \doesglyphexist{62}{\textrangle}%
+ }{2}{3}%
+ \testgroup{%
+ \doesglyphexist{0}{\capitalgrave}%
+ \doesglyphexist{1}{\capitalacute}%
+ \doesglyphexist{2}{\capitalcircumflex}%
+ \doesglyphexist{3}{\capitaltilde}%
+ \doesglyphexist{4}{\capitaldieresis}%
+ \doesglyphexist{5}{\capitalhungarumlaut}%
+ \doesglyphexist{6}{\capitalring}%
+ \doesglyphexist{7}{\capitalcaron}%
+ \doesglyphexist{8}{\capitalbreve}%
+ \doesglyphexist{9}{\capitalmacron}%
+ \doesglyphexist{10}{\capitaldotaccent}%
+ \doesglyphexist{11}{\capitalcedilla}%
+ \doesglyphexist{12}{\capitalogonek}%
+ \doesglyphexist{26}{\t}%
+ \doesglyphexist{27}{\capitaltie}%
+ \doesglyphexist{28}{\newtie}%
+ \doesglyphexist{29}{\capitalnewtie}%
+ \doesglyphexist{45}{\textdblhyphen}%
+ \doesglyphexist{48}{\textzerooldstyle}%
+ \doesglyphexist{49}{\textoneoldstyle}%
+ \doesglyphexist{50}{\texttwooldstyle}%
+ \doesglyphexist{51}{\textthreeoldstyle}%
+ \doesglyphexist{52}{\textfouroldstyle}%
+ \doesglyphexist{53}{\textfiveoldstyle}%
+ \doesglyphexist{54}{\textsixoldstyle}%
+ \doesglyphexist{55}{\textsevenoldstyle}%
+ \doesglyphexist{56}{\texteightoldstyle}%
+ \doesglyphexist{57}{\textnineoldstyle}%
+ \doesglyphexist{77}{\textmho}%
+ \doesglyphexist{79}{\textbigcircle}%
+ \doesglyphexist{91}{\textlbrackdbl}%
+ \doesglyphexist{93}{\textrbrackdbl}%
+ \doesglyphexist{96}{\textasciigrave}%
+ \doesglyphexist{98}{\textborn}%
+ \doesglyphexist{99}{\textdivorced}%
+ \doesglyphexist{100}{\textdied}%
+ \doesglyphexist{108}{\textleaf}%
+ \doesglyphexist{109}{\textmarried}%
+ \doesglyphexist{110}{\textmusicalnote}%
+ \doesglyphexist{126}{\texttildelow}%
+ \doesglyphexist{127}{\textdblhyphenchar}%
+ \doesglyphexist{128}{\textasciibreve}%
+ \doesglyphexist{129}{\textasciicaron}%
+ \doesglyphexist{175}{\textasciimacron}%
+ \doesglyphexist{130}{\textacutedbl}%
+ \doesglyphexist{131}{\textgravedbl}%
+ \doesglyphexist{138}{\textdollaroldstyle}%
+ \doesglyphexist{139}{\textcentoldstyle}%
+ \doesglyphexist{143}{\textnaira}%
+ \doesglyphexist{144}{\textguarani}%
+ \doesglyphexist{145}{\textpeso}%
+ \doesglyphexist{147}{\textrecipe}%
+ \doesglyphexist{152}{\textpertenthousand}%
+ \doesglyphexist{153}{\textpilcrow}%
+ \doesglyphexist{154}{\textbaht}%
+ \doesglyphexist{156}{\textdiscount}%
+ \doesglyphexist{158}{\textopenbullet}%
+ \doesglyphexist{159}{\textservicemark}%
+ \doesglyphexist{160}{\textlquill}%
+ \doesglyphexist{161}{\textrquill}%
+ \doesglyphexist{168}{\textasciidieresis}%
+ \doesglyphexist{171}{\textcopyleft}%
+ \doesglyphexist{173}{\textcircledP}%
+ \doesglyphexist{180}{\textasciiacute}%
+ \doesglyphexist{184}{\textreferencemark}%
+ \doesglyphexist{187}{\textsurd}%
+ }{1}{2}%
+% \end{macrocode}
+% All fonts (up to now) that belong to sub-encoding 1 do have the
+% \cs{textcircled} glyph, but it is too small to be usable. So this
+% test for this group currently doesn't do much good---but who
+% knows maybe one day a font shows up in which this glyph is
+% actually missing.
+% \begin{macrocode}
+ \testgroup{%
+ \doesglyphexist{79}{\textcircled}% this is not a proper test because the symbol is
+ % usually available but not usable
+ }{0}{1}%
+ \testgroup{%
+ \doesglyphexist{13}{\textquotestraightbase}%
+ \doesglyphexist{18}{\textquotestraightdblbase}%
+ \doesglyphexist{23}{\textcapitalcompwordmark}%
+ \doesglyphexist{31}{\textascendercompwordmark}%
+ \doesglyphexist{36}{\textdollar}%
+ \doesglyphexist{39}{\textquotesingle}%
+ \doesglyphexist{42}{\textasteriskcentered}%
+ \doesglyphexist{132}{\textdagger}%
+ \doesglyphexist{133}{\textdaggerdbl}%
+ \doesglyphexist{135}{\textperthousand}%
+ \doesglyphexist{136}{\textbullet}%
+ \doesglyphexist{151}{\texttrademark}%
+ \doesglyphexist{162}{\textcent}%
+ \doesglyphexist{163}{\textsterling}%
+ \doesglyphexist{165}{\textyen}%
+ \doesglyphexist{166}{\textbrokenbar}%
+ \doesglyphexist{167}{\textsection}%
+ \doesglyphexist{169}{\textcopyright}%
+ \doesglyphexist{170}{\textordfeminine}%
+ \doesglyphexist{172}{\textlnot}%
+ \doesglyphexist{174}{\textregistered}%
+ \doesglyphexist{176}{\textdegree}%
+ \doesglyphexist{177}{\textpm}%
+ \doesglyphexist{182}{\textparagraph}%
+ \doesglyphexist{183}{\textperiodcentered}%
+ \doesglyphexist{186}{\textordmasculine}%
+ \doesglyphexist{188}{\textonequarter}%
+ \doesglyphexist{189}{\textonehalf}%
+ \doesglyphexist{190}{\textthreequarters}%
+ \doesglyphexist{214}{\texttimes}%
+ \doesglyphexist{246}{\textdiv}%
+ }{-1}{0}%
+% \end{macrocode}
+% If all groups have all glyphs then we have the full encoding
+% (subset 0).
+% \begin{macrocode}
+ \ifsafesubencodingfound\else
+ \def\subencodingresult{0}%
+ \fi
+% \end{macrocode}
+% If the font is missing some of the core glyphs we make a remark
+% about this, because they will never display.
+% \begin{macrocode}
+ \typeoutdetails{-----------------------------------------}%
+ \typeout{TS1 encoding subset for #1\ifcoremisses \space(ignoring core misses)\fi
+ \space (\ifnum\subencodingresult =
+ \currsubencoding{#1} ok\else bad\fi)}%
+ \typeout{Use sub-encoding \subencodingresult
+ \ifnum\subencodingresult = \currsubencoding{#1}\else
+ \space (not \currsubencoding{#1})\fi}
+ \typeout{-----------------------------------------^^J}%
+ \fi
+}
+% \end{macrocode}
+%
+% This tests all declarations (or most of them) that have been
+% added to the kernel. It is called if no family is given interactively.
+% \begin{macrocode}
+\long\def\testallkerneldefinedfamilies{%
+\testallgroups{ccr}% {0}
+\testallgroups{cmbr}% {0}
+%%\testallgroups{cmr}% {0} % don't test this one as it is the fallback
+ % thus reports that the family is not found
+\testallgroups{cmss}% {0}
+\testallgroups{cmtl}% {0}
+\testallgroups{cmtt}% {0}
+\testallgroups{cmvtt}% {0}
+\testallgroups{pxr}% {0}
+\testallgroups{pxss}% {0}
+\testallgroups{pxtt}% {0}
+\testallgroups{qag}% {0}
+\testallgroups{qbk}% {0}
+\testallgroups{qcr}% {0}
+\testallgroups{qcs}% {0}
+\testallgroups{qhvc}% {0}
+\testallgroups{qhv}% {0}
+\testallgroups{qpl}% {0}
+\testallgroups{qtm}% {0}
+\testallgroups{qzc}% {0}
+\testallgroups{txr}% {0}
+\testallgroups{txss}% {0}
+\testallgroups{txtt}% {0}
+%
+% Next would claim to be 0 (or 2)
+%
+%\testallgroups{lmr}% {1}
+%\testallgroups{lmdh}% {1}
+%\testallgroups{lmss}% {1}
+%\testallgroups{lmssq}% {1}
+%\testallgroups{lmvtt}% {1}
+%\testallgroups{lmtt}% {1} % missing TM, SM and pertenthousand so really 2
+%
+% these are no longer in TeX Live
+%
+%\testallgroups{ptmx}% {2} % gone for a long time it seems
+%\testallgroups{ptmj}% {2} % ditto
+%\testallgroups{ul8}% {2} % ditto
+%
+% next block has tofu chars so results are wrong
+%
+%\testallgroups{bch}% {5} % tofu for blank, ohm
+%\testallgroups{futj}%{5} % tofu for blank, interrobang/down, ohm
+%\testallgroups{futs}%{5} % tofu for blank, ohm
+%\testallgroups{futx}%{5} % probably (currently broken distrib)
+%\testallgroups{pag}% {5} % tofu for blank, interrobang/down, ohm
+%\testallgroups{pbk}% {5} % tofu for blank, interrobang/down, ohm
+%\testallgroups{pcr}% {5} % tofu for blank, interrobang/down, ohm
+%\testallgroups{phv}% {5} % tofu for blank, interrobang/down, ohm
+%\testallgroups{pnc}% {5} % tofu for blank, interrobang/down, ohm
+%\testallgroups{pplj}%{5} % tofu for blank
+%\testallgroups{pplx}%{5} % tofu for blank
+%\testallgroups{ppl}% {5} % tofu for blank interrobang/down
+%\testallgroups{ptm}% {5} % tofu for blank, interrobang/down, ohm
+%\testallgroups{pzc}% {5} % tofu for blank, interrobang/down, ohm
+%\testallgroups{ul9}% {5} % tofu for blank, interrobang/down, ohm
+%\testallgroups{dayroms}%{6} % tofu for blank, interrobang/down, ohm
+%\testallgroups{dayrom}% {6} % tofu for blank, interrobang/down, ohm
+%\testallgroups{augie}%{8} % really only missing euro and full of tofu
+%\testallgroups{put}% {8}
+%\testallgroups{uag}% {8} % probably (currently broken distrib)
+%\testallgroups{ugq}% {8}
+%
+\testallgroups{zi4}% {9}
+%
+%% not installed normally
+%
+%\testallgroups{hls}% {5}
+%\testallgroups{hlst}% {5}
+%\testallgroups{hlct}% {5}
+%\testallgroups{hlh}% {5}
+%\testallgroups{hlx}% {8}
+%\testallgroups{hlce}% {8}
+%\testallgroups{hlcn}% {8}
+%\testallgroups{hlcw}% {8}
+%\testallgroups{hlcf}% {8}
-
+\testallgroups{lato-LF}% {0} % with a bunch of tofu inside --- should probably be changed
+\testallgroups{opensans-TLF}%{0} % with a bunch of tofu inside --- should probably be changed
+\testallgroups{cantarell-TLF}% {0} % with a bunch of tofu inside --- should probably be changed
+\testallgroups{fbb-LF}% {0} % missing centoldstyle ---> 2
+\testallgroups{tli}% {1} % with lots of tofu inside --- should probably be changed
+\testallgroups{Alegreya-OsF}% {2}
+\testallgroups{AlegreyaSans-OsF}% {2}
+\testallgroups{DejaVuSans-TLF}% {2}
+\testallgroups{DejaVuSansCondensed-TLF}% {2}
+\testallgroups{DejaVuSansMono-TLF}% {2} this is missing \textfractionsolidus which makes it 7 really
+\testallgroups{EBGaramond-LF}% {2}
+\testallgroups{Tempora-TLF}% {2}
+\testallgroups{Tempora-TOsF}% {2}
+\testallgroups{Arimo-TLF}% {3}
+\testallgroups{Crlt-TLF}% {3} changed from Carlito-
+\testallgroups{FiraSans-LF}% {3} should be 4
+\testallgroups{IBMPlexSans-TLF}% {3}
+\testallgroups{Merriwthr-OsF}% {3} changed from Merriweather- and should be 2
+\testallgroups{Montserrat-LF}% {3} now 2
+\testallgroups{MontserratAlternates-LF}%{3} now 2
+\testallgroups{SourceCodePro-TLF}% {3}
+\testallgroups{SourceCodePro-TOsF}% {3}
+\testallgroups{SourceSansPro-OsF}% {3}
+\testallgroups{SourceSerifPro-LF}% {3}
+\testallgroups{Tinos-TLF}% {3}
+\testallgroups{AccanthisADFStdNoThree-LF}%{4}
+\testallgroups{Cabin-TLF}% {4}
+\testallgroups{Caladea-TLF}% {4}
+\testallgroups{Chivo-LF}% {4}
+\testallgroups{ClearSans-TLF}% {4}
+\testallgroups{Coelacanth-LF}% {4}
+\testallgroups{CrimsonPro-LF}% {4}
+\testallgroups{FiraMono-TLF}% {4}
+\testallgroups{FiraMono-TOsF}% {4}
+\testallgroups{Go-TLF}% {4}
+\testallgroups{GoMono-TLF}% {4}
+\testallgroups{InriaSans-LF}% {4}
+\testallgroups{InriaSerif-LF}% {4}
+\testallgroups{LibertinusSans-LF}% {4}
+\testallgroups{LibertinusSerif-LF}% {4}
+\testallgroups{LibreBodoni-TLF}% {4}
+\testallgroups{LibreFranklin-TLF}% {4}
+\testallgroups{LinguisticsPro-LF}% {4}
+\testallgroups{LinguisticsPro-OsF}% {4}
+\testallgroups{LinuxBiolinumT-LF}% {4}
+\testallgroups{LinuxLibertineT-LF}% {4}
+\testallgroups{MerriwthrSans-OsF}% {4} name change and now 2
+\testallgroups{MintSpirit-LF}% {4}
+\testallgroups{MintSpiritNoTwo-LF}% {4}
+\testallgroups{PTMono-TLF}% {4}
+\testallgroups{PTSans-TLF}% {4}
+\testallgroups{PTSansCaption-TLF}% {4}
+\testallgroups{PTSansNarrow-TLF}% {4}
+\testallgroups{PTSerif-TLF}% {4}
+\testallgroups{PTSerifCaption-TLF}% {4}
+\testallgroups{Raleway-TLF}% {4}
+\testallgroups{Raleway-TOsF}% {4}
+\testallgroups{Roboto-LF}% {4}
+\testallgroups{RobotoMono-TLF}% {4}
+\testallgroups{RobotoSlab-TLF}% {4}
+\testallgroups{Rosario-LF}% {4}
+\testallgroups{SticksTooText-LF}% {4}
+\testallgroups{UniversalisADFStd-LF}%{4}
+\testallgroups{Almndr-OsF}% {5} name change
+\testallgroups{Baskervaldx-LF}% {5}
+\testallgroups{BaskervilleF-LF}% {5} now 2
+\testallgroups{Bttr-TLF}% {5} name changed from Bitter-...
+\testallgroups{Cinzel-LF}% {5}
+\testallgroups{CinzelDecorative-LF}%{5}
+\testallgroups{DejaVuSerif-TLF}% {5}
+\testallgroups{DejaVuSerifCondensed-TLF}% {5}
+\testallgroups{GilliusADF-LF}% {5}
+\testallgroups{charssil-TLF} %% missing should be 5
+\testallgroups{GilliusADFCond-LF}%{5}
+\testallgroups{GilliusADFNoTwo-LF}%{5}
+\testallgroups{GilliusADFNoTwoCond-LF}%{5}
+\testallgroups{Lbstr-LF}% {5} name change and should be 7
+\testallgroups{OldStandard-TLF}% {5}
+\testallgroups{PlyfrDisplay-LF}%{5} name change
+\testallgroups{PlyfrDisplay-OsF}% {5} name change
+\testallgroups{TheanoDidot-TLF}% {5}
+\testallgroups{TheanoDidot-TOsF}% {5}
+\testallgroups{TheanoModern-TLF}% {5}
+\testallgroups{TheanoModern-TOsF}%{5}
+\testallgroups{TheanoOldStyle-TLF}%{5}
+\testallgroups{TheanoOldStyle-TOsF}%{5}
+\testallgroups{Crimson-TLF}% {6}
+\testallgroups{IBMPlexMono-TLF}% {6} now 3
+\testallgroups{IBMPlexSerif-TLF}% {6} now 3
+\testallgroups{LibertinusMono-TLF}%{6} should be 8
+\testallgroups{LibertinusSerifDisplay-LF}%{6}
+\testallgroups{LinuxLibertineDisplayT-LF}%{6}
+\testallgroups{LinuxLibertineMonoT-LF}%{6}
+\testallgroups{LinuxLibertineMonoT-TLF}%{6}
+\testallgroups{Ovrlck-LF}% {6} name changed
+\testallgroups{CormorantGaramond-LF}%{7}
+\testallgroups{Heuristica-TLF}% {7}
+\testallgroups{Heuristica-TOsF}% {7}
+\testallgroups{IMFELLEnglish-TLF}%{7}
+\testallgroups{LibreBskvl-LF}% {7} %% wrong name LibreBaskerville-TLF
+\testallgroups{LibreCsln-LF}% {7} changed from LibreCaslon-
+\testallgroups{Mrcls-LF}% {7} %% wrong name Marcellus-LF
+\testallgroups{NotoSans-LF}% {7}
+\testallgroups{NotoSansMono-TLF}%{7} now 2
+\testallgroups{NotoSansMono-TOsF}%{7} now 2
+\testallgroups{NotoSerif-LF}% {7}
+\testallgroups{Quattro-LF}% {7} changed from Quattrocento-
+\testallgroups{QuattroSans-LF}% {7} changed from QuattrocentoSans-
+\testallgroups{XCharter-TLF}% {7} now 2
+\testallgroups{XCharter-TOsF}% {7} now 2
+\testallgroups{erewhon-LF}% {7} now 2
+\testallgroups{ComicNeue-TLF}% {7}
+\testallgroups{ComicNeueAngular-TLF}%{7}
+\testallgroups{Frm-LF}%{7} % the superiors are missing; name changed from Forum-LF
+\testallgroups{Cochineal-TLF}% {8} now 5
+\testallgroups{AlgolRevived-TLF}%{9}
+}
+% \end{macrocode}
+%
+% There interaction with the user.
+% \begin{macrocode}
+\typeout{^^J=====================================================================}
+\typeout{| Enter font family to check (or <enter> for kernel defined families)}
+\typeout{=====================================================================}
+\typein[\FontFamilyToCheck]{}
+% \end{macrocode}
+%
+% \begin{macrocode}
+\if!\FontFamilyToCheck!
+ \typeout{=====================================================================}
+ \typeout{| Detailed output? (default no)}
+ \typeout{=====================================================================}
+ \typein[\Details]{}
+ \if!\Details!
+ \def\typeoutdetails#1{}
+ \else
+ \let\typeoutdetails\typeout
+ \fi
+ \testallkerneldefinedfamilies
+\else
+ \let\typeoutdetails\typeout
+ \testallgroups\FontFamilyToCheck
+\fi
+% \end{macrocode}
+%
+% \begin{macrocode}
+\stop
+%</TS1check>
+% \end{macrocode}
+%
% \Finale
%
diff --git a/macros/latex/base/ltthm.dtx b/macros/latex/base/ltthm.dtx
index 180b8accfe..c900f519dd 100644
--- a/macros/latex/base/ltthm.dtx
+++ b/macros/latex/base/ltthm.dtx
@@ -32,7 +32,7 @@
%<*driver>
% \fi
\ProvidesFile{ltthm.dtx}
- [2014/09/29 v1.0f LaTeX Kernel (Theorems)]
+ [2024/03/18 v1.0g LaTeX Kernel (Theorems)]
% \iffalse
\documentclass{ltxdoc}
\GetFileInfo{ltthm.dtx}
@@ -237,16 +237,31 @@
% \end{macro}
%
% \begin{macro}{\@thm}
+% \changes{v1.0c}{1994/04/17}{Use new std counter error message (FMi)}
+% \changes{v1.0g}{2024/03/18}{Use \cs{@kernel@refstepcounter} to avoid an unwanted target (UFi)}
% \begin{macrocode}
+%</2ekernel>
+%<*2ekernel|latexrelease>
+%<latexrelease>\IncludeInRelease{2024/03/18}%
+%<latexrelease> {\@thm}{no link target}%
\def\@thm#1#2{%
- \refstepcounter{#1}%
+ \@kernel@refstepcounter{#1}%
\@ifnextchar[{\@ythm{#1}{#2}}{\@xthm{#1}{#2}}}
+%<latexrelease>\EndIncludeInRelease
+%<latexrelease>\IncludeInRelease{0000/00/00}%
+%<latexrelease> {\@thm}{no link target}%
+%<latexrelease>\def\@thm#1#2{%
+%<latexrelease> \refstepcounter{#1}%
+%<latexrelease> \@ifnextchar[{\@ythm{#1}{#2}}{\@xthm{#1}{#2}}}
+%<latexrelease>\EndIncludeInRelease
+%</2ekernel|latexrelease>
% \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@xthm}
% \begin{macro}{\@ythm}
% \begin{macrocode}
+%<*2ekernel>
\def\@xthm#1#2{%
\@begintheorem{#2}{\csname the#1\endcsname}\ignorespaces}
\def\@ythm#1#2[#3]{%
@@ -273,11 +288,26 @@
% NFSS}
% Providing theorem defaults.
% \task{???}{add `reset@font?}
+% % \changes{v1.0g}{2024/03/18}{Insert link target in the label (UFi)}
% \begin{macrocode}
+%</2ekernel>
+%<*2ekernel|latexrelease>
+%<latexrelease>\IncludeInRelease{2024/03/18}%
+%<latexrelease> {\@begintheorem}{add link targets}%
\def\@begintheorem#1#2{\trivlist
- \item[\hskip \labelsep{\bfseries #1\ #2}]\itshape}
+ \item[\MakeLinkTarget{\@currentcounter}\hskip \labelsep{\bfseries #1\ #2}]\itshape}
\def\@opargbegintheorem#1#2#3{\trivlist
- \item[\hskip \labelsep{\bfseries #1\ #2\ (#3)}]\itshape}
+ \item[\MakeLinkTarget{\@currentcounter}\hskip \labelsep{\bfseries #1\ #2\ (#3)}]\itshape}
+%<latexrelease>\EndIncludeInRelease
+%<latexrelease>\IncludeInRelease{0000/00/00}%
+%<latexrelease> {\@begintheorem}{add link targets}%
+%<latexrelease>\def\@begintheorem#1#2{\trivlist
+%<latexrelease> \item[\hskip \labelsep{\bfseries #1\ #2}]\itshape}
+%<latexrelease>\def\@opargbegintheorem#1#2#3{\trivlist
+%<latexrelease> \item[\hskip \labelsep{\bfseries #1\ #2\ (#3)}]\itshape}
+%<latexrelease>\EndIncludeInRelease
+%</2ekernel|latexrelease>
+%<*2ekernel>
\def\@endtheorem{\endtrivlist}
%</2ekernel>
% \end{macrocode}
diff --git a/macros/latex/base/ltvers.dtx b/macros/latex/base/ltvers.dtx
index bf5dce4ca1..5031ef8307 100644
--- a/macros/latex/base/ltvers.dtx
+++ b/macros/latex/base/ltvers.dtx
@@ -112,10 +112,10 @@
%</2ekernel>
%<latexrelease>\edef\latexreleaseversion
%<*2ekernel|latexrelease>
- {2023-11-01}
+ {2024-06-01}
%</2ekernel|latexrelease>
%<*2ekernel>
-\def\patch@level{1}
+\def\patch@level{0}
% \end{macrocode}
%
% \begin{macro}{\development@branch@name}
diff --git a/macros/latex/base/ltx3info.pdf b/macros/latex/base/ltx3info.pdf
index 9de607772d..deb3923433 100644
--- a/macros/latex/base/ltx3info.pdf
+++ b/macros/latex/base/ltx3info.pdf
Binary files differ
diff --git a/macros/latex/base/ltxdoc.dtx b/macros/latex/base/ltxdoc.dtx
index 584f4f51f6..5e8b494692 100644
--- a/macros/latex/base/ltxdoc.dtx
+++ b/macros/latex/base/ltxdoc.dtx
@@ -30,7 +30,7 @@
%
%<class>\NeedsTeXFormat{LaTeX2e}
%<class>\ProvidesClass{ltxdoc}
-%<class> [2023/03/28 v2.1j Standard LaTeX documentation class]
+%<class> [2024/02/08 v2.1j Standard LaTeX documentation class]
%
%<*driver>
\documentclass{ltxdoc}
@@ -288,12 +288,13 @@
% \section{Useful abbreviations}
%
% |\cmd{\foo}| Prints |\foo| verbatim. It may be used inside moving
-% arguments. It can \emph{not} be use to record commands that are defined as
+% arguments. It can \emph{not} be used to record commands that are defined as
% ``|\outer|'' nor is it possible to use it on conditionals such as
% |\iftrue| or defined by |\newif|.
-% |\cs{foo}| already available with the \texttt{doc} package also prints |\foo|, for those who prefer that
+% |\cs{foo}| Already available with the \texttt{doc} package and also prints |\foo|,
+% for those who prefer that
% syntax. (This second form can be used to record all types of command so the
-% above restrictions do not apply.
+% above restrictions do not apply.)
% \begin{macro}{\cmd}
% \changes{v2.0k}{1994/05/21}{New definition, so \cmd\{ works.}
% \begin{macro}{\cs}
diff --git a/macros/latex/base/ltxdoc.pdf b/macros/latex/base/ltxdoc.pdf
index 96b3705014..881bbdecec 100644
--- a/macros/latex/base/ltxdoc.pdf
+++ b/macros/latex/base/ltxdoc.pdf
Binary files differ
diff --git a/macros/latex/base/makeindx.pdf b/macros/latex/base/makeindx.pdf
index 3ff3c51adf..5914039c46 100644
--- a/macros/latex/base/makeindx.pdf
+++ b/macros/latex/base/makeindx.pdf
Binary files differ
diff --git a/macros/latex/base/modguide.pdf b/macros/latex/base/modguide.pdf
index fc7923303e..9a1122a4c9 100644
--- a/macros/latex/base/modguide.pdf
+++ b/macros/latex/base/modguide.pdf
Binary files differ
diff --git a/macros/latex/base/nfssfont.dtx b/macros/latex/base/nfssfont.dtx
index ae91abf671..0464053c10 100644
--- a/macros/latex/base/nfssfont.dtx
+++ b/macros/latex/base/nfssfont.dtx
@@ -26,8 +26,8 @@
% extension .ins) which are part of the distribution.
%
% \fi
-\def\nfssfontfileversion{v2.2e}
-\def\nfssfontfiledate{2020/11/26}
+\def\nfssfontfileversion{v2.2f}
+\def\nfssfontfiledate{2023/11/07}
%
% \iffalse
@@ -197,7 +197,7 @@
{\PackageWarningNoLine{nfssfont}%
{Encoding file `\next' not found.%
\MessageBreak
- You might have misspelt the name of the encoding
+ You might have misspelled the name of the encoding
\MessageBreak
or perhaps this encoding is not a text encoding,
\MessageBreak
diff --git a/macros/latex/base/nfssfont.pdf b/macros/latex/base/nfssfont.pdf
index cb60d13464..d7f0c1666d 100644
--- a/macros/latex/base/nfssfont.pdf
+++ b/macros/latex/base/nfssfont.pdf
Binary files differ
diff --git a/macros/latex/base/proc.pdf b/macros/latex/base/proc.pdf
index f271e71d3f..fc8f36ae6b 100644
--- a/macros/latex/base/proc.pdf
+++ b/macros/latex/base/proc.pdf
Binary files differ
diff --git a/macros/latex/base/slides.pdf b/macros/latex/base/slides.pdf
index 844914de88..8529f987c6 100644
--- a/macros/latex/base/slides.pdf
+++ b/macros/latex/base/slides.pdf
Binary files differ
diff --git a/macros/latex/base/slifonts.fdd b/macros/latex/base/slifonts.fdd
index 8ddd639d50..b35cd07a8b 100644
--- a/macros/latex/base/slifonts.fdd
+++ b/macros/latex/base/slifonts.fdd
@@ -45,7 +45,7 @@
%<*driver, >
\ProvidesFile{sfonts.drv}
%</driver, >
- [2019/07/09 v2.2f Standard LaTeX slide font definitions]
+ [2023/12/02 v2.2f Standard LaTeX slide font definitions]
%
%<*driver>
\documentclass{ltxdoc}
@@ -95,7 +95,7 @@
% \section{Introduction}
%
% This file contains the external font information for special
-% variants of the the Computer Modern fonts to be used for overhead
+% variants of the Computer Modern fonts to be used for overhead
% slides. They allow to produce slides in a similar fashion as it was
% originally done by \SliTeX{}.
%
@@ -103,7 +103,7 @@
% format. Instead the standard format may be used and internally only
% different font definition files come into play.
%
-% Note, that that you therefore can easily produce slides in different
+% Note that you therefore can easily produce slides in different
% fonts just by calling an appropriate package (like |times|) in
% your |\usepackage| command. This works, for example, with all
% fonts that are defined to be scalable (eg PostScript fonts) since
diff --git a/macros/latex/base/slifonts.pdf b/macros/latex/base/slifonts.pdf
index cce5a2fbd7..7d4e65b5ce 100644
--- a/macros/latex/base/slifonts.pdf
+++ b/macros/latex/base/slifonts.pdf
Binary files differ
diff --git a/macros/latex/base/source2e.pdf b/macros/latex/base/source2e.pdf
index 2f086fe61b..5d03e22da2 100644
--- a/macros/latex/base/source2e.pdf
+++ b/macros/latex/base/source2e.pdf
Binary files differ
diff --git a/macros/latex/base/source2e.tex b/macros/latex/base/source2e.tex
index 302c76822d..6ff2928a42 100644
--- a/macros/latex/base/source2e.tex
+++ b/macros/latex/base/source2e.tex
@@ -342,6 +342,8 @@ page_precedence "rnaA"
\DocInclude{ltoutput} % Output routine
+ \DocInclude{lttagging}% Tagging support
+
\DocInclude{lthyphen} % Hyphenation (hyphen.ltx).
\DocInclude{ltfinal} % Last minute initialisations and dump
@@ -378,7 +380,7 @@ page_precedence "rnaA"
\def\endash{--}
\catcode`\-\active
\def-{\futurelet\temp\indexdash}
-\def\indexdash{\ifx\temp-\endash\fi}
+\def\indexdash{\ifx\temp-\endash\else:\fi}
\PrintIndex
\endgroup
diff --git a/macros/latex/base/source2edoc.cls b/macros/latex/base/source2edoc.cls
index 5f731af7ae..48ae49b29a 100644
--- a/macros/latex/base/source2edoc.cls
+++ b/macros/latex/base/source2edoc.cls
@@ -2,12 +2,12 @@
% This class is buggy and needs fixing
\ProvidesClass{source2edoc}
- [2022/04/03 v0.2c Quick hack to typeset source2.tex
+ [2024/02/14 v0.2e Quick hack to typeset source2.tex
(not usable for anything else and buggy -- will vanish again)!]
-\LoadClass{l3doc}
+\LoadClass[kernel]{l3doc}
\RemoveFromHook{begindocument}[l3doc] % drop the standard setting making " a shortverb
\AddToHook{begindocument}{\MakeShortVerb \|} % but readd | as one
@@ -50,84 +50,6 @@
}
-
-% some l3doc's def are buggy (already fixed there but not distributed yet)
-
-\RenewDocumentCommand \DocInclude { m }
- {
- \relax\clearpage
- \docincludeaux
- \IfFileExists{#1.fdd}
- { \cs_set:Npn \currentfile{#1.fdd} }
- { \cs_set:Npn \currentfile{#1.dtx} }
- \int_compare:nNnTF \@auxout = \@partaux
- { \@latexerr{\string\include\space cannot~be~nested}\@eha }
- { \@docinclude {#1} } % <--- braces needed!
- \int_compare:nNnF { \tex_currentgrouplevel:D } = { 0 }
- {
- \int_compare:nNnT { \tex_interactionmode:D } = { 0 }
- { \int_set:Nn \tex_interactionmode:D { 1 } }
- \msg_fatal:nnn { source2edoc } { missing-endgroup } {#1}
- }
- }
-\msg_new:nnn { source2edoc } { missing-endgroup }
- {
- \str_if_eq:VnTF \@currenvir { document }
- {
- There~are~\int_use:N \tex_currentgrouplevel:D
- \c_space_tl unclosed~groups~in~#1.dtx.
- }
- {
- The~\@currenvir \c_space_tl environment~on~line~\@currenvline
- \c_space_tl doesn't~have~a~matching~\iow_char:N\\end{\@currenvir}.
- }
- }
-\cs_gset:Npn \@docinclude #1
- {
- \clearpage
- \immediate\write\@mainaux{\string\@input{#1.aux}}
- \@tempswatrue
- \if@partsw
- \@tempswafalse
- \cs_set:Npx \@tempb {#1}
- \clist_map_inline:Nn \@partlist
- {
- \if_meaning:w \@tempa \@tempb
- \@tempswatrue
- \fi:
- }
- \fi
- \if@tempswa
- \cs_set_eq:NN \@auxout \@partaux
- \immediate\openout\@partaux #1.aux
- \immediate\write\@partaux{\relax}
- \cs_set_eq:NN \@ltxdoc@PrintIndex \PrintIndex
- \cs_set_eq:NN \PrintIndex \relax
- \cs_set_eq:NN \@ltxdoc@PrintChanges \PrintChanges
- \cs_set_eq:NN \PrintChanges \relax
- \cs_set_eq:NN \@ltxdoc@theglossary \theglossary
- \cs_set_eq:NN \@ltxdoc@endtheglossary \endtheglossary
- \part{\currentfile}
- {
- \cs_set_eq:NN \ttfamily\relax
- \cs_gset:Npx \filekey
- { \filekey,~ \thepart = { \ttfamily \currentfile } } % <-- mising spaces considered harmful
- }
- \DocInput{\currentfile}
- \cs_set_eq:NN \PrintIndex \@ltxdoc@PrintIndex
- \cs_set_eq:NN \PrintChanges \@ltxdoc@PrintChanges
- \cs_set_eq:NN \theglossary \@ltxdoc@theglossary
- \cs_set_eq:NN \endtheglossary \@ltxdoc@endtheglossary
- \clearpage
- \@writeckpt{#1}
- \immediate \closeout \@partaux
- \else
- \@nameuse{cp@#1}
- \fi
- \cs_set_eq:NN \@auxout \@mainaux
- }
-
-
% change the setup here: we have a lot of long names so better run raggeded
\cs_set_protected:Npn \__codedoc_macro_end_style:n #1
@@ -176,7 +98,7 @@
dd%
\else\@ctrerr\fi}
\def\docincludeaux{%
- \def\thepart{\aalph{part}}\def\filesep{\thepart-}%
+ \def\thepart{\ifnum\value{part}<10 0\fi\arabic{part}}\def\filesep{\thepart-}%
\let\filekey\@gobble
\g@addto@macro\index@prologue{%
\gdef\@oddfoot{\parbox[t]{\textwidth}{\strut\footnotesize
@@ -303,6 +225,9 @@ Bug reports can be opened (category \texttt{#1}) at\\%
\AddToHook{cmd/tableofcontents/after}{\global\let\tableofcontents\relax}
+% pages > 1000
+\renewcommand\@pnumwidth{2em}
+
\InputIfFileExists{ltxdoc.cfg}
{\typeout{*************************************^^J%
* Local config file ltxdoc.cfg used^^J%
diff --git a/macros/latex/base/syntonly.dtx b/macros/latex/base/syntonly.dtx
index 9d3baaa024..9844585fa5 100644
--- a/macros/latex/base/syntonly.dtx
+++ b/macros/latex/base/syntonly.dtx
@@ -71,7 +71,7 @@
\ProvidesFile{syntonly.dtx}
%</dtx>
%<*package|dtx>
- [2017/06/30 v2.1e Standard LaTeX2e package]
+ [2024/02/08 v2.1e Standard LaTeX2e package]
%</package|dtx>
% \end{macrocode}
%
@@ -150,7 +150,7 @@
\repeat
% \end{macrocode}
% Since all font changes occur either via |\selectfont| (in
-% text or |\mathversion| (for math mode) it is sufficient
+% text) or |\mathversion| (for math mode), it is sufficient
% to change these to no-ops. In addition we must prevent
% the loading of math fonts, this is done by making
% |\getanddefine@fonts| a no-op.
@@ -184,7 +184,7 @@
% The |\nopages@| macro disables the \LaTeX{} output routine.
% To this end we define a very simple output routine that empties
% the output \emph{and} footnote boxes (remember that the latter
-% are insertions.
+% are insertions).
% \begin{macrocode}
\def\nopages@{%
\output {\setbox\z@\box\@cclv
diff --git a/macros/latex/base/syntonly.pdf b/macros/latex/base/syntonly.pdf
index 42fd93bdff..1a7abb780a 100644
--- a/macros/latex/base/syntonly.pdf
+++ b/macros/latex/base/syntonly.pdf
Binary files differ
diff --git a/macros/latex/base/tlc2.pdf b/macros/latex/base/tlc2.pdf
index 20aa9c1ac3..b84160675d 100644
--- a/macros/latex/base/tlc2.pdf
+++ b/macros/latex/base/tlc2.pdf
Binary files differ
diff --git a/macros/latex/base/tlc3.err b/macros/latex/base/tlc3.err
index d4f94705d7..6700a6b962 100644
--- a/macros/latex/base/tlc3.err
+++ b/macros/latex/base/tlc3.err
@@ -1,4 +1,4 @@
-\newcommand\erratafiledate{2023/10/30} % needs / and not -
+\newcommand\erratafiledate{2024/05/31} % needs / and not -
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% To produce a printed version of this errata file run this file through
@@ -320,12 +320,15 @@
\let\u\underline % needs resetting after hyperref
+\usepackage{hologo}
+\providecommand\XeTeX{\hologo{XeTeX}}
+
\begin{document}
\erratatitle{The \LaTeX{} Companion, Third Edition, Parts I \& II}{\erratafiledate}
-
+\begin{small}
\begin{verbatim}
@book(A-W:MF:2023,
author = {Frank Mittelbach and Ulrike Fischer},
@@ -339,10 +342,9 @@
pagenums = {976 (Part I) and 1008 (Part II)},
bibliography = {yes},
index = {yes},
- isbn = {978-0-13-816648-9},
-)
+ isbn = {978-0-13-816648-9})
\end{verbatim}
-
+\end{small}
\begin{list}{}{\setlength\leftmargin{0cm}%
\setlength\rightmargin{3cm}%
@@ -372,7 +374,7 @@ or digital edition
you own by changing the configuration in the file \texttt{\jobname.cfg}.
\begin{center}
- \Large \bfseries To Err is Human --- Bug Contest
+ \large \bfseries To Err is Human --- Bug Contest
\end{center}
Any mistake found and reported is a gain for all readers of our book.
@@ -398,7 +400,7 @@ Good luck!
\begin{center}
\begin{tabular}{clr}
Contest period ends & Winner \\[4pt]
-2023/?? & & ??? suggestions\\
+2024/03 & Bernd Burghardt & 52 suggestions\\
\end{tabular}
\end{center}
@@ -441,7 +443,7 @@ digital differing only in that respect.
\erroronpage{}{}{FMi}{2023/07/30}{}
-Text or graphics typeset in the the spot color (blue) are not always
+Text or graphics typeset in the spot color (blue) are not always
perfectly aligned. This is a side-effect of the printing technology.
On most pages everything is fine, but occasionally blue text in a
paragraph seems to be slightly above or below the baseline or blue
@@ -592,6 +594,13 @@ the index is always fully regenerated for new printings.
English. Personally, I prefer the version with accent (as does Don
Knuth) so it is deliberate and will not change.
+
+\CHAPTER{Preface}
+
+\erroronpage{I-xlii}{para 1, l.3}{FMi}{2024/04/01}{s}
+\u{the designer} of the Lato fonts \> \u{a co-designer} of the Lato fonts
+
+
\CHAPTER{Chapter 1 --- Introduction}
\erroronpage{I-5}{para 4, l.4}{kb}{2023/04/04}{s}
@@ -606,6 +615,10 @@ not least \> \u{but} not least
\CHAPTER{Chapter 2 --- The Structure of a \LaTeX{} Document}
+\erroronpage{I-31}{para-1,l.-1}{BeB}{2024/03/17}{s}
+would have resulted in ``\verb+# .+'' in the output. \> \\
+would have resulted in ``\verb+#+\u{\texttt{\&}}\verb+ .+'' in the output.
+
\erroronpage{I-34}{l.-1}{FMi}{2023/04/04}{s}
Moved first line of page 35 to 34.
@@ -624,6 +637,10 @@ Situation is the same in the 2023 distributions; listing output updated.
\CHAPTER{Chapter 3 --- Basic Formatting Tools -- Paragraph \ldots}
+\erroronpage{I-143}{exa 3-1-18}{BeB}{2024/03/17}{s}
+Replace in source: \verb+{ peine+ \> \verb+{peine+
+
+
\erroronpage{I-160}{para -2, l.1}{BeB}{2023/07/14}{s}
Repeated word: keys \u{keys} \> keys
@@ -636,18 +653,58 @@ Add a marginal note: \u{No warning if another \LaTeX{} run is necessary!}
\erroronpage{I-163}{example 3-3-14}{BeB}{2023/07/25}{s}
Output of example misses the page numbers in acronym list \> Run example 3 times (not only twice---there is no warning)
+\erroronpage{I-174}{para3,l. -2}{BeB}{2024/03/17}{s}
+the exponent is always a \u{power} of 3 \> the exponent is always a
+\u{multiple} of 3
+\seriouserroronpage{I-177}{exa 3-3-39}{BeB/FMi}{2024/03/17}{s}
+
+The example doesn't really show what the paragraph above discusses
+because it was shortend to fit the available space on the page.
+Use
+\begin{verbatim}
+\newcommand\sample[1]{\textnormal{\noindent #1:}
+ The limit is \qty{30}{\kmh} not $\qty{50}{\kmh}$.\par}}
+\end{verbatim}
+so that both text and math usage of \verb=\qty= are compared in the example.
+
+
+\erroronpage{I-182}{para 4}{BeB}{2024/03/17}{s}
+Add sentence: The command \verb+\textcquote+ is used in Example 16-5-50 on page II-535.
\CHAPTER{Chapter 4 --- Basic Formatting Tools -- Larger \ldots}
+\erroronpage{I-253}{para 2, l.-3}{YEi}{2023/11/27}{s}
+Move comma:\\
+and \textsf{thmtools} packages and \textsf{typed-checklist}\u{,} helps you write \> \\
+and \textsf{thmtools} packages\u{,} and \textsf{typed-checklist} helps you write
+
+
\erroronpage{I-323}{Table 4.4, left column}{BeB}{2023/07/25}{s}
Typo: Assembler (\u{N}otorola68k, x86masm) \> \\ Assembler (\u{M}otorola68k, x86masm)
% Matlab \> Matlab \u{(empty, 5.1)}
% könnte auch aktualisiert werden, steht aber in Version 1.8d nicht drin
+\erroronpage{I-344}{exa 4-3-16}{CAR/FMi}{2024/01/29}{s}
+Use \cs{NewDocumentEnvironment} instead of
+\cs{DeclareDocumentEnvironment} because it is always better to check
+that the declaration is not accidentally overwriting an existing
+environment.
\CHAPTER{Chapter 5 --- The Layout of the Page}
+\erroronpage{I-365}{paras -3 to -2}{YEi}{2023/11/28}{s}
+
+Add/replace:\\
+\ldots package and others. \cs{par} The \u{fifth} section then \> \\
+\ldots package and others.
+\u{In the fifth section we cover ``static'' page} \\
+\u{decorations such as watermarks.} \cs{par} The \u{sixth} section then
+
+\erroronpage{I-368}{table 5.1}{YEi}{2023/11/29}{s}
+A better approximation for \texttt{b5paper} is \u{$6\frac{7}{8}$}${}\times 9 \frac{7}{8}$
+
+
\erroronpage{I-386}{exa 5-3-1, l.7}{EOl}{2023/09/09}{s}
Change:
paragraph over \u{two} pages. \> paragraph over \u{three} pages.
@@ -660,6 +717,14 @@ is not shown.}
\u{\cs{right}} \> \u{\cs{rightmark}}
+\erroronpage{I-393}{Documentation of \rlap{\cs{IfMarksEqualTF}}}{FMi}{2024/05/31}{s}
+
+Add paragraph:
+Note that two retrieved mark values are only considered equal if they
+originated from the same \cs{InsertMark} command — it is not enough
+that they contain the same data, as that may be conincidental.
+
+
\CHAPTER{Chapter 6 --- Tabular Material}
@@ -675,13 +740,27 @@ text can be interpreted as a value, a somewhat ``random'' number and
the rest is dropped. For example, \texttt{31 December 2022} would
result in ``31.00'', which is probably not desired.
+\erroronpage{I-491}{exa 6-7-22, Booklet 114}{EOl}{2024/05/13}{s}
+ Change: remove `0,00' in `actual' column for item `loss'. (This
+is not really an error, but it looks better---and is consistent with the
+`actual' item of `profit' for Booklet 113.)
+
+
+\erroronpage{I-494}{para -2, l.3}{MRu}{2024/03/16}{s}
+
+Use plural: The allowed key\u{s} are \ldots
+
\CHAPTER{Chapter 7 --- Mastering Floats}
-\erroronpage{I-520}{paragraph 4, l.3}{EOl}{2023/09/09}{s}
+\erroronpage{I-520}{para 4, l.3}{EOl}{2023/09/09}{s}
Change:
For \u{a} example \> For example
+\erroronpage{I-612}{para -2, l.1}{EOl}{2024/05/13}{s}
+Change: up \u{do} several \> up to several
+
+
\CHAPTER{Chapter 8 --- Graphics Generation and Manipulation}
\erroronpage{I-619}{para -2, l.2}{FMi}{2023/05/30}{s}
@@ -698,6 +777,9 @@ start from full red, i.e., \> \verb*/left color=red/ instead.
\erroronpage{I-644}{syntaxbox for \cs{foreach}}{BeB}{2023/07/14}{s}
superfluous ``in'': \ldots\{\textsl{commands}\} \u{in} \> \ldots\{\textsl{commands}\}
+\erroronpage{I-645}{para 3, l.4}{EOl}{2024/05/13}{s}
+Correct hyphenation: stan-dalone \> stand-alone
+
\CHAPTER{Chapter 9 --- Font Selection and Encodings}
@@ -716,12 +798,34 @@ Missing space: Theproblem \> The problem
\erroronpage{I-708}{listing}{FMi}{2023/05/14}{s}
Situation is the same in the 2023 distributions; listing output updated.
+\erroronpage{I-726}{para 4, l.5}{MRu}{2024/04/07}{s}
+Add word: more than hundred \> more than \u{one} hundred
+
\erroronpage{I-759}{l.1}{BeB}{2023/08/20}{s}
in the range of 0000 to \u{00FF} \> in the range of 0000 to \u{007F}
+\erroronpage{I-797}{exa 9-6-3}{BYu/FMi}{2024/04/08}{s}
+
+This example may fail with \XeTeX{} because of a deficiency in
+older versions of \pkg{fontspec}. With versions prior 2.9e one has to
+use the \texttt{Extension} key and omit the extension on the other
+lines:
+\begin{verbatim}
+\setmainfont{Alegreya}[
+ Extension = .otf,
+ UprightFont = *-Medium,
+ ItalicFont = *-MediumItalic,
+ BoldFont = *-ExtraBold,
+ BoldItalicFont = *-ExtraBoldItalic
+]
+\end{verbatim}
+
\CHAPTER{Chapter 10 --- Text and Symbol Fonts}
+\erroronpage{II-3}{para-1, l.-2}{BeB}{2024/03/17}{s}
+line first \> first line
+
\erroronpage{II-5}{table 10.1, l. 5}{BeB/FMi}{2023/08/13}{s}
official \u{companion} family name \> \u{related} official \u{font} family name
@@ -732,7 +836,7 @@ then this structure is repeated \u{for the related font families} as often as ne
\erroronpage{II-24}{para 3, l. -2}{BeB}{2023/08/13}{s}
-There is no slanted shape in Grande Mono: \\
+There is no slanted shape in Grande Mono (so it should be in blue): \\
\u{\textsl{naïve}} \> \u{\textsl{\bl naïve}}
@@ -741,8 +845,8 @@ Open Type font is available: \\
\u{— no Open Type —} \> \u{Lucida Handwriting OT}
\erroronpage{II-25}{para -2, l.-2}{BeB}{2023/08/13}{s}
-There are no italic blackletters: \\
-\textit{phœnix's official rôle}\> \textit{\bl phœnix's official rôle}
+There are no italic blackletters (so it should be in blue): \\
+\textit{phœnix's official rôle} \> \textit{\bl phœnix's official rôle}
\erroronpage{II-28}{table 10.14, l. 3}{BeB}{2023/08/13}{s}
Inconsistent order: sl, l \> l, sl
@@ -773,6 +877,8 @@ bold) or in some families for \textttu{ub} (ultra bold).}
\erroronpage{II-40}{table 10.24}{FMi}{2023/08/15}{s}
In table note: \textit{Unfortunately, \u{\texttt{sco}}} \> \textit{Unfortunately, \u{\textttu{sco}}}
+\erroronpage{II-42}{para 3, l.4}{MRu}{2024/04/12}{s}
+rudimentary \> rudimentarily
\erroronpage{II-50}{font sample Cambria}{FMi}{2023/08/14}{s}
@@ -786,7 +892,7 @@ Because of problems with the font names, the Cambria family currently requires a
BoldItalicFont = cambriaz.ttf}
\end{verbatim}
Without it, the bold fonts are not correctly set up, which is why
-\textbf{almost anything} is not in bold and \textbf{Fields} is not typeset in
+\textbf{almost anything} was not in bold and \textbf{Fields} was not typeset in
bold small caps in the sample even though Cambria supports these typefaces.
@@ -928,37 +1034,37 @@ not showing in the example.
\erroronpage{II-114}{table 10.89}{FMi}{2023/04/04}{s}
Added missing \texttt{U+00Fx} line.
-There was a bug in code generating it.
+There was a bug in the code generating it.
\erroronpage{II-117}{table 10.92}{FMi}{2023/04/04}{s}
Added missing \texttt{U+00Fx} line.
-There was a bug in code generating it.
+There was a bug in the code generating it.
\erroronpage{II-121}{table 10.96}{FMi}{2023/04/04}{s}
Added missing \texttt{U+00Fx} line.
-There was a bug in code generating it.
+There was a bug in the code generating it.
\erroronpage{II-122}{table 10.98}{FMi}{2023/04/04}{s}
Added missing \texttt{U+00Fx} line.
-There was a bug in code generating it.
+There was a bug in the code generating it.
\erroronpage{II-122}{table 10.99}{FMi}{2023/04/04}{s}
Added missing \texttt{U+00Fx} line.
-There was a bug in code generating it.
+There was a bug in the code generating it.
\erroronpage{II-123}{table 10.100}{FMi}{2023/04/04}{s}
Added missing \texttt{U+00Fx} line.
-There was a bug in code generating it.
+There was a bug in the code generating it.
\erroronpage{II-124}{table 10.103}{FMi}{2023/04/04}{s}
Added missing \texttt{U+00Fx} line.
-There was a bug in code generating it.
+There was a bug in the code generating it.
@@ -1302,6 +1408,10 @@ is created only if the entry \u{contains} a shorttitle \u{field} and the title a
is created only if the entry \u{has been referenced (prior to typesetting}\\
\u{the bibliography), contains} a shorttitle \u{field,} and the title and shorttitle fields differ.
+\erroronpage{II-535}{footnote}{FMi}{2024/01/07}{s}
+Extend the explanation:\\
+\u{you can} use \cs{mancite} \u{in front of any citation command} to avoid this.
+
\erroronpage{II-560}{exa 16-7-31}{FMi}{2023/08/31}{s}
Jane Doe.\ \textit{A\u{n} second book.}\ 2020.\> Jane Doe.\ \textit{A second book.}\ 2020.
@@ -1319,7 +1429,8 @@ Jane Doe.\ \textit{A\u{n} second book.}\ 2020.\> Jane Doe.\ \textit{A second boo
\CHAPTER{Appendix A --- \LaTeX{} Overview for Preamble, \ldots}
\erroronpage{II-624--629}{}{BeB/FMi}{2023/08/31}{s}
-Replace for consistency with section 1.4: \u{command definition} \> \u{code}
+Replace for consistency with section 1.4: \u{command definition} \> \u{code} \\
+(in the various syntax boxes)
\erroronpage{II-629}{para 1, l.3}{FMi}{2023/08/31}{s}
\u{An} warning \> \u{A} warning
@@ -1328,10 +1439,34 @@ Replace for consistency with section 1.4: \u{command definition} \> \u{code}
\erroronpage{II-633}{para 2}{BeB/FMi}{2023/08/31}{s}
Add at the end: A maximum of nine ``argument'' letters is supported.
+\erroronpage{II-657}{par -2, l. -2}{BeB}{2024/03/17}{s}
+a few that \> a few \u{commands} that
+
+
+\erroronpage{II-658}{first item in the list}{BeB}{2024/03/17}{s}
+square root $\sqrt{x}$ \> square root \texttt{sqrt} $x$
-\erroronpage{II-682}{para -2, l.3}{FMi}{2023/04/28}{s}
+\erroronpage{II-663}{A-3-7}{MRu}{2024/05/01}{}
+In the code, text should read either ``This is the content'' or ``These are the contents''.
+
+\erroronpage{II-682}{para -2, l .3}{FMi}{2023/04/28}{s}
\texttt{Harf\u{b}uzz} \> \texttt{Harf\u{B}uzz}
+\erroronpage{II-678}{para -1, l. -1}{BeB}{2024/03/17}{s}
+it is better use\> it is better \u{to} use
+
+
+\erroronpage{II-687}{l .1}{BeB}{2024/03/17}{s}
+Two further tests should be listed in the syntax box: \verb+\ifVTeX+ \verb+\ifAlephTeX+
+
+
+\seriouserroronpage{II-701}{l. 6}{BeB}{2024/03/17}{s}
+Name changed after the book was typeset: \verb+.notif+\>\verb+.ifnot+
+
+\erroronpage{II-701}{para 3, l. 4; para -2, l. 1; and margin}{BeB}{2024/03/17}{s}
+\verb+.notif+\>\verb+.ifnot+
+
+
\CHAPTER{Appendix B --- Tracing and Resolving Problems}
@@ -1349,9 +1484,10 @@ Appendix title not properly capitalized.
\end{erratalist}
+\newpage
-\section*{Notes on this errata document}
+\section{Notes on this errata document}
\setcounter{collectmore}{3}
@@ -1359,19 +1495,23 @@ Appendix title not properly capitalized.
\begin{multicols}{3}[Thanks to all who have found errors or
omissions. Listed are the people who found an errata entry first.]
\contributor{BeB}{Bernd Burghardt}
+\contributor{BYu}{Boshi Yuan}
\contributor{CAR}{Chris Rowley}
\contributor{DC}{Davide Campagnari}
\contributor{DFl}{Daniel Flipo}
\contributor{EOl}{Edgar Olthof}
\contributor{FMi}{Frank Mittelbach}
\contributor{MJo}{Maciej Jończyk}
+\contributor{MRu}{Mark Rudolph}
\contributor{YFu}{FUJIMURA Yukitoshi}
\contributor{YvH}{Yvon Henel}
+\contributor{YEi}{Yaakov Eisenberg}
\contributor{bb}{Barbara Beeton}
\contributor{kb}{Karl Berry}
\end{multicols}
+
Other people have sent us corrections for errors already found.
Thanks to all of you!
diff --git a/macros/latex/base/tlc3.pdf b/macros/latex/base/tlc3.pdf
index 1eea1e9857..6a1bb622d0 100644
--- a/macros/latex/base/tlc3.pdf
+++ b/macros/latex/base/tlc3.pdf
Binary files differ
diff --git a/macros/latex/base/tulm.pdf b/macros/latex/base/tulm.pdf
index 19d49a6303..a59d513a41 100644
--- a/macros/latex/base/tulm.pdf
+++ b/macros/latex/base/tulm.pdf
Binary files differ
diff --git a/macros/latex/base/usrguide-historic.pdf b/macros/latex/base/usrguide-historic.pdf
index 5084e9eee8..baf42b84af 100644
--- a/macros/latex/base/usrguide-historic.pdf
+++ b/macros/latex/base/usrguide-historic.pdf
Binary files differ
diff --git a/macros/latex/base/usrguide-historic.tex b/macros/latex/base/usrguide-historic.tex
index 4888361160..228a253abb 100644
--- a/macros/latex/base/usrguide-historic.tex
+++ b/macros/latex/base/usrguide-historic.tex
@@ -34,15 +34,15 @@
\title{\LaTeX\ for authors --- historic version}
-\author{\copyright~Copyright 1995--2022, \LaTeX\ Project Team.\\
+\author{\copyright~Copyright 1995--2023, \LaTeX\ Project Team.\\
All rights reserved.%
\footnote{This file may be distributed and/or modified under the
conditions of the \LaTeX{} Project Public License, either version 1.3c
of this license or (at your option) any later version. See the source
- \texttt{usrguide.tex} for full details.}%
+ \texttt{usrguide-historic.tex} for full details.}%
}
-\date{30 August 2022}
+\date{09 November 2023}
\begin{document}
diff --git a/macros/latex/base/usrguide.pdf b/macros/latex/base/usrguide.pdf
index 3704f7e7ff..e4b5e6cf0e 100644
--- a/macros/latex/base/usrguide.pdf
+++ b/macros/latex/base/usrguide.pdf
Binary files differ
diff --git a/macros/latex/base/usrguide.tex b/macros/latex/base/usrguide.tex
index d3ccb2161e..2b9e959627 100644
--- a/macros/latex/base/usrguide.tex
+++ b/macros/latex/base/usrguide.tex
@@ -34,8 +34,8 @@
\usepackage{csquotes}
\usepackage{url}
-\title{\LaTeX\ for authors --- current version}
-\author{\copyright~Copyright 2020-2023, \LaTeX\ Project Team.\\
+\title{\LaTeX\ for authors\\ current version}
+\author{\copyright~Copyright 2020--2024, \LaTeX\ Project Team.\\
All rights reserved.%
\footnote{This file may be distributed and/or modified under the
conditions of the \LaTeX{} Project Public License, either version 1.3c
@@ -43,7 +43,7 @@
\texttt{usrguide.tex} for full details.}%
}
-\date{2023-05-23}
+\date{2024-05-24}
\NewDocumentCommand\cs{m}{\texttt{\textbackslash\detokenize{#1}}}
\NewDocumentCommand\marg{m}{\arg{#1}}
@@ -646,7 +646,7 @@ take account of the possibility that the \meta{token} has been made active
(category code~$13$) and will split at such tokens.
Spaces are trimmed at each end of each item parsed. Exactly one set
of braces will be stripped if an entire item is surrounded by them,
-i.e.~the following inputs and outputs result (each separte item as
+i.e.~the following inputs and outputs result (each separate item as
a brace group).
\begin{verbatim}
a ==> {a}
@@ -794,6 +794,73 @@ a & b & c \\
\end{tabular}
\end{verbatim}
+\subsection{Using the verbatim argument types}
+
+As described above, the \texttt{v}-type argument may be viewed as similar to
+\cs{verb}. Before looking at exactly what that means, it is important to
+highlight some key differences. Most notably, \emph{grabbing} a verbatim-like
+argument is separate from \emph{typesetting} it: the latter is covered in the
+next section.
+
+When grabbing a \texttt{v}-type argument, \LaTeX{} first uses the kernel
+command \cs{dospecials} to turn off the \enquote{special} nature of characters.
+It then makes both spaces and tabs \enquote{active}, so that they can be given
+a custom definition. Any other characters are grabbed as-is: this means that if
+any characters have been made \enquote{special} and are not listed in
+\cs{dospecials}, an error will arise (see below).
+
+The characters that are grabbed as the argument are all those between two
+identical: in contrast to \cs{verb}, the characters \texttt{\textbackslash},
+|{|, |}| and |%| \emph{cannot} be used as the delimiter character. If any of
+the grabbed tokens have \enquote{special} meaning, an error will be issued.
+
+For the \texttt{+v}-type argument, which allows line breaks within the
+argument, newline characters are converted into \cs{obeyedline} commands. The
+standard definition of \cs{obeyedline} is simple |\par|, thus allowing the
+grabbed tokens to be used directly in typesetting. A local redefinition of
+\cs{obeyedline} can be used to achieve other outputs. For example, to retain
+blank lines whilst typesetting, one could use
+\begin{verbatim}
+\renewcommand*\obeyedline{\mbox{}\par}
+\end{verbatim}
+More information about using these arguments in typesetting is in the following
+subsection.
+
+Some additional details that may be useful for those with more \TeX{}
+knowledge: do not worry if this does not make sense to you! Spaces and tabs are
+stored as active characters. In Unicode engines, all other characters are of
+type \enquote{other}. In $8$-bit engines, the ASCII characters other than tab
+and space are of type \enquote{other}, and non-ASCII characters are active. As
+such, token-based comparisons are likely to fail unless set up properly.
+
+\subsection{Typesetting verbatim-like material}
+
+In contrast to \cs{verb}, the \texttt{(+)v}-type argument is only about
+\emph{grabbing} the argument, not \emph{typesetting} it. As such, features that
+users often associate with \enquote{verbatim} are not automatically activated,
+e.g., selecting a monospaced font. Material grabbed by the \texttt{v}-type
+argument does not automatically suppress ligatures: with modern \TeX{} engines,
+this largely can be done without the token manipulation which \cs{verb} uses.
+(In \cs{verb}, ligatures are suppressed by making characters active and
+inserting a zero-width kern before the character itself.)
+
+The \cs{verb} command also selects a monospaced font: this is not intrinsic to
+verbatim material, so will need to be set up using for example \cs{ttfamily}.
+Similarly, the \texttt{verbatim} environment sets up the meaning of \cs{par}
+suitable for breaking lines.
+
+\subsection{Performance}
+
+For document commands where the argument specification is entirely
+comprised of |m| or |+m| entries (or is entirely empty), the internal structure
+created by \cs{NewDocumentCommand} is essentially as efficient
+as provided by |\newcommand(*)|. As such, document commands may replace
+constructs arising from \cs{newcommand}, etc., without a need to be concerned
+about performance. It should be noted that \cs{newcommand(*)} produces expandable
+results, so the direct replacement is \cs{NewExpandableDocumentCommand};
+in most cases, however, it is better to use \cs{NewDocumentCommand} to
+give more robust structures.
+
\subsection{Details about argument delimiters}
In normal (non-expandable) commands, the delimited types look for the
@@ -951,7 +1018,7 @@ The differences between \cs{New...}, \cs{Renew...}, and
\begin{decl}
|\ShowEnvironment| \arg{env}
\end{decl}
-This displays the meaning of the begin end end code for environment \meta{env}.
+This displays the meaning of the begin and end code for environment \meta{env}.
@@ -1052,11 +1119,17 @@ to give a purely numerical result.
Briefly, the floating point expressions may comprise:
\begin{itemize}
\item Basic arithmetic: addition $x\fpbin{+}y$, subtraction $x\fpbin{-}y$,
- multiplication $x\fpbin{*}y$, division $x\fpbin{/}y$, square root~$\sqrt{x}$,
+ multiplication $x\fpbin{*}y$, division $x\fpbin{/}y$, square root~$\fpop{sqrt}{x}$,
and parentheses.
\item Comparison operators: $x\fprel{<}y$,
$x\fprel{<=}y$, $x\fprel{>?}y$,
$x\fprel{!=}y$ \emph{etc.}
+
+ The relation $x\fprel{?}y$ is true exactly if one or both operands is~\nan{} or is
+ a tuple, unless they are equal tuples. Each \meta{relation}
+ can be any (non-empty) combination of |<|, |=|, |>|, and~|?|, plus
+ an optional leading~|!| (which negates the \meta{relation}), with
+ the restriction that the negated \meta{relation} may not start with~|?|.
\item Boolean logic: sign $\fpop{sign} x$,
negation $\fpop{!}x$, conjunction
$x\fprel{\&\&}y$, disjunction $x\fprel{\string|\string|}y$, ternary
@@ -1161,7 +1234,7 @@ therefore shows the same syntax peculiars as discussed
above. Nevertheless, in practice they are usually sufficient. For
example
\begin{verbatim}
-\newcommand\calculateheight[1]{%
+\NewDocumentCommand\calculateheight{m}{%
\setlength\textheight{\dimeval{\topskip+\baselineskip*\inteval{#1-1}}}}
\end{verbatim}
sets the \cs{textheight} to the appropriate value if a page should
@@ -1186,13 +1259,13 @@ Titlecasing here follows the definition given by the Unicode Consortium: the
first character of the input will be converted to (broadly) uppercase, and the
rest of the input to lowercase. The full range of Unicode UTF-8 input can be
supported.
-\begin{quotation}
- \begin{tabular}{rl}
+\begin{flushleft}
+ \begin{tabular}{@{}ll}
|\MakeUppercase{hello WORLD ßüé}| & \MakeUppercase{hello WORLD ßüé} \\
|\MakeLowercase{hello WORLD ßüé}| & \MakeLowercase{hello WORLD ßüé} \\
|\MakeTitlecase{hello WORLD ßüé}| & \MakeTitlecase{hello WORLD ßüé} \\
\end{tabular}
-\end{quotation}
+\end{flushleft}
The case-changing commands take an optional argument which can be used to
tailor the output. This optional argument accepts the key \texttt{locale},
@@ -1208,14 +1281,14 @@ are the arguments to the commands \cs{label}, \cs{ref}, \cs{cite}, \cs{begin}
and \cs{end}. Additional exclusions can be added using the command
\cs{AddToNoCaseChangeList}. Input can be excluded from case changing using the
command \cs{NoCaseChange}.
-\begin{quotation}
- \begin{tabular}{rl}
+\begin{flushleft}
+ \begin{tabular}{@{}ll}
|\MakeUppercase{Some text $y = mx + c$}|
& \MakeUppercase{Some text $y = mx + c$} \\
|\MakeUppercase{\NoCaseChange{iPhone}}|
& \MakeLowercase{\NoCaseChange{iPhone}} \\
\end{tabular}
-\end{quotation}
+\end{flushleft}
To allow robust commands to be used within case changing \emph{and} to produce
the expected output, two additional control commands are available.
@@ -1244,18 +1317,54 @@ apply to a specific one: this is given in BCP-47 format
(\url{https://en.wikipedia.org/wiki/IETF_language_tag}). For example,
the kernel customises the mapping for U+01F0 (\v{j}) when uppercasing in
8-bit engines:
-\begin{quotation}
- |\DeclareUppercaseMapping{"01F0}{\v{J}}|
-\end{quotation}
+\begin{verbatim}
+\DeclareUppercaseMapping{"01F0}{\v{J}}
+\end{verbatim}
as there is no pre-composed \v{J} character, and this is problematic if
the engine does not support Unicode natively. Similarly, to set a locale
\texttt{xx} to behave in the same way as Turkish and retain the difference
between dotted- and dotless-i, one could use for example
-\begin{quotation}
- |\DeclareLowercaseMapping[xx]{"0049}{\i}|\\
- |\DeclareLowercaseMapping[xx]{"0130}{i}|\\
- |\DeclareUppercaseMapping[xx]{"0069}{\.{I}}|\\
- |\DeclareUppercaseMapping[xx]{"0131}{I}|
-\end{quotation}
+\begin{verbatim}
+\DeclareLowercaseMapping[xx]{"0049}{\i}
+\DeclareLowercaseMapping[xx]{"0130}{i}
+\DeclareUppercaseMapping[xx]{"0069}{\.{I}}
+\DeclareUppercaseMapping[xx]{"0131}{I}
+\end{verbatim}
+
+\section{Support for problem solving}
+
+\begin{decl}
+ |\listfiles| \oarg{options}
+\end{decl}
+
+If this command is placed in the preamble then a list of the files
+read in (as a result of processing the document) will be displayed
+on the terminal (and in the log file) at the end of the run. Where
+possible, a short description will also be produced. These descriptions
+will (hopefully) include the descriptions, dates and version numbers
+for package and class files.
+
+Sometimes, it may be that a local edit has been made to a package or
+class file (or rather a copy of such a file). To allow these cases to
+be identified, \cs{listfiles} takes an optional argument which allows
+adjustment of the information printed using a key--value approach
+\begin{description}
+ \item[\texttt{hashes}] Adds the MD5 hash for each file to the
+ information printed
+ \item[\texttt{sizes}] Adds the file size for each file to the
+ information printed
+\end{description}
+Note that as Windows and Unix use different line endings (LF \emph{versus} LF
+CR), the hashes and file sizes from the two systems will not be the same. As
+such, you should compare these values between operating systems of the same
+type.
+
+\emph{Warning}: this command will list only files which were read
+using \LaTeX{} commands such as |\input|\arg{file} or
+|\include|\arg{file}. If the file was read using the primitive \TeX{}
+syntax |\input |\emph{file} (without |{ }| braces around the file name)
+then it will not be listed; failure to use the \LaTeX{} form with the
+braces can cause more severe problems, possibly leading to overwriting
+important files, so \textbf{always put in the braces}.
\end{document}
diff --git a/macros/latex/base/utf8ienc.dtx b/macros/latex/base/utf8ienc.dtx
index b7dfe4b0c0..a2701ac5c8 100644
--- a/macros/latex/base/utf8ienc.dtx
+++ b/macros/latex/base/utf8ienc.dtx
@@ -886,7 +886,8 @@
\else
% \end{macrocode}
%
-% If the input is malformed UTF-8 there may not be enough closing ) so
+% If the input is malformed UTF-8 there may not be enough closing
+% \iffalse(\fi ) so
% add 5 so there are always some remaining then cleanup and remove
% any remaining ones at the end. This avoids |\numexpr| parse errors
% while outputting a package error.
@@ -1660,7 +1661,7 @@
% \end{macrocode}
% According to the Unicode standard Ux04C5 should be an L with ``tail'' not
% with descender (which also exists as Ux04A2) but it looks as if the char
-% names do not make this distinction). Should they?
+% names do not make this distinction. Should they?
% \begin{macrocode}
%<all,x2,t2c,t2b>\DeclareUnicodeCharacter{04C5}{\CYRLDSC}
%<all,x2,t2c,t2b>\DeclareUnicodeCharacter{04C6}{\cyrldsc}
diff --git a/macros/latex/base/utf8ienc.pdf b/macros/latex/base/utf8ienc.pdf
index 27d6973f5d..fb783b8fde 100644
--- a/macros/latex/base/utf8ienc.pdf
+++ b/macros/latex/base/utf8ienc.pdf
Binary files differ
diff --git a/macros/latex/base/webcomp.err b/macros/latex/base/webcomp.err
index 1b3b7a2475..aabef28187 100644
--- a/macros/latex/base/webcomp.err
+++ b/macros/latex/base/webcomp.err
@@ -373,7 +373,7 @@ preferable in a form usable for this file, i.e.,
\begin{flushleft}
|\erroronpage{|\textit{page-number}|}{|\textit{line-identification}|}{|%
\textit{your-initials}|}{|\textit{date}|}{}| \\
- \hspace*{2em}\textit{description of the the errata}
+ \hspace*{2em}\textit{description of the errata}
\end{flushleft}
Here is an example:
\begin{verbatim}
diff --git a/macros/latex/base/webcomp.pdf b/macros/latex/base/webcomp.pdf
index d923e8ecc5..f537f9148f 100644
--- a/macros/latex/base/webcomp.pdf
+++ b/macros/latex/base/webcomp.pdf
Binary files differ