% \iffalse meta-comment % %% File: latex-lab-toc-kernel-changes.dtx (C) Copyright 2022-2023 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 development version of the bundle can be found below % % https://github.com/latex3/latex2e/required/latex-lab % % for those people who are interested or want to report an issue. % % dates for latex-lab-kernel-changes.sty (pulled from various sources, see ins) \def\ltlabkerneldate{2023-10-16} \def\ltlabkernelversion{0.85b} %<*driver> \documentclass{l3doc} \EnableCrossrefs \CodelineIndex \begin{document} \DocInput{latex-lab-toc-kernel-changes.dtx} \end{document} % % % \fi % % \title{The \textsf{latex-lab-toc-kernel-changes} package\\ % Changes and additions to the kernel related to tagging and links in toc entries} % \author{\LaTeX{} Project\thanks{Initial implementation done by Ulrike Fischer}} % \date{Version 0.83 2023-06-07} % % \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}} % % \begin{abstract} % \end{abstract} % % \section{Introduction} % % The followings contains various changes to kernel commands % needed for the tagging of table of contents and similar lists. % \section{General kernel and class changes} % % Some of the changes can probably could go into the kernel. % This are marked with [kernel?], % the other are marked with [latex-lab]. A few changes must be done in the classes. % They are marked as [class]. They are inserted with hooks here: this will break % if a non-standard class is used. % % \subsection{Package declaration} % \begin{macrocode} %<*kernelchange> \ProvidesPackage{latex-lab-kernel-changes} [\ltlabkerneldate\space v\ltlabkernelversion\space General kernel and class changes] % \end{macrocode} % % \subsection{Providing the counter representation \cs{theHxx} generally} % [kernel?] % % The \cs{theHxx} representation allows to create a unique representation of a counter % that is for example used to create destination names. It will also be needed % to add |/Ref| keys to various tagging structures. It makes therefore sense % to provide it by default as soon as a counter is created. The |\@addtoreset| change % (taken also from hyperref) tries to ensure the counter stays unique if it is reset. % % At first we suppress the patches from hyperref: % \begin{macrocode} \def\hyper@nopatch@counter{} % \end{macrocode} % % \begin{macrocode} \def\@definecounter#1{\expandafter\newcount\csname c@#1\endcsname \setcounter{#1}\z@ \global\expandafter\let\csname cl@#1\endcsname\@empty \@addtoreset{#1}{@ckpt}% \global\expandafter\let\csname p@#1\endcsname\@empty \expandafter\gdef\csname theH#1\endcsname{\the\value{#1}}%new \expandafter \gdef\csname the#1\expandafter\endcsname\expandafter {\expandafter\@arabic\csname c@#1\endcsname}} \def\@addtoreset#1#2{\expandafter\@cons\csname cl@#2\endcsname {{#1}}% \expandafter\gdef\csname theH#1\endcsname{\csname theH#2\endcsname.\the\value{#1}}% } % \end{macrocode} % The following counters are defined in the kernel % \begin{macrocode} \gdef\theHenumi{\the\value{enumi}} \gdef\theHenumii{\the\value{enumii}} \gdef\theHenumiii{\the\value{enumiii}} \gdef\theHenumiv{\the\value{enumiv}} \gdef\theHequation{\the\value{equation}} \gdef\theHfootnote{\the\value{footnote}} \gdef\theHmpfootnote{\the\value{mpfootnote}} % \end{macrocode} % % \subsection{Providing and updating \cs{@currentHref}} % [kernel?] % % \cs{@currentHref} contains the current unique representation of a counter. % It is useful also without hyperref as it allows to connect with a |/Ref| % key a toc entry with the heading it refers too. So \cs{refstepcounter} % is extended to update the command. This is done at the begin so that the % hyperref code can still adapt it later (using the cmd/refstepcounter/after hook % would be too late, and could also break with cleverref.) % % We also provide a kernel version that hyperref doesn't touch and so will never % set a target. % \begin{macrocode} \def\@currentHref{} \def\refstepcounter#1{\stepcounter{#1}% \edef\@currentcounter{#1}% \xdef\@currentHref {#1.\csname theH#1\endcsname}% \protected@edef\@currentlabel {\csname p@#1\expandafter\endcsname\csname the#1\endcsname}% } \let\@kernel@refstepcounter\refstepcounter % \end{macrocode} % % \subsection{Assigning the headings level numbers} % [kernel?] % % The code for the toc must be able to compare the level of |subsection| against % |section|. So some numbers are needed. It uses for now the commands used by % |hyperref| for the bookmark levels. While headings are more a class thing, it % could make sense to provide a standard set already in the kernel. % The numbers are a bit different to the one in hyperref, but imho sensible. % % Note for the future: % once that heading stuff is turned into template % instances the template should set that number. % \begin{macrocode} \def\toclevel@document{-10} \def\toclevel@part{-1} \def\toclevel@chapter{0} \def\toclevel@section{1} \def\toclevel@subsection{2} \def\toclevel@subsubsection{3} \def\toclevel@paragraph{4} \def\toclevel@subparagraph{5} \def\toclevel@figure{1} \def\toclevel@table{1} % \end{macrocode} % %\subsection{Storing the relation between target names and structure numbers} % To be able to add a /Ref key to structures the tagging makes use of target names % and stores the relationship in a property. We add a hook to \cs{MakeLinkTarget} to % catch as much as possible, see also tagging issue \#20. This should work also % without hyperref. The property is defined in tagpdf-base, so the code would % work also without tagging but we add a test anyway, this is probably faster. % \begin{macrocode} \ExplSyntaxOn \AddToHookWithArguments{cmd/MakeLinkTarget/after} { \tag_if_active:T { \tl_if_blank:VF \@currentHref { \prop_gput:Nee \g__tag_struct_dest_num_prop {\@currentHref}{\tag_get:n{struct_num}} } } } \ExplSyntaxOff % \end{macrocode} % \begin{macrocode} % % \end{macrocode} % % \subsection{load kernel changes} % \begin{macrocode} %<*package> \RequirePackage{latex-lab-kernel-changes} % \end{macrocode} % % \subsection{\cs{contentsline} extension} % [latex-lab] % The tagging code must add code at the begin and end of \cs{contentsline}. % This code must have access to the arguments. We set it up as config point % for now. % \begin{macrocode} \def\@contentsline@cfgpoint@before#1#2#3#4{} \def\@contentsline@cfgpoint@after#1#2#3#4{} % \end{macrocode} % for the hooks we need that the \cs{l@XX} pass also the destination and % that \cs{l@XX} takes three arguments. % TODO: test that, if there are two many problems we should pass the % destination through a command name ... % \begin{macrocode} \def\contentsline#1#2#3#4% {% \@contentsline@cfgpoint@before{#1}{#2}{#3}{#4}% \gdef\@contentsline@destination{#4}% \csname l@#1\endcsname{#2}{#3}% \@contentsline@cfgpoint@after{#1}{#2}{#3}{#4}% } % \end{macrocode} % % \subsection{\cs{addcontentsline} changes} % [latex-lab] % % \cs{addcontentsline} should always write the unique counter representation % \cs{@currentHref} so that we can create the |/Ref| key. At the same time % we need a hook, so that hyperref can add its bookmarks code, the generic hook % with arguments is ok. % % \begin{macrocode} \def\addcontentsline#1#2#3{% #1=toc extension, #2= heading type, tag \addtocontents{#1}{% \protect\contentsline{#2}{#3}{\thepage}{\@currentHref}\protected@file@percent }} % \end{macrocode} % % \subsection{\cs{@starttoc}} % [kernel?] % % We add a configuration point before and after reading the file % for the tagging. % \begin{macrocode} \def\@starttoc@cfgpoint@before#1{} \def\@starttoc@cfgpoint@after#1{} \def\@starttoc#1{% \begingroup \makeatletter \@starttoc@cfgpoint@before{#1}% \@input{\jobname.#1}% \@starttoc@cfgpoint@after{#1} \if@filesw \expandafter\newwrite\csname tf@#1\endcsname \immediate\openout \csname tf@#1\endcsname \jobname.#1\relax \fi \@nobreakfalse \endgroup} % \end{macrocode} % % \subsection{Formatting of the toc entries} % % \subsubsection{Kernel commands} % [latex-lab] or [kernel?]? % % We need hooks before and after the content and before and after the page number. % The number needs some thing so that it can be tagged as label. % The text and the page % hooks are used in manual \cs{l@xx} commands and in \cs{l@xx} defined by % \cs{@dottedtocline} or by other means. % The arguments of the following hooks are: % \begin{itemize} % \item[\#1] level as a \emph{number} (integer expression), see above for the standard % numbering. The standard first argument of \cs{contentsline} is not used, as % \cs{@dottedtocline} knows only a number. % \item[\#2] content (the second argument of a \cs{contentsline} % \item[\#3] page (the third argument of a \cs{contentsline} % \item[\#3] target (the fourth argument of a \cs{contentsline} % \end{itemize} % \begin{macrocode} \NewMirroredHookPairWithArguments{contentsline/number/before}{contentsline/number/after}{1}% \NewMirroredHookPairWithArguments{contentsline/text/before}{contentsline/text/after}{4}% \NewMirroredHookPairWithArguments{contentsline/page/before}{contentsline/page/after}{4}% % \end{macrocode} % % The dot in the leader must be set as artifact. % But luatex requires that the mc are set outside the leaders. % So we need a config point. % % \cs{@dottedtocline} needs hooks and formatting commands. % We add a sixth argument so that it can grab the destination too. % \begin{macrocode} \def\@dottedtocline@cfgpoint@leaders#1{#1} \def\@dottedtocline#1#2#3#4#5{% \ifnum #1>\c@tocdepth \else \vskip \z@ \@plus.2\p@ {\leftskip #2\relax \rightskip \@tocrmarg \parfillskip -\rightskip \parindent #2\relax\@afterindenttrue \interlinepenalty\@M \leavevmode \@tempdima #3\relax \advance\leftskip \@tempdima \null\nobreak\hskip -\leftskip \UseHookWithArguments{contentsline/text/before}{4}{#1}{#4}{#5}{\@contentsline@destination}% \csname contentsline@text@#1@format\endcsname{#4}% \UseHookWithArguments{contentsline/text/after}{4}{#1}{#4}{#5}{\@contentsline@destination}% \nobreak \@dottedtocline@cfgpoint@leaders{% \leaders\hbox{$\m@th \mkern \@dotsep mu\hbox{.}\mkern \@dotsep mu$}\hfill}% \nobreak \hb@xt@\@pnumwidth{\hfil\normalfont \normalcolor \UseHookWithArguments{contentsline/page/before}{4}{#1}{#4}{#5}{\@contentsline@destination}% #5% \UseHookWithArguments{contentsline/page/after}{4}{#1}{#4}{#5}{\@contentsline@destination}% \kern-\p@\kern\p@}% \par}% \fi} % \end{macrocode} % % \subsubsection{\cs{numberline}} % [kernel?] % Inside or outside the box? % \begin{macrocode} \def\numberline#1{\hb@xt@\@tempdima{% \UseHookWithArguments{contentsline/number/before}{1}{#1}% #1\hfil \UseHookWithArguments{contentsline/number/after}{1}{#1}% }} % \end{macrocode} % % \subsubsection{\cs{l@xx} in the classes} % Depending on the class we have to redefine also more commands % For other classes it should be documented what is needed. % Let the commands grab also the third arguments. If a class redefines them again % it will break tagging anyway. % \begin{macrocode} \AddToHook{class/article/after} { \renewcommand*\l@part[2]{% as in contentsline: content, page \ifnum \c@tocdepth >-2\relax \addpenalty\@secpenalty \addvspace{2.25em \@plus\p@}% \setlength\@tempdima{3em}% \begingroup \parindent \z@ \rightskip \@pnumwidth \parfillskip -\@pnumwidth {\leavevmode \large \bfseries \UseHookWithArguments{contentsline/text/before}{4} {\toclevel@part}{#1}{#2}{\@contentsline@destination}% \csname contentsline@text@-1@format\endcsname{#1}% \UseHookWithArguments{contentsline/text/after}{4} {\toclevel@part}{#1}{#2}{\@contentsline@destination}% \hfil \hb@xt@\@pnumwidth{\hss \UseHookWithArguments{contentsline/page/before}{4} {\toclevel@part}{#1}{#2}{\@contentsline@destination}% #2% \UseHookWithArguments{contentsline/page/after}{4} {\toclevel@part}{#1}{#2}{\@contentsline@destination}% \kern-\p@\kern\p@}}\par \nobreak \endgroup \fi} \renewcommand*\l@section[2]{% \ifnum \c@tocdepth >\z@ \addpenalty\@secpenalty \addvspace{1.0em \@plus\p@}% \setlength\@tempdima{1.5em}% \begingroup \parindent \z@ \rightskip \@pnumwidth \parfillskip -\@pnumwidth \leavevmode \bfseries \advance\leftskip\@tempdima \hskip -\leftskip \UseHookWithArguments{contentsline/text/before}{4} {\toclevel@section}{#1}{#2}{\@contentsline@destination}% \csname contentsline@text@1@format\endcsname{#1}% \UseHookWithArguments{contentsline/text/after}{4} {\toclevel@section}{#1}{#2}{\@contentsline@destination}% \nobreak\hfil \nobreak\hb@xt@\@pnumwidth{\hss \UseHookWithArguments{contentsline/page/before}{4} {\toclevel@section}{#1}{#2}{\@contentsline@destination}% #2% \UseHookWithArguments{contentsline/page/after}{4} {\toclevel@section}{#1}{#2}{\@contentsline@destination}% \kern-\p@\kern\p@}\par \endgroup \fi} } \AddToHook{class/report/after} { \renewcommand*\l@part[2]{% \ifnum \c@tocdepth >-2\relax \addpenalty{-\@highpenalty}% \addvspace{2.25em \@plus\p@}% \setlength\@tempdima{3em}% \begingroup \parindent \z@ \rightskip \@pnumwidth \parfillskip -\@pnumwidth {\leavevmode \large \bfseries \UseHookWithArguments{contentsline/text/before}{4} {\toclevel@part}{#1}{#2}{\@contentsline@destination}% \csname contentsline@text@-1@format\endcsname{#1}% \UseHookWithArguments{contentsline/text/after}{4} {\toclevel@part}{#1}{#2}{\@contentsline@destination}% \hfil \hb@xt@\@pnumwidth{\hss \UseHookWithArguments{contentsline/page/before}{4} {\toclevel@part}{#1}{#2}{\@contentsline@destination}% #2% \UseHookWithArguments{contentsline/page/after}{4} {\toclevel@part}{#1}{#2}{\@contentsline@destination}% \kern-\p@\kern\p@}}\par \nobreak \endgroup \fi} \renewcommand*\l@chapter[2]{% \ifnum \c@tocdepth >\m@ne \addpenalty{-\@highpenalty}% \vskip 1.0em \@plus\p@ \setlength\@tempdima{1.5em}% \begingroup \parindent \z@ \rightskip \@pnumwidth \parfillskip -\@pnumwidth \leavevmode \bfseries \advance\leftskip\@tempdima \hskip -\leftskip \UseHookWithArguments{contentsline/text/before}{4} {\toclevel@chapter}{#1}{#2}{\@contentsline@destination}% \csname contentsline@text@0@format\endcsname {#1}% \UseHookWithArguments{contentsline/text/after}{4} {\toclevel@chapter}{#1}{#2}{\@contentsline@destination}% \nobreak\hfil \nobreak\hb@xt@\@pnumwidth{\hss \UseHookWithArguments{contentsline/page/before}{4} {\toclevel@chapter}{#1}{#2}{\@contentsline@destination}%% #2% \UseHookWithArguments{contentsline/page/after}{4} {\toclevel@chapter}{#1}{#2}{\@contentsline@destination}%% \kern-\p@\kern\p@}\par \penalty\@highpenalty \endgroup \fi} } \AddToHook{class/book/after} { \renewcommand*\l@part[2]{% \ifnum \c@tocdepth >-2\relax \addpenalty{-\@highpenalty}% \addvspace{2.25em \@plus\p@}% \setlength\@tempdima{3em}% \begingroup \parindent \z@ \rightskip \@pnumwidth \parfillskip -\@pnumwidth {\leavevmode \large \bfseries \UseHookWithArguments{contentsline/text/before}{4} {\toclevel@part}{#1}{#2}{\@contentsline@destination}%% \csname contentsline@text@-1@format\endcsname{#1}% \UseHookWithArguments{contentsline/text/after}{4} {\toclevel@part}{#1}{#2}{\@contentsline@destination}%% \hfil \hb@xt@\@pnumwidth{\hss \UseHookWithArguments{contentsline/page/before}{4} {\toclevel@part}{#1}{#2}{\@contentsline@destination}%% #2% \UseHookWithArguments{contentsline/page/after}{4} {\toclevel@part}{#1}{#2}{\@contentsline@destination}%% \kern-\p@\kern\p@}}\par \nobreak \endgroup \fi} \renewcommand*\l@chapter[2]{% \ifnum \c@tocdepth >\m@ne \addpenalty{-\@highpenalty}% \vskip 1.0em \@plus\p@ \setlength\@tempdima{1.5em}% \begingroup \parindent \z@ \rightskip \@pnumwidth \parfillskip -\@pnumwidth \leavevmode \bfseries \advance\leftskip\@tempdima \hskip -\leftskip \UseHookWithArguments{contentsline/text/before}{4} {\toclevel@chapter}{#1}{#2}{\@contentsline@destination}% \csname contentsline@text@0@format\endcsname {#1}% \UseHookWithArguments{contentsline/text/after}{4} {\toclevel@chapter}{#1}{#2}{\@contentsline@destination}% \nobreak\hfil \nobreak\hb@xt@\@pnumwidth{\hss \UseHookWithArguments{contentsline/page/before}{4} {\toclevel@chapter}{#1}{#2}{\@contentsline@destination}% #2% \UseHookWithArguments{contentsline/page/after}{4} {\toclevel@chapter}{#1}{#2}{\@contentsline@destination}% \kern-\p@\kern\p@}\par \penalty\@highpenalty \endgroup \fi} } % \end{macrocode} % \begin{macrocode} % % \end{macrocode}