% \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}
%</driver>
%
% \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}
%</package>
%    \end{macrocode}
