% \iffalse meta-comment % %% File: latex-lab-firstaid.dtx (C) Copyright 2023-2026 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 % license or (at your option) any later version. The latest version % of this license is in the file % % https://www.latex-project.org/lppl.txt % % % The latex-lab bundle is developed in the LaTeX2e GitHub. % Issues may be reported at % % https://github.com/latex3/latex2e/issues % \def\ltlabfirstaiddate{2026-10-26} \def\ltlabfirstaidversion{0.86l} %<*driver> \DocumentMetadata{tagging=on,pdfstandard=ua-2} \documentclass{l3in2edoc} \EnableCrossrefs \CodelineIndex \usepackage{todonotes} \begin{document} \DocInput{latex-lab-firstaid.dtx} \end{document} % % % \fi % % \title{The \textsf{latex-lab-firstaid} package\\ % Temporary patches to external packages needed for the tagging project} % \author{\LaTeX{} Project\thanks{Initial implementation done by Ulrike Fischer}} % \date{v\ltlabfirstaidversion\ \ltlabfirstaiddate} % % \maketitle % % \newcommand{\xt}[1]{\textsl{\textsf{#1}}} % \newcommand{\TODO}[1]{\textbf{[TODO:} #1\textbf{]}} % \newcommand{\docclass}{document class \marginpar{\raggedright document class % customizations}} % % \providecommand\hook[1]{\texttt{#1}} % \providecommand\key[1]{\texttt{#1}} % \providecommand\insttype[1]{\texttt{#1}} % \providecommand\instname[1]{\texttt{#1}} % \providecommand\struct[1]{\texttt{\meta{#1}}} % % \NewDocumentCommand\fmi{sO{}m} % {\IfBooleanTF{#1}{\todo[inline,#2]{#3}}^^A % {\todo[#2]{#3}}} % % \NewDocumentCommand\ufi{sO{}m} % {\IfBooleanTF{#1}{\todo[inline,#2]{UFi:#3}}^^A % {\todo[#2]{UFi:#3}}} % % % \begin{abstract} % \end{abstract} % % \section{Introduction} % % The following contains small temporary changes to external packages to avoid % errors with the new tagging code. % % Similar to the main firstaid package the goal is to remove the % patches once the packages have been updated. % % \changes{v0.85g}{2024/10/04}{Removed firstaid for blindtext. % No longer needed with new \cs{@doendpe} code.} % \changes{v0.85g}{2024/10/04}{Added firstaid for fancyvrb.} % \changes{v0.85n}{2025-10-12}{Added firstaid for pgf.} % \changes{v0.85t}{2026-03-12}{Switch from \texttt{x}- to \texttt{e}-type % expansion in expl3 code} % \changes{v0.85u}{2026-04-24}{Added firstaid for H-floats.} % \changes{v0.85u}{2026-04-24}{Removed microtype firstaid. No longer needed.} % \changes{v0.86f}{2026-09-20}{Added support for listings} % \section{Implementation} % % \begin{macrocode} %<*package> %<@@=tag> % \end{macrocode} % \begin{macrocode} \ProvidesPackage {latex-lab-testphase-firstaid} [% \ltlabfirstaiddate\space v\ltlabfirstaidversion\space Temporary patches to external packages needed for the tagging project] % \end{macrocode} % \begin{macro}[no-user-doc]{\FirstAidNeededT} % This is a very simple help to ensure that we only apply first aid % to an unmodified package or class. It only works in the case the % file has already been loaded and the csname \cs{ver@\#1.\#2} got % defined (holding the current date, version, and short description % info). We then compare its content to a frozen string and make % the modification \verb=#3= only if both agree. If they differ we % assume that the package/class in question got updated by its % maintainer. % \begin{macrocode} \ExplSyntaxOn \providecommand\FirstAidNeededT[3]{ \exp_args:Nce\str_if_eq:onF{ver@#1.#2}{#3} { \typeout{==>~ First~ Aid~ for~ #1.#2~ no~ longer~ applied!^^J \@spaces Expected:^^J \@spaces\@spaces #3^^J \@spaces but~ found:^^J \@spaces\@spaces \use:c{ver@#1.#2}^^J \@spaces so~ I'm~ assuming~ it~ got~ fixed. } } \exp_args:Nce\str_if_eq:onT{ver@#1.#2}{#3} } % \end{macrocode} % \end{macro} % \subsection{tikz/pgf} % ti\textit{k}z inputs libraries with the primitive \cs{input} command. This means that % these libraries are not listed in the file list written by \cs{listfiles} and the new % tagging status report created with the \texttt{check-tagging-status} key. % % We therefore redefine one \texttt{pgf} command to use the \LaTeX{} \cs{input} command. % Check https://github.com/pgf-tikz/pgf/issues/1424 for changes. % \begin{macrocode} \AddToHook{package/pgfrcs/after} {\def\pgfutil@InputIfFileExists#1#2#3{\pgfutil@IfFileExists{#1}{\input{#1}\relax#2}{#3}}} % \end{macrocode} % % \subsection{listings} % The \pkg{listings} package needs various adaptions to enable tagging support. % They are in an external file. % \begin{macrocode} \AddToHook{package/listings/after}[latex-lab-firstaid]{\RequirePackage{latex-lab-listings}} % \end{macrocode} % % \subsection{AMS classes} % % Unfortunately, the AMS classes contain a full inline copy of % \pkg{amsthm} inside the class (thanks to \pkg{dostrip}) and they % use \cs{newcommand}, sigh. % % Thus, to make the new code work with these classes we have to hide % some definitions, load the class and only afterwards restore our % own versions. % % So first save some of the problematical definitions under some % other names (quite a handful): % \begin{macrocode} \let \@kernel@newtheorem \newtheorem \let \@kernel@newtheoremstyle \newtheoremstyle \let \@kernel@theoremstyle \theoremstyle \let \@kernel@proof \proof \let \@kernel@endproof \endproof % \end{macrocode} % % \begin{macrocode} \def\undefine@thm@macros{ \let \newtheoremstyle \relax \let \theoremstyle \relax % \end{macrocode} % % \begin{macrocode} \let \proof \relax \let \endproof \relax % \end{macrocode} % These we also have to undefine but there is no need to restore % them later (our definitions are identical to those in the % classes) we only have to avoid that \cs{newcommand} generates an % error when the class is loaded. % \begin{macrocode} \let \pushQED \relax \let \popQED \relax \let \qedhere \relax \let \mathqed \relax \let \openbox \relax } % \end{macrocode} % % Then undefine them just before the class gets loaded: % \begin{macrocode} \AddToHook{class/amsart/before} [block]{ \undefine@thm@macros } \AddToHook{class/amsbook/before}[block]{ \undefine@thm@macros } \AddToHook{class/amsproc/before}[block]{ \undefine@thm@macros } % \end{macrocode} % After the class got loaded we restore the saved versions. % % Most of the first aid code for the AMS classes needs to be applied after % the class got loaded. % Instead of putting all the code in hooks and thus into the format we now % write it to files that are loaded after the class has been loaded. % \begin{macrocode} \AddToHook{class/amsbook/after}[latex-lab-firstaid]{\input{latex-lab-firstaid-amsbook.ltx}} \AddToHook{class/amsart/after} [latex-lab-firstaid]{\input{latex-lab-firstaid-amsart.ltx}} \AddToHook{class/amsproc/after}[latex-lab-firstaid]{\input{latex-lab-firstaid-amsproc.ltx}} % \end{macrocode} % % \begin{macrocode} % %<*amscls> \ExplSyntaxOn % \end{macrocode} % % Let us first restore the thmlike macros while this is fresh on % our mind. Note that we don't have to restore all the QED-related % commands as ours are identical to those defined by the AMS. % \begin{macrocode} \let \newtheorem \@kernel@newtheorem \let \newtheoremstyle \@kernel@newtheoremstyle \let \theoremstyle \@kernel@theoremstyle \let \proof \@kernel@proof \let \endproof \@kernel@endproof % \end{macrocode} % % % % The amsart, amsbook and amsproc classes do not use \cs{@author} % to store the author list but a command \cs{authors}. To be able % to nevertheless use the authors in the % xmp-metadata we map \cs{@author} to this new command. % % The authors are set with a trivlist, this leads to faulty spacing % and wrong tagging. This is not yet handled here, but an example % how to correct this is in the test-amsart-title test. % \begin{macrocode} \def\@author{\authors} % \end{macrocode} % % % % In these classes the abstract is stored in a \cs{vbox}, as it % ends with a list an explicit \cs{par} is needed. % \changes{v0.85i}{2025/01/26}{Add missing \cs{par} to abstract env (gh/1641)} % \begin{macrocode} \renewenvironment{abstract}{% \ifx\maketitle\relax \ClassWarning{\@classname}{Abstract~ should~ precede~ \protect\maketitle\space in~ AMS~ document~ classes;~ reported}% \fi \global\setbox\abstractbox=\vtop \bgroup \normalfont\Small \list{}{\labelwidth\z@ \leftmargin3pc \rightmargin\leftmargin \listparindent\normalparindent \itemindent\z@ \parsep\z@ \@plus\p@ \let\fullwidthdisplay\relax }% \item[\hskip\labelsep\scshape\abstractname.]% }{% \endlist \par % <--- added \egroup \ifx\@setabstract\relax \@setabstracta \fi } % \end{macrocode} % % % \changes{v0.85w}{2026/05/21}{Use new \cs{newtheoremstyle} with AMS classes} % % In the ams classes's \cs{newtheoremstyle} has different defaults % compared to the standalone \pkg{amsthm} package. Therefore the % classes have their own implementation of the command that we need % to overwrite as well. % % \begin{macrocode} \tl_set:Nn \newtheoremstyle@vspace@default { .5\baselineskip \@plus .2\baselineskip \@minus .2\baselineskip } % \end{macrocode} % % The above takes care of newly defined theoremstyles, but the % default ones are already defined in the class so we have to % adjust their settings directly. % \changes{0.86h}{2026-10-01}{Provide correct theorem-like defaults % for AMS classes (tagging/1632)} % \begin{macrocode} \EditInstance{block}{thm-plain-1} { begin-vspace = \newtheoremstyle@vspace@default } \DeclareInstanceCopy{block}{thm-plain-2}{thm-plain-1} % \end{macrocode} % % \begin{macrocode} \EditInstance{block}{thm-remark-1} { begin-vspace = \newtheoremstyle@vspace@default } \DeclareInstanceCopy{block}{thm-remark-2}{thm-remark-1} % \end{macrocode} % % \begin{macrocode} \EditInstance{block}{thm-definition-1} { begin-vspace = \newtheoremstyle@vspace@default } \DeclareInstanceCopy{block}{thm-definition-2}{thm-definition-1} % \end{macrocode} % % Beside the spacing the thmstyles also differ from the default % (but not for \texttt{amsart.cls}): % \begin{macrocode} %<*amsbook,amsproc> \EditInstance{thmstyle}{plain} { before-hspace = \parindent , caption-decls = \scshape } \EditInstance{thmstyle}{remark} { before-hspace = \parindent , caption-decls = \scshape } \EditInstance{thmstyle}{definition} { before-hspace = \parindent , caption-decls = \scshape } % % \end{macrocode} % % % % % \subsubsection{Headings} % % \changes{0.85r}{2026-01-06} % {Add tagging support for headings in ams-classes, tagging issue \#970} % \changes{v0.85u}{2026-04-24}{Adapt keys to changes in sec-template.} % \changes{0.85y}{2026-07-11}{Provide proper heading instances for all % ams classes (tagging/1477)} % % The classes redefine \cs{@startsection} and define their own % heading commands which are not tagging compatible. % This code is therefore disabled and replaced by standard % definitions that process the heading arguments and call a % suitable template instance. The top-level definitions are % identical for all classes (only the heading instances then % differ). % % \begin{macrocode} \DeclareDocumentCommand \part {s ={shorttitle}o m} { \ParseLaTeXeHeading {part} {#1} {#2} {#3} } % \end{macrocode} % % Chapters only exist in \cls{amsbook} and their top-level % definition is also slightly special as we need a different % heading instance for numbered and unnumbered chapters. % \begin{macrocode} %<*amsbook> \DeclareDocumentCommand \chapter {s ={shorttitle}O{} m} { \IfBooleanTF{#1} { \ParseLaTeXeHeading {chapter*} {#1} {#2} {#3} } { \ParseLaTeXeHeading {chapter} {#1} {#2} {#3} } } % % \end{macrocode} % % \begin{macrocode} \DeclareDocumentCommand \section {s ={shorttitle}o m} { \ParseLaTeXeHeading {section} {#1} {#2} {#3} } % \end{macrocode} % % The \cs{specialsection} command is a variation of the % \texttt{section} layout so has its own heading instance. % \begin{macrocode} \DeclareDocumentCommand \specialsection {s ={shorttitle}o m} { \ParseLaTeXeHeading {specialsection} {#1} {#2} {#3} } % \end{macrocode} % % \begin{macrocode} \DeclareDocumentCommand \subsection {s ={shorttitle}o m} { \ParseLaTeXeHeading {subsection} {#1} {#2} {#3} } % \end{macrocode} % % % \begin{macrocode} \DeclareDocumentCommand \subsubsection {s ={shorttitle}o m} { \ParseLaTeXeHeading {subsubsection} {#1} {#2} {#3} } % \end{macrocode} % % % \begin{macrocode} \DeclareDocumentCommand \paragraph {s ={shorttitle}o m} { \ParseLaTeXeHeading {paragraph} {#1} {#2} {#3} } % \end{macrocode} % % % \begin{macrocode} \DeclareDocumentCommand \subparagraph {s ={shorttitle}o m} { \ParseLaTeXeHeading {subparagraph} {#1} {#2} {#3} } % \end{macrocode} % % % % The heading template instances have some subtle differences in the % different AMS classes. We therefore set all of them up by % document class, even though some of the code is the same. % % \begin{macrocode} %<*amsbook> % \end{macrocode} % % % \begin{macrocode} \DeclareInstance{heading}{part}{display} { , name = part , level = -1 , placement = page , placement-start-code = \cleardoublepage \thispagestyle{empty} \null \vfil \markboth{}{} , placement-end-code = \vfil \vfil \newpage \thispagestyle{empty} , mark-cmd = \partmark {#1} , heading-decls = \centering\fontsize{\@xviipt}{22}\bfseries , headformat-instance = part , text = \partname , number-format = #1 , title-decls = \fontsize{\@xxpt}{25}\bfseries } % \end{macrocode} % % Current heading templates aren't flexible enough and do not % properly support altering the layout for unnumbered headings % compared to their numbered counterparts. For this reason we have % two heading instances, one for \cs{chapter} and one for \cs{chapter*}. % % \begin{macrocode} \DeclareInstance{heading}{chapter}{display} { , name = chapter , level = 0 , mark-cmd = \chaptermark {#1} , para-indent = true , placement = top , after-penalty-vspace = 42pt % 32pt plus \topskip , after-vspace = 22pt , heading-decls = \normalsize\mdseries\centering , headformat-instance = chapter , text = \MakeUppercase{\chaptername} , number-format = #1 , title-decls = \fontsize{\@xivpt}{18} \bfseries , contents-extra = \addtocontents{lof}{\protect\addvspace{10\p@}} \addtocontents{lot}{\protect\addvspace{10\p@}} } % \end{macrocode} % % \begin{macrocode} \DeclareInstanceCopy{heading}{chapter*}{chapter} \EditInstance{heading}{chapter*}{ after-penalty-vspace = 72pt } % 62pt + \topskip % \end{macrocode} % % \begin{macrocode} \DeclareInstance{headformat}{chapter}{display} { , heading-indent = 0pt , separator-b = \par \nobreak \vspace{18pt} } % \end{macrocode} % % % \begin{macrocode} \DeclareInstance{heading}{section}{display} { , name = section , level = 1 , mark-cmd = \sectionmark{#1} , para-indent = true , before-vspace = 0.7\linespacing plus \linespacing , after-vspace = 0.5\linespacing , heading-decls = \normalfont \bfseries \centering , headformat-instance = section , number-format = #1. , number-decls = \upshape } \DeclareInstance{headformat}{section}{hang} { separator-b = \hspace{0.5em} } % \end{macrocode} % % A \cs{specialsection} is like a \cs{section} with two changes in % the parameter settings. % \begin{macrocode} \DeclareInstanceCopy{heading}{specialsection}{section} \EditInstance{heading}{specialsection} { , before-vspace = 2\linespacing plus \linespacing , heading-decls = \large \scshape \centering } % \end{macrocode} % % \begin{macrocode} \DeclareInstance{heading}{subsection}{runin} { , name = subsection , level = 2 , mark-cmd = \subsectionmark{#1} , before-vspace = 0.5\linespacing plus 0.7\linespacing , after-hspace = \fontdimen2\font , heading-decls = \normalfont \bfseries , headformat-instance = subsection , number-format = #1. , number-decls = \upshape , title-format = #1 \AddPunct{.} } \DeclareInstance{headformat}{subsection}{runin} { , separator-b = \hspace{0.5em} , heading-indent = \normalparindent } % \end{macrocode} % % \begin{macrocode} \DeclareInstance{heading}{subsubsection}{runin} { , name = subsubsection , level = 3 , mark-cmd = \subsubsectionmark{#1} , before-vspace = 0pt , after-hspace = \fontdimen2\font , heading-decls = \normalfont \itshape , headformat-instance = subsubsection , number-format = #1. , number-decls = \upshape , title-format = #1 \AddPunct{.} } \DeclareInstance{headformat}{subsubsection}{runin} { , separator-b = \hspace{0.5em} , heading-indent = \normalparindent } % \end{macrocode} % % \begin{macrocode} \DeclareInstance{heading}{paragraph}{runin} { , name = paragraph , level = 4 , mark-cmd = \paragraphmark{#1} , before-vspace = 0pt , after-hspace = \fontdimen2 \font , heading-decls = \normalfont , headformat-instance = paragraph , number-format = #1. , number-decls = \upshape , title-format = #1 \AddPunct{.} } \DeclareInstance{headformat}{paragraph}{runin} { , separator-b = \hspace{0.5em} , heading-indent = \normalparindent } % \end{macrocode} % % \begin{macrocode} \DeclareInstance{heading}{subparagraph}{runin} { , name = subparagraph , level = 5 , mark-cmd = \subparagraphmark{#1} , before-vspace = 0pt , after-hspace = \fontdimen2\font , heading-decls = \normalfont , headformat-instance = subparagraph , number-format = #1. , number-decls = \upshape , title-format = #1 \AddPunct{.} } \DeclareInstance{headformat}{subparagraph}{runin} { , separator-b = \hspace{0.5em} } % \end{macrocode} % % The running header setup from amsbook doesn't correctly function % and needs adjustments. For now we provide some simple % redefinitions which do not necessarily produce exactly the same results. % \begin{macrocode} \def\partmark#1{% \markboth{}{} } \def\chaptermark#1{% \markboth {\MakeUppercase{% \ifnum \c@secnumdepth >\m@ne \thechapter. \ % \fi #1}}{} } \def\sectionmark#1{% \markright {\MakeUppercase{% \ifnum \c@secnumdepth >\z@ \thesection. \ % \fi #1}} } % \end{macrocode} % % \begin{macrocode} % % \end{macrocode} % % % % % % % \begin{macrocode} %<*amsart> % \end{macrocode} % % The use of \cs{mdseries} in several of the instances is really % odd (and not done in \cls{amsbook} or \cls{amsproc}) but it is % what the current class generates as a layout, so we keep it that % way. % % \begin{macrocode} \DeclareInstance{heading}{part}{display} { , name = part , level = -1 % -1 or 0 ? , mark-cmd = \partmark{#1} , para-indent = true , before-vspace = \linespacing plus \linespacing , after-vspace = 0.5 \linespacing , heading-decls = \normalfont \bfseries \raggedright , headformat-instance = part , text = \partname , number-format = \theheading . , number-decls = \mdseries \upshape % proc: has just \upshape } \DeclareInstance{headformat}{part}{hang} { , separator-b = \hspace{0.5em} } % \end{macrocode} % % \begin{macrocode} \DeclareInstance{heading}{section}{display} { , name = section , level = 1 , mark-cmd = \sectionmark{#1} , para-indent = true , before-vspace = 0.7\linespacing plus \linespacing , after-vspace = 0.5\linespacing , heading-decls = \normalfont \scshape \centering , headformat-instance = section , number-format = \theheading . , number-decls = \mdseries \upshape } \DeclareInstance{headformat}{section}{hang} { , separator-b = \hspace{0.5em} } % \end{macrocode} % % The \cs{specialsection} command is a variation of the % \texttt{section} layout. % % \begin{macrocode} \DeclareInstanceCopy{heading}{specialsection}{section} \EditInstance{heading}{specialsection} { , before-vspace = \linespacing plus \linespacing , heading-decls = \normalfont \centering } % \end{macrocode} % % \begin{macrocode} \DeclareInstance{heading}{subsection}{runin} { , name = subsection , level = 2 , mark-cmd = \subsectionmark{#1} , before-vspace = 0.5\linespacing plus 0.7\linespacing , after-hspace = \fontdimen2\font , heading-decls = \normalfont \bfseries , headformat-instance = subsection , number-format = \theheading . , number-decls = \mdseries \upshape , title-format = #1 \AddPunct{.} } \DeclareInstance{headformat}{subsection}{runin} { , separator-b = \hspace{0.5em} } % \end{macrocode} % % \begin{macrocode} \DeclareInstance{heading}{subsubsection}{runin} { , name = subsubsection , level = 3 , mark-cmd = \subsubsectionmark{#1} , before-vspace = 0.5\linespacing plus 0.7\linespacing , after-hspace = \fontdimen2\font , heading-decls = \normalfont \itshape , headformat-instance = subsubsection , number-format = \theheading . , number-decls = \mdseries \upshape , title-format = #1 \AddPunct{.} } \DeclareInstance{headformat}{subsubsection}{runin} { , separator-b = \hspace{0.5em} } % \end{macrocode} % % \begin{macrocode} \DeclareInstance{heading}{paragraph}{runin} { , name = paragraph , level = 4 , mark-cmd = \paragraphmark{#1} , before-vspace = 0pt , after-hspace = \fontdimen2\font , heading-decls = \normalfont , headformat-instance = paragraph , number-format = \theheading . , number-decls = \mdseries \upshape , title-format = #1 \AddPunct{.} } \DeclareInstance{headformat}{paragraph}{runin} { , separator-b = \hspace{0.5em} } % \end{macrocode} % % \begin{macrocode} \DeclareInstance{heading}{subparagraph}{runin} { , name = subparagraph , level = 5 , mark-cmd = \subparagraphmark{#1} , before-vspace = 0pt , after-hspace = \fontdimen2\font , heading-decls = \normalfont , headformat-instance = subparagraph , number-format = \theheading . , number-decls = \mdseries \upshape , title-format = #1 \AddPunct{.} } \DeclareInstance{headformat}{subparagraph}{runin} { , separator-b = \hspace{0.5em} } % \end{macrocode} % % \begin{macrocode} % % \end{macrocode} % % % % % % \begin{macrocode} %<*amsproc> % \end{macrocode} % % \begin{macrocode} \DeclareInstance{heading}{part}{display} { , name = part , level = -1 % -1 or 0 ? , mark-cmd = \partmark{#1} , para-indent = true , before-vspace = \linespacing plus \linespacing , after-vspace = 0.5 \linespacing , heading-decls = \normalfont \bfseries \raggedright , headformat-instance = part , text = \partname , number-format = \theheading . , number-decls = \upshape } \DeclareInstance{headformat}{part}{hang} { , separator-b = \hspace{0.5em} } % \end{macrocode} % % \begin{macrocode} \DeclareInstance{heading}{section}{display} { , name = section , level = 1 , mark-cmd = \sectionmark{#1} , para-indent = true , before-vspace = 0.7\linespacing plus \linespacing , after-vspace = 0.5\linespacing , heading-decls = \normalfont \bfseries \centering , headformat-instance = section , number-format = \theheading . , number-decls = \upshape } \DeclareInstance{headformat}{section}{hang} { , separator-b = \hspace{0.5em} } % \end{macrocode} % % The \cs{specialsection} command is a variation of the % \texttt{section} layout. % \begin{macrocode} \DeclareInstanceCopy{heading}{specialsection}{section} \EditInstance{heading}{specialsection} { , before-vspace = \linespacing plus \linespacing , heading-decls = \large \scshape \centering } % \end{macrocode} % % \begin{macrocode} \DeclareInstance{heading}{subsection}{runin} { , name = subsection , level = 2 , mark-cmd = \subsectionmark{#1} , before-vspace = 0.5\linespacing plus 0.7\linespacing , after-hspace = \fontdimen2\font , heading-decls = \normalfont \bfseries , headformat-instance = subsection , number-format = \theheading . , number-decls = \upshape , title-format = #1 \AddPunct{.} } \DeclareInstance{headformat}{subsection}{runin} { , separator-b = \hspace{0.5em} , heading-indent = \normalparindent } % \end{macrocode} % % \begin{macrocode} \DeclareInstance{heading}{subsubsection}{runin} { , name = subsubsection , level = 3 , mark-cmd = \subsubsectionmark{#1} , before-vspace = 0.5\linespacing plus 0.7\linespacing , after-hspace = \fontdimen2\font , heading-decls = \normalfont \itshape , headformat-instance = subsubsection , number-format = \theheading . , number-decls = \upshape , title-format = #1 \AddPunct{.} } \DeclareInstance{headformat}{subsubsection}{runin} { , separator-b = \hspace{0.5em} , heading-indent = \normalparindent } % \end{macrocode} % % \begin{macrocode} \DeclareInstance{heading}{paragraph}{runin} { , name = paragraph , level = 4 , mark-cmd = \paragraphmark{#1} , before-vspace = 0pt , after-hspace = \fontdimen2\font , heading-decls = \normalfont , headformat-instance = paragraph , number-format = \theheading . , number-decls = \upshape , title-format = #1 \AddPunct{.} } \DeclareInstance{headformat}{paragraph}{runin} { , separator-b = \hspace{0.5em} , heading-indent = \normalparindent } % \end{macrocode} % % \begin{macrocode} \DeclareInstance{heading}{subparagraph}{runin} { , name = subparagraph , level = 5 , mark-cmd = \subparagraphmark{#1} , before-vspace = 0pt , after-hspace = \fontdimen2\font , heading-decls = \normalfont , headformat-instance = subparagraph , number-format = \theheading . , number-decls = \upshape , title-format = #1 \AddPunct{.} } \DeclareInstance{headformat}{subparagraph}{runin} { , separator-b = \hspace{0.5em} } % \end{macrocode} % % \begin{macrocode} % % \end{macrocode} % % % % % \begin{macrocode} %<*amsbook> % \end{macrocode} % % The AMS classes do a lot of low-level overwrites to macros % building out the table of contents structures. \cs{@starttoc} % being one example which is partially fixed here. This isn't the % full fix: various \cs{l@...} macros also need changes, but that % has to wait for another day \ldots\ for now we only make sure % that the code doesn't break badly, but they layout is not % matching what the class normally produces! % \begin{macrocode} \def\@starttoc#1#2{% \begingroup \setTrue{#1}% \ifx\contentsname#2% \chapter[unnumbered,toc=]{\contentsname}% \else \chapter[=,unnumbered]{#2}% \fi \typeout{#2}% \makeatletter \@input{\jobname.#1}% \if@filesw \@xp\newwrite\csname tf@#1\endcsname \immediate\@xp\openout\csname tf@#1\endcsname \jobname.#1\relax \fi \global\@nobreakfalse \endgroup \newpage } % \end{macrocode} % % \begin{macrocode} \AddToHook{begindocument}{ \@namedef{r@tocindent-1}{1em} \@namedef{r@tocindent0}{1em} \@namedef{r@tocindent1}{1em} } % \end{macrocode} % % % \begin{macrocode} % % \end{macrocode} % % \begin{macrocode} \ExplSyntaxOff % %<*package> % \end{macrocode} % % % \begin{macrocode} \ExplSyntaxOff % \end{macrocode} % % % % % % \subsection{fncychap} % % First aid for \pkg{fncychap} is kept in a separate file. % \begin{macrocode} \AddToHook{package/fncychap/after}[latex-lab-firstaid]{\input{latex-lab-firstaid-fncychap.ltx}} % \end{macrocode} % % % \begin{macrocode} % %<*fncychap> % \end{macrocode} % % % \begin{macrocode} \ExplSyntaxOn % \end{macrocode} % % The \pkg{fncychap} package has its own way of offering % customizations including arbitrary rewrites for the commands % \cs{DOCH}, \cs{DOTI}, and \cs{DOTIS}. In order to support % customizations in existing documents (defining chapter layout % variations in this fashion) we define a headformat in which the % three commands are simply called to typeset the heading, i.e., % the template doesn't offer any customizations through % keys---everything is done through the interfaces of % \pkg{fncychap} as before. % % For the same reason most of the keys of the chapter instance are % nonfunctional, i.e., they exist but aren't used with a few % exceptions. After all, the purpose here is to make \pkg{fncychap} % tagging compatible and not to extend its functionality or offer % additional customization possibilities. % % The two values in the heading chapter instance that we need to % alter are \key{after-vspace} and set it to zero (because this is % handled inside \cs{DOTI} or \cs{DOTIS}) and % \key{headformat-instance} as we want to call our own instance % suitable to deal with the customization possibilities offerered % by \pkg{fncychap}. Thus we edit the default \insttype{heading} % \instname{chapter} instance in the following way. % % \begin{macrocode} \EditInstance{heading}{chapter}{ after-vspace = 0pt , headformat-instance = fncychap } % \end{macrocode} % % This means we have to declare a new template \instname{fncychap} % of type \insttype{headformat} (with no keys as explained above): % \begin{macrocode} \DeclareTemplateInterface{headformat}{fncychap}{6}{} % \end{macrocode} % % % The code for this template is fairly simple. % \begin{macrocode} \DeclareTemplateCode{headformat}{fncychap}{6}{} { % \end{macrocode} % Output some debugging info at the start. % \begin{macrocode} \__head_show_arguments:nnnnnn {#1}{#2}{#3}{#4}{#5}{#6} % \end{macrocode} % Everything else happens in a group to keep changes local. % \begin{macrocode} \group_begin: % \end{macrocode} % First, make a link target (with slight difference depending on % whether or not the chapter is numbered). % \begin{macrocode} \bool_if:NTF \l__head_unnumbered_bool { \MakeLinkTarget [ \l__head_name_tl ] {} } { \MakeLinkTarget { \l__head_name_tl } } % \end{macrocode} % Next follow some default paragraph settings that may or may not % be overwritten by declarations for a specific chapter layout % from the package. % \begin{macrocode} \parindent 0pt \raggedright \interlinepenalty 10000 \normalfont % \end{macrocode} % Then we have a few tagging socket settings for \cs{parbox} or % \env{minipage} environments, because some heading designs use % \cs{parbox}es and they need the special settings in the context % of a heading to make the tagging work. % \begin{macrocode} \AssignTaggingSocketPlug{parbox/before}{heading} \AssignTaggingSocketPlug{minipage/before}{heading} \AssignTaggingSocketPlug{para/restore}{noop} % \end{macrocode} % Finally, we have the bare heading design as used in the % package. When the heading is numbered then \cs{DOCH} is % responsible to place the fixed heading text (e.g., Chapter) and the % chapter number. % % We start by calling \cs{fncychap@setup@thechapter} which gives % \cs{thechapter} a special definition while the heading is typeset % (since we are in a group here this is reverted immmediately after). % \begin{macrocode} \fncychap@setup@thechapter % \end{macrocode} % % \begin{macrocode} \bool_if:NF \l__head_unnumbered_bool { \DOCH } % \end{macrocode} % If we are in \enquote{main matter} then \cs{DOTI} typesets the % chapter title, otherwise \cs{DOTIS} is used to typeset the % chapter title. % \begin{macrocode} \legacy_if:nTF { @mainmatter } { \DOTI{#4} } { \DOTIS{#4} } % \end{macrocode} % We finish off with a \cs{par} to ensure that we are back in % vertical mode and then close the group. % \begin{macrocode} \par \group_end: } % \end{macrocode} % % % We use this template to create the \insttype{headformat} instance % used in the \insttype{heading} instance. Since the template has no % keys this is a trivial declaration: % \begin{macrocode} \DeclareInstance{headformat}{fncychap}{fncychap}{} % \end{macrocode} % % % % To put a \struct{heading-number} structure around the number % without really knowing how the heading layout is done, we hook % into \cs{thechapter}. This redefinition only happens within the % \texttt{headformat} instance when we typeset the % heading. Elsewhere \cs{thechapter} retains its usual definition, % e.g., when used inside the document or in a running header or toc % entry. % % \changes{v0.86k}{2026-10-25}{Pass number not an unexpanded % \cs{thechapter} to toc (tagging/1668)} % \begin{macrocode} \def\fncychap@setup@thechapter{ \def\thechapter{\thespecialchapter{\@arabic\c@chapter}} } % \end{macrocode} % % \begin{macrocode} \def\appendix{\par \setcounter{chapter}{0} \setcounter{section}{0} \gdef\@chapapp{\appendixname} \gdef\thechapter{\@Alph\c@chapter} % \end{macrocode} % Add the special setup for using in the \texttt{headformat} % template above. % \begin{macrocode} \gdef\fncychap@setup@thechapter{ \def\thechapter{\thespecialchapter{\@Alph\c@chapter}} } } % \end{macrocode} % % % % % The \cs{thespecialchapter} ensures that hmode is started and then % normally generates a \struct{heading-number} structure but only % if we aren't already in an \struct{Lbl}. It then typesets the % current number. % \changes{v0.86k}{2026-10-25}{Pass number not an unexpanded % \cs{thechapter} to toc (tagging/1668)} % \begin{macrocode} \protected\def\thespecialchapter#1{ \leavevmode \tag_if_in:nTF{Lbl} { #1 } { \UseTaggingSocket{inline/begin}{tag=heading-number} #1 \UseTaggingSocket{inline/end} } } % \end{macrocode} % % % % \begin{macro}{\mghrulefill} % % This here is a special rule definition from \pkg{fncychap} that % we overwrite to add the necessary tagging support. % \begin{macrocode} \protected\def\mghrulefill#1{\leavevmode \UseTaggingSocket{rule}{}{ \leaders\hrule\@height #1\hfill\kern\z@ } } % \end{macrocode} % \end{macro} % % % % \begin{macrocode} \ExplSyntaxOff % \end{macrocode} % % \begin{macrocode} % %<*package> % \end{macrocode} % % % % % % % % \subsection{cleveref} % % The cleveref package redefines \cs{@makefntext} and this means that the patches in % the new footnote code fails. We use a hook instead. % \changes{v0.85h}{2024/10/16}{Remove redefinition of refstepcounter. It no longer uses % the hook.} % \begin{macrocode} \AddToHook{package/cleveref/after} { \let\@makefntext\cref@old@makefntext \AddToHook{cmd/@makefntext/before}{% \cref@constructprefix{footnote}{\cref@result}% \protected@edef\cref@currentlabel{% [footnote][\arabic{footnote}][\cref@result]% \p@footnote\@thefnmark}} } % \end{macrocode} % % \subsection{booktabs} % In some cases booktabs inserts a % \cs{multispan} into the table (through the commands \cs{@cmidruleb} % and \cs{@cmidrulea} and this then errors % with the tagging code. % This affects both tabular and longtable % (but longtable more as booktabs handles lines in longtable differently). % See also issue \url{https://github.com/latex3/tagging-project/issues/69} % % \changes{0.85u}{2026-04-24}{Use tagging sockets} % \begin{macrocode} \ExplSyntaxOn \AddToHook{package/booktabs/after} { \def\@cmidrulea{ \multispan\@cmidla &\multispan\@cmidlb \unskip\hskip\cmrkern@l { \UseTaggingSocket{tbl/leaders/begin} \CT@arc@\leaders\hrule \@height\@thisrulewidth\hfill\kern\z@} \hskip\cmrkern@r \UseTaggingSocket{tbl/leaders/end} \tbl_gdecr_row_count: \cr} \def\@cmidruleb{% \multispan\@cmidlb \unskip\hskip \cmrkern@l% { \UseTaggingSocket{tbl/leaders/begin} \CT@arc@\leaders\hrule \@height\@thisrulewidth\hfill\kern\z@} \hskip\cmrkern@r \UseTaggingSocket{tbl/leaders/end} \tbl_gdecr_row_count: \cr} } \ExplSyntaxOff % \end{macrocode} % % % \subsection{fancyvrb} % The firstaid adds first partial tagging support to the environments % of fancyvrb (inline verbatim is untested). % This supports then also packages like minted which internally uses fancyvrb % and classes like l3doc (where currently the verbatim environment based on fancyvrb % is overwritten by the block code). % The environments are surrounded by a \texttt{verbatim} structure, % every line by a \texttt{codeline} % structure. Line numbers are tagged as \texttt{Lbl}, inside of the % \texttt{codeline} structure. The frame lines are marked as artifact. % % \begin{macro}[no-user-doc]{\FV@LeaveVMode} % If we are in vmode we have to open a semantic-para structure, if we are % in hmode we have to set para mode to flattened before the fancyvrb code % issues the\cs{par}. The closing of the semantic-para structure is handled by the % doendpe code in the block code. % \changes{0.85u}{2026-04-24}{Use tagging sockets} % \begin{macrocode} \ExplSyntaxOn \AddToHook{package/fancyvrb/after} { \def\FV@LeaveVMode{% \if@noskipsec \leavevmode \else \if@FV@ResetMargins\if@inlabel\leavevmode\fi\fi \fi \ifvmode \@noparlisttrue \UseTaggingSocket{para/semantic/begin}{} \else \tagpdfsetup{para/flattened=true} \@noparlistfalse \unskip\par \fi } % \end{macrocode} % \end{macro} % % \begin{macro}[no-user-doc]{\FV@List} % At the begin of the list code we have to tag the frame as artifact % and start the \texttt{verbatim} structure % \begin{macrocode} \def\FV@List#1{% \begingroup \FV@UseKeyValues \FV@LeaveVMode \if@inlabel\else\setbox\@labels=\box\voidb@x\fi \FV@ListNesting{#1}% \FV@ListParameterHook \FV@ListVSpace \FV@SetLineWidth \FV@InterLinePenalty \let\FV@ProcessLine\FV@ListProcessLine@i \FV@CatCodes \FV@FormattingPrep \FV@ObeyTabsInit \cs_if_exist:NT \FV@BeginListFrame { \UseTaggingSocket{mc}{artifact}{\FV@BeginListFrame} } \UseTaggingSocket{struct/begin}{tag=\UseStructureName{block/verbatim}} } % \end{macrocode} % \end{macro} % \begin{macro}[no-user-doc]{\FV@EndList} % At the end of the list code we close the \texttt{verbatim} structure and % tag the frame as artifact. % \begin{macrocode} \def\FV@EndList{% \FV@ListProcessLastLine \UseTaggingSocket{struct/end} \cs_if_exist:NT \FV@EndListFrame { \UseTaggingSocket{mc}{artifact}{\FV@EndListFrame} } \@endparenv \endgroup \@endpetrue } % \end{macrocode} % \end{macro} % % \begin{macro}[no-user-doc]{\FV@ListProcessLine} % At last the tagging of the code lines. Here we have to tag also % numbers and frame parts if they exist. % \begin{macrocode} \def\FV@ListProcessLine#1{% \hbox to \hsize{% \kern\leftmargin \hbox to \linewidth{% \UseTaggingSocket{struct/begin}{tag=\UseStructureName{block/verbatim/codeline}} \cs_if_exist:NT \FV@LeftListNumber { \UseTaggingSocket{struct-mc}{tag=\UseStructureName{block/verbatim/linenumber}} { \FV@LeftListNumber } } \cs_if_exist:NT \FV@LeftListFrame { \UseTaggingSocket{mc}{artifact}{\FV@LeftListFrame} } \UseTaggingSocket{mc}{}{\FancyVerbFormatLine{#1}}% \UseTaggingSocket{struct/end}\hss \cs_if_exist:NT \FV@RightListFrame { \UseTaggingSocket{mc}{artifact}{\FV@RightListFrame} } \cs_if_exist:NT \FV@RightListNumber { \UseTaggingSocket{struct-mc}{tag=\UseStructureName{block/verbatim/linenumber}} { \FV@RightListNumber } } } \hss}} } \ExplSyntaxOff % \end{macrocode} % \end{macro} % % \subsection{The \pkg{float} package first aid} % % The float package has a number of incompatibilites: % \begin{itemize} % \item Restyling floats with \cs{restylefloat} breaks the tagging tagging support. % \item New float types created with \cs{newfloat} are not properly tagged (tagging issue 890) % \item Non-floating floats using the \texttt{H} placement are not properly tagged. % \end{itemize} % The following firstaid addresses these problems. % A flaw is that if the H-float is inside a paragraph and followed % by text there the text is tagged as a new semantic-para structure. % % Because of this and other limitations the final solution may look noticeably different % including the used tagging sockets, etc. % TODO % % The firstaid for \pkg{float} is kept in a separate file. % \begin{macrocode} \AddToHook{package/float/after}[latex-lab-firstaid]{\input{latex-lab-firstaid-float.ltx}} % % \end{macrocode} % \begin{macrocode} %<*float> \ProvidesFile{latex-lab-firstaid-float.ltx} [\ltlabfirstaiddate\space \ltlabfirstaidversion\space LaTeX-lab-firstaid: Tagging support for the float package] % \end{macrocode} % Tagging sockets for the H-floats % \begin{macrocode} \ExplSyntaxOn \NewTaggingSocket{float/H/begin}{1} \NewTaggingSocketPlug{float/H/begin}{default} { \mode_if_horizontal:T {\tag_mc_end_push: \tag_struct_end:} \tag_struct_begin:n {tag=\UseStructureName{float/#1}} } \AssignTaggingSocketPlug{float/H/begin}{default} \NewTaggingSocket{float/H/end}{0} \NewTaggingSocketPlug{float/H/end}{default} { \tag_struct_end: \mode_if_horizontal:T { \tag_struct_begin:n {tag=\UseStructureName{para/textblock}} \tag_mc_begin_pop:n {} } } \AssignTaggingSocketPlug{float/H/end}{default} % \end{macrocode} % and here the redefinitions of the commands of \pkg{float} % for the H-floats: % \begin{macrocode} \def\@float@HH#1[H]{\UseTaggingSocket{float/H/begin}{#1}% \expandafter\let\csname end#1\endcsname\float@endH \let\@currbox\float@box \def\@captype{#1}\setbox\@floatcapt=\vbox{}% \expandafter\ifx\csname fst@#1\endcsname\relax \@flstylefalse\else\@flstyletrue\fi \setbox\@currbox\color@vbox\normalcolor \vbox\bgroup \hsize\columnwidth \@parboxrestore \@floatboxreset \@setnobreak \ignorespaces} \renewcommand\float@endH{\@endfloatbox\UseTaggingSocket{float/H/end} \vskip\intextsep \if@flstyle\setbox\@currbox\float@makebox\columnwidth\fi \box\@currbox\vskip\intextsep\relax} \ExplSyntaxOff % \end{macrocode} % Float defines two float styles which need to get tagging support. % This here is the plain style which is also used for plaintop and boxed: % \begin{macrocode} \renewcommand\floatc@plain[2]{% \setbox\@tempboxa\hbox{\measuring@true{\@fs@cfont #1:} #2}% \UseTaggingSocket{caption/begin}{\@current@float@struct}% \ifdim\wd\@tempboxa>\hsize \UseTaggingSocket{caption/label/begin}% {\@fs@cfont #1:}% \UseTaggingSocket{caption/label/end}% % \end{macrocode} % The space is intentional! % \begin{macrocode} \UseTaggingSocket{para/begin} % #2\par \else \hbox to \hsize {\hfil \UseTaggingSocket{caption/label/begin}% {\@fs@cfont #1:}% \UseTaggingSocket{caption/label/end}% % \end{macrocode} % The space is intentional! % \begin{macrocode} \UseTaggingSocket{para/begin} % #2% \UseTaggingSocket{para/end}\hfil}% \par \fi % \end{macrocode} % The caption structure is not closed here, but in the \cs{float@caption} % and \cs{float@ccon} commands. % \begin{macrocode} } % \end{macrocode} % This adds tagging support to the ruled style: % \begin{macrocode} \renewcommand\floatc@ruled[2]{% \UseTaggingSocket{caption/begin}{\@current@float@struct}% \UseTaggingSocket{caption/label/begin}% {\@fs@cfont #1}% \UseTaggingSocket{caption/label/end}% % \end{macrocode} % The space is intentional! % \begin{macrocode} \UseTaggingSocket{para/begin} #2\par % % \end{macrocode} % The caption is not closed here but in the \cs{float@caption} % and \cs{float@ccon} commands. % \begin{macrocode} } % \end{macrocode} % The \pkg{float} package adds a final optional argument to caption which can be used to % add text (this is not documented). % We add the \texttt{caption/end} socket after this test, so that it is part of the % caption. We also force a \cs{par} to avoid nested mc with pdflatex. % \begin{macrocode} \long\def\float@caption#1[#2]#3{\par\addcontentsline{\@nameuse{ext@#1}}{#1}% {\protect\numberline{\@nameuse{the#1}}{\ignorespaces #2}} \global\setbox\@floatcapt\vbox\bgroup\@parboxrestore \normalsize\@fs@capt{\@nameuse{fnum@#1}}{\ignorespaces #3}% \@ifnextchar[{\float@ccon}{\UseTaggingSocket{caption/end}\egroup}%] } \long\def\float@ccon[#1]{#1\par\UseTaggingSocket{caption/end}\egroup} % \end{macrocode} % If a new float is declared it should setup the container. We also adapt % the tag of this container: % \begin{macrocode} \renewcommand\newfloat[3]{\@namedef{ext@#1}{#3} \tagpdfsetup{float/new=#1,role/new-tag=#1-floats/Sect}% \AssignStructureRole{float/#1s}{#1-floats}% \let\float@do=\relax \xdef\@tempa{\noexpand\float@exts{\the\float@exts \float@do{#3}}}% \@tempa \floatplacement{#1}{#2}% \@ifundefined{fname@#1}{\floatname{#1}{#1}}{} \expandafter\edef\csname ftype@#1\endcsname{\value{float@type}}% \addtocounter{float@type}{\value{float@type}} \restylefloat{#1}% \expandafter\edef\csname fnum@#1\endcsname% {\expandafter\noexpand\csname fname@#1\endcsname{} \expandafter\noexpand\csname the#1\endcsname} \@ifnextchar[{\float@newx{#1}}%] {\@ifundefined{c@#1}{\newcounter{#1}\@namedef{the#1}{\arabic{#1}}}% {}}} % % \end{macrocode} % % \subsection{The \pkg{apacite} firstaid} % The apacite package redefines \cs{@lbibitem} and removes the arguments. % This means that the patching with a generic hook with arguments fails. So we readd the argument. % \changes{0.85x}{2026-06-08}{Correct braces around argument.} % \begin{macrocode} %<*package> \AddToHook{package/apacite/after} {\if@APAC@natbib@apa\def\@lbibitem[#1]#2{\NAT@swatrue\orig@nat@@@@lbibitem[#1]{#2}}\fi} % \end{macrocode} % \begin{macrocode} % % \end{macrocode}