% \iffalse meta-comment
%
%% File: latex-lab-mathtagging.dtx
%
% Copyright (C) 2022-2023 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 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.
%
%
\def\ltmathtaggingdate{2023-03-08}
\def\ltmathtaggingversion{v0.5a}
%
%<*driver>
\documentclass{l3doc}
\EnableCrossrefs
\CodelineIndex 

\usepackage{todonotes}

\begin{document}
  \DocInput{latex-lab-mathtagging.dtx}
\end{document}
%</driver>
%
% \fi
%
%
% \title{The \texttt{latex-lab-mathtagging} code\thanks{}}
% \author{Frank Mittelbach, Joseph Wright, \LaTeX{} Project}
%
% \maketitle
%
% \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}}
%
% ^^A \car {...} for marginal comments
% ^^A \car*{...} for longer inline comments
%
% \NewDocumentCommand\car{sO{}m}
%   {\IfBooleanTF{#1}{\todo[inline,color=blue!10,#2]{#3}}^^A
%                    {\todo[color=blue!10,#2]{#3}}}
%
% \NewDocumentCommand\fmi{sO{}m}
%   {\IfBooleanTF{#1}{\todo[inline,#2]{#3}}^^A
%                    {\todo[#2]{#3}}}
%
%
%
% \begin{abstract}
%    This is an experimental prototype. It captures math material
%    (basically okay, but the interfaces for packages aren't yet
%    there) and tags the material (which is not yet anywhere near the
%    final state). That part is provided for experimentation and to
%    gather feedback, etc.
% \end{abstract}
%
% \tableofcontents
%
% \section{Introduction}
% \car*{Todo: update all the documentation! Both here and 
%   (what little there is!) in the implementation section.}
%
% This file implements capture of all math mode material at the outer
% level, i.e., a formula is captured in its entirety with inner text
% blocks (possibly containing further math) absorbed as part of the
% formula. For example,
%\begin{verbatim}
%      \[ a \in A \text{ for all $a<5$}  \]
%\end{verbatim}
% would only result in a single capture of the tokens
% ``\verb*/a \in A \text{ for all $a<5$}/''.
%
% \subsection{Code level interfaces}
%
% \begin{function}{\math_register_env:n, \math_register_env:nn}
%   \begin{syntax}
%     \cs{math_register_env:n} \Arg{env}
%     \cs{math_register_env:nn} \Arg{env} \Arg{options}
%   \end{syntax}
%   Registers the \meta{env} as a math environment which should be captured
%   and made available. This is necessary for all top-level math mode
%   environments: low-level errors may result if these are not correct
%   set up. One or more key--value \meta{options} may also be given:
%   \begin{itemize}
%     \item[\texttt{arg-spec}] The argument specification taken by the
%       beginning of the environment; this is used to remove non-mathematical
%       material.
%   \end{itemize}
% \end{function}
%
% \begin{function}{\math_processor:n}
%   \begin{syntax}
%     \cs{math_processor:n} \Arg{tokens}
%   \end{syntax}
%   Declares that the captured math content should be passed to the
%   \meta{tokens}, which will receive the environment type as |#1| and
%   the content as |#2|.
% \end{function}
%
% \subsection{Document level interfaces}
%
% \begin{function}{\RegisterMathEnvironment}
%   \begin{syntax}
%     \cs{RegisterMathEnvironment} \oarg{options} \Arg{env}
%   \end{syntax}
%   Registers the \meta{env} as a math environment which should be captured
%   and made available. This is necessary for all top-level math mode
%   environments: low-level errors may result if these are not correct
%   set up. One or more key--value \meta{options} may also be given:
%   \begin{itemize}
%     \item[\texttt{arg-spec}] The argument specification taken by the
%       beginning of the environment; this is used to remove non-mathematical
%       material.
%   \end{itemize}
% \end{function}
% 
% \section{Known current bugs, etc.}
%     \car*{New Section, now with subsections.\\
%      As indicated, these lists are probably incomplete.\\
%      Some of these have been addressed in a more recent branch.} 
%
% \subsection{Capture/grabbing problems}
% 
% \begin{enumerate}
%   \item Incorrect grabbing of |$|-math when there is also 
%      explicit |$|-math within a \textit{text environment} 
%      that is itself within the math that should all be grabbed.
%   \item Similar incorrect grabbing with |$$| also.
%   \item The grabbing, for all the display environments (and |\) \]|), needs
%       to deal with nesting: \pkg{amsmath} contains code for this. 
%   \item 
% \end{enumerate} 
%
% \subsection{Other problems}
% 
% \begin{enumerate} 
%   \item 
%      The presence of \cs{m@th} in association with \cs{ensuremath} 
%      does not necessarily indicate fakemath.  This is because  
%      wanting mathsurround to be zero is very reasonable and common, 
%      \emph{even when the math is genuine} (and hence needs to be collected).
%   \item User-defined environments can create problems; but this area, of 
%      new, copied and changed environments, has not yet been developed. 
% 
%  \car*{Joseph wrote, inter alia:\\
%      My thinking [regarding] \cs{RegisterMathEnvironment}\\
%    - (New) Math environments should not be created-then-patched, but only
%    generated by a [(future)] dedicated command (\cs{DeclareMathEnviornment}, 
%    presumably)\\
%    - Math environments created with \pkg{ltcmd} [commands] should not be copied, . . .\\
%    - Package authors should be able to manually set up math environments with a public boolean.}
%
%   \item 
% \end{enumerate} 
%
%
% \subsection{Other ToDos}
%
% \begin{enumerate}
%  \item Add (some of) the math display commands that were \enquote{lifted from 
%    plain}, e.g., \cs{displaylines} \cs{eqalign}(??).
%  \item 
% \end{enumerate}
%
%
% \car*{\cs{MaybeStop} (temporarily) not executed, as it is unknown on Chris' system.}
% \iffalse
%  \MaybeStop{\setlength\IndexMin{200pt}  \PrintIndex  }
% \else
%  \StopEventually{\setlength\IndexMin{200pt}  \PrintIndex  }
% \fi
%
% \section{The Implementation}
%
%    \begin{macrocode}
%<@@=math>
%    \end{macrocode}
%
%    \begin{macrocode}
%<*kernel>
%    \end{macrocode}
%
% \subsection{File declaration}
%
%    \car{Change description here?}
%    \begin{macrocode}
\ProvidesFile{latex-lab-mathtagging.ltx}
             [\ltmathtaggingdate\space
              \ltmathtaggingversion\space
              Grab all the math(s) and tag it (experiments)]
%    \end{macrocode}
%
%    Temp loading \ldots
%    \begin{macrocode}
\AddToHook{begindocument/before}{\RequirePackage{latex-lab-testphase-block-tagging}}
%    \end{macrocode}
%
%    \begin{macrocode}
\ExplSyntaxOn
%    \end{macrocode}
%
% \subsection{Setup}
%
% Loading \pkg{amsmath} is an absolute requirement: this avoids needing to
% have conditional definitions and deals with how to define \cs{[}/\cs{]}
% neatly.
%    \begin{macrocode}
\tl_gput_right:Nn \@kernel@before@begindocument
  { \RequirePackage { amsmath } }
%    \end{macrocode} 
%
%
% \subsection{Data structures}
%
%
%
% \begin{variable}{\l_@@_collected_bool} 
%   Tracks whether math mode material has been collected, which happens inside
%   \pkg{amsmath} environments as well as those handled directly here.
%
%
%    \begin{macrocode}
\bool_new:N \l_@@_collected_bool
%    \end{macrocode}
% \end{variable}
% 
%  \car{Change first tl name below: `env' $=>$ `info'?\\
%        Or do we need an extra storage tl?}
%
% \begin{variable}{\g_@@_grabbed_env_tl, \g_@@_grabbed_math_tl}
%    \begin{macrocode}
\tl_new:N \g_@@_grabbed_env_tl
\tl_new:N \g_@@_grabbed_math_tl
%    \end{macrocode}
% \end{variable}
%
% \subsection{Interface commands}
%
% \begin{macro}
%   {\@@_process:nn, \@@_process:Vn, \@@_process_auxi:nn, \@@_process_auxii:nn}
%   A no-op place-holder; the internal wrapper means that it does not need to
%   be concerned with internals.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_process:nn #1#2
  {
    \legacy_if:nF { measuring@ }
      {
        \tl_if_in:nnF {#2} { \m@th }
          { \tl_trim_spaces_apply:nN {#2} \@@_process_auxi:nn {#1} }
      }
  }
\cs_generate_variant:Nn \@@_process:nn { V }
\cs_new_protected:Npn \@@_process_auxi:nn #1#2
  {
    \tl_gset:Nn \g_@@_grabbed_env_tl {#2}
    \tl_gset:Nn \g_@@_grabbed_math_tl {#1}
    \@@_process_auxii:nn {#2} {#1}
  }
\cs_new_protected:Npn \@@_process_auxii:nn #1#2 { }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\math_processor:n}
%   A simple installer
%    \begin{macrocode}
\cs_new_protected:Npn \math_processor:n #1
  { \cs_set_protected:Npn \@@_process_auxii:nn ##1##2 {#1} }
%    \end{macrocode}
% \end{macro}
%
% \subsection{Content grabbing}
%
% \begin{macro}{\@@_grab_dollar:w}
%   Grab up to a single |$|, for inline math mode, suppressing
%   any processing if the first token is \tn{m@th}.
%
%    \fmi{what's that test doing?} 
%
%    \car{It is some kind of fix, to avoid the remote 
%      possibility that the math is empty, making the code 
%      produce an unwanted \texttt{\$\$}.} 
% 
%\car{cf.~the code for this in \cs{@ensuredmath}} 
%
%\car{It is harmless but unnecessary in the dollardollar grabbing below.}
%
%    \begin{macrocode}
\cs_new_protected:Npn \@@_grab_dollar:w % $
  #1 $
  {
%    \end{macrocode}
%    \fmi{what's that test doing?}
%    \begin{macrocode}
    \tl_if_blank:nF {#1}
      {
        \@@_process:nn { math } {#1} % $
% fairly simple this one
        \tagmcend %end P-chunk, in code: \tag_mc_end_push:
        \@kernel@math@begin
        #1 $
        \@kernel@math@end
        \tagmcbegin{}  % restart P-chunk (whatsits in pdftex)
      }
  }
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\@@_grab_dollardollar:w}
%   And for the classical \TeX{} display structure.
%    \begin{macrocode}

\skip_new:N \l_@@_tmpa_skip
  
\cs_new_protected:Npn \@@_grab_dollardollar:w % $$
  #1 $$
  {
    \tl_if_blank:nF {#1}
      {
        \@@_tag_dollardollar_display:nn { equation* }{#1}
        #1
        $$
      }
  }

\cs_new_protected:Npn \@kernel@close@P {
  \tagmcend %end P-chunk, in code: \tag_mc_end_push:
        \int_gincr:N \g__tag_para_end_int
        \bool_if:NT \l__tag_para_show_bool
          { \tag_mc_begin:n{artifact}
            \rlap{\color_select:n{red}\tiny\ \int_use:N\g__tag_para_end_int}
            \tag_mc_end:
          }
        \tag_struct_end:
}
  


\cs_new_protected:Npn \@@_tag_dollardollar_display:nn #1#2 {
  \@@_process:nn {#1} {#2}
  \@kernel@close@P
  \@kernel@math@begin
%        \skip_set:Nn \belowdisplayskip      {-\belowdisplayskip}
%        \skip_set:Nn \belowdisplayshortskip {-\belowdisplayshortskip}
%        \int_set:Nn \postdisplaypenalty {10000}
%%
%        \group_insert_after:N \@@_tag_dollardollar_display_end:
}

\cs_new_protected:Npn \@@_tag_dollardollar_display_end: {
%  \typeout{== tag dollarldollar display end}
%  \ShowTagging{struct-stack}
  \tagpdfparaOff
  \para_raw_end:
  \tagpdfparaOn
  \l_@@_tmpa_skip \lastskip  
  \@kernel@math@end
  \penalty \postdisplaypenalty
  \skip_vertical:n { -\l_@@_tmpa_skip }
%
  \@doendpe             % this has no \end{...} to take care of it
}


%    \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\@@_grab_inline:w}
%   Collect inline math content and deal with the need to move to math mode.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_grab_inline:w % \(
  #1 \)
  {
    \tl_if_blank:nF {#1}
      {
        \@@_process:nn { math } {#1}
        $ #1 $
      }
    \bool_set_false:N \l_@@_collected_bool
  }
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\@@_grab_eqn:w}
%   For the most common use of \cs{[}/\cs{]}: turn into an environment.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_grab_eqn:w % \[
  #1 \]
   {
%     \typeout{collected? = \bool_if:NTF \l_@@_collected_bool {true}{false}}
     \begin { equation* } #1 \end { equation* }
   }
%    \end{macrocode}
% \end{macro}
%
% \subsection{Marking math environments}
%
% A general mechanism for math mode environments that do not grab their
% content (\emph{cf.}~most \pkg{amsmath} environments).
%
% \begin{variable}{\l_@@_env_name_tl}
%  To allow us to carry out \enquote{special effects}
%    \begin{macrocode}
\tl_new:N \l_@@_env_name_tl
%    \end{macrocode}
% \end{variable}
%
% Here we set up specialised handling of environments. The idea for the
% \texttt{arg-spec} key is that if an environment takes arguments, we
% don't worry during the main grabbing. Rather, we remove the arguments
% from the grabbed content and forward only the payload. That is done by
% (ab)using \pkg{ltcmd}.
%    \begin{macrocode}
\keys_define:nn { @@ }
  {
     arg-spec .code:n =
       {
         \ExpandArgs { c } \DeclareDocumentCommand
           { @@_env \l_@@_env_name_tl _aux: }
           {#1}
           { \@@_env_forward:w }
       }
  }
%    \end{macrocode}
%
% \begin{macro}{\math_register_env:nn}
% \begin{macro}{\math_register_env:n}
% \begin{macro}{\RegisterMathEnvironment}
%   Set up to capture environment content and make available.
% 
%    \begin{macrocode}
\cs_new_protected:Npn \math_register_env:nn #1#2
  {
    \tl_set:Nn \l_@@_env_name_tl {#1}
    \keys_set:nn { @@ } {#2}
    \cs_gset_eq:cc { @@_env_ #1 _begin: } {#1}
    \cs_gset_eq:cc { @@_env_ #1 _end: } { end #1 }
%
    \ExpandArgs { nnx } \RenewDocumentEnvironment {#1} { b }
      {
%        \bool_set_true:N \exp_not:N \l_@@_collected_bool
%        \cs_if_exist:cTF { @@_env #1 _aux: }
%          {
%            \exp_not:c { @@_env #1 _aux: }
%              ####1 \exp_not:N \@@_env_end: {#1}
%          }
%          { \exp_not:N \@@_process:nn {#1} {####1} }
        \exp_not:N \bool_if:NTF \exp_not:N \l_@@_collected_bool
          {
%            \typeout{===>B1}
          }
          {
%            \typeout{===>B2}
            \cs_if_exist:cTF { @@_env #1 _aux: }
              {
                \exp_not:c { @@_env #1 _aux: }
                  ####1 \exp_not:N \@@_env_end: {#1}
              }
              { \exp_not:N \@@_process:nn {#1} {####1} }
            \exp_not:n { \@kernel@math@registered@begin }
            \bool_set_true:N \exp_not:N \l_@@_collected_bool
          }
%        \exp_not:N \tracingall  
        \exp_not:c { @@_env_ #1 _begin: }
        ####1
        \exp_not:c { @@_env_ #1 _end: }
%        \exp_not:c { @@_env_ #1 _end: }
%        \exp_not:N \tracingnone
%        \exp_not:n { \@kernel@math@registered@end }
     }
      {
      }
  }

\cs_set_protected:Npn \__cs_tmp:w #1
  {
    \group_begin:
      \exp_args:No \__cs_generate_internal_variant:n
        { \tl_to_str:n {#1} }
    \group_end:
  }
\__cs_tmp:w { nnxx }
  
  
\cs_new_protected:Npn \math_register_halign_env:nn #1#2
  {
    \tl_set:Nn \l_@@_env_name_tl {#1}
    \keys_set:nn { @@ } {#2}
    \cs_gset_eq:cc { @@_env_ #1 _begin: } {#1}
    \cs_gset_eq:cc { @@_env_ #1 _end: } { end #1 }
%
    \ExpandArgs { nnxx } \RenewDocumentEnvironment {#1} { b }
      {
%        \bool_set_true:N \exp_not:N \l_@@_collected_bool
%        \cs_if_exist:cTF { @@_env #1 _aux: }
%          {
%            \exp_not:c { @@_env #1 _aux: }
%              ####1 \exp_not:N \@@_env_end: {#1}
%          }
%          { \exp_not:N \@@_process:nn {#1} {####1} }
        \exp_not:N \bool_if:NTF \exp_not:N \l_@@_collected_bool
          {
%            \typeout{===>B1}
          }
          {
%            \typeout{===>B2}
            \cs_if_exist:cTF { @@_env #1 _aux: }
              {
                \exp_not:c { @@_env #1 _aux: }
                  ####1 \exp_not:N \@@_env_end: {#1}
              }
              { \exp_not:N \@@_process:nn {#1} {####1} }
            \exp_not:n { \@kernel@math@registered@begin }
            \bool_set_true:N \exp_not:N \l_@@_collected_bool
          }
%        \exp_not:N \tracingall  
        \exp_not:c { @@_env_ #1 _begin: }
        ####1
%        \exp_not:c { @@_env_ #1 _end: }
%        \exp_not:N \tracingnone
     }
      {
        \exp_not:c { @@_env_ #1 _end: }
      }
  }

\cs_new_protected:Npn \math_register_odd_env:nn #1#2
  {
    \tl_set:Nn \l_@@_env_name_tl {#1}
    \keys_set:nn { @@ } {#2}
    \cs_gset_eq:cc { @@_env_ #1 _begin: } {#1}
    \cs_gset_eq:cc { @@_env_ #1 _end: } { end #1 }
%
    \ExpandArgs { nnxx } \RenewDocumentEnvironment {#1} { b }
      {
        \exp_not:N \bool_if:NTF \exp_not:N \l_@@_collected_bool
          {
%            \typeout{===>B1}
          }
          {
%            \typeout{===>B2}
            \cs_if_exist:cTF { @@_env #1 _aux: }
              {
                \exp_not:c { @@_env #1 _aux: }
                  ####1 \exp_not:N \@@_env_end: {#1}
              }
              { \exp_not:N \@@_process:nn {#1} {####1} }
            \exp_not:n { \@kernel@math@registered@begin }
            \bool_set_true:N \exp_not:N \l_@@_collected_bool
          }
%        \exp_not:N \tracingall  
        \exp_not:c { @@_env_ #1 _begin: }
        ####1
     }
      {
        \exp_not:c { @@_env_ #1 _end: }
% needed if we don't have $$...$$        
%        \exp_not:n { \typeout{---> @kernel@math@registered@end }}
        \exp_not:n { \@kernel@math@registered@end }
      }
  }


%  FMi: compare with block change!
%
%  \DeclareRobustCommand*\begin[1]{%
%  \UseHook{env/#1/before}%
%  \@ifundefined{#1}%
%    {\def\reserved@a{\@latex@error{Environment #1 undefined}\@eha}}%
%    {\def\reserved@a{\def\@currenvir{#1}%
%        \edef\@currenvline{\on@line}%
%        \@execute@begin@hook{#1}%
%        \csname #1\endcsname}}%
%  \@ignorefalse
%  \begingroup
%  \@endpefalse  % tmp!!! is it ok to drop this here?
%  \reserved@a}


\cs_new:Npn \@kernel@math@registered@begin {
%  \ShowTagging{struct-stack} 
%\typeout{==>A1}\ShowTagging{struct-stack,mc-current}
  \mode_if_vertical:TF
       {
%         \legacy_if:nTF { @endpe }
%           { \legacy_if_set_false:n { @endpe } }
%           { \__block_list_beginpar_vmode: }
%
%         \typeout{==>~ at:~ \g__tag_struct_tag_tl}
%         
         \exp_args:Noo\str_if_eq:nnF \g__tag_struct_tag_tl { \l__tag_para_main_tag_tl }    % needs correction!
             {
%               \typeout{==>A2}
               \__block_beginpar_vmode:
             }              % needs correction!
       }
       {
%         \typeout{==>A3}
         \@kernel@close@P
%         \tagmcend                      % needs correction!
       }
  \@kernel@math@begin
  \tagpdfparaOff
%  \typeout{==>MC1}\ShowTagging{mc-current}
}

\cs_new:Npn \@kernel@math@registered@end {
%  \typeout{==>MC2}\ShowTagging{mc-current}
  \para_raw_end:
  \tagpdfparaOn
  \@kernel@math@end
%  \typeout{==>MC3}\ShowTagging{mc-current}
  \@endpetrue
}
  
\cs_new_protected:Npn \math_register_env:n #1
  { \math_register_env:nn {#1} { } }
\NewDocumentCommand \RegisterMathEnvironment { O{} m }
  { \math_register_env:nn {#2} {#1} }
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\@@_env_forward:w}
%    \begin{macrocode}
\cs_new_protected:Npn \@@_env_forward:w #1 \@@_env_end: #2 
  { \@@_process:nn {#2} {#1} }
%    \end{macrocode}
% \end{macro}
% 
% \subsection{Document commands} 
%
% \car*{Add one more here: \texttt{displaymath}, which
%        is equivalent to \cs{[} , \cs{]}\\
%        and hence to the basic \texttt{equation*}.\\
%       Added in more recent branch.}
%
% \begin{macro}
%   {\equation, \@@_equation_begin:, \equation*, \@@_equation_star_begin:}
% \begin{macro}
%   {\endequation, \@@_equation_end:, \endequation*, \@@_equation_star_end:}
%   These environments are not set up by \pkg{amsmath} to collect their body,
%   so we do that here. This has to be done \emph{after} we can be sure
%   \pkg{amsmath} is loaded.
%
% \car*{Note that with \pkg{amsmath} loaded, \texttt{equation*} and \texttt{equation}\\
%        are the two basics: they are used to define the other single-row\\
%        display environments, etc.}
%
%    \begin{macrocode}
\tl_gput_right:Nn \@kernel@before@begindocument
  {
    \math_register_env:n { equation }
    \math_register_env:n { equation* }
% at the moment register_env can only do display math
%    \math_register_env:n { math }
    \RenewDocumentEnvironment{math} {b}{$#1$}{}
% and this one doesn't work either    
%    \math_register_env:n { displaymath }
    \RenewDocumentEnvironment{displaymath} {b}{\[#1\]}{}    
  }
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\(, \)}
%  If math mode has not been collected, we need to  do that; otherwise, worry
%  about whether we are in math mode or not. The closing command here can only
%  occur inside a collected math block: otherwise it will be simply used as
%  a delimiter.
%    \begin{macrocode}
\cs_gset_protected:Npn \( % \)
  {
    \bool_if:NTF \l_@@_collected_bool
      {
        \mode_if_math:TF
          { \@badmath }
          { $ }
      }
      {
        \bool_set_true:N \l_@@_collected_bool
        \@@_grab_inline:w
      }
  } % \(
\cs_gset_protected:Npn \)
  {
    \mode_if_math:TF
      { $ }
      { \@badmath }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\[, \]}
%   Again, we need to watch for when \pkg{amsmath} is loaded after this code.
%   The flag usage here is to cover the case where \cs{[}/\cs{]} is hidden
%   inside another environment. In this case the grabbing happens on
%    the outer level and should not be repeated.
%    \begin{macrocode}
\tl_gput_right:Nn \@kernel@before@begindocument
  {
    \cs_gset_protected:Npn \[ % \]
       {
        \bool_if:NTF \l_@@_collected_bool
          { \begin { equation* } }
          { \@@_grab_eqn:w }
      } % \[
    \cs_gset_protected:Npn \]
      {
        \bool_if:NTF \l_@@_collected_bool
          { \end{ equation* } }
          { \@badmath }
      }
  }
%    \end{macrocode}
% \end{macro}
% 
%
% \begin{macro}{\ensuremath}
%   A bit of nesting fun to make sure we collect only if required.
%   \fmi{why does ensuremath need handling at all?}
% 
%   \car{Indeed!  Currently, this is setup to process the math that 
%     it has anyways already captured as its argument; thus it is more 
%     efficient than leaving the capture to be repeated by the \cs{everymath}}
% 
%    \begin{macrocode}
%\cs_gset_protected:Npn \ensuremath #1
%  {
%    \mode_if_math:TF
%      {#1}
%      {
%        \bool_if:NTF \l_@@_collected_bool
%          { \@ensuredmath {#1} }
%          {
%            \bool_set_true:N \l_@@_collected_bool
%            \@@_process:nn { math } {#1}
%            \@ensuredmath {#1}
%            \bool_set_false:N \l_@@_collected_bool
%          }
%      }
%  }
%    \end{macrocode}
% \end{macro}
%
% \subsection{\cs{everymath} and \cs{everydisplay}}
%
% The business end for grabbing inline math and \enquote{raw} \TeX{}
% display. Most display math mode is actually handled elsewhere, as we
% have macro control.
%    \begin{macrocode}

\tl_new:N\tmpmathcontent

  
\def\@kernel@math@begin {
%  \typeout{==>~math~begin}
% needs different handling if we support nesting
  \tl_gset:Nx\tmpmathcontent
     {
       LaTeX~ formula~ starts~
       \exp_not:N\begin{\g__math_grabbed_env_tl}
       \space
       \exp_not:V\g__math_grabbed_math_tl
       \space
       \exp_not:N\end{\g__math_grabbed_env_tl} 
       \space LaTeX~ formula~ ends~
    }
  \tagstructbegin{tag=Formula,
    AFinline-o=\tmpmathcontent,
    title-o=\g__math_grabbed_env_tl,
    actualtext=\tmpmathcontent
%    alt=\tmpmathcontent
  }
% inner formula if multiple parts (not really implemented yet)
  \grabaformulapartandstart
% the above does:  
%    \tagstructbegin{tag=Formula}\tagmcbegin{}
%  or just
% \tagmcbegin{}
}
\def\@kernel@math@end {
%  \typeout{==>~math~end}
%  \ShowTagging{struct-stack}
  \tagmcend
  \if@subformulas
    \tagstructend
  \else
  \fi
  \tagstructend
%  \ShowTagging{struct-stack} 
}
  
\exp_args:No \tex_everymath:D
  {
    \tex_the:D \tex_everymath:D
    \bool_if:NF \l_@@_collected_bool
      {
        \bool_set_true:N \l_@@_collected_bool
        \@@_grab_dollar:w
      }
  }
\exp_args:No \tex_everydisplay:D
  {
    \tex_the:D \tex_everydisplay:D
    \iftrue  % this may have to be a settable flag!
%      {
%        \typeout{==>~ in~ everydisplay}
        \skip_set:Nn \belowdisplayskip      {-\belowdisplayskip}
        \skip_set:Nn \belowdisplayshortskip {-\belowdisplayshortskip}
        \int_set:Nn \postdisplaypenalty {10000}
%
        \group_insert_after:N \@@_tag_dollardollar_display_end:
%      }
    \fi
    \bool_if:NF \l_@@_collected_bool
      {
        \bool_set_true:N \l_@@_collected_bool
        \@@_grab_dollardollar:w
      }
  }
%    \end{macrocode}
%
% \subsection{Modifying kernel environments}
%
%   We need to cover this even though it is, of course, not encouraged.
%    \begin{macrocode}
\math_register_env:n { eqnarray }
\math_register_env:n { eqnarray* }
%    \end{macrocode}
%
% Places where math mode is (ab)used.
%    \begin{macrocode}
\clist_map_inline:nn
  { tabular }
  {
    \AddToHook{ env / #1 / begin }
      { \bool_set_true:N \l_@@_collected_bool }
  }
%    \end{macrocode}
%
% \begin{macro}{\@@_m@th:, \m@th}
%   Handle non-math use of math mode. At present nesting isn't supported as
%   \cs{m@th} pops up in a few places that \emph{are} math mode!
%    \begin{macrocode}
\cs_new_eq:NN \@@_m@th: \m@th
\cs_gset_protected:Npn \m@th
  {
    \bool_set_true:N \l_@@_collected_bool
    \@@_m@th:
  }
%    \end{macrocode}
% \end{macro}
%
% \subsection{Modifying \pkg{amsmath}}
%
% \begin{macro}{\@@_amsmath_align@:nn}
% \begin{macro}
%   {
%     \@@_amsmath_gather@:n ,
%     \@@_amsmath_multline@:n
%   }
% \begin{macro}{\align@}
% \begin{macro}{\gather@, \multline@}
%   Mark up all of the display environments as the content is captured anyway.
%   We then use an internal macro in each environment type to insert the
%   processing code. Each of these is slightly different, so we cannot use a
%   simple loop here. The test for \cs{split@tag} is required as the
%   \texttt{split} environment internally uses \texttt{gather} \emph{when not
%   within an \pkg{amsmath}} environment, for example inside \texttt{equation}.
%   Without the precaution, we'd get two copies of the grabbed math, the second
%   of which would start with \cs{split@tag}.
%    \begin{macrocode}



\tl_gput_right:Nn \@kernel@before@begindocument {
%
\renewenvironment{gather*}{%
  \start@gather\st@rredtrue
}
{%
% this redirection doesn't work if we alter "gather"!
  %  \endgather
% so replace it with its real meaning
  \math@cr \black@\totwidth@ \egroup
  $$\ignorespacesafterend
}
%    \end{macrocode}
%    
%    \begin{macrocode}
\def\common@align@ending {
  \math@cr \black@\totwidth@
  \egroup
  \ifingather@
    \restorealignstate@
    \egroup
    \nonumber
    \ifnum0=`{\fi\iffalse}\fi
  \else
    $$%
  \fi
  \ignorespacesafterend
}
\renewenvironment{alignat}{%
  \start@align\z@\st@rredfalse
}{%
  \common@align@ending
}
\renewenvironment{alignat*}{%
  \start@align\z@\st@rredtrue
}{%
  \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
}
\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{flalign}{%
  \start@align\tw@\st@rredfalse\m@ne
}{%
  \common@align@ending
}
\renewenvironment{flalign*}{%
  \start@align\tw@\st@rredtrue\m@ne
}{%
  \common@align@ending
}
%
\renewenvironment{multline*}{\start@multline\st@rredtrue}
{%
  \iftagsleft@ \@xp\lendmultline@ \else \@xp\rendmultline@ \fi
  \ignorespacesafterend
}
%    \end{macrocode}
%    Also for "false?"
%    \begin{macrocode}
\def\measuring@true{\let\ifmeasuring@\iftrue\tag_stop:}
%    \end{macrocode}
%
%    \begin{macrocode}
%    
  \math_register_halign_env:nn {align}{}
  \math_register_halign_env:nn {align*}{}
  \math_register_halign_env:nn {flalign}{}
  \math_register_halign_env:nn {flalign*}{}
  \math_register_halign_env:nn {gather}{}
  \math_register_halign_env:nn {gather*}{}
  \math_register_halign_env:nn {multline}{}
  \math_register_halign_env:nn {multline*}{}
  \math_register_halign_env:nn {xalignat}{}
  \math_register_halign_env:nn {xalignat*}{}
  \math_register_halign_env:nn {xxalignat}{}
  %
  \@namedef{maketag @ @ @} #1{%
%    \typeout{--->maketag @ @ @}
    \ifmeasuring@
      \hbox{\m@th\normalfont#1}%
    \else
      \tagmcend \tagstructbegin{tag=Lbl}%
      \tagmcbegin{tag=Lbl}%
      \hbox{\m@th\normalfont#1}%
      \tagmcend \tagstructend \tagmcbegin{}%
    \fi
  }
%    \end{macrocode}
%    
%    \begin{macrocode}
    \def\intertext@{%
      \def\intertext##1{%
        \ifvmode\else\\\@empty\fi
        \noalign{%
% we have to flip the sign on the skip because we flipped it on the outside
          \penalty\postdisplaypenalty\vskip-\belowdisplayskip
          \vbox{
%    \end{macrocode}
% Stop tagging when measuring:
%    \begin{macrocode}
           \ifmeasuring@\tag_stop:\fi
           \normalbaselines
            \ifdim\linewidth=\columnwidth
            \else \parshape\@ne \@totalleftmargin \linewidth
            \fi
%    \end{macrocode}
% End the previous mc:\fmi{if we use 2 levels of formulas this would
%    need changing}
%    \begin{macrocode}
            \tag_mc_end_push:
%    \end{macrocode}
% We are already in a par so we change now to Span:\fmi{not true any longer}
%    \begin{macrocode}
            \tagpdfsetup{paratag=P}%
            \tagpdfparaOn
            \noindent\ignorespaces##1\par
%    \end{macrocode}
% Restart the MC
%    \begin{macrocode}
            \tag_mc_begin_pop:n{}}%
          \penalty\predisplaypenalty\vskip\abovedisplayskip%
        }%
      }
    }
%    \end{macrocode}
%    
%    \begin{macrocode}
\@namedef{math@cr @ @ @ gather}{%
    \ifst@rred\nonumber\fi
   &\relax
    \make@display@tag
%
    \maybestartnewformulatag
%
    \ifst@rred\else\global\@eqnswtrue\fi
    \global\advance\row@\@ne
    \cr
}
%    \end{macrocode}
%    
%    \begin{macrocode}
\@namedef{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
%
    \maybestartnewformulatag
%
  \ifst@rred\else\global\@eqnswtrue\fi
  \global\lineht@\z@
  \cr
}
%    \end{macrocode}
%    
%    \begin{macrocode}
\def\restore@math@cr{\@namedef{math@cr @ @ @}{
%
    \maybestartnewformulatag
%
    \cr}}
\restore@math@cr
%    \end{macrocode}
%    
%    \begin{macrocode}
}
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
%
%
%

%  \begin{macro}{}
%    
%    \begin{macrocode}
\cs_new:Npn \@@_split_at_nl_first:w #1 \\ #2 \\ #3 \s_stop
  {
    \quark_if_nil:nTF {#2}
      { {#1} {  } }
      {
        \@@_split_chk_if_begin:ww #1 \begin \q_nil \s_mark
          #2 \\ #3 \s_stop
      }
  }
\cs_new:Npn \@@_split_chk_if_begin:ww #1 \begin #2 #3 \s_mark
    #4 \\ \q_nil \\ \s_stop
  {
    \quark_if_nil:nTF {#2}
      { {#1} {#4} }
      {
        \exp_after:wN \@@_split_collect_one_end:w
          \@@_split_cleanup_begin_q_nil:w #1 \begin{#2} #3 \\ #4 \s_stop
            { } { 1 }
      }
  }
\cs_new:Npn \@@_split_cleanup_begin_q_nil:w #1 \begin \q_nil {#1}
\cs_new:Npn \@@_split_collect_one_end:w #1 \end #2 #3 \s_stop #4 #5
  {
    \exp_args:Nf \@@_split_check_count_begins:nnnn
      { \@@_split_count_begins:n { #4 #1 } } {#5}
      { #4 #1 \end{#2} } {#3}
  }
\cs_new:Npn \@@_split_count_begins:n #1
  { \int_eval:n { 0 \@@_split_count_begins:w #1 \begin \q_nil } }
\cs_new:Npn \@@_split_count_begins:w #1 \begin #2
  { \quark_if_nil:nF {#2} { +1 \@@_split_count_begins:w } }
\cs_new:Npn \@@_split_check_count_begins:nnnn #1 #2 #3 #4
  {
    \int_compare:nNnTF {#1} = {#2}
      {
        \exp_last_unbraced:Nf \@@_split_final_cleanup:nn
          { \split:n { \@@_split_guard:n {#3} #4 } }
      }
      {
        \exp_args:No \use_ii_i:nn
          { \exp_after:wN { \int_value:w \int_eval:n { #2 + 1 } } }
          { \@@_split_collect_one_end:w #4 \s_stop {#3} }
      }
  }
\cs_new:Npn \@@_split_final_cleanup:nn #1 #2
  {
      \exp:w \@@_split_final_cleanup:w #1
        \@@_split_guard:n \q_nil \s_mark { }
      {#2}
  }
\cs_new:Npn \@@_split_final_cleanup:w #1 \@@_split_guard:n #2 #3 \s_mark #4
  {
    \quark_if_nil:nTF {#2}
      { \exp_end: { #4 #1 } }
      { \@@_split_final_cleanup:w #3 \s_mark { #4 #1 #2 } }
  }
\NewDocumentCommand \splitnl { mm +m }
  {
    \tl_set:Nf \l_tmpa_tl { \split:n {#3} }
    \show \l_tmpa_tl
    \exp_after:wN \__splitnl_aux:nnNN \l_tmpa_tl #1 #2
  }


\cs_new:Npn \split:n #1 {
    \@@_split_at_nl_first:w #1 \\ \q_nil \\ \s_stop }

\cs_new:Npn \@@_split_at_nl:NN #1#2 {
  \tl_set:Nf \l_tmpa_tl {
      \exp_after:wN \@@_split_at_nl_first:w #1 \\ \q_nil \\ \s_stop }
  \exp_after:wN \@@_split_at_nl_aux:nnNN \l_tmpa_tl #1 #2
}

\cs_new_protected:Npn \@@_split_at_nl_aux:nnNN #1 #2 #3 #4
  {
    \tl_gset:Nn #4 {#1}
    \tl_gset:Nn #3 {#2}
}

%    \end{macrocode}
%  \end{macro}
%
%
%  \begin{macro}{\maybestartnewformulatag}
%    
%    \begin{macrocode}

\newif\if@subformulas
\tl_new:N \result  
  
\cs_new_protected:Npn\grabaformulapartandstart {
  \@@_split_at_nl:NN  \g__math_grabbed_math_tl \result
  \typeout{====>first-result=\meaning\result}
  \typeout{====>first-tmpmathcontent=\meaning\g__math_grabbed_math_tl}
  \tl_if_empty:NTF \g__math_grabbed_math_tl
     {
       \typeout{====>formula~ has~ no~ subparts}
       \global\@subformulasfalse
     }
     {
       \typeout{====>formula~ has~ subparts}
       \global\@subformulastrue
       \edef\resulttitle{\g__math_grabbed_env_tl\space (part)}
       \tagstructbegin{tag=Formula,
%    \end{macrocode}
%    For now we don't put anything in /alt or /ActualText on subformulas
%    \begin{macrocode}
%         alt=\result,
         title-o=\resulttitle
       }
    }
    \tagmcbegin{}
}

\cs_new_protected:Npn\grabaformulapartandmayberestart {
  \@@_split_at_nl:NN  \g__math_grabbed_math_tl \result
  \typeout{====>result=\meaning\result}
  \typeout{====>tmpmathcontent=\meaning\g__math_grabbed_math_tl}
%  \tl_if_empty:NTF \g__math_grabbed_math_tl
%     {
%       \typeout{====>tmpmathcontent=empty}
%     }
%     {
%       \typeout{====>tmpmathcontent=not-empty}
       \edef\resulttitle{\g__math_grabbed_env_tl\space (part)}
       \tagstructbegin{tag=Formula,
         alt=\result,
         title-o=\resulttitle
       }
%    }
    \tagmcbegin{}
}
%    \end{macrocode}
%  \end{macro}
%
%
%
%
%    \begin{macrocode}
\def\maybestartnewformulatag {
\if@subformulas
 \ifmeasuring@\else
%
  \tl_if_empty:NF \g__math_grabbed_math_tl
     {
       \tagmcend 
       \tagstructend
       \grabaformulapartandmayberestart
     }
 \fi
\fi
}
%    \end{macrocode}
%
%    The breqn packages changes catcodes and that isn't yet covered
%    by our mechanism.
%    \begin{macrocode}
%\AddToHook{package/breqn/after}{
%  \typeout{===>~ in~ hook}
%  \math_register_halign_env:nn {dmath}{}
%  \math_register_halign_env:nn {dgroup*}{}
%}  
%    \end{macrocode}
%    
%    \begin{macrocode}
\ExplSyntaxOff
%    \end{macrocode}
%    
%    \begin{macrocode}
%<@@=>
%    \end{macrocode}
%    
%    \begin{macrocode}
%
%    \end{macrocode}
%
%    \begin{macrocode}
%</kernel>
%    \end{macrocode}
%
% \Finale
%
% 

