% \iffalse meta-comment % %% File: latex-lab-listings.dtx (C) Copyright 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 % \def\ltlablistingsdate{2026-09-21} \def\ltlablistingsversion{0.80a} %<*driver> \DocumentMetadata{tagging=on,pdfstandard=ua-2} \documentclass[kernel]{l3in2edoc} \usepackage{longtable,tikz} \EnableCrossrefs \CodelineIndex \usepackage{todonotes} \begin{document} \DocInput{latex-lab-listings.dtx} \end{document} % % % \fi % % % \title{The \textsf{latex-lab-listings} package\\ % Tagging support for the listings package} % \author{\LaTeX{} Project\thanks{Initial implementation done by Ulrike Fischer}} % \date{v\ltlabenumversion\ \ltlabenumdate} % % \maketitle % % \newcommand{\xt}[1]{\textsl{\textsf{#1}}} % \newcommand{\TODO}[1]{\textbf{[TODO:} #1\textbf{]}} % \newcommand{\docclass}{document class \marginpar{\raggedright document class % customizations}} % % \newcommand\insttype[1]{\texttt{#1}} % % % \providecommand\hook[1]{\texttt{#1}} % % \ProvideDocumentCommand\fmi{sO{}m} % {\IfBooleanTF{#1}{\todo[inline,#2]{#3}}^^A % {\todo[#2]{#3}}} % % \begin{abstract} % This adds tagging support to the listings package. % \end{abstract} % % \section{Use} % This package is loaded through a firstaid % automatically after the listings package in a current LaTeX-dev. It can also be loaded manually % after the package itself. % % \section{Open points} % \begin{itemize} % \item frames are not properly tagged (top and bottom at least produce stray structures/mc) % \item mathescape does not work: the math is not tagged as math (but it is not clear if it should) % Reenabling math tagging is not trivial, this probably requires some slow token-by-token % math grabbing. % \item Escapes to latex work, and e.g. \cs{emph} is correctly tagged, but tagging of math is disabled. % It can be reenabled with \cs{MathCollectTrue} inside the escape. Not clear if this can be % activated easily automatically. % \item A command \cs{lstinline} which uses braces to delimit the argument is currently not % tagged as this errors if used inside the argument of another command, see tagging issue % \##1074 % \item more ??? % \end{itemize} % % \begin{macrocode} %<*package> % \end{macrocode} % % \section{Implementation} % \begin{macrocode} \ProvidesPackage{latex-lab-listings}% [\ltlablistingsdate\space v\ltlabenumversion\space tagging-support for the listings package] % \end{macrocode} % We need to patch some commands. % \begin{macrocode} \RequirePackage{etoolbox} % \end{macrocode} % \subsection{Sockets} % % This socket will tag the line numbers % \begin{macrocode} \ExplSyntaxOn \NewTaggingSocket{lstlisting/number}{2} \NewTaggingSocketPlug{lstlisting/number}{default} { \tag_mc_end_push: \tagstructbegin{tag=Lbl} \tagmcbegin{} #2 \tagmcend \tagstructend \tag_mc_begin_pop:n{} } \AssignTaggingSocketPlug{lstlisting/number}{default} \ExplSyntaxOff % \end{macrocode} % We redefine the numbers key to insert the new tagging socket % \begin{macrocode} \lst@Key{numbers}{none}{% \let\lst@PlaceNumber\@empty \lstKV@SwitchCases{#1}% {none:\\% left:\def\lst@PlaceNumber{\llap{\normalfont \UseTaggingSocket{lstlisting/number} {} {\lst@numberstyle{\thelstnumber}}\kern\lst@numbersep}}\\% right:\def\lst@PlaceNumber{\rlap{\normalfont \kern\linewidth \kern\lst@numbersep \UseTaggingSocket{lstlisting/number} {} {\lst@numberstyle{\thelstnumber}}}}% }{\PackageError{Listings}{value `#1' for keyword `numbers' not supported}\@ehc}} % \end{macrocode} % We need new blockenv and block instance for listings. % Spacing is done by listings outside of the block so we can set the vspace to zero. % \begin{macrocode} \DeclareInstance{blockenv}{lstlisting}{std} { name = lstlisting, tag-name = verbatim, tag-attr-class = , tagging-recipe = standard, inner-level-counter = , transparent-level = true, block-instance = lstlisting , inner-instance = , final-code = \AssignStructureRole {para/textblock}% {\UseStructureName{block/verbatim/codeline}}\ignorespaces, tagging-suppress-paras = true } \DeclareInstance{block}{lstlisting-1}{std} { ,left-margin = 0pt ,para-vspace = 0pt ,begin-vspace=0pt ,end-vspace= 0pt } \DeclareInstanceCopy{block}{lstlisting-2}{lstlisting-1} \DeclareInstanceCopy{block}{lstlisting-3}{lstlisting-1} \DeclareInstanceCopy{block}{lstlisting-4}{lstlisting-1} \DeclareInstanceCopy{block}{lstlisting-5}{lstlisting-1} \DeclareInstanceCopy{block}{lstlisting-6}{lstlisting-1} % \end{macrocode} % Now we need to use the new blockenv instance for the display mode. % We insert it with \cs{lst@EveryDisplay}. This % is a bit fishy, as this is not a hook and perhaps some other code will overwrite it, % but the PreInit hook is too late: captions are outside of the structure % if the listing is not a float. % We disable math collection. Perhaps mathescape needs to reenable it. % \begin{macrocode} \def\lst@EveryDisplay{% \MathCollectFalse \ifx\lst@float\relax \SimpleBlockEnv{lstlisting}{}% \else \SimpleBlockEnv{lstlisting}{tagging-recipe = standalone} \fi} % \end{macrocode} % The inline command can use hooks: % \begin{macrocode} \lst@AddToHook{PreInit} {% \ifhmode \UseTaggingSocket{inline/begin}{tag=\UseStructureName{text/verb}}% \fi } % \end{macrocode} % If we have a display, we need the structure number, so that the caption % can find its parent. % \begin{macrocode} \lst@AddToHook{DeInit} {\ifhmode \UseTaggingSocket{inline/end}% \else \edef\@current@float@struct{\UseName{tag_get:n}{struct_num}}\BlockEnvEnd \fi}% % \end{macrocode} % The float type must be setup: % \begin{macrocode} \tagpdfsetup{float/new=lstlisting} % \end{macrocode} % The caption itself can inherit most code from the \cs{@makecaption} definition, % but we must redirect the para tag. % \begin{macrocode} \def\lst@makecaption{% \AssignStructureRole {para/textblock}{\UseStructureName{span}}\def\@captype{lstlisting}\@makecaption} % \end{macrocode} % Titles are captions without labels, so we need to void the socket and we must ensure % that the \cs{@captype} is set even if there is no float: % \begin{macrocode} \def\lst@maketitle{\def\@captype{lstlisting}% \AssignStructureRole {para/textblock}{\UseStructureName{span}} \AssignTaggingSocketPlug{caption/label/begin}{noop}% \AssignTaggingSocketPlug{caption/label/end}{noop}% \AssignSocketPlug{caption/label}{noop}% \@makecaption\lst@title@dropdelim} % \end{macrocode} % If a listings ends with empty lines and the \texttt{showlines} option is false % it stores the remaining lines in a box. We need to suppress tagging there to avoid % a stray structure: % \begin{macrocode} \patchcmd\lst@DeInit{\setbox\@tempboxa\vbox{\lst@DoNewLines}} {\setbox\@tempboxa\vbox{\SuspendTagging{\lst@DeInit}\lst@DoNewLines}}{}{\fail} % \end{macrocode} % To avoid that \cs{lstinline} errors when used inside an argument, we disable math collection % and tagging for now if it is used with braces, see tagging issue \#1074 % \begin{macrocode} \def\lst@InlineG{% \MathCollectFalse\SuspendTagging{}% \lst@Init\relax \lst@IfNextCharActive{\lst@InlineM\}}{% \let\lst@arg\@empty \lst@InlineGJ}} % \end{macrocode} % % At last we handle the spaces by inserting a fake space: \newcommand\lst@invisiblespace{\pdffakespace\ } \lst@AddToHook{Init}{\lst@ifshowspaces\else \let\lst@outputspace\lst@invisiblespace\fi} % \begin{macrocode} % % \end{macrocode}