\iow_newline:
\c_backslash_str mml\c_space_tl \int_use:N \g_@@_math_total_int
\iow_newline:
\l_@@_tmpa_str
\iow_newline:
\l_@@_content_hash_tl
\iow_newline:
}
}
% \end{macrocode}
% \end{plugdecl}
%
% With luatex we automatically generate mathml with \pkg{luamml} if the package
% can be loaded and \pkg{unicode-math} is detected.
% We start the process in the begindocument/end hook
% so that the reading from a previous compilation can happen before!
%
% For other engines, for future name changes
% and in case luamml is not loaded we provide
% some commands
% \begin{macrocode}
\cs_new_protected:Npn\@@_provide_luamml_commands:
{
\providecommand\luamml_flag_structelem:{}
\cs_if_free:NT \luamml_structelem:
{
\cs_set_eq:NN\luamml_structelem:\luamml_flag_structelem:
}
\providecommand\luamml_flag_process:{}
\cs_if_free:NT \luamml_process:
{
\cs_set_eq:NN\luamml_process:\luamml_flag_process:
}
\providecommand\luamml_flag_ignore:{}
\cs_if_free:NT \luamml_ignore:
{
\cs_set_eq:NN\luamml_ignore:\luamml_flag_ignore:
}
}
% \end{macrocode}
% \begin{macrocode}
\sys_if_engine_luatex:TF
{
% \end{macrocode}
% Temporary (!) fixes for endarray
% \begin{macrocode}
\cs_new_protected:Npn \@@_correct_luamml_array_patches:
{
\AddToHook{package/array/after}
{
\cs_set:Npn \endarray
{
\tbl_crcr:n{endarray}
\__luamml_array_save_array:
\egroup
\UseTaggingSocket{tbl/finalize}
\tbl_restore_outer_cell_data:
\egroup
\mode_if_math:T { \__luamml_array_finalize_array: }
\@arrayright
\gdef \@preamble {}
}
\cs_set:Npn \@classz
{
\@classx
\@tempcnta \count@
\prepnext@tok
\@addtopreamble {
\ifcase \@chnum
\hfil
\hskip 1sp
\d@llarbegin
\cs_if_eq:NNTF \d@llarbegin \begingroup {
\insert@column
\d@llarend
} {
\__luamml_array_init_col:
\insert@column
\luamml_flag_save:nn {} {mtd}
\d@llarend
\__luamml_array_finalize_col:w 0~
}
\do@row@strut
\hfil
\or
\hskip 1sp
\d@llarbegin
\cs_if_eq:NNTF \d@llarbegin \begingroup {
\insert@column
\d@llarend
} {
\__luamml_array_init_col:
\insert@column
\luamml_flag_save:nn {} {mtd}
\d@llarend
\__luamml_array_finalize_col:w 1~
}
\do@row@strut
\hfil
\or
\hfil
\hskip 1sp
\d@llarbegin
\cs_if_eq:NNTF \d@llarbegin \begingroup {
\insert@column
\d@llarend
} {
\__luamml_array_init_col:
\insert@column
\luamml_flag_save:nn {} {mtd}
\d@llarend
\__luamml_array_finalize_col:w 2~
}
\do@row@strut
\or
\setbox \ar@mcellbox \vbox \@startpbox { \@nextchar }
\insert@pcolumn
\@endpbox
\ar@align@mcell
\do@row@strut
\or
\vtop \@startpbox { \@nextchar }
\insert@pcolumn
\@endpbox
\do@row@strut
\or
\vbox \@startpbox { \@nextchar }
\insert@pcolumn
\@endpbox
\do@row@strut
\fi
}
\prepnext@tok
}
}
}
% \end{macrocode}
%
% \begin{macrocode}
\AddToHook{begindocument/before}
{
\str_case:on \g_@@_luamml_load_tl
{
{ 1 } {
\RequirePackage { luamml }
\@@_correct_luamml_array_patches:
\AddToHook{begindocument/end}
{
\@@_luamml_activate_write:
}
}
{-1 } {
\AddToHook{begindocument/end}
{
\msg_note:nnnn { tag }
{ luamml-status }{ disabled }{ not~create }
}
}
{ 0 }
{
\@ifpackageloaded { unicode-math }
{
\RequirePackage { luamml }
\@@_correct_luamml_array_patches:
\AddToHook{begindocument/end}
{
\@@_luamml_activate_write:
}
}
{ \msg_warning:nn { tag }{ unicode-math-missing } }
}
}
\@@_provide_luamml_commands:
}
}
{
\@@_provide_luamml_commands:
}
\msg_new:nnn { tag }{ luamml-status }
{
luamml~has~been~#1~and~will~#2~an~MathML~file.
}
\msg_new:nnn { tag }{ unicode-math-missing }
{
The~package~unicode-math~is~missing\\
luamml~will~not~create~an~MathML~file.\\
To~avoid~this~warning~load~unicode-math~\\
or~disable~luamml~with~\\
\tl_to_str:n{\tagpdfsetup{math/mathml/luamml/load=false}}\\
or~force~luamml~with~\\
\tl_to_str:n{\tagpdfsetup{math/mathml/luamml/load=true}}
}
\cs_new_protected:Npn \@@_luamml_activate_write:
{
\bool_if:NT \g_@@_luamml_write_bool
{
% \end{macrocode}
% to avoid that nothing is written in the first run, we must activate the sockets:
% \begin{macrocode}
\bool_gset_true:N\g__tag_math_mathml_AF_bool
\AssignSocketPlug{tagsupport/math/struct/begin}{mathml-AF}
\AssignSocketPlug{tagsupport/math/struct/end}{mathml-AF}
\AssignSocketPlug{tagsupport/math/substruct/begin}{single}
\AssignSocketPlug{tagsupport/math/substruct/end}{single}
\int_set:Nn \l__luamml_pretty_int { 7 }
\RegisterFamilyMapping\symsymbols{oms}
\RegisterFamilyMapping\symletters{oml}
\AssignSocketPlug{tagsupport/math/mathml/write/prepare}{On}
\iow_new:N \g_@@_luamml_iow
\iow_open:Nn \g_@@_luamml_iow {\c_sys_jobname_str-luamml-mathml.html}
\iow_now:Ne \g_@@_luamml_iow { \c_@@_mathml_write_init_tl }
\cs_new:Npn \@@_luamml_output_hook:n ##1
{
\tl_if_empty:NF \l_@@_mathml_write_before_tl
{
\iow_now:Ne \g_@@_luamml_iow
{
\l_@@_mathml_write_before_tl
##1
\c_@@_mathml_write_after_tl
}
}
}
\__luamml_register_output_hook:N \@@_luamml_output_hook:n
% \end{macrocode}
% At the end of the document we must finish and close the file:
% \begin{macrocode}
\AddToHook{enddocument/afterlastpage}
{
\iow_now:Ne \g_@@_luamml_iow
{ \c_@@_mathml_write_final_tl }
\iow_close:N \g_@@_luamml_iow
}
\msg_note:nnnn { tag }
{ luamml-status }{ enabled }{ create }
}
}
% \end{macrocode}
% And now keys to activate/deactivate luamml feature
% \begin{variable}{\g_@@_luamml_load_tl}
% This variable will be used to suppress the loading of luamml
% altogether.
% \begin{macrocode}
\tl_new:N \g_@@_luamml_load_tl
\tl_gset:Nn \g_@@_luamml_load_tl {0}
% \end{macrocode}
% \end{variable}
% \begin{variable}{\g_@@_luamml_write_bool}
% This variable decides if luamml writes a mathml
% altogether.
% \begin{macrocode}
\bool_new:N \g_@@_luamml_write_bool
\bool_gset_true:N \g_@@_luamml_write_bool
% \end{macrocode}
% \end{variable}
% \begin{macro}{\@@_luamml_ignore:,\@@_luamml_structelem:}
% Internal variants of the luamml commands, that can be remapped if needed.
% \begin{macrocode}
\cs_new:Npn\@@_luamml_structelem:{}
\cs_new:Npn\@@_luamml_ignore:{}
% \end{macrocode}
% \end{macro}
%
% \begin{macrocode}
\msg_new:nnn { tag }{ PDF-2.0-recommended }
{
The~key~#1~will~not~work~properly~with~PDF~#2.\\
Switching~to~PDF~2.0~is~recommended.
}
\keys_define:nn { __tag / setup }
{
% \end{macrocode}
% At first a key to suppress the loading altogether
% \begin{macrocode}
math/mathml/luamml/load .choice: ,
math/mathml/luamml/load/true .code:n = {\tl_gset:Nn \g_@@_luamml_load_tl{1}},
math/mathml/luamml/load/false .code:n = {\tl_gset:Nn \g_@@_luamml_load_tl{-1}},
math/mathml/luamml/load .default:n = true,
math/mathml/luamml/load .usage:n=preamble,
% \end{macrocode}
% A key to activate math structure elements.
% \changes{v0.6j}{2024-11-19}{no longer enable globally for better fake math handling, issue \#764}
% \begin{macrocode}
math/mathml/structelem .choice:,
math/mathml/structelem/true .code:n =
{
\pdf_version_compare:NnT < {2.0}
{
\msg_warning:nnne { tag }{ PDF-2.0-recommended }
{ math/mathml/structelem }{ \pdf_version: }
}
\cs_set:Npn\@@_luamml_structelem:{\luamml_structelem:}
\cs_set:Npn\@@_luamml_ignore:{\luamml_ignore:}
},
math/mathml/structelem/false .code:n =
{
\cs_set_eq:NN\@@_luamml_structelem:\prg_do_nothing:
\cs_set_eq:NN\@@_luamml_ignore:\prg_do_nothing:
},
math/mathml/structelem .default:n = true,
% \end{macrocode}
% and a key to call the ignore flag. This should only be used locally.
% \begin{macrocode}
math/mathml/ignore .code:n = {\luamml_ignore:},
% \end{macrocode}
% \begin{macrocode}
math/mathml/luamml/write .choice:,
math/mathml/luamml/write/true .code:n =
{
\tl_gset:Nn \g_@@_luamml_load_tl{1}
\bool_gset_true:N \g_@@_luamml_write_bool
},
math/mathml/luamml/write/false .code:n =
{
\bool_gset_false:N \g_@@_luamml_write_bool
},
math/mathml/luamml/write .default:n = true,
math/mathml/luamml/write .usage:n=preamble,
% \end{macrocode}
% alias keys for compatibility
% \begin{macrocode}
math/mathml/luamml .bool_gset:N = \g_@@_luamml_write_bool,
math/mathml/luamml .usage:n=preamble
}
% \end{macrocode}
% \begin{socketdecl}{tagsupport/math/mathml/write}
% This writes a html-dummy with the hash and the math content.
% This should be optional, so it uses a socket that can be disabled
%
% \begin{macrocode}
\socket_new:nn {tagsupport/math/mathml/write}{0}
% \end{macrocode}
% \end{socketdecl}
%
% \begin{plugdecl}{On}
% \begin{macrocode}
\socket_new_plug:nnn{tagsupport/math/mathml/write}{On}
{
\iow_now:Ne \g_@@_writedummy_iow
{
\l_@@_mathml_write_before_tl
\c_@@_mathml_write_after_tl
}
}
% \end{macrocode}
% \end{plugdecl}
% And now a key to activate the socket.
% \begin{macrocode}
\keys_define:nn { __tag / setup }
{
math/mathml/write-dummy .code:n =
{
\bool_gset_true:N \g__tag_math_mathml_AF_bool
\tl_if_exist:NF\g_@@_writedummy_iow
{
\iow_new:N \g_@@_writedummy_iow
\iow_open:Nn \g_@@_writedummy_iow
{
\c_sys_jobname_str-mathml-dummy.html
}
\iow_now:Ne \g_@@_writedummy_iow
{
\c_@@_mathml_write_init_tl
}
\AssignSocketPlug {tagsupport/math/mathml/write/prepare}{On}
\AssignSocketPlug {tagsupport/math/mathml/write}{On}
\AddToHook{enddocument/afterlastpage}
{
\iow_now:Ne \g_@@_writedummy_iow
{ \c_@@_mathml_write_final_tl }
\iow_close:N \g_@@_writedummy_iow
}
}
},
math/mathml/write-dummy .usage:n=preamble
}
% \end{macrocode}
%
% \begin{macro}{\@@_AF_process_mathml_files:}
% \begin{macrocode}
\box_new:N\l_@@_tmpa_box
\cs_new_protected:Npn \@@_AF_process_mathml_files:
{
\hbox_set:Nn \l_@@_tmpa_box
{
\pdfdict_put:nnn { l_pdffile/Filespec }{AFRelationship} { /Supplement }
\pdfdict_put:nne
{ l_pdffile }{Subtype}
{ \pdf_name_from_unicode_e:n{application/mathml+xml} }
\char_set_catcode_other:N \#
\cs_set_eq:NN\mml \@@_AF_html_reader:w
\clist_map_inline:Nn \l__tag_math_mathml_files_clist
{
\file_if_exist:nTF {##1.html}
{
\typeout{Info:~reading~mathml~file~##1}
\file_input:n {##1.html}
\bool_gset_true:N\g__tag_math_mathml_AF_bool
}
{
\typeout{Info:~mathml~file~##1~does~not~exist}%info message
}
}
}
\bool_if:NT\g__tag_math_mathml_AF_bool
{
\typeout{Info:~Activating~mathml~support}
\AssignSocketPlug{tagsupport/math/struct/begin}{mathml-AF}
\AssignSocketPlug{tagsupport/math/struct/end}{mathml-AF}
% \end{macrocode}
% mathml handling doesn't like subparts, so we disable them for now:
% \begin{macrocode}
\AssignSocketPlug{tagsupport/math/substruct/begin}{single}
\AssignSocketPlug{tagsupport/math/substruct/end}{single}
\AddToHook{enddocument/info}
{
\iow_term:n{MathML~statistic}
\iow_term:n{================}
\iow_term:e{==>~\int_use:N\g_@@_mathml_total_int\c_space_tl
MathML~fragments~read}
\iow_term:e{==>~\int_use:N\g_@@_mathml_int\c_space_tl
different~MathML~fragments}
\iow_term:e{==>~\int_use:N\g_@@_math_total_int\c_space_tl
math~fragments~found}
\iow_term:e{==>~\int_use:N\g_@@_mathml_AF_found_int\c_space_tl
fitting~MathML~AF~found}
\iow_term:e{==>~\int_use:N\g_@@_mathml_AF_attached_int\c_space_tl
MathML~AF~attached}
}
}
}
\AddToHook{begindocument}{\@@_AF_process_mathml_files:}
% \end{macrocode}
% \end{macro}
%
% \subsection{Mathstyle detection}
% In some cases we need to detect the mathstyle used in a \cs{mathchoice}
% command and to disable/enable tagging in the unused branches.
% This is currently only used in the amstext command \cs{text}
% but is perhaps also needed in other cases, so we create a general command.
%
%\begin{macro}{\l_@@_mathstyle_int,\g_@@_mathchoice_int,mathstyle}
% \begin{macrocode}
\int_new:N \l_@@_mathstyle_int
\int_new:N \g_@@_mathchoice_int
\property_new:nnnn{mathstyle}{now}{-1}{\int_use:N \l_@@_mathstyle_int }
% \end{macrocode}
%\end{macro}
% For now internal, but perhaps will need a public version.
% The command should be used in every branch of a \cs{mathchoice}
% (with the correct mathstyle number) and with an unique label (which should
% be the same in every branch).
% \cs{g_@@_mathchoice_int} can be, e.g., increased before the mathchoice and
% then used.
% \begin{macro}{\@@_tag_if_mathstyle:nn}
% \begin{macrocode}
\cs_new_protected:Npn \@@_tag_if_mathstyle:nn #1 #2
%#1 refers to label
%#2 is a number for the mathstyle (typically 0,2,4,6)
{
\int_set:Nn \l_@@_mathstyle_int {#2}
\property_record:nn {#1} { mathstyle }
\int_compare:nNnTF { \property_ref:nn {#1}{ mathstyle} } = { #2 }
{ \tag_resume:n{\mathchoice} }{ \tag_suspend:n{\mathchoice} }
}
\cs_generate_variant:Nn \@@_tag_if_mathstyle:nn {en}
% \end{macrocode}
% \end{macro}
%
% \subsection{Tagging options}
% \begin{macrocode}
\keys_define:nn { __tag / setup }
{
math/mathml/sources .clist_set:N = \l__tag_math_mathml_files_clist,
math/alt/use .bool_set:N = \l__tag_math_alt_bool,
viewer/pane/mathml .bool_set:N = \l__tag_math_mathml_pane_bool,
viewer/pane/mathml .initial:n = true,
viewer/pane/mathsource .bool_set:N = \l__tag_math_texsource_pane_bool,
math/mathml/AF .bool_set:N = \l__tag_math_mathml_AF_bool,
math/mathml/AF .initial:n = true,
math/tex/AF .bool_set:N = \l__tag_math_texsource_AF_bool,
math/tex/AF .initial:n = true
}
% \end{macrocode}
% alt is required for pdf/UA-1.
% TODO: l3pdfmeta should support this test.
% \begin{macrocode}
\AddToHook{begindocument/end}
{
\str_if_eq:eeT
{1}
{
\exp_last_unbraced:Ne\use_i:nn
{\GetDocumentProperties{document/pdfstandard-UA}}
\c_empty_tl\c_empty_tl
}
{
\bool_if:NF \l__tag_math_alt_bool
{
\typeout{PDF/UA-1~detected.~Enabling~alt~text~on~Formula}
}
\bool_set_true:N\l__tag_math_alt_bool
}
}
% \end{macrocode}
%
% \subsection{Sockets}
% \subsubsection{Main inline math sockets}
%
% \begin{socketdecl}
% {
% tagsupport/math/inline/begin,
% tagsupport/math/inline/end,
% tagsupport/math/inline/formula/begin,
% tagsupport/math/inline/formula/end,
% }
% The first two sockets are meant to embed inline
% math into the surrounding (so to close/reopen, e.g., MC-chunks).
% The other two implement the actual formula structure.
% The formula sockets are despite their naming not symmetric:
% the begin socket is issued after the math has started, while
% the end socket is after the math!
% \changes{v0.6j}{2024-11-19}{change the socket to two arguments so that it can
% be used as tagging socket}
% \begin{macrocode}
\socket_new:nn {tagsupport/math/inline/begin}{0}
\socket_new:nn {tagsupport/math/inline/end}{0}
\socket_new:nn {tagsupport/math/inline/formula/begin}{2} %
\socket_new:nn {tagsupport/math/inline/formula/end}{0}
% \end{macrocode}
%\end{socketdecl}
%
%
% \begin{plugdecl}{MC}
% \begin{macrocode}
\socket_new_plug:nnn
{tagsupport/math/inline/begin}
{MC}
{\tag_mc_end_push:}
\socket_new_plug:nnn
{tagsupport/math/inline/end}
{MC}
{\tag_mc_begin_pop:n{}}
% \end{macrocode}
% \end{plugdecl}
%
% We probably will want to test different tagging recipes.
% \begin{plugdecl}{default}
% \begin{macrocode}
\socket_new_plug:nnn
{tagsupport/math/inline/formula/begin}
{default}
% \end{macrocode}
% \changes{v0.6g}{2024-10-02}{disable paratagging, issue \#711}
% \changes{v0.6j}{2024-11-19}{activate structelem locally issue \#764}
% \changes{v0.6j}{2024-11-19}{change to two arguments}
% \begin{macrocode}
{ \tagpdfparaOff
\@@_luamml_structelem:
\tag_socket_use:n{math/content}
\tag_socket_use:n{math/struct/begin}
% \end{macrocode}
% TODO: does inline math need subformula handling?
% \begin{macrocode}
% inner formula if multiple parts (not really implemented yet)
\tag_socket_use:n{math/substruct/begin}
#2
\tag_socket_use:n{math/end}
}
\socket_new_plug:nnn
{tagsupport/math/inline/formula/end}
{default}
{
\socket_use:n{tagsupport/math/substruct/end}
\socket_use:n{tagsupport/math/struct/end}
}
% \end{macrocode}
% \end{plugdecl}
%
% \subsubsection{Main display math sockets}
%
% \begin{socketdecl}
% {
% tagsupport/math/display/begin,
% tagsupport/math/display/end,
% tagsupport/math/display/formula/begin,
% tagsupport/math/display/formula/end,
% }
% The first two sockets are meant to embed display
% math into the surrounding (so to close/reopen, e.g., MC-chunks and
% P-structure).
% The other two implement the actual formula structure.
% The formula sockets are despite their naming not symmetric:
% the begin socket is issued after the math has started, while
% the end socket is after the math!
% \changes{v0.6j}{2024-11-19}{change number of arguments of formula/begin socket}
% \begin{macrocode}
\socket_new:nn {tagsupport/math/display/begin}{0}
\socket_new:nn {tagsupport/math/display/end}{0}
\socket_new:nn {tagsupport/math/display/formula/begin}{2} %
\socket_new:nn {tagsupport/math/display/formula/end}{0}
% \end{macrocode}
%\end{socketdecl}
% \begin{plugdecl}{default}
% \begin{macrocode}
\socket_new_plug:nnn
{tagsupport/math/display/begin}
{default}
{ \__tag_tool_close_P: }
\socket_new_plug:nnn
{tagsupport/math/display/end}
{default}
{
}
% \end{macrocode}
% \end{plugdecl}
% \begin{plugdecl}{default}
% \changes{v0.6j}{2024-11-19}{moved \cs{tagpdfparaOff} into the socket, tagging/765}
% \begin{macrocode}
\socket_new_plug:nnn
{tagsupport/math/display/formula/begin}
{default}
{
\tagpdfparaOff
\@@_luamml_structelem:
\tag_socket_use:n{math/content}
\tag_socket_use:n{math/struct/begin}
\tag_socket_use:n{math/substruct/begin}
#2
\tag_socket_use:n{math/end}
}
\socket_new_plug:nnn
{tagsupport/math/display/formula/end}
{default}
{
\socket_use:n{tagsupport/math/substruct/end}
\socket_use:n{tagsupport/math/struct/end}
}
% \end{macrocode}
% \end{plugdecl}
%
% \subsubsection{Internal sockets}
%
% \begin{variable}{\l_@@_content_template_tl}
% The default text used as alt or actual text.
% \begin{macrocode}
\tl_new:N\l_@@_content_template_tl
\tl_set:Nn \l_@@_content_template_tl
{
LaTeX~ formula~ starts~
\exp_not:N\begin{\g_@@_grabbed_env_tl}
\c_space_tl
\exp_not:V\g_@@_grabbed_math_tl
\c_space_tl
\exp_not:N\end{\g_@@_grabbed_env_tl}
\c_space_tl LaTeX~ formula~ ends~
}
% \end{macrocode}
% \end{variable}
% \begin{variable}{\l_@@_texsource_template_tl}
% The default text used as texsource
% \begin{macrocode}
\tl_new:N\l_@@_texsource_template_tl
\tl_const:Nn\c_@@_inline_env_tl {math}
\tl_set:Nn \l_@@_texsource_template_tl
{
\tl_if_eq:NNTF\g_@@_grabbed_env_tl\c_@@_inline_env_tl
{
$
\exp_not:V\g_@@_grabbed_math_tl
$
}
{
\exp_not:N\begin{\g_@@_grabbed_env_tl}
\exp_not:V\g_@@_grabbed_math_tl
\exp_not:N\end{\g_@@_grabbed_env_tl}
}
}
% \end{macrocode}
% \end{variable}
%
% \begin{socketdecl}{tagsupport/math/content}
% The math content is stored in associated files and used for
% actual and alternative text. As the exact text is still
% unclear we use a socket to be able to test variants.
% The socket should set all four tl vars above, if needed
% to identical values. It can use the two variables
% \cs{g_@@_grabbed_env_tl} and \cs{g_@@_grabbed_math_tl}
% \begin{macrocode}
\socket_new:nn {tagsupport/math/content}{0}
% \end{macrocode}
% \end{socketdecl}
%
% Some default sockets to set the contents.
% TODO: think about naming convention.
% TODO: think how this should organized so that one
% has options to change from the outside and so that
% there are less repetitions.
% \begin{plugdecl}{actual+source}
% \begin{macrocode}
\socket_new_plug:nnn
{tagsupport/math/content}
{actual+source}
{
\tl_set:Ne\l_@@_content_actual_tl
{
\l_@@_content_template_tl
}
\tl_set:Ne \l_@@_content_AF_source_tl
{
\l_@@_texsource_template_tl
}
\tl_set:Nn \l_@@_content_AF_mathml_tl {}
\tl_set:Nn \l_@@_content_alt_tl {}
}
% \end{macrocode}
% \end{plugdecl}
%
% \begin{plugdecl}{alt+source}
% \begin{macrocode}
\socket_new_plug:nnn
{tagsupport/math/content}
{alt+source}
{
\tl_set:Ne\l_@@_content_alt_tl
{
\l_@@_content_template_tl
}
\tl_set:Ne \l_@@_content_AF_source_tl
{
\l_@@_texsource_template_tl
}
\tl_set:Nn \l_@@_content_AF_mathml_tl {}
\tl_set:Nn \l_@@_content_actual_tl {}
}
% \end{macrocode}
% \end{plugdecl}
% \begin{macrocode}
\socket_assign_plug:nn {tagsupport/math/content}{alt+source}
% \end{macrocode}
%
% \begin{socketdecl}{tagsupport/math/struct/begin,
% tagsupport/math/struct/end}
% For the main structure we use a socket too.
% This allows, e.g., to create a special one for luamml
% which setups additional objects.
% The begin socket can use the two variables
% \cs{g_@@_grabbed_env_tl} and \cs{g_@@_grabbed_math_tl}
% \begin{macrocode}
\socket_new:nn {tagsupport/math/struct/begin}{0}
\socket_new:nn {tagsupport/math/struct/end}{0}
% \end{macrocode}
% \end{socketdecl}
%
% \begin{plugdecl}{default}
% TODO: think about some naming convention ...
% \begin{macrocode}
\socket_new_plug:nnn
{tagsupport/math/struct/begin}
{default}
{
\bool_if:NTF\l__tag_math_texsource_AF_bool
{ \tl_set_eq:NN \l_@@_content_AF_source_tmpa_tl \l_@@_content_AF_source_tl }
{ \tl_clear:N \l_@@_content_AF_source_tmpa_tl }
\tl_if_eq:NnTF\g_@@_grabbed_env_tl {math}
{
\tl_set:Nn\l_@@_attribute_class_tl{inline}
}
{
\tl_set:Nn\l_@@_attribute_class_tl{display}
}
\bool_if:NF\l__tag_math_alt_bool
{ \tl_set:Nn \l_@@_content_alt_tl{} }
\tag_struct_begin:n
{
tag=Formula,
attribute-class=\l_@@_attribute_class_tl,
texsource = \l_@@_content_AF_source_tmpa_tl,
title-o = \g_@@_grabbed_env_tl,
actualtext = \l_@@_content_actual_tl,
alt = \l_@@_content_alt_tl
}
}
\socket_new_plug:nnn
{tagsupport/math/struct/end}
{default}
{ \tag_struct_end: }
\socket_assign_plug:nn {tagsupport/math/struct/begin}{default}
\socket_assign_plug:nn {tagsupport/math/struct/end}{default}
% \end{macrocode}
% \end{plugdecl}
%
% \begin{plugdecl}{mathml-AF}
% This socket tries to add a mathml-AF to formula.
% It is activated if a mathml.html has been found and loaded.
% As it disturbs the reading of the AF
% it currently deactivates the /Alt key,
% unless it has been reenabled with |math/alt/use=true|
% \begin{macrocode}
\cs_generate_variant:Nn \str_mdfive_hash:n {o}
\tl_new:N\l_@@_content_hash_tl
% \end{macrocode}
% we need to save the grabbed math:
% \begin{macrocode}
\tl_new:N\l_@@_grabbed_math_tl
% \end{macrocode}
% the socket definition
% \begin{macrocode}
\socket_new_plug:nnn
{tagsupport/math/struct/begin}
{mathml-AF}
{
\int_gincr:N\g_@@_math_total_int
\tl_set:Ne\l_@@_content_hash_tl
{\str_mdfive_hash:o { \l_@@_content_AF_source_tl }}
\tl_set_eq:NN\l_@@_grabbed_math_tl\g_@@_grabbed_math_tl
\tl_if_eq:NnTF\g_@@_grabbed_env_tl {math}
{
\tl_set:Nn\l_@@_attribute_class_tl{inline}
}
{
\tl_set:Nn\l_@@_attribute_class_tl{display}
}
\bool_if:NF\l__tag_math_alt_bool
{ \tl_set:Nn \l_@@_content_alt_tl{} }
% \end{macrocode}
% debugging option. TODO: hide in debug key.
% \begin{macrocode}
\tl_if_exist:cTF { g_@@_mathml_ \l_@@_content_hash_tl _tl }
{
\int_gincr:N\g_@@_mathml_AF_found_int
\bool_if:NTF \l__tag_math_mathml_AF_bool
{
\int_gincr:N\g_@@_mathml_AF_attached_int
\typeout {Inserting~mathml~with~Hash~\l_@@_content_hash_tl}
}
{
\typeout {Ignoring~mathml~with~Hash~\l_@@_content_hash_tl}
}
}
{
\bool_if:NT \l__tag_math_mathml_AF_bool
{
\typeout {WARNING:~mathml~missing~for~hash~\l_@@_content_hash_tl}
}
}
\socket_use:n {tagsupport/math/mathml/write/prepare}
\socket_use:n {tagsupport/math/mathml/write} % write hash if request
\bool_if:NTF\l__tag_math_texsource_AF_bool
{ \tl_set_eq:NN \l_@@_content_AF_source_tmpa_tl \l_@@_content_AF_source_tl }
{ \tl_clear:N \l_@@_content_AF_source_tmpa_tl }
\tag_struct_begin:n
{
tag=Formula,
attribute-class=\l_@@_attribute_class_tl, %
AFref =
\bool_if:NT\l__tag_math_mathml_AF_bool
{
\cs_if_exist_use:c {g_@@_mathml_ \l_@@_content_hash_tl _tl}
},
texsource = \l_@@_content_AF_source_tmpa_tl, % should be after mathml AF!
title-o = \g_@@_grabbed_env_tl, %
alt = \l_@@_content_alt_tl
}
}
% \end{macrocode}
% not really needed but looks more symmetric:
% \begin{macrocode}
\socket_new_plug:nnn
{tagsupport/math/struct/end}
{mathml-AF}
{
\tag_struct_end:
}
% \end{macrocode}
% \end{plugdecl}
%
% \begin{socketdecl}{tagsupport/math/substruct/begin,
% tagsupport/math/substruct/end}
% This holds the code to handle subparts of the formula.
% \begin{macrocode}
\socket_new:nn {tagsupport/math/substruct/begin}{0}
\socket_new:nn {tagsupport/math/substruct/end}{0}
% \end{macrocode}
% \end{socketdecl}
%
% \begin{plugdecl}{default}
% \begin{macrocode}
\socket_new_plug:nnn
{tagsupport/math/substruct/begin}
{default}
{ \grabaformulapartandstart }
\socket_new_plug:nnn
{tagsupport/math/substruct/end}
{default}
{
\tagmcend
\if@subformulas
\tagstructend
\fi
}
\socket_assign_plug:nn {tagsupport/math/substruct/begin}{default}
\socket_assign_plug:nn {tagsupport/math/substruct/end}{default}
% \end{macrocode}
% \end{plugdecl}
% \begin{plugdecl}{single}
% We need an option to disable subparts as it is unclear
% if consumers can handle them:
% \begin{macrocode}
\socket_new_plug:nnn
{tagsupport/math/substruct/begin}
{single}
{
\typeout{====>subpart~splitting~deactivated}
\typeout{====>grabbed~math=\meaning\g_@@_grabbed_math_tl}
\tag_mc_begin:n{}
}
\socket_new_plug:nnn
{tagsupport/math/substruct/end}
{single}
{ \tag_mc_end:}
% \end{macrocode}
% \end{plugdecl}
%
% \begin{socketdecl}{tagsupport/math/end}
% A socket used at the end of the math (before the closing dollar(s))
% which can, e.g., set a flag for luamml.
% \begin{macrocode}
\socket_new:nn {tagsupport/math/end}{0}
% \end{macrocode}
% \end{socketdecl}
%
%
% \changes{v0.6j}{2024-11-19}{removed enable/disable command and assign tagging sockets directly}
% \begin{macrocode}
\socket_assign_plug:nn {tagsupport/math/inline/begin}{MC}
\socket_assign_plug:nn {tagsupport/math/inline/end}{MC}
\socket_assign_plug:nn {tagsupport/math/inline/formula/begin}{default}
\socket_assign_plug:nn {tagsupport/math/inline/formula/end}{default}
\socket_assign_plug:nn {tagsupport/math/display/begin}{default}
\socket_assign_plug:nn {tagsupport/math/display/end}{default}
\socket_assign_plug:nn {tagsupport/math/display/formula/begin}{default}
\socket_assign_plug:nn {tagsupport/math/display/formula/end}{default}
% \end{macrocode}
%
%
% \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:nnTF {#2} { \m@th }
{ \bool_set_true:N\l_@@_fakemath_bool }
{ \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}
% \begin{macro}{\@@_grab_dollar:n}
% \changes{v0.6c}{2024-08-22}{Correct handling of empty math segments}
% Top-level function to handle grabbing of inline math mode delimited by
% |$| tokens. We provide two different ways to do that: a token-by-token
% one that can be used everywhere, and a fast delimited one that does not
% work anywhere that the end |$| token may be hidden, most obviously in
% tabulars. The function here is therefore set up as a variable starting
% point.
% \begin{macrocode}
\cs_new_protected:Npn \@@_grab_dollar:w { \@@_grab_dollar_delim:w }
% \end{macrocode}
% After grabbing inline math material, there is again common processing
% independent of mechanism of collection.
% \begin{macrocode}
\cs_new_protected:Npn \@@_grab_dollar:n #1
{
% \end{macrocode}
% We need to do processing first as this picks up \enquote{fake} math mode:
% that information is needed below.
% \begin{macrocode}
\@@_process:nn { math } {#1}
% \end{macrocode}
% We do not want math tagging in fakemath or when measuring,
% We also do not want math tagging if tagging has been suspended.
% \begin{macrocode}
\bool_lazy_any:nTF
{
{\legacy_if_p:n { measuring@ }}
{ \l_@@_fakemath_bool }
{ \tl_if_blank_p:n {#1} }
}
{
\@@_luamml_ignore:
#1 $ % $
}
{
\tag_socket_use:n {math/inline/begin} %end P-MC
% \end{macrocode}
% We do no use a tagging socket here, so that the argument (the
% math) is not lost, tagging-project issue 661.
% \changes{v0.6j}{2024-11-19}{change socket to tagging socket}
% \begin{macrocode}
\tag_socket_use:nnn {math/inline/formula/begin}{}{#1}
$ % $
\tag_socket_use:n {math/inline/formula/end}
\tag_socket_use:n {math/inline/end} % restart P-MC
}
}
% \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\@@_grab_dollar_delim:w}
% Grab up to a single |$|, for inline math mode, suppressing
% any processing if the token is \tn{m@th} found in the content.
% \begin{macrocode}
\cs_new_protected:Npn \@@_grab_dollar_delim:w #1 $ % $
{ \@@_grab_dollar:n {#1} }
% \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_grab_dollardollar:w}
% And for the classical \TeX{} display structure.
% \begin{macrocode}
\cs_new_protected:Npn \@@_grab_dollardollar:w % $$
#1 $$
{
\tl_if_blank:nF {#1}
{
\@@_process:nn { equation* } {#1}
\tag_socket_use:n {math/display/begin}
\tag_socket_use:nn{math/display/formula/begin}{}{#1}
}
$$
}
% \end{macrocode}
%
% The end code is added through a \cs{aftergroup} so we
% store it inside a command.
% \changes{v0.6j}{2024-11-19}{removed unneeded \cs{tagpdfparaOn}}
% \begin{macrocode}
\cs_new_protected:Npn \@@_tag_dollardollar_display_end:
{
% \typeout{== tag dollarldollar display end}
% \ShowTagging{struct-stack}
\para_raw_end:
% \end{macrocode}
% The \cs{postdisplaypenalty} was temporarily set to 10000 inside
% the display and the \cs{belowdisplayskip} and the
% \cs{belowdisplayshortskip} was negated, so whatever was inserted
% it should have been a negative skip. Whatever skip was added we
% pick it ups value up here, so that we can correct the spacing
% after the tagging code was inserted.
% \begin{macrocode}
\l_@@_tmpa_skip \lastskip
\tag_socket_use:n{math/display/formula/end}
% \end{macrocode}
% Now we add a skip without indroducing a page break possibility,
% that should bring the current vertical position back to the point
% where \TeX{} would add the penalty and the \enquote{below skip}.
% \changes{v0.6f}{2024-09-30}{Correct logic for inserting below skips
% after displays (tagging/721)}
% \begin{macrocode}
\nobreak
\skip_vertical:n { -\l_@@_tmpa_skip } % remove the negative belowdisplayskip
% \end{macrocode}
% Then we finally add the real stuff:
% \begin{macrocode}
\penalty \postdisplaypenalty
\skip_vertical:n { -\l_@@_tmpa_skip } % insert the correct 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}
{
$ #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{Token-by-token inline grabbing}
%
% Grabbing inline math token-by-token is more involved. The mechanism here
% is essentially a simplified version of that originally seen in
% \pkg{collcell} and refined in \pkg{siunitx}. We make use of the fact that
% in math mode spaces are ignored, so we have to deal with only \texttt{N}-type
% tokens and groups. Furthermore, there is no need to look inside groups, so
% the only special cases are a small selection of \texttt{N}-type tokens.
%
% \begin{variable}{\l_@@_grabbed_tl}
% For collection of the material piecewise.
% \begin{macrocode}
\tl_new:N \l_@@_grabbed_tl
% \end{macrocode}
% \end{variable}
%
% \begin{variable}{\l_@@_grab_env_int}
% Needed to count up the number of nested environments encountered.
% \begin{macrocode}
\int_new:N \l_@@_grab_env_int
% \end{macrocode}
% \end{variable}
%
% \begin{macro}{\@@_grab_dollar_loop:}
% \begin{macro}{\@@_grab_loop:}
% The lead-off here establishes a group: we need that as we will have to
% be careful in the way \tn{cr} is handled and ensure this is only
% manipulated whilst grabbing. The main loop is then started.
% \begin{macrocode}
\cs_new_protected:Npn \@@_grab_dollar_loop:
{
\group_begin:
\tl_clear:N \l_@@_grabbed_tl
\@@_grab_loop:
}
\cs_new_protected:Npn \@@_grab_loop:
{
\peek_remove_spaces:n
{
\peek_meaning:NTF \c_group_begin_token
{ \@@_grab_loop_group:n }
{ \@@_grab_loop_token:N }
}
}
% \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\@@_grab_loop_group:n}
% \begin{macro}{\@@_grab_loop_store:n}
% Handling of grabbed groups is pretty easy.
% \begin{macrocode}
\cs_new_protected:Npn \@@_grab_loop_group:n #1
{ \@@_grab_loop_store:n { {#1} } }
\cs_new_protected:Npn \@@_grab_loop_store:n #1
{
\tl_put_right:Nn \l_@@_grabbed_tl {#1}
\@@_grab_loop:
}
% \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\@@_grab_loop_token:N}
% \begin{macro}
% {
% \@@_grab_loop_$: ,
% \@@_grab_loop_\\: ,
% \@@_grab_loop_\begin: ,
% \@@_grab_loop_\end: ,
% \@@_grab_loop_\ignorespaces: ,
% \@@_grab_loop_\unskip: ,
% \@@_grab_loop_\textonly@unskip:
% }
% Filter out the special cases: for performance reasons, use a hash table
% approach rather than a loop (\emph{cf.}~\pkg{collcell}).
% \begin{macrocode}
\cs_new_protected:Npn \@@_grab_loop_token:N #1
{
\cs_if_exist_use:cF
{ @@_grab_loop_ \token_to_str:N #1 : }
{ \@@_grab_loop_store:n {#1} }
}
\cs_new_protected:cpn { @@_grab_loop_ \token_to_str:N $ : }
{ \@@_grab_loop_end: }
\cs_new_protected:cpn { @@_grab_loop_ \token_to_str:N \\ : }
{
\int_compare:nNnTF \l_@@_grab_env_int = 0
{ \@@_grab_loop_newline: }
{ \@@_grab_loop_store:n { \\ } }
}
% \end{macrocode}
% In contrast to \pkg{collcell}, nesting is tracked by counting
% \cs{begin}/\cs{end} pairs: this is needed in case there is a tabular-like
% construct containing |\\| inside a cell. As a result, the end-of-tabular
% can be detected without checking the name argument: if \cs{end} is
% encountered at nesting level~0, we've hit the end of a cell. In that case,
% end the row and leave the environment to clean up.
% \begin{macrocode}
\cs_new_protected:cpn { @@_grab_loop_ \token_to_str:N \begin : }
{
\int_incr:N \l_@@_grab_env_int
\@@_grab_loop_store:n { \begin }
}
\cs_new_protected:cpn { @@_grab_loop_ \token_to_str:N \end : }
{
\int_compare:nNnTF \l_@@_grab_env_int = 0
{
\@@_grab_loop_newline:
\end
}
{
\int_decr:N \l_@@_grab_env_int
\@@_grab_loop_store:n { \end }
}
}
\tl_map_inline:nn { \ignorespaces \unskip \textonly@unskip }
{
\cs_new_protected:cpn { @@_grab_loop_ \token_to_str:N #1 : }
{ \@@_grab_loop: }
}
% \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\@@_grab_loop_newline:}
% To allow collection of tokens in the part of the \tn{halign} template after
% |#|, we need \TeX{} to see the primitive with the loop token in the right
% place. That is done by re-defining \tn{cr} at present. Ideally there would
% be a socket in the definition of \texttt{tabular}, etc., to handle this:
% there is also the need to examine in interaction with \pkg{longtable}, which
% also redefines \tn{cr}.
% \begin{macrocode}
\cs_new_protected:Npn \@@_grab_loop_newline:
{
\if_false: { \fi:
\cs_set_protected:Npn \cr
{
\@@_grab_loop:
\tex_cr:D
}
\if_false: } \fi:
\\
}
% \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_grab_loop_end:}
% Clean up and pass on.
% \begin{macrocode}
\cs_new_protected:Npn \@@_grab_loop_end:
{
\exp_args:NNV \group_end:
\@@_grab_dollar:n \l_@@_grabbed_tl
}
% \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 { nne } \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: }
% \exp_not:N \tracingnone
}
{
}
}
\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 { nnee } \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:N \tracingnone
}
{
\exp_not:c { @@_env_ #1 _end: }
}
}
% \end{macrocode}
% TODO: the following command is neither documented nor used. Is is needed?
% \begin{macrocode}
\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 { nnee } \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}
%
\tag_if_active:T
{
\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}
\__tag_tool_close_P:
}
\tag_socket_use:nn{math/display/formula/begin}{}{}
% \typeout{==>MC1}\ShowTagging{mc-current}
}
\cs_new:Npn \@kernel@math@registered@end {
% \typeout{==>MC2}\ShowTagging{mc-current}
\para_raw_end:
\tagpdfparaOn
\tag_socket_use:n{tagsupport/math/display/formula/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 }
{ $ }
}
{
\@@_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 \[ % \]
{
\@@_grab_eqn:w
% \bool_if:NTF \l_@@_collected_bool
% { \begin { equation* } }
% { \@@_grab_eqn:w }
} % \[
\cs_gset_protected:Npn \]
{
\@badmath
% \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}
\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}
%
% Tabulars currently contain a \$ that shouldn't trigger math
% tagging.
% \begin{macrocode}
\RequirePackage{array}
\tl_if_in:NnT\@tabular{$}
{
\def\@tabular{%
\leavevmode
\UseTaggingSocket{tbl/hmode/begin}%
\hbox \bgroup
\bool_set_true:N \l_@@_collected_bool
$
\bool_set_false:N \l_@@_collected_bool
\col@sep\tabcolsep \let\d@llarbegin\begingroup
\let\d@llarend\endgroup
% \end{macrocode}
% A proper switching mechanism is needed: for the present, do directly.
% \begin{macrocode}
\cs_set_protected:Npn \@@_grab_dollar:w { \@@_grab_dollar_loop: }
\@tabarray}
}
% \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{Disable math grabbing in the begindocument hook}
% For example amsart uses math to measure text there.
%
% \begin{macrocode}
\tl_gput_right:Nn\@kernel@before@begindocument
{
\bool_set_true:N\l_@@_collected_bool
}
\tl_gput_right:Nn\@kernel@after@begindocument
{
\bool_set_false:N\l_@@_collected_bool
}
% \end{macrocode}
%
% \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_suspend:n{\measuring}}
% \end{macrocode}
%
% \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 {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}
\@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}{\@@_split_at_nl:NN}
% This splits grabbed math at newlines.
%
% \begin{macrocode}
\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
}
% \end{macrocode}
% and the auxiliary commands
% \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_protected:Npn \@@_split_at_nl_aux:nnNN #1 #2 #3 #4
{
\tl_gset:Nn #4 {#1}
\tl_gset:Nn #3 {#2}
}
\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 } }
}
\cs_new:Npn \@@_split:n #1 {
\@@_split_at_nl_first:w #1 \\ \q_nil \\ \s_stop }
% this looks unused.
%\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
% }
% \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_@@_grabbed_math_tl \result
\typeout{====>first-result=\meaning\result}
\typeout{====>first-tmpmathcontent=\meaning\g_@@_grabbed_math_tl}
\tl_if_empty:NTF \g_@@_grabbed_math_tl
{
\typeout{====>formula~ has~ no~ subparts}
\global\@subformulasfalse
}
{
\typeout{====>formula~ has~ subparts}
\global\@subformulastrue
\edef\resulttitle{\g_@@_grabbed_env_tl\space (part)}
\tagstructbegin{tag=Formula,
% \end{macrocode}
% For now we don't put real content in /alt or /ActualText on subformulas
% but we add a short text to satisfy the pdf/ua-2 validator
% \begin{macrocode}
% alt=\result,
alt = subformula,
title-o=\resulttitle
}
}
\tagmcbegin{}
}
\cs_new_protected:Npn\grabaformulapartandmayberestart {
\@@_split_at_nl:NN \g_@@_grabbed_math_tl \result
\typeout{====>result=\meaning\result}
\typeout{====>tmpmathcontent=\meaning\g_@@_grabbed_math_tl}
% \tl_if_empty:NTF \g_@@_grabbed_math_tl
% {
% \typeout{====>tmpmathcontent=empty}
% }
% {
% \typeout{====>tmpmathcontent=not-empty}
\edef\resulttitle{\g_@@_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_@@_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}
%
% \Finale
%
%