summaryrefslogtreecommitdiff
path: root/macros/latex-dev/required/latex-lab/latex-lab-table.dtx
diff options
context:
space:
mode:
authorNorbert Preining <norbert@preining.info>2023-11-03 03:02:40 +0000
committerNorbert Preining <norbert@preining.info>2023-11-03 03:02:40 +0000
commit1e464deefd235880a2fac2390e896bfd2b523151 (patch)
treee9294919c95d4a444e911d20d2e3ddd60e45f9d1 /macros/latex-dev/required/latex-lab/latex-lab-table.dtx
parent2da66dea964ffa47d24f26081f2942a6e1ef1121 (diff)
CTAN sync 202311030302
Diffstat (limited to 'macros/latex-dev/required/latex-lab/latex-lab-table.dtx')
-rw-r--r--macros/latex-dev/required/latex-lab/latex-lab-table.dtx1975
1 files changed, 1975 insertions, 0 deletions
diff --git a/macros/latex-dev/required/latex-lab/latex-lab-table.dtx b/macros/latex-dev/required/latex-lab/latex-lab-table.dtx
new file mode 100644
index 0000000000..700d4ce6c1
--- /dev/null
+++ b/macros/latex-dev/required/latex-lab/latex-lab-table.dtx
@@ -0,0 +1,1975 @@
+% \iffalse meta-comment
+%
+%% File: latex-lab-table.dtx (C) Copyright 2023 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\ltlabtbldate{2023-10-30}
+\def\ltlabtblversion{0.85d}
+%<*driver>
+\documentclass{l3doc}
+\EnableCrossrefs
+\CodelineIndex
+\begin{document}
+ \DocInput{latex-lab-table.dtx}
+\end{document}
+%</driver>
+%
+% \fi
+%
+% \providecommand\hook[1]{\texttt{#1\DescribeHook[noprint]{#1}}}
+% \providecommand\socket[1]{\texttt{#1\DescribeSocket[noprint]{#1}}}
+% \providecommand\plug[1]{\texttt{#1\DescribePlug[noprint]{#1}}}
+%
+% \NewDocElement[printtype=\textit{socket},idxtype=socket,idxgroup=Sockets]{Socket}{socketdecl}
+% \NewDocElement[printtype=\textit{hook},idxtype=hook,idxgroup=Hooks]{Hook}{hookdecl}
+% \NewDocElement[printtype=\textit{plug},idxtype=plug,idxgroup=Plugs]{Plug}{plugdecl}
+%
+%
+%
+%
+% \title{The \textsf{latex-lab-table} package\\
+% Changes related to the tagging of tables}
+% \author{Frank \& Ulrike, \LaTeX{} Project\thanks{Initial implementation done by Frank Mittelbach}}
+% \date{v\ltlabtblversion\ \ltlabtbldate}
+%
+% \maketitle
+%
+% \newcommand{\xt}[1]{\textsl{\textsf{#1}}}
+% \newcommand{\TODO}[1]{\textbf{[TODO:} #1\textbf{]}}
+% \newcommand{\docclass}{document class \marginpar{\raggedright document class
+% customizations}}
+%
+%
+% \begin{abstract}
+% The following code implements a first draft for the tagging of
+% tables. It still has a large number of limitations and restrictions!
+% \end{abstract}
+%
+% \tableofcontents
+%
+% \section{Documentation}
+%
+% In \LaTeX{} the word \texttt{table} is used as the name of the float environment that can contain
+% a data table\footnote{But it does not really have to, you can put
+% other material into such environments.} along with a caption and some additional text. The environments for
+% actual data tables have various names like \texttt{tabular}, \texttt{tabular*},
+% \texttt{tabularx} and \texttt{longtable}---the last should not be used inside a float
+% and supports its own caption command.
+%
+% In this documentation \enquote{table} always means such data tables and not the float
+% environment.
+%
+% Tagging of tables is on one side doesn't look very difficult: one only has to
+% surround rows and cells by TR and TH or TD structures.
+% But there are difficulties:
+% \begin{itemize}
+% \item
+% One is that over the years various packages related to tables have
+% been written that all change some of the internals. Inserting the
+% tagging commands and testing all the variants and various nestings
+% is not trivial.
+%
+% \item
+% The other difficulty is that most of the existing environments to
+% create tables do not know the concept of headers as a semantic
+% structures.
+%
+% \item
+% Headers are only produced through visual formatting, e.g., by
+% making them bold or by underlying some color. But accessible
+% tables need headers (and the PDF/UA standards requires them) and
+% this means that additional syntax to declare headers (when they
+% can't be guessed) must be developed. This is still an area for
+% research.
+% \end{itemize}
+%
+% Right now, this module therefore does implement only some basic
+% support for the tagging of tables. A list of the known limitations
+% is shown below.
+%
+% The module is not loaded automatically (i.e., not yet integrated
+% into any \texttt{phase-XX}) and by itself it doesn't activate
+% tagging. For experimenting with table tagging it is therefore best
+% to load it in combination
+% with phase-III in \cs{DocumentMetadata}, i.e.:
+%
+% \begin{verbatim}
+% \DocumentMetadata{testphase={phase-III,table}}
+% \end{verbatim}
+%
+% It will then automatically tag all table environments it already supports with
+% the exception of tables in the header and footer of the page (where tagging is disabled).
+% Such tables can be nested.
+%
+% If a table should not be tagged as table, for example because it is merely used
+% to produce a layout or because it is a not yet (fully) supported table structure,
+% the tagging can be disabled with
+% \verb|\tagpdfsetup{table-tagging=false}|.
+%
+% Inside cells the automatic tagging of paragraphs is disabled with the exception of
+% p/m/b-type cells.
+%
+% Rows do not need to contain a full number of \&, missing cells are automatically
+% added with an empty TD-structure.
+%
+% There is some basic support\footnote{This is not meant to be the
+% final interface, though.} for headers. With
+% \begin{quote}
+% \verb|\tagpdfsetup{table-header-rows={|\meta{list of row numbers}\verb|}|
+% \end{quote}
+% you can
+% declare which (absolute) row numbers should be tagged as header rows.
+% It applies to all tables until it is changed to a different list of row numbers or undone by setting
+% the key to \meta{empty}.
+% A row number can be
+% negative, then the counting starts from the end of the table. There is no support
+% for header columns yet. In a \env{longtable} the code will currently use the \cs{endhead} or
+% \cs{endfirsthead} rows as header if one of these commands has been
+% used and in that case the code
+% ignores a \texttt{table-header-rows} setting.
+%
+% You should not insert meaningful text with \verb+!{...}+ or \verb+@{...}+ or \cs{noalign}
+% between the rows or columns of the table.
+% With pdflatex such text will be unmarked, with lualatex it will be marked as artifact.
+% Either case means that it will be currently ignored in the
+% structure.\footnote{While it is theoretically possible
+% to collect such text and move it into a structure it would require manual markup
+% from the author to clarify where this text belongs too.}
+%
+% As mentioned below the \pkg{colortbl} doesn't yet work properly with the tagging,
+% but once it does, then colors inside the table will probably be
+% simply ignored (at least initially). If such a color
+% has a semantic meaning (like \enquote{important value}) this meaning will be lost.
+%
+% Feedback and problems with the code can be reported at
+% \url{https://github.com/latex3/tagging-project} either in form of
+% explicit issues or as a \enquote{discussion topic}, whatever works best.
+%
+%
+% \section{Limitations}
+%
+% \begin{itemize}
+% \item The code loads the \pkg{array} package and so does not work without it (that is
+% not really a limitation, but can affect existing tables).
+%
+% \item It supports only a restricted number of tables types. Currently
+% \env{tabular}, \env{tabular*}, \env{tabularx}, and \env{longtable}.
+%
+% \item the \env{array} environment is assumed to be part of math and tagging as a table is disabled for
+% it.
+%
+% \item Row spans are not yet supported (and the \pkg{multirow} package is untested).
+%
+% \item The \pkg{colortbl} package breaks tagging if there are nested tables. It also breaks
+% the filling up of incomplete rows.
+%
+% \item The \pkg{tabularray} package use a completed different
+% method to create tables and will not be supported by this code.
+%
+% \item The \pkg{nicematrix} package is currently incompatible.
+%
+% \item Most other packages related to tables in \LaTeX{} are not yet tested,
+% that includes packages that change rules like \pkg{booktabs}, \pkg{hhline},
+% \pkg{arydshln}, \pkg{hvdashln}.
+%
+% \item \env{longtable} currently only works with lualatex.
+% With other engines it breaks as its output
+% routine clashes with the code which closes open MC-chunks at pagebreaks and
+% if this is resolved there will probably be problems with the head and foot boxes
+% (but this can't be tested currently).
+%
+% \item Not every table should be tagged as a Table structure, often they are
+% only used as layout help, e.g. to align authors in a title pages. In such uses
+% the tagging of the table must be deactivated with \verb|\tagpdfsetup{table-tagging=false}|.
+%
+% \item Only simple header rows are currently supported. Columns and complex headers with
+% subheaders will be handled later as that needs some syntax changes. Tables
+% with more than one header row are probably not pdf/UA as the headers array in
+% the cells is missing.
+%
+% \item A \pkg{longtable} \cs{caption} is currently simply formatted as a multicolumn and
+% not tagged as a \texttt{Caption} structure.
+%
+% \item The \pkg{caption} package will quite probably break the \pkg{longtable} caption.
+%
+% \item The setup for \pkg{longtable} requires lots of patches to internal \pkg{longtable}
+% commands and so can easily break if other packages try to patch \pkg{longtable} too.
+%
+% \item The \env{longtable} environment supports footnotes in p-type columns, but it hasn't been
+% tested yet if this works also with the tagging code.
+%
+% \item The code is quite noisy and fills the log with lots of
+% messages.\footnote{Helpful for us at this stage.}
+% \end{itemize}
+%
+%
+%
+% \section{Introduction}
+%
+%
+% \section{Technical details and problems}
+%
+% The implementation has to take care of various details.
+%
+% \subsection{TODOs}
+%
+% \begin{itemize}
+% \item
+% Test \texttt{array-006-longtable.lvt} and
+% \texttt{array-007-longtable.lvt} have errors with pdftex (para
+% tagging)
+%
+% \item
+% Instead of before/after hooks we should add sockets directly
+% into the code.
+%
+% \item Debugging code and messages must be improved.
+%
+% \item Cells need an \texttt{Headers} array.
+%
+% \item Row spans should be supported (but perhaps need syntax support)
+%
+% \item Longtable captions should be properly supported.
+%
+% \item Handle p-cells better. para-tagging should probably be enabled,
+% but Part can't be a child of TD, so this should probably be changed to Div here.
+% Also there is a stray MC somewhere.
+%
+% \item More packages must be tested.
+% \end{itemize}
+%
+%
+% \section{Implementation}
+% \begin{macrocode}
+%<@@=tbl>
+%<*package>
+% \end{macrocode}
+% \begin{macrocode}
+\ProvidesExplPackage {latex-lab-testphase-table} {\ltlabtbldate} {\ltlabtblversion}
+ {Code related to the tagging of tables}
+% \end{macrocode}
+% This builds on \pkg{array} so we load it by default:
+% \begin{macrocode}
+\RequirePackage{array}
+% \end{macrocode}
+%
+%
+% \subsection{Variables}
+% \begin{macro}
+% {
+% \l_@@_celltag_tl
+% ,\l_@@_rowtag_tl
+% ,\l_@@_cellattribute_tl
+% ,\l_@@_rowattribute_tl
+% ,\g_@@_missingcells_int
+% ,\l_@@_tmpa_clist
+% ,\l_@@_tmpa_seq
+% ,\l_@@_tmpa_tl
+% }
+% This is for the celltag, e.g. TD or TH:
+% \begin{macrocode}
+\tl_new:N \l_@@_celltag_tl
+\tl_set:Nn \l_@@_celltag_tl {TD}
+% \end{macrocode}
+% For the rowtag, probably always TR:
+% \begin{macrocode}
+\tl_new:N \l_@@_rowtag_tl
+\tl_set:Nn \l_@@_rowtag_tl {TR}
+% \end{macrocode}
+% And here cell and row attributes:
+% \begin{macrocode}
+\tl_new:N \l_@@_cellattribute_tl
+\tl_set:Nn \l_@@_cellattribute_tl {}
+\tl_new:N \l_@@_rowattribute_tl
+\tl_set:Nn \l_@@_rowattribute_tl {}
+% \end{macrocode}
+% This will contain the number of missing cells used:
+% \begin{macrocode}
+\int_new:N \g_@@_missing_cells_int
+% \end{macrocode}
+% Temp variables
+% \begin{macrocode}
+\clist_new:N \l_@@_tmpa_clist
+\seq_new:N \l_@@_tmpa_seq
+\tl_new:N \l_@@_tmpa_tl
+% \end{macrocode}
+% \end{macro}
+%
+% \subsection{Sockets}
+%
+% The code uses a number of sockets to inject the tagging
+% commands. These can be easily set to a noop-plug in case the
+% automated tagging is not wanted At first sockets for the begin and
+% end of cells and rows
+%
+% \begin{socketdecl}{tagsupport/tblcell/begin,
+% tagsupport/tblcell/end,
+% tagsupport/tblrow/begin,
+% tagsupport/tblrow/end,
+% }
+% \begin{macrocode}
+\NewSocket{tagsupport/tblcell/begin}{0}
+\NewSocket{tagsupport/tblcell/end}{0}
+\NewSocket{tagsupport/tblrow/begin}{0}
+\NewSocket{tagsupport/tblrow/end}{0}
+% \end{macrocode}
+% \end{socketdecl}
+%
+% \begin{socketdecl}{tagsupport/tbl/init}
+% This socket should be at the begin of the table, inside a group.
+% It is meant for settings like disabling paratagging. This socket
+% can perhaps be merged later into the begin-sockets when they are
+% no longer added as hooks but in the environment definitions.
+% \begin{macrocode}
+\NewSocket{tagsupport/tbl/init}{0}
+% \end{macrocode}
+% \end{socketdecl}
+%
+%
+% \begin{socketdecl}{tagsupport/tbl/finalize}
+% To fine tune the structure (change cells to header cells, remove
+% unwanted structures, move a foot to the end, etc.) we also need a
+% socket that is executed at the end of the table but \emph{before}
+% all the variables are restored to the outer or default values.
+% The code in the socket can make assignments, but probably
+% shouldn't do typesetting and not write whatsits.
+% \begin{macrocode}
+\NewSocket{tagsupport/tbl/finalize}{0}
+% \end{macrocode}
+% \end{socketdecl}
+%
+% \begin{socketdecl}{tagsupport/tbl/finalize/longtable}
+% \env{longtable} needs its own socket to fine tune the structure.
+% Simply switching the plug in the previous socket interferes with
+% enabling/disabling the tagging.
+% \begin{macrocode}
+\NewSocket{tagsupport/tbl/finalize/longtable}{0}
+% \end{macrocode}
+% \end{socketdecl}
+%
+% \begin{socketdecl}{tagsupport/tblhmode/begin,
+% tagsupport/tblhmode/end,
+% tagsupport/tblvmode/begin,
+% tagsupport/tblvmode/end
+% }
+%
+% These sockets are used in the begin and end code of environments,
+% to allow a fast enabling and disabling of the tagging. We
+% distinguish between tables that can be used inside paragraphs and
+% standalone tables like longtable.
+% \begin{macrocode}
+\NewSocket{tagsupport/tblhmode/begin}{0}
+\NewSocket{tagsupport/tblhmode/end}{0}
+\NewSocket{tagsupport/tblvmode/begin}{0}
+\NewSocket{tagsupport/tblvmode/end}{0}
+% \end{macrocode}
+% \end{socketdecl}
+%
+% This are the standard plugs for tagging of cells and rows.
+%
+% \begin{plugdecl}{TD}
+% \begin{macrocode}
+\NewSocketPlug{tagsupport/tblcell/begin}{TD}
+ {
+ \tag_struct_begin:n
+ {
+ tag =\l_@@_celltag_tl,
+ attribute-class =\l_@@_cellattribute_tl
+ }
+ \seq_gput_right:Ne \g_@@_struct_cur_seq { \tag_get:n {struct_num} }
+% \end{macrocode}
+% we store the cells of multicolumns as negative number. This allow to skip them
+% or to use them as needed.
+% \begin{macrocode}
+ \int_step_inline:nn { \g_@@_span_tl - 1 }
+ {
+ \seq_gput_right:Ne \g_@@_struct_cur_seq { -\tag_get:n {struct_num} }
+ }
+ \tag_mc_begin:n{}
+ }
+% \end{macrocode}
+% \end{plugdecl}
+%
+% \begin{plugdecl}{TD}
+% \begin{macrocode}
+\NewSocketPlug{tagsupport/tblcell/end}{TD}
+ {
+ \tag_mc_end:
+ \tag_struct_end:
+ }
+% \end{macrocode}
+% \end{plugdecl}
+%
+% In p-columns we need a slightly different plug which reactivates the
+% paragraph tagging.
+% tagging
+% \begin{plugdecl}{TD}
+% \begin{macrocode}
+\NewSocketPlug{tagsupport/tblcell/begin}{TDpbox}
+ {
+ \tag_struct_begin:n
+ {
+ tag =\l__tbl_celltag_tl,
+ attribute-class =\l__tbl_cellattribute_tl
+ }
+ \seq_gput_right:Ne \g__tbl_struct_cur_seq { \tag_get:n {struct_num} }
+ \int_step_inline:nn { \g__tbl_span_tl - 1 }
+ {
+ \seq_gput_right:Ne \g__tbl_struct_cur_seq { -\tag_get:n {struct_num} }
+ }
+ \tagpdfparaOn
+ \tl_set:Nn \l__tag_para_main_tag_tl {Div}
+ }
+% \end{macrocode}
+% \end{plugdecl}
+%
+% \begin{plugdecl}{TD}
+% \begin{macrocode}
+\NewSocketPlug{tagsupport/tblcell/end}{TDpbox}
+ {
+ \tag_struct_end:
+ }
+% \end{macrocode}
+% \end{plugdecl}
+%
+% \begin{plugdecl}{TR}
+% \begin{macrocode}
+\NewSocketPlug{tagsupport/tblrow/begin}{TR}
+ {
+ \seq_gclear:N \g_@@_struct_cur_seq
+ \tag_struct_begin:n
+ {
+ tag =\l_@@_rowtag_tl,
+ attribute-class=\l_@@_rowattribute_tl
+ }
+ \seq_gput_right:Ne \g_@@_struct_rows_seq { \tag_get:n {struct_num} }
+ }
+% \end{macrocode}
+% \end{plugdecl}
+%
+% \begin{plugdecl}{TR}
+% \begin{macrocode}
+\NewSocketPlug{tagsupport/tblrow/end}{TR}
+ {
+ \__tag_tbl_add_missing_cells:n { \g_@@_missing_cells_int }
+ \seq_gput_right:Ne \g_@@_struct_cells_seq
+ {
+ \seq_use:Nn \g_@@_struct_cur_seq {,}
+ }
+ \int_compare:nNnTF { \g_@@_row_int } = { \seq_count:N\g_@@_struct_cells_seq }
+ {
+ \typeout
+ {==>~
+ stucture~stored~for~row~\int_use:N\g_@@_row_int :~
+ \seq_use:Nn \g_@@_struct_cur_seq {,}
+ }
+ }
+ { \ERROR } % should not happen ...
+ \tag_struct_end:
+ }
+% \end{macrocode}
+% \end{plugdecl}
+%
+% And the plugs for the table as whole. The code can be different for
+% normal tables which can also be used inline and nested and
+% \enquote{vmode} tables like longtable.
+%
+% \begin{plugdecl}{Table}
+% Inside a table we currently only disable paratagging. We assume
+% that these sockets are in an environment group, so there is no
+% need to reenable paratagging.
+% \begin{macrocode}
+\NewSocketPlug{tagsupport/tbl/init}{Table}
+ {
+ \tag_if_active:T
+ {
+ \bool_set_false:N \l__tag_para_bool
+ }
+ }
+% \end{macrocode}
+% \end{plugdecl}
+%
+%
+% \begin{plugdecl}{Table}
+% This plug will fine tune the structure.
+% \begin{macrocode}
+\NewSocketPlug{tagsupport/tbl/finalize}{Table}
+ {
+ \@@_set_header_rows:
+ }
+% \end{macrocode}
+% \end{plugdecl}
+%
+% \begin{plugdecl}{Table}
+% This plug will fine tune the structure of longtable.
+% \begin{macrocode}
+\NewSocketPlug{tagsupport/tbl/finalize/longtable}{Table}
+ {
+% \end{macrocode}
+% If neither \cs{endhead} nor \cs{endfirsthead} has been used
+% we use the standard header command:
+% \begin{macrocode}
+ \bool_lazy_and:nnTF
+ { \seq_if_empty_p:N \g_@@_LT@head_rows_seq }
+ { \seq_if_empty_p:N \g_@@_LT@firsthead_rows_seq }
+ { \@@_set_header_rows: }
+% \end{macrocode}
+% Otherwise, if firsthead has not been used we use head. For this
+% we simple retrieve the row numbers and then call the header
+% command.
+% \begin{macrocode}
+ {
+ \seq_if_empty:NTF \g_@@_LT@firsthead_rows_seq
+ {
+ \clist_set:Ne \l_@@_header_rows_clist
+ {\seq_use:Nn \g_@@_LT@head_rows_seq {,}}
+ \@@_set_header_rows:
+ }
+% \end{macrocode}
+% In the other case we use firsthead.
+% \begin{macrocode}
+ {
+ \clist_set:Ne \l_@@_header_rows_clist
+ { \seq_use:Nn \g_@@_LT@firsthead_rows_seq {,} }
+ \@@_set_header_rows:
+% \end{macrocode}
+% Additionally we have to remove the head to avoid duplication. The
+% one option here is to remove the rows from the kid sequence of
+% the table (which will lead to orphaned structure elements), the
+% other to make them artifact. For now we use the first option for
+% pdf 1.7 and the second for pdf 2.0.
+% \begin{macrocode}
+ \pdf_version_compare:NnTF < {2.0}
+ {
+ \seq_map_inline:Nn \g_@@_LT@head_rows_seq
+ {
+ \seq_gset_item:cnn
+ {g__tag_struct_kids_ \g_@@_struct_table_tl _seq}
+ { ##1 }
+ {}
+% \end{macrocode}
+% Not sure if needed, but if needed we can remove also the P tag.
+% This is currently disabled as it produce warnings. TODO: This
+% needs also a tagpdf command which takes care of debug code.
+% \begin{macrocode}
+ \tl_set:Ne \l_@@_tmpa_tl
+ { \seq_item:Nn\g_@@_struct_rows_seq {##1} }
+ \prop_if_exist:cT
+ { g__tag_struct_ \l_@@_tmpa_tl _prop }
+ {
+ %\prop_gremove:cn {g__tag_struct_ \l_@@_tmpa_tl _prop} {P}
+ }
+ }
+ }
+ {
+ \seq_map_inline:Nn \g_@@_LT@head_rows_seq
+ {
+ \tl_set:Ne \l_@@_tmpa_tl
+ { \seq_item:Nn\g_@@_struct_rows_seq {##1} }
+ \prop_if_exist:cT
+ { g__tag_struct_ \l_@@_tmpa_tl _prop }
+ {
+ \@@_struct_prop_gput:Vnn \l_@@_tmpa_tl {S}{/Artifact}
+ }
+ }
+ }
+ }
+ }
+% \end{macrocode}
+% The foot is handled similar, the difference is
+% that we have to move it to the end one of them
+% is not empty, but do nothing if they aren't there.
+% \begin{macrocode}
+ \bool_lazy_and:nnF
+ { \seq_if_empty_p:N \g_@@_LT@foot_rows_seq }
+ { \seq_if_empty_p:N \g_@@_LT@lastfoot_rows_seq }
+ {
+% \end{macrocode}
+% If lastfoot is empty move foot to the end.
+% \begin{macrocode}
+ \seq_if_empty:NTF \g_@@_LT@lastfoot_rows_seq
+ {
+ \seq_map_inline:Nn \g_@@_LT@foot_rows_seq
+ {
+ \tl_set:Ne \l_@@_tmpa_tl
+ {
+ \seq_item:cn
+ {g__tag_struct_kids_ \g_@@_struct_table_tl _seq}
+ {##1}
+ }
+ \seq_gset_item:cnn
+ {g__tag_struct_kids_ \g_@@_struct_table_tl _seq}
+ { ##1 }
+ {}
+ \seq_gput_right:cV
+ {g__tag_struct_kids_ \g_@@_struct_table_tl _seq}
+ \l_@@_tmpa_tl
+ }
+ }
+% \end{macrocode}
+% If lastfoot is not empty we move that.
+% \begin{macrocode}
+ {
+ \seq_map_inline:Nn \g_@@_LT@lastfoot_rows_seq
+ {
+ \tl_set:Ne \l_@@_tmpa_tl
+ {
+ \seq_item:cn
+ {g__tag_struct_kids_ \g_@@_struct_table_tl _seq}
+ {##1}
+ }
+ \seq_gset_item:cnn
+ {g__tag_struct_kids_ \g_@@_struct_table_tl _seq}
+ { ##1 }
+ {}
+ \seq_gput_right:cV
+ {g__tag_struct_kids_ \g_@@_struct_table_tl _seq}
+ \l_@@_tmpa_tl
+ }
+% \end{macrocode}
+% and we hide foot
+% \begin{macrocode}
+ \pdf_version_compare:NnTF < {2.0}
+ {
+ \seq_map_inline:Nn \g_@@_LT@foot_rows_seq
+ {
+ \seq_gset_item:cnn
+ {g__tag_struct_kids_ \g_@@_struct_table_tl _seq}
+ { ##1 }
+ {}
+% \end{macrocode}
+% Not sure if needed, but if needed we can remove also the P tag.
+% This is currently disabled as it produce warnings.
+% TODO: This needs also
+% a tagpdf command which takes care of debug code.
+% \begin{macrocode}
+ \tl_set:Ne \l_@@_tmpa_tl
+ { \seq_item:Nn\g_@@_struct_rows_seq {##1} }
+ \prop_if_exist:cT
+ { g__tag_struct_ \l_@@_tmpa_tl _prop }
+ {
+ %\prop_gremove:cn {g__tag_struct_ \l_@@_tmpa_tl _prop} {P}
+ }
+ }
+ }
+ {
+ \seq_map_inline:Nn \g_@@_LT@foot_rows_seq
+ {
+ \tl_set:Ne \l_@@_tmpa_tl
+ { \seq_item:Nn\g_@@_struct_rows_seq {##1} }
+ \prop_if_exist:cT
+ { g__tag_struct_ \l_@@_tmpa_tl _prop }
+ {
+ \@@_struct_prop_gput:Vnn \l_@@_tmpa_tl {S}{/Artifact}
+ }
+ }
+ }
+ }
+ }
+ }
+% \end{macrocode}
+% \end{plugdecl}
+%
+% \begin{plugdecl}{Table}
+% \begin{macrocode}
+\NewSocketPlug{tagsupport/tblhmode/begin}{Table}
+ {
+ \mode_leave_vertical:
+ \tag_mc_end_push:
+% \end{macrocode}
+% Close the P-chunk. This assumes that para-tagging is active.
+% For nested tables that is not necessarly true, so we test for it.
+% \begin{macrocode}
+ \bool_lazy_and:nnT
+ { \bool_if_exist_p:N \l__tag_para_bool } { \l__tag_para_bool }
+ { \tag_struct_end:n { text } }
+ \tag_struct_begin:n {tag=Table}
+ \tl_gset:Ne \g_@@_struct_table_tl { \tag_get:n {struct_num} }
+ }
+% \end{macrocode}
+% \end{plugdecl}
+%
+% \begin{plugdecl}{Table}
+% \begin{macrocode}
+\NewSocketPlug{tagsupport/tblhmode/end}{Table}
+ {
+ \tag_struct_end:
+% \end{macrocode}
+% reopen the P-chunk. This assumes that para-tagging is active.
+% For nested tables that is not necessarly true, so we test for it.
+% \begin{macrocode}
+ \bool_lazy_and:nnT
+ { \bool_if_exist_p:N \l__tag_para_bool } { \l__tag_para_bool }
+ { \tag_struct_begin:n { tag=\l__tag_para_tag_tl } }
+ \tag_mc_begin_pop:n{}
+ }
+% \end{macrocode}
+% \end{plugdecl}
+%
+% \begin{plugdecl}{Table}
+% \begin{macrocode}
+\NewSocketPlug{tagsupport/tblvmode/begin}{Table}
+ {
+ \tag_struct_begin:n {tag=Table}
+ \tl_gset:Ne \g_@@_struct_table_tl { \tag_get:n {struct_num} }
+ }
+% \end{macrocode}
+% \end{plugdecl}
+%
+% \begin{plugdecl}{Table}
+% \begin{macrocode}
+\NewSocketPlug{tagsupport/tblvmode/end}{Table}
+ {
+ \tag_struct_end:
+ \par
+ }
+% \end{macrocode}
+% \end{plugdecl}
+%
+%
+%
+%
+%
+%\subsection{Environments}
+%
+% Currently only tabular, tabular*, tabularx and longtable.
+% We must use the \texttt{before} and \texttt{after} hooks as the \texttt{end}
+% hook is executed before the end of the last row and then MC are messed up.
+% This means that this sockets should only contain code that doesn't needs to be
+% grouped!
+% \begin{macrocode}
+\AddToHook{env/tabular/before} {\UseSocket{tagsupport/tblhmode/begin}}
+\AddToHook{env/tabular/after} {\UseSocket{tagsupport/tblhmode/end}}
+\AddToHook{env/tabular*/before} {\UseSocket{tagsupport/tblhmode/begin}}
+\AddToHook{env/tabular*/after} {\UseSocket{tagsupport/tblhmode/end}}
+\AddToHook{env/tabularx/before} {\UseSocket{tagsupport/tblhmode/begin}}
+\AddToHook{env/tabularx/after} {\UseSocket{tagsupport/tblhmode/end}}
+\AddToHook{env/longtable/before}{\UseSocket{tagsupport/tblvmode/begin}}
+\AddToHook{env/longtable/after} {\UseSocket{tagsupport/tblvmode/end}}
+% \end{macrocode}
+%
+% The \env{array} environment is math. So we disable table tagging for now.
+% \begin{macrocode}
+\AddToHook{env/array/begin} {\__tag_tbl_disable:}
+% \end{macrocode}
+%
+%
+% \subsection{Interfaces to tagging}
+%
+% \subsubsection{Tagging helper commands}
+%
+% \begin{macro}{\@@_set_colspan:n}
+% This commands takes a number, checks if is larger than one,
+% checks if the colspan attribute exists (we can't predefine an
+% arbitrary number), and updates \cs{l_@@_cellattribute_tl}.
+% \begin{macrocode}
+\tag_if_active:T
+ { \cs_generate_variant:Nn \__tag_attr_new_entry:nn {ee} }
+\cs_new_protected:Npn \@@_set_colspan:n #1
+ {
+ \tag_if_active:T
+ {
+ \int_compare:nNnT {#1}>{1}
+ {
+ \prop_get:NeNF \g__tag_attr_entries_prop
+ {colspan-\int_eval:n{#1}}
+ \l_@@_tmpa_tl
+ {
+ \__tag_attr_new_entry:ee
+ {colspan-\int_eval:n{#1}}
+ {/O /Table /ColSpan~\int_eval:n{#1}}
+ }
+ \tl_set:Ne \l_@@_cellattribute_tl
+ {colspan-\int_eval:n{#1}}
+ }
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \subsubsection{Disabling/enabling}
+%
+% For now we have only the option true/false but this will probably be extended
+% to allow different setups like first row header etc.
+
+% \begin{macro}{\__tag_tbl_disable:}
+%
+% \begin{macrocode}
+\cs_new_protected:Npn \__tag_tbl_disable:
+ {
+ \AssignSocketPlug{tagsupport/tblcell/begin}{noop}
+ \AssignSocketPlug{tagsupport/tblcell/end}{noop}
+ \AssignSocketPlug{tagsupport/tblrow/begin}{noop}
+ \AssignSocketPlug{tagsupport/tblrow/end}{noop}
+ \AssignSocketPlug{tagsupport/tbl/init}{noop}
+ \AssignSocketPlug{tagsupport/tbl/finalize}{noop}
+ \AssignSocketPlug{tagsupport/tbl/finalize/longtable}{noop}
+ \AssignSocketPlug{tagsupport/tblhmode/begin}{noop}
+ \AssignSocketPlug{tagsupport/tblhmode/end}{noop}
+ \AssignSocketPlug{tagsupport/tblvmode/begin}{noop}
+ \AssignSocketPlug{tagsupport/tblvmode/end}{noop}
+ }
+% \end{macrocode}
+% \end{macro}
+
+
+% \begin{macro}{\__tag_tbl_enable:}
+%
+% \begin{macrocode}
+\cs_new_protected:Npn \__tag_tbl_enable:
+ {
+ \AssignSocketPlug{tagsupport/tblcell/begin}{TD}
+ \AssignSocketPlug{tagsupport/tblcell/end}{TD}
+ \AssignSocketPlug{tagsupport/tblrow/begin}{TR}
+ \AssignSocketPlug{tagsupport/tblrow/end}{TR}
+ \AssignSocketPlug{tagsupport/tbl/init}{Table}
+ \AssignSocketPlug{tagsupport/tbl/finalize}{Table}
+ \AssignSocketPlug{tagsupport/tbl/finalize/longtable}{Table}
+ \AssignSocketPlug{tagsupport/tblhmode/begin}{Table}
+ \AssignSocketPlug{tagsupport/tblhmode/end}{Table}
+ \AssignSocketPlug{tagsupport/tblvmode/begin}{Table}
+ \AssignSocketPlug{tagsupport/tblvmode/end}{Table}
+ }
+% \end{macrocode}
+% \end{macro}
+
+% \begin{macrocode}
+% TODO decide about key name
+\keys_define:nn { __tag / setup }
+ {
+ table-tagging .choices:nn = { true, on }
+ { \__tag_tbl_enable: },
+ table-tagging .choices:nn = { false, off }
+ { \__tag_tbl_disable: },
+ table-tagging .default:n = true,
+ table-tagging .initial:n = true
+ }
+% \end{macrocode}
+%
+% Table tagging should be disabled in the head and foot.
+% \begin{macrocode}
+\AddToHook{begindocument}
+ {
+ \cs_if_exist:NT \@kernel@before@head
+ {
+ \tl_put_right:Nn \@kernel@before@head {\__tag_tbl_disable:}
+ \tl_put_right:Nn \@kernel@before@foot {\__tag_tbl_disable:}
+ }
+ }
+% \end{macrocode}
+%
+% \subsubsection{Header support}
+%
+% Accessible table must have header cells declaring the meaning of the
+% data in a row or column. To allow a data cell to find it header cell(s)
+% a number of things must be done:
+% \begin{itemize}
+% \item every cell meant as a header should use the tag \texttt{TH}.
+%
+% \item header cells should have a \texttt{Scope} attribute with the
+% value \texttt{Column}, \texttt{Row} or \texttt{Both}. This is not
+% needed in the first row or column of a table.
+%
+% \item For more complex cases both \texttt{TD} and \texttt{TH} cell
+% can contain a \texttt{Headers} attribute, that is an array of
+% \texttt{ID}s of \texttt{TH} cell.
+% \end{itemize}
+%
+% For now we support only header rows.
+%
+% At first we define attributes for the three standard cases:
+% We delay to begin document
+% as we can't know if tagpdf is already loaded.
+% \begin{macrocode}
+\AddToHook{begindocument}
+ {
+ \tag_if_active:T
+ {
+ \tagpdfsetup
+ {
+ newattribute =
+ {TH-col}{/O /Table /Scope /Column},
+ newattribute =
+ {TH-row}{/O /Table /Scope /Row},
+ newattribute =
+ {TH-both}{/O /Table /Scope /Both},
+ }
+% \end{macrocode}
+%
+% And we put all three into the class map (perhaps the next tagpdf
+% should do that directly with newattribute):
+%
+% \begin{macrocode}
+ \seq_gput_left:Ne\g__tag_attr_class_used_seq
+ {\pdf_name_from_unicode_e:n{TH-col}}
+ \seq_gput_left:Ne\g__tag_attr_class_used_seq
+ {\pdf_name_from_unicode_e:n{TH-row}}
+ \seq_gput_left:Ne\g__tag_attr_class_used_seq
+ {\pdf_name_from_unicode_e:n{TH-both}}
+ }
+ }
+
+% \end{macrocode}
+%
+% \begin{variable}{\l_@@_header_rows_clist}
+% This holds the numbers of the header rows. Negative numbers are
+% possible and count from the back.
+% \begin{macrocode}
+\clist_new:N \l_@@_header_rows_clist
+% \end{macrocode}
+% \end{variable}
+%
+% \begin{macro}{\@@_set_header_rows:}
+% TEMP: Next tagpdf will have the right command which also updates
+% the debug info.
+% For now a temporary command:
+% \begin{macrocode}
+\cs_if_free:NTF \__tag_struct_prop_gput:nnn
+ {
+ \cs_new_protected:Npn \@@_struct_prop_gput:nnn #1#2#3
+ { \prop_gput:cnn { g__tag_struct_#1_prop }{#2}{#3} }
+ }
+ { \cs_new_protected:Npn \@@_struct_prop_gput:nnn #1#2#3
+ { \__tag_struct_prop_gput:nnn {#1}{#2}{#3} }
+ }
+\cs_generate_variant:Nn \@@_struct_prop_gput:nnn {nne,Vnn}
+% \end{macrocode}
+%
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_set_header_rows:
+ {
+ \clist_map_inline:Nn \l_@@_header_rows_clist
+ {
+ \clist_set:Ne\l_@@_tmpa_clist
+ {
+ \seq_item:Nn \g_@@_struct_cells_seq {##1}
+ }
+ \clist_map_inline:Nn \l_@@_tmpa_clist
+ {
+% \end{macrocode}
+% We can have negative numbers in the list from the multicolumn.
+% \begin{macrocode}
+ \prop_if_exist:cT { g__tag_struct_####1_prop }
+ {
+ \@@_struct_prop_gput:nnn{ ####1 }{S}{/TH}
+% \end{macrocode}
+% This need refinement once row headers (and perhaps other attributes)
+% are used too, but for now it should be ok.
+% \begin{macrocode}
+ \prop_get:cnNTF
+ { g__tag_struct_####1_prop }
+ { C }
+ \l_@@_tmpa_tl
+ {\@@_struct_prop_gput:nne{ ####1 }{C}{[/TH-col~\l_@@_tmpa_tl]} }
+ {\@@_struct_prop_gput:nnn{ ####1 }{C}{/TH-col}}
+ }
+ }
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% And some key support:
+% \begin{macrocode}
+% TODO decide about key name
+\keys_define:nn { __tag / setup }
+ {
+ table-header-rows .clist_set:N = \l_@@_header_rows_clist
+ }
+% \end{macrocode}
+%
+% \subsection{Changes to \pkg{array} commands}
+%
+%
+%
+% \begin{macro}{\@@_show_curr_cell_data:}
+% Show the row/column index and span count for current table cell
+% for debugging.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_show_curr_cell_data: {
+ \typeout { ==>~ current~cell~data:~
+ \int_use:N \g_@@_row_int ,
+ \int_use:N \g_@@_col_int ,
+ \g_@@_span_tl
+ }
+}
+% \end{macrocode}
+% \end{macro}
+%
+%
+%
+%
+% \begin{macro}{\insert@column}
+% \cs{insert@column} is defined in \pkg{array}, here only the two
+% sockets are inserted.
+% \begin{macrocode}
+\def\insert@column{%
+ \@@_show_curr_cell_data:
+ \UseSocket{tagsupport/tblcell/begin}%
+ \the@toks \the \@tempcnta
+ \ignorespaces \@sharp \unskip
+ \the@toks \the \count@ \relax
+ \UseSocket{tagsupport/tblcell/end}%
+}
+% \end{macrocode}
+% \end{macro}
+%
+%
+% \begin{macro}{\@classz}
+% \begin{macrocode}
+\def\@classz{\@classx
+ \@tempcnta \count@
+ \prepnext@tok
+ \@addtopreamble{\ifcase \@chnum
+ \hfil
+ \hskip1sp%
+ \d@llarbegin
+ \insert@column
+ \d@llarend \do@row@strut \hfil \or
+ \hskip1sp\d@llarbegin \insert@column \d@llarend \do@row@strut \hfil \or
+ \hfil\hskip1sp\d@llarbegin \insert@column \d@llarend \do@row@strut \or
+ \setbox\ar@mcellbox\vbox
+ \@startpbox{\@nextchar}
+ \AssignSocketPlug{tagsupport/tblcell/begin}{TDpbox}
+ \AssignSocketPlug{tagsupport/tblcell/end}{TDpbox}
+ \insert@column \@endpbox
+ \ar@align@mcell
+ \do@row@strut \or
+ \vtop \@startpbox{\@nextchar}
+ \AssignSocketPlug{tagsupport/tblcell/begin}{TDpbox}
+ \AssignSocketPlug{tagsupport/tblcell/end}{TDpbox}
+ \insert@column \@endpbox\do@row@strut \or
+ \vbox \@startpbox{\@nextchar}
+ \AssignSocketPlug{tagsupport/tblcell/begin}{TDpbox}
+ \AssignSocketPlug{tagsupport/tblcell/end}{TDpbox}
+ \insert@column \@endpbox\do@row@strut
+ \fi}\prepnext@tok}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@array,\@@@@array}
+% We modificate the \cs{@array} from \pkg{array}.
+% \begin{macrocode}
+\def\@array[#1]#2{%
+ \@tempdima \ht \strutbox
+ \advance \@tempdima by\extrarowheight
+ \setbox \@arstrutbox \hbox{\vrule
+ \@height \arraystretch \@tempdima
+ \@depth \arraystretch \dp \strutbox
+ \@width \z@}%
+% \end{macrocode}
+% The total number of table columns of the current table is
+% determined in \cs{@@_determine_table_cols:} but this is called in
+% a group, so local settings do not survive. Thus, to save away the
+% outer value of \cs{g_@@_table_cols_tl} we do it before the group.
+% \begin{macrocode}
+ \tl_set_eq:NN \l_@@_saved_table_cols_tl \g_@@_table_cols_tl
+% \end{macrocode}
+%
+% \begin{macrocode}
+ \begingroup
+ \@mkpream{#2}
+% \end{macrocode}
+% Next call has to happen immediately after \cs{@mkpream} because
+% it uses implementation details from that.
+% \begin{macrocode}
+ \@@_determine_table_cols:
+% \end{macrocode}
+%
+% \begin{macrocode}
+ \xdef\@preamble{%
+ \noexpand
+% \end{macrocode}
+% \cs{ialign} in the original definition is replaced by
+% \cs{ar@ialign} defined below.
+% \begin{macrocode}
+ \ar@ialign
+ \@halignto
+ \bgroup \@arstrut
+% \end{macrocode}
+% A socket is inserted
+% \begin{macrocode}
+ \UseSocket{tagsupport/tblrow/begin}%
+% \end{macrocode}
+% At the start of the preamble for the first column we set
+% \cs{g_@@_col_int} to \texttt{1} as we are no longer "at" but "in"
+% the first column. This is done in \cs{@@_init_cell_data:}. In
+% later columns this data is updated via \cs{@@_update_cell_data:}.
+% \begin{macrocode}
+ \@@_init_cell_data:
+ \@preamble
+ \tabskip \z@ \cr}%
+ \endgroup
+ \@arrayleft
+% \end{macrocode}
+% Another socket for tagging. TODO: what about \cs{arrayleft}?
+% \begin{macrocode}
+ \UseSocket{tagsupport/tbl/init}
+ \if #1t\vtop \else \if#1b\vbox \else \vcenter \fi \fi
+ \bgroup
+ \let \@sharp ##\let \protect \relax
+ \lineskip \z@
+ \baselineskip \z@
+ \m@th
+ \let\\\@arraycr \let\tabularnewline\\\let\par\@empty
+%\show\@preamble
+ \@preamble}
+% \end{macrocode}
+% Finally, also set \cs{@@@@array} to the new definition:
+% \begin{macrocode}
+\let\@@@@array\@array
+% \end{macrocode}
+% \end{macro}
+%
+%
+% \begin{macro}{\@@_init_cell_data:}
+%
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_init_cell_data: {
+ \int_gset:Nn \g_@@_col_int {1}
+ \tl_gset:Nn \g_@@_span_tl {1}
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_update_cell_data:}
+% Updating cell data in columns after the first means we have to
+% increment the \cs{g_@@_col_int} by the span count of the previous
+% cell (in case it was a \cs{multicolumn} and then reset the
+% \cs{g_@@_span_tl} to one (as the default).
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_update_cell_data: {
+ \int_gadd:Nn \g_@@_col_int { \g_@@_span_tl }
+ \tl_gset:Nn \g_@@_span_tl {1}
+}
+% \end{macrocode}
+% \end{macro}
+%
+%
+%
+% \begin{macro}{\@@_determine_table_cols:}
+% Current implementation of \cs{@mkpream} uses the scratch counter
+% \cs{count@} to keep track of the number of toks registers it needs
+% (2 per column), but this can't be used as it counts also
+% insertings made with \verb+!{}+ and \verb+@{}+.
+% So similar as does longtable for \cs{LT@cols} we count the
+% numbers of ambersands instead.
+% \begin{macrocode}
+\cs_new:Npn \@@_determine_table_cols: {
+ \seq_set_split:NnV\l_@@_tmpa_seq {&}\@preamble
+ \tl_gset:Ne \g_@@_table_cols_tl { \seq_count:N \l_@@_tmpa_seq }
+ \typeout{ ==>~ Table~ has~ \g_@@_table_cols_tl \space columns }
+}
+% \end{macrocode}
+% \end{macro}
+%
+%
+% \begin{macro}{\@arraycr}
+% Add code that figures out if the current table row is incomplete
+% (not enough \verb=&=s). It can then do extra actions, such as
+% inserting missing cell tags.
+% \begin{macrocode}
+\protected\def\@arraycr{
+ \relax
+ \@@_store_missing_cells:n{@arraycr}
+ %
+ \iffalse{\fi\ifnum 0=`}\fi
+ \@ifstar \@xarraycr \@xarraycr}
+% \end{macrocode}
+% \end{macro}
+%
+%
+%
+% \begin{macro}{\@@_store_missing_cells:n,
+% \__tag_tbl_add_missing_cells:n}
+% The storing and use of the number of missing cells
+% must happen at different places as the testing happens at
+% the end of the last cell of a row, but
+% still inside that cell, so we use two commands. The second is used in
+% the endrow socket.
+% \begin{macrocode}
+\cs_new:Npn \@@_store_missing_cells:n #1 {
+ \int_compare:nNnT \g_@@_col_int > 0
+ {
+ \int_gset:Nn \g_@@_missing_cells_int
+ {
+ \g_@@_table_cols_tl
+ - \g_@@_col_int
+ - \g_@@_span_tl
+ + 1
+ }
+ \int_compare:nNnT \g_@@_missing_cells_int < 0 \ERROR % should not happen
+ \typeout{==>~
+ (#1)~
+ This~ row~ needs~
+ \int_use:N \g_@@_missing_cells_int \space
+ additional~ cell(s)
+ }
+ }
+}
+% \end{macrocode}
+%
+% \begin{macrocode}
+\cs_new:Npn \__tag_tbl_add_missing_cells:n #1
+ {
+% \end{macrocode}
+% The TD-socket messages are issued after the message about the end-row socket,
+% but the structure is ok, so better issue a message for now to avoid confusion:
+% \begin{macrocode}
+ \int_compare:nNnT {#1}>{0}
+ {
+ \typeout{==>~
+ ~Inserting~\int_eval:n{#1}~additional~cell(s)~into~previous~row:}
+ }
+ \int_step_inline:nn { #1 }
+ {
+ \UseSocket{tagsupport/tblcell/begin}
+ \UseSocket{tagsupport/tblcell/end}
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+%
+%
+% \begin{macro}{\endarray}
+% If tables are nested into another then it is necessary to
+% restore information about the cell the inner table started
+% in. Otherwise, \cs{g_@@_row_int}, \cs{g_@@_col_int}, and
+% \cs{g_@@_span_tl} reflect the status in the outer table as they
+% are globally manipulated. We restore in all cases even if we are
+% not in a nesting situation as that makes the code simpler (and
+% probably faster).
+%
+% \cs{endtabular} and \cs{endtabular*} inherit from \cs{endarray}
+% so we only need to change that. \texttt{tabularx} is handled
+% below.
+% \begin{macrocode}
+\def\endarray{
+ \@@_store_missing_cells:n{endarray}
+ \crcr \egroup
+ \UseSocket{tagsupport/tbl/finalize}
+ \int_gset:Nn \g_@@_col_int { \l_@@_saved_col_tl }
+ \int_gset:Nn \g_@@_row_int { \l_@@_saved_row_tl }
+ \tl_gset_eq:NN \g_@@_span_tl \l_@@_saved_span_tl
+ \tl_gset_eq:NN \g_@@_table_cols_tl \l_@@_saved_table_cols_tl
+ \tl_gset_eq:NN \g_@@_struct_table_tl \l_@@_saved_struct_table_tl
+ \seq_gset_eq:NN \g_@@_struct_rows_seq \l_@@_saved_struct_rows_seq
+ \seq_gset_eq:NN \g_@@_struct_cells_seq\l_@@_saved_struct_cells_seq
+ \seq_gset_eq:NN \g_@@_struct_cur_seq \l_@@_saved_struct_cur_seq
+ \typeout{==>~ restored~cell~data:~
+ \int_use:N \g_@@_row_int,
+ \int_use:N \g_@@_col_int,
+ \l_@@_saved_span_tl \space
+ (
+ \int_compare:nNnTF \g_@@_table_cols_tl = 0
+ { outer~ level }
+ { max:~ \g_@@_table_cols_tl }
+ )
+ }
+ \egroup
+ \@arrayright \gdef\@preamble{}%
+}
+% \end{macrocode}
+% \end{macro}
+%
+%
+% \begin{macro}{\@addamp}
+% If we are after the first column we have to insert a \verb=&= and
+% also update the cell data.
+% \begin{macrocode}
+\def\@addamp {
+ \if@firstamp
+ \@firstampfalse
+ \else
+ \edef\@preamble{\@preamble &
+ \@@_update_cell_data:
+ }
+ \fi
+}
+% \end{macrocode}
+% \end{macro}
+%
+%
+%
+% \begin{macro}{
+% \g_@@_col_int,
+% \g_@@_row_int,
+% \g_@@_span_tl,
+% \g_@@_table_cols_tl}
+% \cs{g_@@_row_int} holds the current row number in the table. The value
+% \texttt{0} means we haven't yet processed the table preamble. It
+% is incremented by every \cs{cr} including the one ending the
+% table preamble.
+%
+% \cs{g_@@_col_int} holds the current column number. The value
+% \texttt{0} means we have not yet started the table or just finished a table row
+% (with \verb=\\= typically); any other positive value means we
+% are currently typesetting a cell in that column in some row
+% (denoted by the \cs{g_@@_row_int}.
+%
+% In a \cs{multicolumn} it holds the column number of the first
+% spanned column and \cs{g_@@_span_tl} the info how many cells are
+% spanned.
+%
+% \cs{g_@@_span_tl} is normally \texttt{1} except in a
+% \cs{multicolumn} cell.
+% \begin{macrocode}
+\int_new:N \g_@@_col_int
+\int_new:N \g_@@_row_int
+\tl_new:N \g_@@_span_tl
+\tl_new:N \g_@@_table_cols_tl
+
+\tl_gset:Nn \g_@@_span_tl {1}
+\tl_gset:Nn \g_@@_table_cols_tl {0} % indicates outer level
+% \end{macrocode}
+% \end{macro}
+%
+%
+% \begin{macro}{\l_@@_saved_col_tl,\l_@@_saved_row_tl,
+% \l_@@_saved_span_tl,\l_@@_saved_table_cols_tl}
+%
+% Saving the outer values if we are nesting tables is necessary (as
+% the above variables are globally altered. For this we use always
+% token lists because they don't change and we do not need to blow
+% additional integer registers.
+% \begin{macrocode}
+\tl_new:N \l_@@_saved_col_tl
+\tl_new:N \l_@@_saved_row_tl
+\tl_new:N \l_@@_saved_span_tl
+\tl_new:N \l_@@_saved_table_cols_tl
+
+\tl_set:Nn \l_@@_saved_col_tl{0}
+\tl_set:Nn \l_@@_saved_row_tl{0}
+\tl_set:Nn \l_@@_saved_span_tl{1}
+\tl_set:Nn \l_@@_saved_table_cols_tl{0} % indicates outer level
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}
+% {
+% \g_@@_struct_table_tl, \l_@@_saved_struct_table_tl,
+% \g_@@_struct_rows_seq,\l_@@_saved_struct_rows_seq,
+% \g_@@_struct_cells_seq,\l_@@_saved_struct_cells_seq,
+% \g_@@_struct_cur_seq,\l_@@_saved_struct_cur_seq
+% }
+% We need to store the structure numbers for the fine tuning in the
+% finalize socket. For now we use a rather simple system: A
+% sequence that hold the numbers for the row structures, and one
+% that holds comma lists for the cells.
+%
+% \cs{g_@@_struct_table_tl} will hold the structure number of the
+% table, \cs{g_@@_struct_rows_seq} will hold at index i the
+% structure number of row i, \cs{g_@@_struct_cells_seq} will hold
+% at index i a comma list of the cell structure numbers of row i.
+% \cs{g_@@_struct_cur_seq} is used as a temporary store for the
+% cell structures of the current row. We need also local version
+% to store and restore the values.
+%
+% \begin{macrocode}
+\tl_new:N \g_@@_struct_table_tl
+\tl_new:N \l_@@_saved_struct_table_tl
+\seq_new:N \g_@@_struct_rows_seq
+\seq_new:N \l_@@_saved_struct_rows_seq
+\seq_new:N \g_@@_struct_cells_seq
+\seq_new:N \l_@@_saved_struct_cells_seq
+\seq_new:N \g_@@_struct_cur_seq
+\seq_new:N \l_@@_saved_struct_cur_seq
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\ar@ialign}
+% A new command that replaces \cs{ialign} above. \cs{everycr} is
+% also applied to the \cs{cr} ending the preamble so we have to
+% program around that.
+% \begin{macrocode}
+\def\ar@ialign{%
+% \end{macrocode}
+% Before starting a table we locally stored the information related
+% to the current cell (if any) so that we can restore it once the
+% table is finished.
+% \begin{macrocode}
+ \tl_set:No \l_@@_saved_col_tl {\int_use:N \g_@@_col_int }
+ \tl_set:No \l_@@_saved_row_tl {\int_use:N \g_@@_row_int }
+ \tl_set_eq:NN \l_@@_saved_span_tl \g_@@_span_tl
+ \tl_set_eq:NN \l_@@_saved_struct_table_tl \g_@@_struct_table_tl
+ \seq_set_eq:NN \l_@@_saved_struct_rows_seq \g_@@_struct_rows_seq
+ \seq_set_eq:NN \l_@@_saved_struct_cells_seq \g_@@_struct_cells_seq
+ \seq_set_eq:NN \l_@@_saved_struct_cur_seq \g_@@_struct_cur_seq
+%
+ \typeout{==>~ saved~cell~data:~
+ \l_@@_saved_row_tl,
+ \l_@@_saved_col_tl,
+ \l_@@_saved_span_tl \space
+ (
+ \int_compare:nNnTF \l_@@_saved_table_cols_tl = 0
+ { outer~ level }
+ { max:~ \l_@@_saved_table_cols_tl }
+ )
+ }
+% \end{macrocode}
+% These are the initial values when starting a table:
+% \begin{macrocode}
+ \int_gzero:N \g_@@_row_int
+ \int_gzero:N \g_@@_col_int
+ \tl_gset:Nn \g_@@_span_tl {1}
+ \seq_gclear:N\g_@@_struct_rows_seq
+ \seq_gclear:N\g_@@_struct_cells_seq
+ \seq_gclear:N\g_@@_struct_cur_seq
+% \end{macrocode}
+%
+% \begin{macrocode}
+ \everycr{%
+ \noalign{%
+% \end{macrocode}
+% We use \cs{g_@@_col_int} equal zero to indicate that we are just
+% after a TR (or at the very beginning of the table). Using the row
+% count is not so good as longtable may split the table in chunks.
+% \begin{macrocode}
+ \int_compare:nNnT \g_@@_col_int > 0
+ { \UseSocket{tagsupport/tblrow/end} }
+ \int_gincr:N \g_@@_row_int % this row about to start
+ \int_gzero:N \g_@@_col_int % we are before first col
+ }%
+ }%
+ \tabskip\z@skip\halign}
+% \end{macrocode}
+% \end{macro}
+%
+%
+% \begin{macro}{\multicolumn}
+%
+% \cs{multicolumn} is also defined in \pkg{array}. The redefinition
+% has to solve two problems: it must handle the row begin if it is
+% used there, and it must save the numbers of cells it spans so
+% that we can add a suitable ColSpan attribute.\footnote{FMi: This can
+% now perhaps cleaned up somewhat}
+% \begin{macrocode}
+\long\def\multicolumn#1#2#3{%
+ % alternative: determine first col with vmode test ...
+ % \ifvmode
+ % \multispan{#1}\typeout{A==> vmode}%
+ % \else
+ % \multispan{#1}\typeout{A==> not vmode}
+ % \fi
+ % but this makes the \crcr handling really complicated which would
+ % then need to become something like
+ % \ifvmode \expandafter \@gobble
+ % \else \expandafter \@iden \fi {\cr\noalign{do something}}%
+ % so not used.
+ % Instead:
+ \multispan{#1}\begingroup
+% \end{macrocode}
+% Insert rowbegin socket only if this multicolumn
+% replaces the preamble of the first column. In that case we have
+% to set \cs{g_@@_col_int} to 1 since this is no longer done in the
+% preamble for the cell.
+% \begin{macrocode}
+ \int_compare:nNnTF \g_@@_col_int = 0
+ {
+ \UseSocket{tagsupport/tblrow/begin}
+ \int_gset:Nn \g_@@_col_int {1}
+ }
+% \end{macrocode}
+% If we are in a later column we use \cs{g_@@_span_tl} from the
+% previous column to update.
+% \begin{macrocode}
+ {
+ \int_gadd:Nn \g_@@_col_int { \g_@@_span_tl }
+ }
+% \end{macrocode}
+% Then we set the span value so that it can be use in the next column.
+% \begin{macrocode}
+ \tl_gset:Nn \g_@@_span_tl {#1}
+% \end{macrocode}
+%
+% \begin{macrocode}
+ \def\@addamp{\if@firstamp\@firstampfalse \else
+ \@preamerr 5\fi}%
+ \@mkpream{#2}\@addtopreamble\@empty
+ \endgroup
+% \end{macrocode}
+% Now we update the colspan attribute. This needs setting after
+% the group as it is hidden inside the plug in \cs{insert@column}.
+% \begin{macrocode}
+ \@@_set_colspan:n {#1}
+% \end{macrocode}
+% \begin{macrocode}
+ \def\@sharp{#3}%
+ \@arstrut \@preamble
+ \null
+ \ignorespaces}
+% \end{macrocode}
+% \end{macro}
+%
+% \subsection{longtable}
+%
+% Longtable is complicated. When at the begin the \cs{endhead},
+% \cs{endfirsthead}, \cs{endfoot} and \cs{endlastfoot} are used to
+% setup head and foot they create each a structure subtree with one or
+% more rows. From this structures we want to keep at most two (head
+% and foot) and move the foot to the end of the table. When the head
+% and foot boxes are (re)inserted on following pages we want to mark
+% them up as artifact with the exception of the head at the begin and
+% the foot box at the end.
+%
+% TODO: When a line is killed the structure subtree is there already
+% too and must be removed.
+%
+% Hyperref patches longtable. This must be disabled and replace with
+% genuine code
+% \begin{macrocode}
+\let\@kernel@refstepcounter\refstepcounter
+\def\hyper@nopatch@longtable{}
+% \end{macrocode}
+% \begin{macrocode}
+\def\@@_patch_LT@array[#1]#2{%
+% \end{macrocode}
+% \cs{LT@array} is executed in a group, so we can disable para-tagging here.
+% \begin{macrocode}
+ \UseSocket{tagsupport/tbl/init}%
+ \@kernel@refstepcounter{table}\stepcounter{LT@tables}%
+% \end{macrocode}
+% The target is created rather late and a \cs{label} can come earlier,
+% so we have to define \cs{@currentHref} explicitly. We can't currently
+% assume that \cs{theHtable} is defined always.
+% \begin{macrocode}
+ \tl_gset:Ne \@currentHref {table.\cs_if_exist_use:N\theHtable}
+ \int_gzero:N \g_@@_row_int
+ \seq_gclear:N\g_@@_struct_rows_seq
+ \seq_gclear:N\g_@@_struct_cells_seq
+ \seq_gclear:N\g_@@_struct_cur_seq
+ \seq_gclear:N\g_@@_LT@firsthead_rows_seq
+ \seq_gclear:N\g_@@_LT@head_rows_seq
+ \seq_gclear:N\g_@@_LT@lastfoot_rows_seq
+ \seq_gclear:N\g_@@_LT@foot_rows_seq
+ \if l#1%
+ \LTleft\z@ \LTright\fill
+ \else\if r#1%
+ \LTleft\fill \LTright\z@
+ \else\if c#1%
+ \LTleft\fill \LTright\fill
+ \fi\fi\fi
+ \let\LT@mcol\multicolumn
+ \let\LT@@@@tabarray\@tabarray
+ \let\LT@@@@hl\hline
+ \def\@tabarray{%
+ \let\hline\LT@@@@hl
+ \LT@@@@tabarray}%
+ \let\\\LT@tabularcr
+ \let\tabularnewline\\%
+ \def\newpage{\noalign{\break}}%
+ \def\pagebreak{\noalign{\ifnum`}=0\fi\@testopt{\LT@no@pgbk-}4}%
+ \def\nopagebreak{\noalign{\ifnum`}=0\fi\@testopt\LT@no@pgbk4}%
+ \let\hline\LT@hline \let\kill\LT@kill\let\caption\LT@caption
+ \@tempdima\ht\strutbox
+ \let\@endpbox\LT@endpbox
+ \ifx\extrarowheight\@undefined
+ \let\@acol\@tabacol
+ \let\@classz\@tabclassz \let\@classiv\@tabclassiv
+ \def\@startpbox{\vtop\LT@startpbox}%
+ \let\@@@@startpbox\@startpbox
+ \let\@@@@endpbox\@endpbox
+ \let\LT@LL@FM@cr\@tabularcr
+ \else
+ \advance\@tempdima\extrarowheight
+ \col@sep\tabcolsep
+ \let\@startpbox\LT@startpbox\let\LT@LL@FM@cr\@arraycr
+ \fi
+ \setbox\@arstrutbox\hbox{\vrule
+ \@height \arraystretch \@tempdima
+ \@depth \arraystretch \dp \strutbox
+ \@width \z@}%
+ \let\@sharp##\let\protect\relax
+ \begingroup
+ \@mkpream{#2}%
+ \@@_determine_table_cols:
+ \xdef\LT@bchunk{%
+% \end{macrocode}
+% At the start of a chunk we set \cs{g_@@_col_int} to zero to make
+% sure that we aren't generating /TR with the \cs{cr} ending the
+% chunk preamble.
+% \begin{macrocode}
+ \int_gzero:N \g_@@_col_int
+ \global\advance\c@LT@chunks\@ne
+ \global\LT@rows\z@\setbox\z@\vbox\bgroup
+ \LT@setprevdepth
+ \tabskip\LTleft \noexpand\halign to\hsize\bgroup
+ \tabskip\z@ \@arstrut
+% \end{macrocode}
+% Insert the socket and the setting of the conditional
+% \begin{macrocode}
+ \UseSocket{tagsupport/tblrow/begin}%
+ \@@_init_cell_data:
+% \end{macrocode}
+% \begin{macrocode}
+ \@preamble \tabskip\LTright \cr}%
+ \endgroup
+ \expandafter\LT@nofcols\LT@bchunk&\LT@nofcols
+ \LT@make@row
+ \m@th\let\par\@empty
+% \end{macrocode}
+% Socket and conditional
+% \begin{macrocode}
+ \everycr{%
+ \noalign{%
+% \end{macrocode}
+% In \pkg{longtable} we have a bunch of extra \cs{cr}s that are
+% executed whenever a chunk ends. In that case they should not
+% increment the main row counter, sigh.
+% \begin{macrocode}
+ \typeout{--longtable-->~chunk~row:~ \the\LT@rows \space
+ row:~ \the\g_@@_row_int \space
+ column:~ \the\g_@@_col_int
+ }
+ \int_compare:nNnT \g_@@_col_int > 0
+ {
+ \UseSocket{tagsupport/tblrow/end}
+ }
+% \end{macrocode}
+% This prevents any of the additional \cs{cr}s at the end of the
+% chunk to add another /TR. Then once we really start a new chunk
+% it gets incremented so\ldots
+% \begin{macrocode}
+ \int_gzero:N \g_@@_col_int % before first col
+% \end{macrocode}
+% And for the same reason such \cs{cr}s should not increment the
+% main row counter (but it has to be incremented after the preamble
+% of a chunk), so here we test against \cs{LT@rows} which is
+% \cs{LTchunksize} at the end of a chunk.
+% \begin{macrocode}
+ \int_compare:nNnT \LT@rows < \LTchunksize
+ { \int_gincr:N \g_@@_row_int } % this row about to start
+ }%
+ }%
+% \end{macrocode}
+% \begin{macrocode}
+ \lineskip\z@\baselineskip\z@
+ \LT@bchunk}
+% \end{macrocode}
+% The end code most stop to insert the endrow too.
+% \begin{macrocode}
+\def\@@_patch_endlongtable{%
+ \@@_store_missing_cells:n{endlongtable}
+ \crcr
+ \noalign{%
+ \UseSocket{tagsupport/tbl/finalize/longtable}
+ \int_gzero:N \g_@@_row_int % this prevents considering the next
+ % \crcr as another row end.
+ \let\LT@entry\LT@entry@chop
+ \xdef\LT@save@row{\LT@save@row}}%
+ \LT@echunk
+ \LT@start
+ \unvbox\z@
+ \LT@get@widths
+ \if@filesw
+ {\let\LT@entry\LT@entry@write\immediate\write\@auxout{%
+ \gdef\expandafter\noexpand
+ \csname LT@\romannumeral\c@LT@tables\endcsname
+ {\LT@save@row}}}%
+ \fi
+ \ifx\LT@save@row\LT@@@@save@row
+ \else
+ \LT@warn{Column~\@width s~have~changed\MessageBreak
+ in~table~\thetable}%
+ \LT@final@warn
+ \fi
+ \endgraf\penalty -\LT@end@pen
+ \ifvoid\LT@foot\else
+ \global\advance\vsize\ht\LT@foot
+ \global\advance\@colroom\ht\LT@foot
+ \dimen@\pagegoal\advance\dimen@\ht\LT@foot\pagegoal\dimen@
+ \fi
+ \endgroup
+ \global\@mparbottom\z@
+ \endgraf\penalty\z@\addvspace\LTpost
+ \ifvoid\footins\else\insert\footins{}\fi}
+% \end{macrocode}
+%
+%
+%
+% \begin{macro}{\@@_patch_LT@t@bularcr}
+%
+% \begin{macrocode}
+\def\@@_patch_LT@t@bularcr{%
+ \global\advance\LT@rows\@ne
+ \ifnum\LT@rows=\LTchunksize
+% \end{macrocode}
+% At the end of the chunk \verb=\\= is doing something special and
+% so we loose \cs{@@_store_missing_cells:n}. Below is about the
+% right place to add it do this code branch.
+% \begin{macrocode}
+ \@@_store_missing_cells:n{echunk}
+ \gdef\LT@setprevdepth{%
+ \prevdepth\z@
+ \global\let\LT@setprevdepth\relax}%
+ \expandafter\LT@xtabularcr
+ \else
+ \ifnum0=`{}\fi
+ \expandafter\LT@LL@FM@cr
+ \fi}
+
+% \end{macrocode}
+% \end{macro}
+%
+%
+%
+% \begin{macro}{\@@_patch_LT@end@hd@ft}
+% This command is used to store the head and foot boxes.
+% We need to retrieve and store the row so that we can clean
+% up the structure in the finalize code.
+% \begin{macrocode}
+\def\@@_patch_LT@end@hd@ft#1{%
+% \end{macrocode}
+% To handle missing columns in the header we need this:
+% \begin{macrocode}
+ \__tbl_store_missing_cells:n{head/foot}
+ \int_step_inline:nn
+ { \LT@rows + 1 }
+ {
+ \seq_gput_left:ce
+ {g_@@_\cs_to_str:N #1 _rows_seq }
+ { \int_eval:n {\g_@@_row_int + 1 - ##1 } }
+ }
+% \end{macrocode}
+% We also have to set the chunk rows to its max value before
+% calling \cs{LTechunk} so that we don't get extra increments of
+% the main row counter due to \cs{everycr}.
+% \begin{macrocode}
+ \int_gset:Nn \LT@rows { \LTchunksize }
+ \LT@echunk
+ \ifx\LT@start\endgraf
+ \LT@err
+ {Longtable head or foot not at start of table}%
+ {Increase LTchunksize}%
+ \fi
+ \setbox#1\box\z@
+ \LT@get@widths
+ \LT@bchunk}
+% \end{macrocode}
+% \end{macro}
+
+% \begin{macro}{\@@_patch_LT@start}
+% \begin{macrocode}
+\def\@@_patch_LT@start{%
+ \let\LT@start\endgraf
+ \endgraf\penalty\z@\vskip\LTpre\endgraf
+ \ifdim \pagetotal<\pagegoal \else
+ \dimen@=\pageshrink
+ \advance \dimen@ 1sp %
+ \kern\dimen@\penalty 9999\endgraf \kern-\dimen@
+ \fi
+ \dimen@\pagetotal
+ \advance\dimen@ \ht\ifvoid\LT@firsthead\LT@head\else\LT@firsthead\fi
+ \advance\dimen@ \dp\ifvoid\LT@firsthead\LT@head\else\LT@firsthead\fi
+ \advance\dimen@ \ht\LT@foot
+ \edef\LT@reset@vfuzz{\vfuzz\the\vfuzz\vbadness\the\vbadness\relax}%
+ \vfuzz\maxdimen
+ \vbadness\@M
+ \setbox\tw@\copy\z@
+ \setbox\tw@\vsplit\tw@ to \ht\@arstrutbox
+ \setbox\tw@\vbox{\unvbox\tw@}%
+ \LT@reset@vfuzz
+ \advance\dimen@ \ht
+ \ifdim\ht\@arstrutbox>\ht\tw@\@arstrutbox\else\tw@\fi
+ \advance\dimen@\dp
+ \ifdim\dp\@arstrutbox>\dp\tw@\@arstrutbox\else\tw@\fi
+ \advance\dimen@ -\pagegoal
+ \ifdim \dimen@>\z@
+ \vfil\break
+ \else
+ \ifdim\pageshrink>\z@\pageshrink\z@\fi
+ \fi
+ \global\@colroom\@colht
+ \ifvoid\LT@foot\else
+ \global\advance\vsize-\ht\LT@foot
+ \global\advance\@colroom-\ht\LT@foot
+ \dimen@\pagegoal\advance\dimen@-\ht\LT@foot\pagegoal\dimen@
+ \maxdepth\z@
+ \fi
+ \MakeLinkTarget{table}
+ \ifvoid\LT@firsthead\copy\LT@head\else\box\LT@firsthead\fi\nobreak
+% \end{macrocode}
+% Avoid that following uses of the box add content:
+% \begin{macrocode}
+ \tagmcbegin{artifact}
+ \tag_mc_reset_box:N\LT@head
+ \tagmcend
+ \output{\LT@output}}
+% \end{macrocode}
+% \end{macro}
+%
+%
+% \begin{macro}{\@@_patch_LT@output}
+% We must also avoid that the reuse of the foot box leads to
+% duplicated content:
+% \begin{macrocode}
+\def\@@_patch_LT@output{%
+ \ifnum\outputpenalty <-\@Mi
+ \ifnum\outputpenalty > -\LT@end@pen
+ \LT@err{floats and marginpars not allowed in a longtable}\@ehc
+ \else
+ \setbox\z@\vbox{\unvbox\@cclv}%
+ \ifdim \ht\LT@lastfoot>\ht\LT@foot
+ \dimen@\pagegoal
+ \advance\dimen@\ht\LT@foot
+ \advance\dimen@-\ht\LT@lastfoot
+ \ifdim\dimen@<\ht\z@
+ \setbox\@cclv\vbox{\unvbox\z@\copy\LT@foot\vss}%
+ \@makecol
+ \@outputpage
+ \global\vsize\@colroom
+ \setbox\z@\vbox{\box\LT@head}%
+ \fi
+ \fi
+ \unvbox\z@\box\ifvoid\LT@lastfoot\LT@foot\else\LT@lastfoot\fi
+% \end{macrocode}
+% Reset attribute of foot box:
+% \begin{macrocode}
+ \tagmcbegin{artifact}
+ \tag_mc_reset_box:N \LT@foot
+ \tagmcend
+ \fi
+ \else
+ \setbox\@cclv\vbox{\unvbox\@cclv\copy\LT@foot\vss}%
+% \end{macrocode}
+% Reset attribute of foot box:
+% \begin{macrocode}
+ \tagmcbegin{artifact}
+ \tag_mc_reset_box:N \LT@foot
+ \tagmcend
+ \@makecol
+ \@outputpage
+ \global\vsize\@colroom
+ \copy\LT@head\nobreak
+ \fi}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_patch_\LT@makecaption}
+% This patch is quite similar to the one for LaTeX's \cs{@makecaption}
+% we also have to change the parbox sockets.
+% \begin{macrocode}
+\def\@@_patch_LT@makecaption#1#2#3{%
+ \LT@mcol\LT@cols c{%
+ % test can go after merge
+ \str_if_exist:cT { l__socket_tagsupport/parbox/before_plug_str }
+ {
+ \AssignSocketPlug{tagsupport/parbox/before}{noop}
+ \AssignSocketPlug{tagsupport/parbox/after}{noop}
+ }
+ \hbox to\z@{\hss\parbox[t]\LTcapwidth{%
+ \reset@font
+ \tag_stop:n{caption}
+ \sbox\@tempboxa{#1{#2:~}#3}%
+ \tag_start:n{caption}
+ \ifdim\wd\@tempboxa>\hsize
+ #1{#2:~}#3%
+ \else
+ \hbox to\hsize{\hfil#1{#2:~}#3\hfil}%
+ \fi
+ \endgraf\vskip\baselineskip}%
+ \hss}}}
+% \end{macrocode}
+% \end{macro}
+%
+%
+%
+% Overwrite the longtable definition. That will probably break somewhere as
+% they are various package which patch too.
+% \begin{macrocode}
+\AddToHook{package/longtable/after}
+ {
+ \seq_new:N \g_@@_LT@firsthead_rows_seq
+ \seq_new:N \g_@@_LT@head_rows_seq
+ \seq_new:N \g_@@_LT@lastfoot_rows_seq
+ \seq_new:N \g_@@_LT@foot_rows_seq
+ \cs_set_eq:NN \LT@array\@@_patch_LT@array
+ \cs_set_eq:NN \endlongtable\@@_patch_endlongtable
+ \cs_set_eq:NN \LT@start\@@_patch_LT@start
+ \cs_set_eq:NN \LT@output\@@_patch_LT@output
+ \cs_set_eq:NN \LT@t@bularcr\@@_patch_LT@t@bularcr
+ \cs_set_eq:NN \LT@end@hd@ft\@@_patch_LT@end@hd@ft
+ \cs_set_eq:NN \LT@makecaption\@@_patch_LT@makecaption
+ }
+% \end{macrocode}
+
+
+
+
+
+% \subsection{tabularx}
+%
+% In tabularx we mainly need to ensure that no tagging is done during
+% the trial.
+%
+% \begin{macrocode}
+\def\@@_patch_TX@endtabularx{%
+ \expandafter\expandafter\expandafter
+ \TX@find@endtabularxa\csname end\TX@\endcsname
+ \endtabularx\TX@\endtabularx\TX@find@endtabularxa
+ \expandafter\TX@newcol\expandafter{\tabularxcolumn{\TX@col@width}}%
+ \let\verb\TX@verb
+ \def\@elt##1{\global\value{##1}\the\value{##1}\relax}%
+ \edef\TX@ckpt{\cl@@@@ckpt}%
+ \let\@elt\relax
+ \TX@old@table\maxdimen
+ \TX@col@width\TX@target
+ \global\TX@cols\@ne
+ \TX@typeout@
+ {\@spaces Table Width\@spaces Column Width\@spaces X Columns}%
+% \end{macrocode}
+% Here we stop tagging:
+% \begin{macrocode}
+ \tag_stop:n{tabularx}
+ \TX@trial{\def\NC@rewrite@X{%
+ \global\advance\TX@cols\@ne\NC@find p{\TX@col@width}}}%
+ \loop
+ \TX@arith
+ \ifTX@
+ \TX@trial{}%
+ \repeat
+% \end{macrocode}
+% And now we restart it again.
+% \begin{macrocode}
+ \tag_start:n{tabularx}
+ {\let\@footnotetext\TX@ftntext\let\@xfootnotenext\TX@xftntext
+ \csname tabular*\expandafter\endcsname\expandafter\TX@target
+ \the\toks@
+ \csname endtabular*\endcsname}%
+ \global\TX@ftn\expandafter{\expandafter}\the\TX@ftn
+ \ifnum0=`{\fi}%
+ \expandafter\expandafter\expandafter
+ \TX@find@endtabularxbb
+ \expandafter\end\expandafter{\TX@}%
+ \endtabularx\TX@\endtabularx\TX@find@endtabularxb
+}
+
+\AddToHook{package/tabularx/after}
+ {\cs_set_eq:NN \TX@endtabularx\@@_patch_TX@endtabularx }
+% \end{macrocode}
+% \begin{macrocode}
+%</package>
+% \end{macrocode}
+%
+%
+% \begin{macrocode}
+%<*latex-lab>
+\ProvidesFile{table-latex-lab-testphase.ltx}
+ [\ltlabtbldate\space v\ltlabtblversion\space latex-lab wrapper table]
+\RequirePackage{latex-lab-testphase-table}
+%</latex-lab>
+% \end{macrocode}