diff options
author | Norbert Preining <norbert@preining.info> | 2023-09-15 03:02:43 +0000 |
---|---|---|
committer | Norbert Preining <norbert@preining.info> | 2023-09-15 03:02:43 +0000 |
commit | deda1937c52481b2259e1061840b99e18e8ca361 (patch) | |
tree | 2dede32b7c181f98c1fa00cfa9d531a306e5d5fd /macros/latex-dev/required/latex-lab/latex-lab-math.dtx | |
parent | 527001b634c06d34f92d1809f507add012c320f6 (diff) |
CTAN sync 202309150302
Diffstat (limited to 'macros/latex-dev/required/latex-lab/latex-lab-math.dtx')
-rw-r--r-- | macros/latex-dev/required/latex-lab/latex-lab-math.dtx | 1314 |
1 files changed, 1314 insertions, 0 deletions
diff --git a/macros/latex-dev/required/latex-lab/latex-lab-math.dtx b/macros/latex-dev/required/latex-lab/latex-lab-math.dtx new file mode 100644 index 0000000000..d593f93320 --- /dev/null +++ b/macros/latex-dev/required/latex-lab/latex-lab-math.dtx @@ -0,0 +1,1314 @@ +% \iffalse meta-comment +% +%% File: latex-lab-math.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\ltlabmathdate{2023-09-11} +\def\ltlabmathversion{0.5c} +% +%<*driver> +\documentclass{l3doc} +\EnableCrossrefs +\CodelineIndex + +\usepackage{todonotes} + +\begin{document} + \DocInput{latex-lab-math.dtx} +\end{document} +%</driver> +% +% \fi +% +% +% \title{The \texttt{latex-lab-math} code\thanks{}} +% \author{Frank Mittelbach, Joseph Wright, \LaTeX{} Project} +% \date{v\ltlabmathversion\ \ltlabmathdate} +% +% \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-math.ltx} + [\ltlabmathdate\space + v\ltlabmathversion\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}} +% \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 +% \end{macrocode} +% We do not want math tagging in fakemath or when measuring, +% so we imitate the test inside +% \cs{@@_process:nn} for now, see https://github.com/latex3/tagging-project/issues/5 +% \begin{macrocode} + \legacy_if:nTF { measuring@ } + { #1 $ } + { + \tl_if_in:nnTF {#1} { \m@th } + { #1 $ } + { + \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 + $$ + } + } +% \end{macrocode} +% To allow to use the code without tagging we guard. But probably tagpdf should +% provide some tools for such manual para-ends. +% \begin{macrocode} +\cs_new_protected:Npn \@kernel@close@P { + \tag_if_active:T + { + \tagmcend %end P-chunk, should perhaps be \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 +% \end{macrocode} +% This reinserts the below display skips. It must be doubled to +% get the right amount: +% \begin{macrocode} + \skip_vertical:n { -\l_@@_tmpa_skip * 2 } +% + \@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} +% \end{macrocode} +% flipping the \cs{belowdisplay} values is done so that we get (assumption) +% a negative skip and not make the page bigger then we take that out, +% then we add the tagging code (in \cs{@@_tag_dollardollar_display_end} ) and +% then we put a real \cs{postdisplaypenalty} in and +% the right skip (of which we don't know if it is short or a +% normal \cs{belowdisplayskip}). This might need some refinement if that skip +% is actually negative from the start +% (not sure it ever is and is worth bothering about) +% \begin{macrocode} + \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 +% +% |