% \iffalse meta-comment
%
%% File: latex-lab-amsmath.dtx
%
% Copyright (C) 2022-2026 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
% 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
%
%<*driver>
\DocumentMetadata{tagging=on,pdfstandard=ua-2}
\documentclass{l3in2edoc}

\EnableCrossrefs
\CodelineIndex
\begin{document}
  \DocInput{latex-lab-amsmath.dtx}
\end{document}
%</driver>
%
% \fi
%
%
% \title{The \texttt{latex-lab-amsmath} code\thanks{}}
% \author{\LaTeX{} Project}
%
% \maketitle
%
% \newcommand\fmi[1]{\begin{quote} TODO: \itshape #1\end{quote}}
% \newcommand\NEW[1]{\marginpar{\mbox{}\hfill\fbox{New: #1}}}
% \providecommand\class[1]{\texttt{#1.cls}}
% \providecommand\pkg[1]{\texttt{#1}}
% \providecommand\hook[1]{\texttt{#1}}
%
% \begin{abstract}
% \end{abstract}
%
% \tableofcontents
%
% \section{Introduction}
%
% This file implements adaptations to the \pkg{amsmath} package needed for
% the tagging project.
%
% \MaybeStop{\setlength\IndexMin{200pt}  \PrintIndex  }
%
% \section{The Implementation}
%
% Better no @@ expansion here \ldots ...
%    \begin{macrocode}
%<@@=>
%    \end{macrocode}
%
%    \begin{macrocode}
%<*kernel>
%    \end{macrocode}
%
% \subsection{File declaration}
%    \begin{macrocode}
\ProvidesFile{latex-lab-amsmath.ltx}
        [2026-04-25 v0.1j amsmath adaptions]
%    \end{macrocode}
%
%    \begin{macrocode}
\ExplSyntaxOn
%    \end{macrocode}
%
% \subsection{Measuring}
% When measuring we neither want tagging nor the luamml processing.
% \changes{0.1h}{2025-06-20}{moved redefinition to begin document, see tagging-project issue \#920}
% \begin{macro}{\measuring@true}
%    \begin{macrocode}
\AddToHook{begindocument}
 {
   \def\measuring@true{\let\ifmeasuring@\iftrue\tag_suspend:n{\measuring}\luamml_ignore:}
 } 
%    \end{macrocode}
% \end{macro}
%
% \subsection{Display environments}
% \changes{0.1e}{2025-01-31}{moved redefinitions from latex-lab-math and luamml into this file}
%
% \subsubsection{Tag}
%  The tag/label must be saved, so that it can be reinserted later.
%
%  TODO: \cs{maketag@@@} is perhaps used in places where tagging/luamml handling
%  is not wanted. This must be checked and handled.
% \begin{macro}{\maketag@@@}
%    \begin{macrocode}
\def\maketag@@@#1
  {%
    \ifmeasuring@
      \hbox{\m@th\normalfont#1}%
    \else
      \UseTaggingSocket{math/display/tag/begin}
      \hbox{\m@th\normalfont#1
      \UseTaggingSocket{math/luamml/mtable/tag/save}
      }%
      \UseTaggingSocket{math/display/tag/end}
    \fi
   }
%    \end{macrocode}
% \end{macro}
% \cs{eqref} uses \cs{tagform@} and so \cs{maketag@@@} but we do not want this tagging
% there.
%
% \begin{macro}{\eqref}
% \begin{macro}{\maketag@@@notog}
%    \begin{macrocode}
\def\maketag@@@notag#1{\hbox{\m@th\normalfont#1}}
\DeclareRobustCommand{\eqref}[1]
  {\textup{\let\maketag@@@\maketag@@@notag\tagform@{\ref{#1}}}}
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \subsubsection{align \& friends}
%
% Most display environment uses a common command for the end which contains
% the luamml socket to finalize the mtable.
% \begin{macro}{\common@align@ending}
%    \begin{macrocode}
\def\common@align@ending {
  \math@cr \black@\totwidth@
  \UseExpandableTaggingSocket {math/luamml/mtable/finalize} {\@currenvir}
  \egroup
  \ifingather@
    \restorealignstate@
    \egroup
    \nonumber
    \ifnum0=`{\fi\iffalse}\fi
  \else
    \dollardollar@end
  \fi
  \ignorespacesafterend
}
%    \end{macrocode}
% \end{macro}
% Now we redefine the display alignments to use these ending.
%    \begin{macrocode}
\renewenvironment{align}{%
  \start@align\@ne\st@rredfalse\m@ne
}{%
  \common@align@ending
}
\renewenvironment{align*}{%
  \start@align\@ne\st@rredtrue\m@ne
}{%
  \common@align@ending
}
\renewenvironment{alignat}{%
  \start@align\z@\st@rredfalse
}{%
  \common@align@ending
}
\renewenvironment{alignat*}{%
  \start@align\z@\st@rredtrue
}{%
  \common@align@ending
}
\renewenvironment{flalign}{%
  \start@align\tw@\st@rredfalse\m@ne
}{%
  \common@align@ending
}
\renewenvironment{flalign*}{%
  \start@align\tw@\st@rredtrue\m@ne
}{%
  \common@align@ending
}
\renewenvironment{xalignat}{%
  \start@align\@ne\st@rredfalse
}{%
  \common@align@ending
}
\renewenvironment{xalignat*}{%
  \start@align\@ne\st@rredtrue
}{%
  \common@align@ending
}
\renewenvironment{xxalignat}{%
  \start@align\tw@\st@rredtrue
}{%
  \common@align@ending
}
%    \end{macrocode}
%
% And register these environments for the math grabbing.
%    \begin{macrocode}
  \math_register_halign_env:nn {align}{}
  \math_register_halign_env:nn {align*}{}
  \math_register_halign_env:nn {alignat}{}
  \math_register_halign_env:nn {alignat*}{}
  \math_register_halign_env:nn {flalign}{}
  \math_register_halign_env:nn {flalign*}{}
  \math_register_halign_env:nn {xalignat}{}
  \math_register_halign_env:nn {xalignat*}{}
  \math_register_halign_env:nn {xxalignat}{}
%    \end{macrocode}
%
% The align preamble (used in \cs{align@}) needs code for luamml
% to save the cells.
% \begin{macro}{\align@preamble}
%    \begin{macrocode}
\def\align@preamble{%
   &\hfil
    \strut@
    \setboxz@h
      {
        \@lign
         $
          \m@th\displaystyle{##}
         \ifmeasuring@
          \luamml_ignore:
         \else
          \UseTaggingSocket{math/luamml/save/nNn}{ {} \displaystyle {mtd} }
         \fi
         $
      }%
    \ifmeasuring@
      \savefieldlength@
    \else
      \UseTaggingSocket{math/luamml/mtable/finalizecol}{box}
    \fi
    \set@field
    \tabskip\z@skip
   &\setboxz@h
      {
        \@lign
         $
           \m@th\displaystyle{{}##}
           \ifmeasuring@
           \luamml_ignore:
           \else
           \UseTaggingSocket{math/luamml/save/nNn}{ {} \displaystyle {mtd} }
           \fi
         $
      }%
    \ifmeasuring@
      \savefieldlength@
    \else
      \UseTaggingSocket{math/luamml/mtable/finalizecol}{box}
    \fi
    \set@field
    \hfil
    \tabskip\alignsep@
}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\math@cr@@@align}
%    \begin{macrocode}
\def\math@cr@@@align{%
  \ifst@rred\nonumber\fi
  \if@eqnsw \global\tag@true \fi
  \global\advance\row@\@ne
  \add@amps\maxfields@
  \omit
  \kern-\alignsep@
  \iftag@
    \setboxz@h{\@lign\strut@{\make@display@tag}}%
    \place@tag
  \fi
  \UseTaggingSocket{math/luamml/mtable/tag/set}
  \ifst@rred\else\global\@eqnswtrue\fi
  \global\lineht@\z@
  \cr
}
%    \end{macrocode}
% \end{macro}
%
% \subsubsection{\texttt{gather} and \texttt{gather*}}
%
% \begin{macro}{\gather@}
%    \begin{macrocode}
\def\gather@#1{%
    \ingather@true \let\split\insplit@
    \let\tag\tag@in@align \let\label\label@in@display
    \chardef\dspbrk@context\z@
    \intertext@ \displ@y@ \Let@
    \let\math@cr@@@\math@cr@@@gather
    \gmeasure@{#1}%
    \global\shifttag@false
    \tabskip\z@skip
    \global\row@\@ne
    \halign to\displaywidth\bgroup
        \strut@
        \setboxz@h
          {
           $\m@th\displaystyle{##}
            \UseTaggingSocket{math/luamml/save/nNn}{ {} \displaystyle {mtd} }
           $
          }%
        \UseTaggingSocket{math/luamml/mtable/finalizecol}{box}
        \calc@shift@gather
        \set@gather@field
        \tabskip\@centering
       &\setboxz@h{\strut@{##}}%
       \place@tag@gather
       \UseTaggingSocket{math/luamml/mtable/tag/set}
        \tabskip \iftagsleft@ \gdisplaywidth@ \else \z@skip \span\fi
        \crcr
        #1%
}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\endgather}
%    \begin{macrocode}
\def\endgather{
      \math@cr
      \black@ \totwidth@
      \UseExpandableTaggingSocket{math/luamml/mtable/finalize} {gather}
  \egroup
  \dollardollar@end
  \ignorespacesafterend
}
%    \end{macrocode}
% \end{macro}
%
% The original definition of \texttt{gather*} uses \cs{endgather}
% but this redirection doesn't work if we alter \texttt{gather} so we use
% the real meaning and add the socket.
% \begin{environment}{gather*}
%    \begin{macrocode}
\renewenvironment{gather*}
 {
   \start@gather\st@rredtrue
 }
 {
    \math@cr
    \black@\totwidth@
    \UseExpandableTaggingSocket{math/luamml/mtable/finalize} {gather}
   \egroup
   \dollardollar@end
   \ignorespacesafterend
 }
%    \end{macrocode}
% \end{environment}
%
% Register both environments
%    \begin{macrocode}
\math_register_halign_env:nn {gather}{}
\math_register_halign_env:nn {gather*}{}
%    \end{macrocode}
%
% \subsubsection{gathered, aligned and alignedat}
% These environments are not grabbed as they are inside other display
% environments but they need various sockets for luamml support.
% \begin{macro}{\start@aligned}
%    \begin{macrocode}
\renewcommand{\start@aligned}[2]{
  \RIfM@
  \else
    \nonmatherr@ {\begin{\@currenvir}}
  \fi
  \savecolumn@ % Assumption: called inside a group
  \UseTaggingSocket{math/luamml/annotate/false}{}{ \alignedspace@left }
  \ams@start@box {#1} \bgroup
    \maxfields@ #2 \relax
    \ifnum \maxfields@ > \m@ne
      \multiply \maxfields@ \tw@
      \let \math@cr@@@ \math@cr@@@alignedat
      \alignsep@ \z@skip
    \else
      \let \math@cr@@@ \math@cr@@@aligned
      \alignsep@ \minalignsep
    \fi
    \Let@ \chardef \dspbrk@context \@ne
    \default@tag
    \spread@equation % no-op if already called
    \global \column@ \z@
    \ialign \bgroup
      & \column@plus
        \hfil
        \strut@
        $
          \m@th
          \displaystyle
          {##}
          \UseTaggingSocket{math/luamml/save/nNn}{ {} \displaystyle {mtd} }
        $
        \UseTaggingSocket{math/luamml/mtable/finalizecol}{last}
        \tabskip \z@skip
      & \column@plus
        $
          \m@th
          \displaystyle
          {
            {}
            ##
          }
          \UseTaggingSocket{math/luamml/save/nNn}{ {} \displaystyle {mtd} }
        $
        \UseTaggingSocket{math/luamml/mtable/finalizecol}{last}
        \hfil
        \tabskip\alignsep@
      \crcr
      \ams@return@opt@arg
}
%    \end{macrocode}
% \end{macro}
%
% \begin{environment}{gathered}
%    \begin{macrocode}
\renewenvironment{gathered}[1][c]{%
    \RIfM@\else
        \nonmatherr@{\begin{gathered}}%
    \fi
%    \end{macrocode}
% This annotates the space
%    \begin{macrocode}
    \UseTaggingSocket{ math/luamml/annotate/false } {}{ \alignedspace@left }
    \ams@start@box{#1}\bgroup
        \Let@ \chardef\dspbrk@context\@ne \restore@math@cr
        \spread@equation
        \ialign\bgroup
            \hfil\strut@$\m@th\displaystyle##
%    \end{macrocode}
% This save the cell and then finalize it.
%    \begin{macrocode}
            \UseTaggingSocket{math/luamml/save/nNn}{ {} \displaystyle {mtd} }
            $
            \UseTaggingSocket{math/luamml/mtable/finalizecol}{last}
            \hfil
            \crcr
    \ams@return@opt@arg
}{%
  \endaligned
}
%    \end{macrocode}
% \end{environment}
%
% \begin{macro}{\endaligned}
% \changes{v0.1k}{2026-04-26}{Apply change in amsmath v2.18b}
%    \begin{macrocode}
\def\endaligned
 {
    \relax
    \ifnum\column@>\z@
       \math@cr@@@
    \else
       \crcr
    \fi
      \UseExpandableTaggingSocket{math/luamml/mtable/innertable/save}
    \egroup
    \restorecolumn@
  \egroup
  \UseTaggingSocket{math/luamml/mtable/innertable/finalize}
 }
%    \end{macrocode}
% \end{macro}
%
% \subsubsection{multline and multline*}
%
% \texttt{multline*} needs a redefinition before it is registered as it uses
% \cs{endmultline}, this must be replaced by the true code.
%
% \begin{environment}{multline*}
%    \begin{macrocode}
\renewenvironment{multline*}{\start@multline\st@rredtrue}
 {%
  \iftagsleft@ \@xp\lendmultline@ \else \@xp\rendmultline@ \fi
  \ignorespacesafterend
 }
%    \end{macrocode}
% \end{environment}
%
% And now we register both
%    \begin{macrocode}
\math_register_halign_env:nn {multline}{}
\math_register_halign_env:nn {multline*}{}
%    \end{macrocode}
%
% In the internal commands we have to add sockets for alignment attributes
% \begin{macro}{\multline@}
%    \begin{macrocode}
\def\multline@#1{%
    \Let@
    \@display@init{\global\advance\row@\@ne \global\dspbrk@lvl\m@ne}%
    \chardef\dspbrk@context\z@
    \restore@math@cr
    \let\tag\tag@in@align
    \global\tag@false \global\let\raise@tag\@empty
    \mmeasure@{#1}%
    \let\tag\gobble@tag \let\label\@gobble
    \tabskip \if@fleqn \@mathmargin \else \z@skip \fi
    \totwidth@\displaywidth
    \if@fleqn
        \advance\totwidth@-\@mathmargin
    \fi
    \halign\bgroup
        \hbox to\totwidth@{%
            \if@fleqn
                \hskip \@centering \relax
            \else
                \hfil
            \fi
            \strut@
            $\m@th\displaystyle{}##\endmultline@math
            \hfil
        }%
        \crcr
        \if@fleqn
            \hskip-\@mathmargin
            \def\multline@indent{\hskip\@mathmargin}% put it back
        \else
            \hfilneg
            \def\multline@indent{\hskip\multlinegap}%
        \fi
        \iftagsleft@
            \iftag@
                \begingroup
                    \ifshifttag@
                        \rlap{\vbox{%
                                \normalbaselines
                                \hbox{%
                                    \strut@
                                    \make@display@tag
                                }%
                                \vbox to\lineht@{}%
                                \raise@tag
                        }}%
                        \multline@indent
                    \else
                        \setbox\z@\hbox{\make@display@tag}%
                        \dimen@\@mathmargin \advance\dimen@-\wd\z@
                        \ifdim\dimen@<\multlinetaggap
                          \dimen@\multlinetaggap
                        \fi
                        \box\z@ \hskip\dimen@\relax
                    \fi
                \endgroup
            \else
                \multline@indent
            \fi
        \else
            \multline@indent
        \fi
    \ifmeasuring@ \else
      \UseTaggingSocket{math/luamml/mtable/aligncol} {left}
    \fi
    #1%
    \ifmeasuring@ \else
      \UseTaggingSocket{math/luamml/mtable/aligncol} {right}
    \fi
}
%    \end{macrocode}
% \end{macro}
%
% Luckily, \texttt{multline} uses \cs{endmultline@math} in exactly
% the spot where we have to set the flag.
% Less luckily, \cs{endmultline@math} sometimes get overwritten for the last line.
% But that isn't much of a problem since we want special behavior there anyway.
% \begin{macro}{\endmultline@math}
%    \begin{macrocode}
\def\endmultline@math
 {
   \UseTaggingSocket{math/luamml/save/nNn}{ {} \displaystyle {mtd} }
   $
   \UseTaggingSocket{math/luamml/mtable/finalizecol}{last}
 }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\rendmultline@}
%    \begin{macrocode}
\def\rendmultline@{%
    \iftag@
%    \end{macrocode}
% we need to surround the math token with tagging sockets.
%    \begin{macrocode}
      \UseTaggingSocket{math/luamml/save/nNn}{ {} \displaystyle {mtd} }
      $
      \UseTaggingSocket{math/luamml/mtable/finalizecol}{last}
        \let\endmultline@math\relax
            \ifshifttag@
                \hskip\multlinegap
                \llap{\vtop{%
                    \raise@tag
                    \normalbaselines
                    \setbox\@ne\null
                    \dp\@ne\lineht@
                    \box\@ne
                    \hbox{\strut@\make@display@tag}%
                }}%
            \else
                \hskip\multlinetaggap
                \make@display@tag
            \fi
%    \end{macrocode}
% Here we set the tag TODO: is that sensible with multline? Where is the tag saved?
%    \begin{macrocode}
    \UseTaggingSocket{math/luamml/mtable/tag/set}
    \else
        \hskip\multlinegap
    \fi
    \hfilneg
        \math@cr
%    \end{macrocode}
% Now we finalize the mtable.
%    \begin{macrocode}
       \UseExpandableTaggingSocket {math/luamml/mtable/finalize} {multline}
  \egroup
  \dollardollar@end
}
%    \end{macrocode}
% \end{macro}
% And something similar for the left version
% \begin{macro}{\lendmultline@}
%    \begin{macrocode}
\def\lendmultline@{%
        \hfilneg
        \hskip\multlinegap
        \math@cr
        \UseExpandableTaggingSocket {math/luamml/mtable/finalize} {multline}
    \egroup
    \dollardollar@end
}
%    \end{macrocode}
% \end{macro}
%
% \subsection{Cases}
%
% \begin{macro}{env@cases}
%    \begin{macrocode}
\def\env@cases{%
  \let\@ifnextchar\new@ifnextchar
  \left\lbrace
  \def\arraystretch{1.2}%
  \array{@{}l@{\quad}l@{\luamml_ignore:}}%
}
%    \end{macrocode}
% \end{macro}
%
% \subsubsection{smallmatrix}

% \begin{environment}{smallmatrix}
%    \begin{macrocode}
\renewenvironment {smallmatrix} {
  \UseTaggingSocket{ math/luamml/annotate/false } {} { \null\, }
  \vcenter \bgroup
    \Let@
    \restore@math@cr
    \default@tag
    \baselineskip 6 \ex@
    \lineskip 1.5 \ex@
    \lineskiplimit \lineskip
    \ialign \bgroup
        \hfil
        $
        \m@th
        \scriptstyle
        ##
        % No \scriptsize here since we want to add the mstyle nodes
        \UseTaggingSocket{math/luamml/save/nn}{ {} {mtd} }
        $
        \UseTaggingSocket{math/luamml/mtable/finalizecol}{last}
        \hfil
      &&
        \thickspace
        \hfil
        $
        \m@th
        \scriptstyle
        ##
        % No \scriptsize here since we want to add the mstyle nodes
        \UseTaggingSocket{math/luamml/save/nn}{ {} {mtd} }
        $
        \UseTaggingSocket{math/luamml/mtable/finalizecol}{last}
        \hfil
      \crcr
}{%
      \crcr
      \UseExpandableTaggingSocket{math/luamml/mtable/smallmatrix/save}
    \egroup
  \egroup
  \UseTaggingSocket{math/luamml/mtable/innertable/finalize}
  \UseTaggingSocket{ math/luamml/annotate/false } {}{ \, }
}
%    \end{macrocode}
% \end{environment}
%
% \subsection{The split environment}
%
% The split environment is not trivial to handle as it has a rather convoluted
% implementation in amsmath: depending on in which display environment it is embedded
% it takes different branches, which makes it difficult to finalize the mtable.
%
% The following patches work with leqno and reqno if the (default) \texttt{centertags}
% are used.
% The currently fail (the structure is wrong) if the option \texttt{tbtags} is used.
% The alignment of the cells is currently not handled.
% A simple debug command until everything is sorted.
% \begin{macro}{\__math_split_debug_typeout:n}
%    \begin{macrocode}
\cs_new:Npn\__math_split_debug_typeout:n#1{\use_none:n{#1}}
%    \end{macrocode}
% \end{macro}
% We need to detect if \cs{gather@split} has been used or not
% \begin{macro}{\l__math_gathersplit_bool}
%    \begin{macrocode}
\bool_new:N\l__math_gathersplit_bool
%    \end{macrocode}
% \end{macro}
% At first a redefinition of the main environment. Here we only have to add
% the saving command for the inner table:
% \begin{environment}{split}
%    \begin{macrocode}
\renewenvironment{split}{%
  \__math_split_debug_typeout:n {begin~split}
  \if@display
    \ifinner
       \@xp\@xp\@xp\split@aligned
    \else
      \ifst@rred \else \global\@eqnswtrue \fi
    \fi
  \else
    \let\endsplit\@empty \@xp\collect@body\@xp\split@err
  \fi
  \collect@body\gather@split
}{\__math_split_debug_typeout:n{end~split}%
     \crcr
    \UseExpandableTaggingSocket{math/luamml/mtable/innertable/save}%
    \egroup
  \egroup
  \iftagsleft@ \@xp\lendsplit@ \else \@xp\rendsplit@ \fi
}
%    \end{macrocode}
% \end{environment}
%
% In \cs{gather@split} we have to add the finalization socket.
% We also set the boolean to true so that we can detect if
% the finalization has already happened. Perhaps this
% could be done in the luamml code instead?
% \begin{macro}{\gather@split}
%    \begin{macrocode}
\def\gather@split#1#2#3{
  \__math_split_debug_typeout:n{gather@split}%
  \@xp\endgroup \reset@equation % math@cr will handle equation numbering
  \iftag@
     \toks@\@xp{\df@tag}%
     \edef\split@tag{%
       \gdef\@nx\df@tag{\the\toks@}%
       \global\@nx\tag@true \@nx\nonumber
     }%
  \else \let\split@tag\@empty
  \fi
  \bool_set_true:N\l__math_gathersplit_bool
  \spread@equation
  \vcenter\bgroup
    \gather@{\split@tag
    \begin{split}#1\end{split}}%
    \def\endmathdisplay@a{%
      \__math_split_debug_typeout:n{endmathdisplay@a}
      \__math_split_debug_typeout:n{finalize~innertable~endmathdisplay@a}
      \math@cr
      \black@ \totwidth@
      \egroup
      \egroup
      \UseExpandableTaggingSocket{math/luamml/mtable/innertable/finalize}%
    }%
}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\insplit@}
% In \cs{insplit@} we have to add the sockets which store the cell content.
%    \begin{macrocode}
\def\insplit@{\__math_split_debug_typeout:n{insplit@}%
  \global\setbox\z@\vbox\bgroup
    \Let@ \chardef\dspbrk@context\@ne \restore@math@cr
    \default@tag % disallow use of \tag here
    \ialign\bgroup
      \hfil
      \strut@
      $\m@th\displaystyle {##}%
      \UseTaggingSocket{math/luamml/save/nNn}{ {} \displaystyle {mtd} }%
      $%
      \UseTaggingSocket{math/luamml/mtable/finalizecol}{last}%
      &$\m@th\displaystyle {{}##}%
      \UseTaggingSocket{math/luamml/save/nNn}{ {} \displaystyle {mtd} }%
      $%
      \UseTaggingSocket{math/luamml/mtable/finalizecol}{last}%
      \hfill % Why not \hfil?---dmj, 1994/12/28
      \crcr
}
%    \end{macrocode}
% \end{macro}
% And now the difficult part. Depending on the options leqno/reqno \cs{lendsplit@}
% or \cs{rendsplit@} are used for the typesetting and the inner table must
% be finalized here in case this hasn't happen yet. This must be tested with the
% boolean from \cs{gather@split}
%    \begin{macrocode}
\def\lendsplit@{%
    \global\setbox9\vtop{\unvcopy\z@}%
    \ifinalign@
        \setbox\@ne\vbox{%
            \unvcopy\z@
            \global\setbox8\lastbox
        }%
        \setbox\@ne\hbox{%
            \unhcopy8%
            \unskip
            \setbox\tw@\lastbox
            \unskip
            \global\setbox\thr@@\lastbox
        }%
        \__math_split_debug_typeout:n{lendsplit@/aligncase}
        \ifctagsplit@
         \__math_split_debug_typeout:n{lendsplit@/aligncase/centertags}
            \gdef\split@{%
                \hbox to\wd\thr@@{}%
               &\vcenter{\vbox{\moveleft\wd\thr@@\box9}}%
               \__math_split_debug_typeout:n{finalize~innertable~aligncase}
               \UseTaggingSocket{math/luamml/mtable/innertable/finalize}%
            }%
        \else
        %TODO, not correct yet.
         \__math_split_debug_typeout:n{lendsplit@/aligncase/tbtags}
            \gdef\split@{%
                \hbox to\wd\thr@@{}%
               &\vbox{\moveleft\wd\thr@@\box9}%
               \__math_split_debug_typeout:n{finalize~innertable~aligncase}
               \UseTaggingSocket{math/luamml/mtable/innertable/finalize}%
            }%
        \fi
    \else
%    \end{macrocode}
% If not in align we need to test for \cs{gather@split}
%    \begin{macrocode}
        \ifctagsplit@
           \bool_if:NTF \l__math_gathersplit_bool
            {
              \__math_split_debug_typeout:n{lendsplit/equationcase/centertags}
              \gdef\split@%
               {\UseTaggingSocket{math/luamml/annotate/false}{}{\vcenter{\box9}}}
            }
            {
              \__math_split_debug_typeout:n {lendsplit/gathercase/centertags}
              \gdef\split@{\vcenter{\box9}%
              \__math_split_debug_typeout:n {finalize~innertable~gathercase}
              \UseTaggingSocket{math/luamml/mtable/innertable/finalize}}
            }
        \else
          % TODO tbtags not correct yet.
           \bool_if:NTF \l__math_gathersplit_bool
            {
              \__math_split_debug_typeout:n {lendsplit/equationcase/tbtags}
              \gdef\split@%
               {\UseTaggingSocket{math/luamml/annotate/false}{}{\box9}}
            }
            {
              \__math_split_debug_typeout:n {lendsplit/gathercase/tbtags}
              \gdef\split@{
                \box9%
                \__math_split_debug_typeout:n {finalize~innertable~gathercase}
                \UseTaggingSocket{math/luamml/mtable/innertable/finalize}}
            }
        \fi
    \fi
    \aftergroup\split@
}
%    \end{macrocode}
%
% \begin{macro}{\rendsplit@}
% And more or less the same for the \cs{rendsplit@} environment.
%    \begin{macrocode}
\def\rendsplit@{%
    \ifinalign@
        \global\setbox9 \vtop{%
            \unvcopy\z@
            \global\setbox8 \lastbox
            \unskip
        }%
        \setbox\@ne\hbox{%
            \unhcopy8
            \unskip
            \global\setbox\tw@\lastbox
            \unskip
            \global\setbox\thr@@\lastbox
        }%
        \ifctagsplit@
            \gdef\split@{%
                \hbox to\wd\thr@@{}
                &\vcenter{\vbox{\moveleft\wd\thr@@\boxz@}}%
            \__math_split_debug_typeout:n {rendsplit/aligncase/centertags}
            \__math_split_debug_typeout:n {finalize~innertable~aligncase}
            \UseTaggingSocket{math/luamml/mtable/innertable/finalize}
            }%
        \else
           \__math_split_debug_typeout:n{rendsplit@/aligncase/tbtags}
           %TODO tbtags is not correct yet
            \global\setbox7 \hbox{\unhbox\tw@\unskip}%
            \gdef\split@{%
                \global\@tempcnta\column@
               &\setboxz@h{}%
                \savetaglength@
                \global\advance\row@\@ne
                \vbox{\moveleft\wd\thr@@\box9}%
               \crcr
                \noalign{\global\lineht@\z@}%
                \add@amps\@tempcnta
                \UseTaggingSocket{math/luamml/annotate/false}{}{\box\thr@@}
               &\box7
                 \__math_split_debug_typeout:n {finalize~innertable~aligncase}
                 \UseTaggingSocket{math/luamml/mtable/innertable/finalize}%
            }%
        \fi
%    \end{macrocode}
% and again the if we are not in align we need to test for \cs{gathersplit}
%    \begin{macrocode}
    \else
        \ifctagsplit@
          \bool_if:NTF \l__math_gathersplit_bool
            {
              \__math_split_debug_typeout:n {rendsplit/equationcase/centertags}
              \gdef\split@%
               {\UseTaggingSocket{math/luamml/annotate/false}{}{\vcenter{\boxz@}}}
            }
            {
              \__math_split_debug_typeout:n  {rendsplit/gathercase/centertags}
              \gdef\split@{\vcenter{\boxz@}%
               \__math_split_debug_typeout:n {finalize~innertable~gathercase}
               \UseTaggingSocket{math/luamml/mtable/innertable/finalize}}
            }
        \else
           \bool_if:NTF \l__math_gathersplit_bool
            {
              \__math_split_debug_typeout:n {rendsplit/equationcase/tbtags}
              \gdef\split@{%
                \UseTaggingSocket{math/luamml/annotate/false}{}{\boxz@}}
            }
            {
              \__math_split_debug_typeout:n {rendsplit/gathercase/tbtags}
              \gdef\split@{%
                \boxz@
                \UseTaggingSocket{math/luamml/mtable/innertable/finalize}}
            }
        \fi
    \fi
    \aftergroup\split@
}
%    \end{macrocode}
% \end{macro}
% \subsection{\cs{intertext}}
% The \cs{intertext} command errors with active tagging as it is processed twice
% which leads to duplicated structures.
%
% \begin{macro}{\intertext@}  
%    \begin{macrocode}
\NewTaggingSocket  {math/intertext}{2}
\NewTaggingSocketPlug {math/intertext}{kernel}
 {
  \tag_mc_end_push:
  \tagpdfparaOn
  #2
  \tagpdfparaOff
  \tag_mc_begin_pop:n{}
 }
\AssignTaggingSocketPlug{math/intertext}{kernel} 
%    \end{macrocode}
% This can go once luamml defines the plug directly
%    \begin{macrocode}
\IfSocketPlugExistsF {math/intertext}{luamml}
 {
   \int_new:N \l__luamml_struct_tmpa_int
   \NewTaggingSocketPlug{math/intertext}{luamml}
     {
       \tag_mc_end_push:
        \tag_struct_begin:n{
          tag = mtext,
          stash,
        }
        \int_set:Nn \l__luamml_struct_tmpa_int { \tag_get:n{struct_num} }
        \tag_mc_begin:n{}
        #2
        \tag_mc_end:
        \tag_struct_end:
        \__luamml_amsmath_save_intertext_with_struct_elem:N \l__luamml_struct_tmpa_int
        \tag_mc_begin_pop:n{}    
     }
  \AddToHook{package/luamml/after}{\AssignTaggingSocketPlug{math/intertext}{luamml}}  
 }
%    \end{macrocode}
%    \begin{macrocode}
\def\intertext@{%
  \def\intertext##1{%
    \ifvmode\else\\\@empty\fi
    \noalign{%
      \penalty\postdisplaypenalty\vskip\belowdisplayskip
      \vbox{
%    \end{macrocode}
% Stop tagging when measuring:
%    \begin{macrocode}
       \ifmeasuring@\tag_suspend:n{\measuring}\fi
       \normalbaselines
        \ifdim\linewidth=\columnwidth
        \else \parshape\@ne \@totalleftmargin \linewidth
        \fi
%    \end{macrocode}
% \changes{v0.1j}{2026-04-25}{Removed unneeded setup command}
% \changes{v0.1j}{2026-04-25}{Use tagging socket and luamml code to resolve issue tagging/981}
%  Use the tagging socket
%    \begin{macrocode}
       \UseTaggingSocket{math/intertext}{}
        { 
        \noindent\ignorespaces##1\par
        }
      }% end vbox
      \penalty\predisplaypenalty\vskip\abovedisplayskip%
    }%
}}
%    \end{macrocode}
% \end{macro}
%
% \subsection{\cs{text}}
%
% The \cs{text} command uses \cs{mathchoice} which \enquote{typesets} the argument
% four times. This makes it quite problematic for tagging. Without precautions
% structure objects would be created four times and would get MC-chunks as kids
% that don't really exist. amsmath contains a switch that allows to execute code
% only in the first (displaymath) branch, but that isn't usable here. At first because
% we don't know if the first branch creates the same structure as the one that is
% actually used. At second because the engines executes some commands like \cs{label}
% and \cs{pdfannot} only at shipout from the branch that really was used. So we would
% get structure data from one \cs{mathchoice}-branch and MC-labels and links from another
% one and that gets very messy.
%
% We therefore have to avoid that tagging is active in unused branches. In pdflatex it
% is not possible to detect the mathstyle before, so we use a label. With lualatex is
% is possible to redefine \cs{text} not to use \cs{mathchoice}
%
% \begin{macro}{\text@}
%    \begin{macrocode}
\AddToHook{package/amstext/after}
 {
%    \end{macrocode}
% currently amsmath is loaded in a begindocument hook, so this
% test is fine. If amstext is loaded earlier (in the kernel), this needs perhaps a change.
% \changes{v0.1d}{2024/12/03}{Add tagging socket for luamml support}
% \changes{v0.1i}{2025-09-29}{Additional braces to allow use in subscripts, tagging issue 995}
% \changes{v0.1k}{2026-02-19}{Redefine \cs{text@} with luatex always}
%    \begin{macrocode}
   \sys_if_engine_luatex:TF
    {
      \def\text@#1{{
        \tag_socket_use:nnn {math/luamml/hbox}{}
       {{%
        \ifcase\mathstyle
        \hbox{{#1}}\or
        \hbox{{#1}}\or
        \hbox{{#1}}\or
        \hbox{{#1}}\or
        \hbox{{\let\f@size\sf@size\selectfont#1}}\or
        \hbox{{\let\f@size\sf@size\selectfont#1}}\or
        \hbox{{\let\f@size\ssf@size\selectfont#1}}\or
        \hbox{{\let\f@size\ssf@size\selectfont#1}}\or
        \ERROR
        \fi
        \check@mathfonts
      }}}}
    }
    {
      \tag_if_active:T
       {
         \def\text@#1
          {{
           \int_gincr:N\g__math_mathchoice_int
           \tag_suspend:n{\text@}
           \mathchoice
            {
             \__math_tag_if_mathstyle:en{mathchoice-\int_use:N\g__math_mathchoice_int}{0}
             \textdef@\displaystyle\f@size{#1}
            }
            {
             \__math_tag_if_mathstyle:en{mathchoice-\int_use:N\g__math_mathchoice_int}{2}
             \textdef@\textstyle\f@size{\firstchoice@false #1}
            }
            {
             \__math_tag_if_mathstyle:en{mathchoice-\int_use:N\g__math_mathchoice_int}{4}
             \textdef@\textstyle\sf@size{\firstchoice@false #1}
            }
            {
              \__math_tag_if_mathstyle:en{mathchoice-\int_use:N\g__math_mathchoice_int}{6}
              \textdef@\textstyle \ssf@size{\firstchoice@false #1}
            }
            \check@mathfonts
          }}
      } 
    }    
 }
%    \end{macrocode}
% \end{macro}
%
% \subsection{\cs{pmb}}
% \cs{pmb} prints its argument three times. For tagging we must mark
% two of occurrences as artifact.
% For luatex the attributes in the box must be reset, for this
% we switch to expl3-boxes.
% \begin{macro}{\pbm@@,\pmb@}
% \changes{0.1g}{2025-05-23}{correct box names, tagging issue #842}
% TODO: this is wrong with mathml-SE tagging (see also the related bm code in latex-lab-mathpkg).
%    \begin{macrocode}
\cs_new:Npn\__math_patch_amsbsy_pmb:
 {
   \NewTaggingSocket{amsbsy/pmb}{2}
   \NewTaggingSocketPlug{amsbsy/pmb}{default}
    {
      \tag_mc_end:\tag_mc_begin:n{artifact}
      \tag_mc_reset_box:N##1
      ##2
      \tag_mc_end:
      \tag_mc_begin:n{}
    }
   \AssignTaggingSocketPlug{amsbsy/pmb}{default} 
   \def\pmb@@##1##2##3{\leavevmode\hbox_set:Nn\l__math_tmpa_box{##3}
      \dimen@-\box_wd:N\l__math_tmpa_box
      \kern-.5\ex@\box_use:N\l__math_tmpa_box
      \UseTaggingSocket{amsbsy/pmb}{\l__math_tmpa_box}
        {
          \kern\dimen@\kern.25\ex@\raise.4\ex@\box_use:N\l__math_tmpa_box
          \kern\dimen@\kern.25\ex@\box_use_drop:N\l__math_tmpa_box
        }
    }
   \def\pmb@##1##2{\hbox_set:Nn\l__math_tmpa_box{$\m@th##1{##2}$}
     \setboxz@h{$\m@th##1\mkern.5mu$}\pmbraise@\wdz@
     \binrel@{##2}
     \dimen@-\box_wd:N\l__math_tmpa_box
     \binrel@@{
       \mkern-.8mu\box_use:N\l__math_tmpa_box
       \UseTaggingSocket{amsbsy/pmb}{\l__math_tmpa_box}
        {
          \kern\dimen@\mkern.4mu\raise\pmbraise@\box_use:N\l__math_tmpa_box
          \kern\dimen@\mkern.4mu\box_use_drop:N\l__math_tmpa_box
        }
       }
    }
  } 
\AddToHook{package/amsbsy/after}
  {
    \__math_patch_amsbsy_pmb:
  }
%    \end{macrocode}
% \end{macro}
%
% 
%    \begin{macrocode}
\ExplSyntaxOff
%    \end{macrocode}
%
%
%    \begin{macrocode}
%</kernel>
%    \end{macrocode}
%
% \Finale
%
