texlive[54677] Master/texmf-dist: keyvaltable (5apr20)

commits+karl at tug.org commits+karl at tug.org
Sun Apr 12 00:50:13 CEST 2020


Revision: 54677
          http://tug.org/svn/texlive?view=revision&revision=54677
Author:   karl
Date:     2020-04-12 00:50:13 +0200 (Sun, 12 Apr 2020)
Log Message:
-----------
keyvaltable (5apr20)

Modified Paths:
--------------
    trunk/Master/texmf-dist/doc/latex/keyvaltable/keyvaltable.pdf
    trunk/Master/texmf-dist/source/latex/keyvaltable/keyvaltable.dtx
    trunk/Master/texmf-dist/tex/latex/keyvaltable/keyvaltable.sty

Modified: trunk/Master/texmf-dist/doc/latex/keyvaltable/keyvaltable.pdf
===================================================================
(Binary files differ)

Modified: trunk/Master/texmf-dist/source/latex/keyvaltable/keyvaltable.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/keyvaltable/keyvaltable.dtx	2020-04-11 22:49:53 UTC (rev 54676)
+++ trunk/Master/texmf-dist/source/latex/keyvaltable/keyvaltable.dtx	2020-04-11 22:50:13 UTC (rev 54677)
@@ -22,7 +22,7 @@
 %<package>\NeedsTeXFormat{LaTeX2e}[1999/12/01]
 %<package>\ProvidesPackage{keyvaltable}
 %<*package>
-    [2020/02/19 v2.1 Package for filling tables using key-value lists]
+    [2020/04/05 v2.2 Package for filling tables using key-value lists]
 %</package>
 %
 %<*driver>
@@ -47,7 +47,7 @@
     showhead=false,headformat={\bfseries\footnotesize},
     rowbg=black!7!white..black!3!white,
     showrules=false,
-    shape=tabu]{GoalApproach}{
+    backend=tabu]{GoalApproach}{
   id: align=r, default=(\alph{kvtRow}), head=\#;
   goal: align=X[l];
   approach: align={X[2,l]};
@@ -223,7 +223,10 @@
 % \NiceDescribeKey{align}{vals={l,c,r,p,X,\ldots}, init=l}
 %   This property specifies the alignment of content in the
 %   column.  The \meta{value} can be set to any column alignment
-%   understood by table environments.
+%   understood by table environments.\footnote{More complex values, for
+%   instance using the notation of the \pkgname{array} package for
+%   inserting material before or after a column, are permitted but not
+%   further tested. Use at your own risk.}
 %
 % \NiceDescribeKey{default}{vals=\vmeta{content}, init=\vmeta{empty}}
 %   This property specifies the default \meta{content} of a cell in this
@@ -497,7 +500,15 @@
 % \end{KeyValTable}
 % \end{LTXexample}
 %
+% By default, all counters start at value $1$. Through the following
+% possibilities, this behavior can be changed.
 %
+% \NiceDescribeKey{resume}{vals={true,false}, init=false, def=true}\label{opt:resume}
+% This option is available in |KeyValTable| environments. When this
+% option is set to |true|, the value of the |kvtRow| counter is resumed
+% from the previous |KeyValTable| environment. The other two counters
+% are not affected by this option.
+%
 % \subsection{Row Labeling}
 %
 % Row numbering can easily be combined with row labeling.
@@ -608,27 +619,33 @@
 % list of \meta{property}|=|\meta{value} pairs.
 % The following \meta{property} keys can be configured.
 %
-% \NiceDescribeKey{shape}
-%    {vals={multipage,onepage,tabular,tabularx,longtable,xltabular,tabu,longtabu},
-%     init=multipage}
-% This property specifies the table's shape. For \meta{value}, the
-% package currently supports |multipage| and |onepage| as well as
-% |tabular|, |tabularx|, |longtable|, |xltabular|, |tabu|, and
-% |longtabu|.  In case of |multipage|, the table may span multiple pages
-% and on each page, the column header is repeated. In case of |onepage|,
-% the table does not split into multiple pages.  The remaining values
-% use the respective environment for producing the table (see
-% \cref{sec:AltTabEnv} for the effect).
+% \NiceDescribeKeys{2}
+%   {backend}{vals={tabular,tabularx,longtable,xltabular,tabu,longtabu}}
+%   {shape}{vals={multipage,onepage}, init=multipage}
+% The |backend| property specifies the table environment to be used for
+% producing the table. A set of six environments is currently supported,
+% including environments that can span multiple pages and environments
+% whose columns can stretch/shrink to fill the available space ("|X|"
+% columns).
+% The |shape| property abstracts from the concrete environments.
+% In case of |multipage|, the table may span multiple pages and
+% depending on whether |X|-columns are used or not, an appropriate
+% environment is selected. In case of |onepage|, the table does not
+% split into multiple pages.
+% See \cref{sec:AltTabEnv} for more details on the available shapes and
+% backends.
+% Only one of |shape| and |backend| can be specified. If both are
+% specified, the property that is specified last wins.
 %
 % \NiceDescribeKey{width}{vals=\vmeta{dimension}, init=\cmd\linewidth}
 % This property specifies the width of the table, if the selected
-% |shape| supports it (see \cref{sec:AltTabEnv}).
+% |shape|/|backend| supports it (see \cref{sec:AltTabEnv}).
 %
 % \NiceDescribeKeys{2}
 %   {valign}{vals={t,c,b}, init=\vmeta{empty}}
 %   {halign}{vals={l,c,r}, init=\vmeta{empty}}
 % These two properties specify the vertical and, respectively, horizontal
-% alignment of the table, if the selected |shape| supports it (see
+% alignment of the table, if the selected |shape|/|backend| supports it (see
 % \cref{sec:AltTabEnv}).
 %
 % \NiceDescribeKey{showhead}{vals={true,false}, init=true}
@@ -733,7 +750,59 @@
 % \label{fig:TableOptionExamples}
 % \end{figure}
 %
+% \subsubsection{Table Styles and Resumable Options}
 %
+% Rather than specifying properties for individual tables or table
+% types, \thispackage also supports named \emph{table styles}.
+%
+% \NiceDescribeKey{style}{vals=\vmeta{list of style names}, init=\vmeta{empty}}
+% Through this property of tables or table types, a list of styles can
+% be applied to a single table or, respectively, a table type. Each
+% style must have been defined with |\kvtNewTableStyle| before.
+%
+% \NiceDescribeMacro{\kvtNewTableStyle}{\marg{name}\marg{options}}
+% This macro declares a new table style with the given \meta{name} and
+% defines it to be equivalent to using the given \meta{options}.
+% The \meta{name} must not already be defined.
+%
+% \NiceDescribeMacro{\kvtRenewTableStyle}{\marg{name}\marg{options}}
+% This macro re-defines an existing table style \meta{name} with new
+% \meta{options}.
+%
+% The following example demonstrates table styles for an individual
+% table.
+%
+% \begin{LTXexample}[morepreset=\RecipePreset,morekeywords={style,kvtNewTableStyle}]
+% \kvtNewTableStyle{plain}{
+%   norules,nobg,headformat=\textbf}
+% \begin{KeyValTable}[style=plain]{Recipe}
+% \Row{amount=150g, ingredient=ice cream,
+%   step=put into bowl}
+% \Row{amount= 50g, ingredient=cherries,
+%   step=heat up and add to bowl}
+% \end{KeyValTable}
+% \end{LTXexample}
+%
+% \NiceNote{The \meta{options} in |\kvtNewTableStyle| can be left empty.
+% In this case, the table style does not have any effect on the appearance
+% of tables. However, the style can already be used for "tagging" tables
+% and table types, while the final options for the style can be
+% configured at a later point in time.}
+%
+% Even without table styles, the appearance of the previous
+% |KeyValTable| can be used again through the following option.
+% \NiceDescribeKey{resume*}{vals={true,false}, init=false, def=true}
+% When set to |true|, this option makes the table use the options from
+% the previous |KeyValTable| environment. This option also implies the
+% |resume| option (see \vref{opt:resume}).
+
+% If the previous environment also used |resume*|, then the options of
+% its predecessor environment are used, and so forth.
+% Note that this means that table options are not accumulated over
+% subsequent uses of |resume*|.
+% This behavior is the same as in the \pkgname{enumitem} package.
+%
+%
 % \subsection{Column Appearance}
 %
 % Column appearance is configured through the parameters |align|,
@@ -1116,11 +1185,11 @@
 %
 % \subsection{Captions}
 %
-% There are two ways to add captions to (\pkgname{keyvaltable}-) tables:
+% There are two ways to add captions to \pkgname{keyvaltable} tables:
 % The first way is to enclose the table in a |table| environment. This
 % is particularly suit for tables that do not span multiple pages, such
-% as those produced through the |onepage| shape (or |tabular|,
-% |tabularx|, and |tabu| -- see \cref{sec:AltTabEnv}).
+% as those produced through the |onepage| shape or the backends
+% |tabular|, |tabularx|, and |tabu| (see \cref{sec:AltTabEnv}).
 %
 % \begin{LTXexample}[morepreset=\RecipePreset,morekeywords={caption,label,ref}]
 % \begin{table}
@@ -1137,20 +1206,37 @@
 % \end{LTXexample}
 %
 % The second way to add captions is through the |caption| option of
-% \pkgname{keyvaltable} tables. This is particularly suit for tables
-% that can span multiple pages, such as those produced through the
-% |multipage| shape (or |longtable|, |xltabular|, and |longtabu| -- see
-% \cref{sec:AltTabEnv}).
+% \pkgname{keyvaltable} tables. This option is available for the
+% "multipage" shape and, respectively, the table backends |longtable|,
+% |xltabular|, and |longtabu| (see \cref{sec:AltTabEnv}).
 %
-% \NiceDescribeKeys{2}
+% \NiceDescribeKeys{4}
 %    {caption}{vals=\vmeta{text}, init=\vmeta{none}}
+%    {caption/lot}{vals=\vmeta{text}, init=\vmeta{none}}
+%    {caption/alt}{vals=\vmeta{text}, init=\vmeta{none}}
 %    {label}{vals=\vmeta{name}, init=\vmeta{none}}
 % These options set the caption and, respectively, label of a table.
-% The caption is added to the end of the table.
+% Through the option |caption/lot|, the caption to be put into the list
+% of tables can be specified; if omitted, |caption| is used.
+% Through the option |caption/alt|, the alternative caption to be
+% displayed on those pages of multipage tables where the main caption is
+% not shown; if omitted, no caption is displayed on these pages.
+%
+% The position of the caption is determined by the following option.
+%
+% \NiceDescribeKey{captionpos}{vals={t,b}, init=b}
+% This option specifies the position of table captions. Value "|t|"
+% specifies that captions are at the top of (above) their tables; value
+% "|b|" specifies that captions are at the bottom of (below) their
+% tables.
+% Moreover, in case of "|t|" the main caption is on top of the
+% \emph{first} page of a table while in case of "|b|" the main caption
+% is at the bottom of the \emph{last} page of a table.
+%
 % The following example shows the options in action.
 %
-% \begin{LTXexample}[morepreset=\RecipePreset,morekeywords={caption,label,ref}]
-% \begin{KeyValTable}[shape=multipage,
+% \begin{LTXexample}[morepreset=\RecipePreset\setcounter{table}{0},morekeywords={caption,label,ref}]
+% \begin{KeyValTable}[captionpos=t,
 %   caption=Cherries++, label=Cherries2]{Recipe}
 % \Row{amount=150g, ingredient=ice cream,
 %   step=put into bowl}
@@ -1163,28 +1249,33 @@
 %
 % \subsection{Alternative Table Environments}
 % \label{sec:AltTabEnv}
-%
-% Originally, the \thispackage package uses the \pkgname{tabu} package
-% and |tabu|, resp. |longtabu| environments for typesetting the actual
-% tables. Through the |shape| option of tables, the table environment
-% used by \thispackage tables can be changed.
-% \Vref{tab:TabEnv} compares
-% the possible shapes/environments with regards to
+% The \thispackage package internally uses traditional table
+% environments, such as |tabular|, for typesetting the actual tables.
+% Through the |shape| and |backend| properties of a table or table type,
+% the table environment used by for the table or, respectively, table
+% type can be changed.
+% \Vref{tab:TabEnv} compares the possible shapes/environments with
+% regards to
 % \begin{itemize}[nosep]
 % \item whether they support tables that span multiple pages,
 % \item whether they support |caption| and |label| options,
 % \item whether they support |X|-type (variable-width) columns,
-% \item and whether their width can be specified (through the |width| option).
+% \item whether their width can be specified (through the |width|
+%   option), and
+% \item whether they support a vertical or horizontal alignment of the
+%   table to be specified.
 % \end{itemize}
-% Finally, the table also displays the
-% package(s) that must be loaded manually when the respective shapes are
+% Finally, the table also lists the names of the packages that provide
+% the respective environments. The packages for the shapes |onepage| and
+% |multipage| are loaded automatically. All other packages must be
+% loaded via |\usepackage| when the respective shape or backend shall be
 % used.
 % \begin{table}\centering
 %   \newcommand\RHead[1]{\rotatebox{90}{\small\varwidth{\linewidth}#1\endvarwidth}}%
 %   \newcommand\YesNo[1]{\ifstrequal{#1}{yes}{\checkmark}{}}%
-% \NewKeyValTable[shape=tabular,headformat=\sffamily\textbf]{ShapeProps}{
+% \NewKeyValTable[backend=tabular,headformat=\sffamily\textbf]{ShapeProps}{
 %   shape: format=\small\texttt;
-%   env: format=\small\texttt, head=environment;
+%   env: format=\small\texttt, head=backend;
 %   multipage: align=c, head=\RHead{multipage}, format=\YesNo;
 %   caption:   align=c, head=\RHead{caption}, format=\YesNo;
 %   Xcols:     align=c, head=\RHead{\texttt{X} columns}, format=\YesNo;
@@ -1199,14 +1290,14 @@
 % \Row{shape=onepage,   env=tabu,      multipage=no,  caption=no,  Xcols=yes, width=yes, align=v, packages=tabu}
 % \Row{shape=multipage, env=longtabu,  multipage=yes, caption=yes, Xcols=yes, width=yes, align=h, packages={tabu, longtable}}
 % \midrule
-% \Row{shape=tabular,   env=tabular,   multipage=no,  caption=no,  Xcols=no,  width=no,  align=v}
-% \Row{shape=tabularx,  env=tabularx,  multipage=no,  caption=no,  Xcols=yes, width=yes, align=v, packages={tabularx}}
-% \Row{shape=longtable, env=longtable, multipage=yes, caption=yes, Xcols=no,  width=no,  align=h, packages={longtable}}
-% \Row{shape=xltabular, env=xltabular, multipage=yes, caption=yes, Xcols=yes, width=yes, align=h, packages={xltabular}}
-% \Row{shape=tabu,      env=tabu,      multipage=no,  caption=no,  Xcols=yes, width=yes, align=v, packages={tabu}}
-% \Row{shape=longtabu,  env=longtabu,  multipage=yes, caption=yes, Xcols=yes, width=yes, align=h, packages={tabu,longtable}}
+% \Row{                 env=tabular,   multipage=no,  caption=no,  Xcols=no,  width=no,  align=v}
+% \Row{                 env=tabularx,  multipage=no,  caption=no,  Xcols=yes, width=yes, align=v, packages={tabularx}}
+% \Row{                 env=longtable, multipage=yes, caption=yes, Xcols=no,  width=no,  align=h, packages={longtable}}
+% \Row{                 env=xltabular, multipage=yes, caption=yes, Xcols=yes, width=yes, align=h, packages={xltabular}}
+% \Row{                 env=tabu,      multipage=no,  caption=no,  Xcols=yes, width=yes, align=v, packages={tabu}}
+% \Row{                 env=longtabu,  multipage=yes, caption=yes, Xcols=yes, width=yes, align=h, packages={tabu,longtable}}
 % \end{KeyValTable}
-% \caption{Comparison of table shapes / environments}
+% \caption{Comparison of table shapes and backends}
 % \label{tab:TabEnv}
 % \end{table}
 %
@@ -1219,11 +1310,11 @@
 %   l: align=l; c: align=c; r: align=r;}[headers={
 %   l+c+r: head=\textbf{\kvtTableOpt{shape} shape}\\ ::}]
 %
-% \begin{KeyValTable}[shape=tabular]{ShapeNoX}
+% \begin{KeyValTable}[backend=tabular]{ShapeNoX}
 %   \Row{l=left,   c=center,     r=right}
 %   \Row{l=left-2, c=2-center-2, r=2-right}
 % \end{KeyValTable}\\
-% \begin{KeyValTable}[shape=longtable]{ShapeNoX}
+% \begin{KeyValTable}[backend=longtable]{ShapeNoX}
 %   \Row{l=left,   c=center,     r=right}
 %   \Row{l=left-2, c=2-center-2, r=2-right}
 % \end{KeyValTable}
@@ -1236,24 +1327,24 @@
 %   l: align=l; X: align=X; r: align=r;}[headers={
 %   l+X+r: head=\textbf{\kvtTableOpt{shape} shape}\\ ::}]
 %
-% \begin{KeyValTable}[shape=tabularx]{ShapeWithX}
+% \begin{KeyValTable}[backend=tabularx]{ShapeWithX}
 %   \Row{l=left,   X=expandable,   r=right}
 %   \Row{l=left-2, X=expandable-2, r=2-right}
 % \end{KeyValTable}\medskip\\
-% \begin{KeyValTable}[shape=xltabular]{ShapeWithX}
+% \begin{KeyValTable}[backend=xltabular]{ShapeWithX}
 %   \Row{l=left,   X=expandable,   r=right}
 %   \Row{l=left-2, X=expandable-2, r=2-right}
 % \end{KeyValTable}
-% \begin{KeyValTable}[shape=tabu]{ShapeWithX}
+% \begin{KeyValTable}[backend=tabu]{ShapeWithX}
 %   \Row{l=left,   X=expandable,   r=right}
 %   \Row{l=left-2, X=expandable-2, r=2-right}
 % \end{KeyValTable}
-% \begin{KeyValTable}[shape=longtabu]{ShapeWithX}
+% \begin{KeyValTable}[backend=longtabu]{ShapeWithX}
 %   \Row{l=left,   X=expandable,   r=right}
 %   \Row{l=left-2, X=expandable-2, r=2-right}
 % \end{KeyValTable}
 % \end{LTXexample}
-% \caption{Examples for the shape option}
+% \caption{Examples for the backend option}
 % \label{fig:TableTypes}
 % \end{figure}
 %
@@ -1492,6 +1583,44 @@
 %
 % \subsection{Auxiliary Code}
 %
+% \subsubsection{List Parsing}
+%
+% \begin{macro}{\kvt at DeclareTrimListParser}
+% The |\kvt at DeclareTrimListParser|(|*|)\marg{command}\marg{separator}
+% macro is equivalent to \pkgname{etoolbox}'s |\DeclareListParser|,
+% except that the \meta{command} is defined such that it will remove
+% trailing spaces from list elements before passing the list elements to
+% the processing macro (i.e., to |\do| or the user-provided macro).
+% Note: With |\DeclareListParser|, \meta{command} is defined to only
+% remove leading spaces but not trailing ones.
+% This implementation relies on the internals of
+% \pkgname{etoolbox} and works with v2.4 of the package, at least.
+%    \begin{macrocode}
+\newcommand\kvt at DeclareTrimListParser{%
+  \@ifstar{\kvt at DeclareTrimListParser@i{*}}
+          {\kvt at DeclareTrimListParser@i{}}}
+\newcommand\kvt at DeclareTrimListParser@i[3]{%
+  \DeclareListParser#1{#2}{#3}\expandafter
+  \patchcmd\csname etb at lst@\expandafter\@gobble\string#2\endcsname
+    {\etb at listitem}{\kvt at etb@listitem}{}
+    {\kvt at warn{Failed to patch a command defined by the etoolbox
+      package, possibly because etoolbox internals have changed.
+      You might encounter superfluous spaces.}}}
+%    \end{macrocode}
+% The cascade of |\expandafter| below ensures that first the trimming
+% macro is expanded and afterwards the outer |\unexpanded| of the
+% timming macro's expansion is expanded, which by definition of the
+% "noexp" trimming macro fully expands the macro's logic.
+% The auxiliary macro below is only for switching the two arguments such
+% that the expansion control can be applied to the second argument.
+%    \begin{macrocode}
+\newcommand\kvt at etb@listitem[2]{%
+  \expandafter\expandafter\expandafter\kvt at etb@listitem at i
+  \expandafter\expandafter\expandafter{\trim at post@space at noexp{#2}}{#1}}
+\newcommand\kvt at etb@listitem at i[2]{\etb at listitem{#2}{#1}}
+%    \end{macrocode}
+% \end{macro}
+%
 % \begin{macro}{\kvt at dossvlist}
 % The |\kvt at dossvlist|\marg{list} macro parses a semicolon-separated
 % list and runs |\do|\meta{item} for every element of the list.
@@ -1503,7 +1632,7 @@
 % \begin{macro}{\kvt at forpsvlist}
 % The |\kvt at forpsvlist|\marg{handler}\marg{list} parses a `+'-separated list.
 %    \begin{macrocode}
-\DeclareListParser*{\kvt at forpsvlist}{+}
+\kvt at DeclareTrimListParser*{\kvt at forpsvlist}{+}
 %    \end{macrocode}
 % \end{macro}
 %
@@ -1510,10 +1639,12 @@
 % \begin{macro}{\kvt at dobrklist}
 % The |\kvt at dobrklist|\marg{list} parses a `|\\|'-separated list.
 %    \begin{macrocode}
-\DeclareListParser{\kvt at dobrklist}{\\}
+\kvt at DeclareTrimListParser{\kvt at dobrklist}{\\}
 %    \end{macrocode}
 % \end{macro}
 %
+% \subsubsection{Errors and Warnings}
+%
 % \begin{macro}{\kvt at error}
 % \begin{macro}{\kvt at warn}
 % These macros produce error and warning messages.
@@ -1524,6 +1655,8 @@
 % \end{macro}
 % \end{macro}
 %
+% \subsubsection{Setting Keys}
+%
 % \begin{macro}{\kvt at setkeys}
 % \begin{macro}{\kvt at setcmdkeys}
 % \begin{macro}{\kvt at setcskeys}
@@ -1648,8 +1781,11 @@
 % The following code defines the possible table options.
 %
 % \changes{v0.2}{2016/05/21}{Added ``shape'' table option}
-% \changes{v2.0}{2019/05/11}{added table options "caption" and "label"}
+% \changes{v2.0}{2019/05/11}{Added table options "caption" and "label"}
 % \changes{v2.1}{2020/01/18}{Added ``valign'' and ``halign'' table options}
+% \changes{v2.2}{2020/02/24}{Added ``style'' table option}
+% \changes{v2.2}{2020/02/27}{added option "backend"}
+% \changes{v2.2}{2020/03/08}{added option "captionpos"}
 %    \begin{macrocode}
 \define at cmdkey[kvt]{Table}{rowbg}{}
 \define at cmdkey[kvt]{Table}{headbg}{}
@@ -1658,12 +1794,13 @@
 \define at cmdkey[kvt]{Table}{width}{}
 \define at boolkey[kvt]{Table}{showhead}{}
 \define at boolkey[kvt]{Table}{showrules}{}
-\define at cmdkey[kvt]{Table}{caption}{}
-\define at cmdkey[kvt]{Table}{label}{}
+\define at choicekey[kvt]{Table}{captionpos}{t,b}
+  {\csdef{cmdkvt at Table@captionpos}{#1}}
 \define at choicekey[kvt]{Table}{valign}{t,c,b}
   {\csdef{cmdkvt at Table@valign}{#1}}
 \define at choicekey[kvt]{Table}{halign}{l,c,r}
   {\csdef{cmdkvt at Table@halign}{#1}}
+\define at key[kvt]{Table}{style}{\kvt at UseTableStyles{#1}}
 %    \end{macrocode}
 % The following options only abbreviate options defined above.
 % \changes{v2.1}{2020/01/14}{added abbreviation option "norules"}
@@ -1676,15 +1813,49 @@
   \ifbool{#1}
     {\kvt at setkeys{showrules=false}{Table}}
     {\kvt at setkeys{showrules=true}{Table}}}
+\define at key[kvt]{Table}{backend}{\ifinlist{#1}{\kvt@@tablebackends}
+  {\csdef{cmdkvt at Table@shape}{#1}}
+  {\kvt at error{Table backend '#1' not known}
+     {Check for misspellings in '#1'}}}
+\define at key[kvt]{Table}{shape}{\ifinlist{#1}{\kvt@@tableshapes}
+  {\csdef{cmdkvt at Table@shape}{#1}}
+  {\ifinlist{#1}{\kvt@@tablebackends}
+    {\kvt at warn{Using a backend ('#1') as shape is deprecated.
+      Use the 'backend' option instead.}%
+     \csdef{cmdkvt at Table@shape}{#1}}
+    {\kvt at error{Table shape '#1' not known}
+       {Check for misspellings in '#1'}}}}
 %    \end{macrocode}
-% When adding further |shape| options below, ensure to also add a
-% corresponding |\kvt at DefineStdTabEnv| counterpart further below in the
-% code.
+%
+% The following table options only apply to individual |KeyValTable|
+% environments and cannot be set with |\NewKeyValTable| or |\kvtSet|.
+% \changes{v2.2}{2020/02/23}{added table options "resume" and "resume*"}
+% \changes{v2.2}{2020/03/12}{added options "caption/lot" and "caption/alt"}
 %    \begin{macrocode}
-\define at choicekey[kvt]{Table}{shape}
-  {multipage,onepage,tabular,longtable,tabularx,xltabular,tabu,longtabu}
-  {\csdef{cmdkvt at Table@shape}{#1}}
+\define at cmdkey[kvt]{TableEnv}{caption}{}
+\define at cmdkey[kvt]{TableEnv}{caption/lot}{}
+\define at cmdkey[kvt]{TableEnv}{caption/alt}{}
+\define at cmdkey[kvt]{TableEnv}{label}{}
+\define at boolkey[kvt]{TableEnv}{resume}[true]{%
+  \ifbool{#1}{\ifundef\kvt@@rowcountlast
+    {\kvt at error{No previous table whose counter could be resumed.}
+      {Check whether the "resume" is intentional and whether a
+       previously existing predecessor table has disappeared.}}{}}{}}
+\define at boolkey[kvt]{TableEnv}{resume*}[true]{%
+  \ifbool{#1}
 %    \end{macrocode}
+% The |\kvt@@lastenvopt| macro holds the previous |KeyValTable|'s
+% options. Beyond these options, |resume*| automatically also sets
+% |resume|.
+%    \begin{macrocode}
+    {\ifundef\kvt@@lastenvopt
+       {\kvt at error{No previous table whose options could be resume*'d.}
+         {Check whether the "resume*" is intentional and whether a
+          previously existing predecessor table has disappeared.}}{}%
+     \kvt at setcmdkeys\kvt@@lastenvopt{Table}%
+     \kvt at setkeys{resume}{TableEnv}}
+    {}}
+%    \end{macrocode}
 %
 %
 % \subsubsection{Column Options}
@@ -1808,9 +1979,11 @@
 %
 % \subsubsection{Option Defaults}
 %
-% The following sets the default values for the options.
+% The following sets the default values for the options. This is done
+% only after the package is otherwise completely processed, to ensure
+% that all features are already defined/registered at that point.
 %    \begin{macrocode}
-\kvtSet{%
+\AtEndOfPackage{\kvtSet{%
   rowbg=white..black!10,
   headbg=black!14,
   showhead=true,
@@ -1819,7 +1992,7 @@
   headalign=,
   shape=multipage,
   width=\linewidth,
-  caption={}, label={},
+  captionpos=b,
 %    \end{macrocode}
 % Column options
 %    \begin{macrocode}
@@ -1838,7 +2011,7 @@
   ColGroup/align=c,
   ColGroup/format=\kvtStrutted,
   HeadCell/align=c,
-}
+}}
 %    \end{macrocode}
 %
 %
@@ -1928,6 +2101,10 @@
 % \meta{tname} and adds the column with the configuration to the table.
 %    \begin{macrocode}
 \def\kvt at parsecolspec#1#2:#3:#4\@undefined{%
+%    \end{macrocode}
+% Catch syntax errors first.
+%    \begin{macrocode}
+  \kvt at checkcolspecempty{#4}{column}{#2}%
   \def\kvt@@column{#2}%
   \trim at spaces@in\kvt@@column
   \expandafter\kvt at parsecolspec@i\expandafter{\kvt@@column}{#1}{#3}}
@@ -2066,6 +2243,13 @@
 % \meta{cgopts}.
 %    \begin{macrocode}
 \def\kvt at parsecolgroup#1#2:#3:#4\@undefined{%
+%    \end{macrocode}
+% Catch syntax errors first.
+%    \begin{macrocode}
+  \kvt at checkcolspecempty{#4}{column group}{#2}%
+%    \end{macrocode}
+% Next, check for a valid \meta{cgname}.
+%    \begin{macrocode}
   \ifinlistcs{#2}{kvt at allcolumns@#1}{\kvt at error
     {Name `#2' cannot be used for a column group in table type `#1',
      as it is already used for a column}
@@ -2116,6 +2300,23 @@
 %    \end{macrocode}
 % \end{macro}
 %
+% \begin{macro}{\kvt at checkcolspecempty}
+% The |\kvt at checkcolspecempty|\marg{empty}\marg{type}\marg{name}
+% macro checks the \meta{empty} parameter of a parsing macro for a
+% colon-separated key-value pair.
+% If \meta{empty} is empty, this corresponds to the valid case that only
+% the name of a column group was provided and no properties. If
+% \meta{empty} equals ":", then a name and properties were provided. In
+% all other cases, superfluous colons were found.
+%    \begin{macrocode}
+\newcommand\kvt at checkcolspecempty[3]{%
+  \ifstrempty{#1}{}{\ifstrequal{#1}{:}{}{\kvt at error
+    {Too many ':' in definition of #2 '#3'}
+    {Check whether there is an accidental ':' that should actually be
+     a ',' or ';'.}}}}
+%    \end{macrocode}
+% \end{macro}
+%
 % \begin{macro}{\kvt at checkcolgroup}
 % The |\kvt at checkcolgroup|\marg{span-psv}\marg{tname}\marg{cgname} macro
 % performs some checks on \meta{span-psv} as a specification of which
@@ -2245,8 +2446,7 @@
 % header for the columns is added as header row.
 %    \begin{macrocode}
   \def\do##1{%
-    \def\kvt@@tmp{##1}\trim at post@space at in\kvt@@tmp%
-    \expandafter\ifstrequal\expandafter{\kvt@@tmp}{::}
+    \ifstrequal{##1}{::}
       {\appto\kvt@@parseheadrows{%
          \cseappto{kvt@@custheadrows@#2}{%
            \csexpandonce{kvt at headings@#2}}}}
@@ -2315,7 +2515,7 @@
 % for the column in |\kvt@@curhd|) and set |\kvt@@lasthd| to the
 % current one.
 %    \begin{macrocode}
-      {\ifnum\kvt@@span>\z@ \expandafter\kvt at concludecolumn\fi
+      {\ifnum\kvt@@span>\z@ \expandafter\kvt at concludehdcolumn\fi
        \ifdefvoid\kvt@@curhd{}{\ifcsdef{kvt@@hdcelldone@\kvt@@curhd}{%
          \kvt at error{Header cell `\kvt@@curhd' must consist of only
             consecutive columns, but it is not}%
@@ -2323,7 +2523,7 @@
            specified in `\string\NewKeyValTable{#1}'}}{}}%
        \kvt@@span\@ne \let\kvt@@lasthd\kvt@@curhd}%
   }\dolistcsloop{kvt at displaycols@#1}%
-  \kvt at concludecolumn
+  \kvt at concludehdcolumn
 %    \end{macrocode}
 % Finally, conclude the whole header row and append the row to the
 % overall list of rows, stored in \cs{kvt@@custheadrows@\meta{tname}},
@@ -2341,11 +2541,34 @@
 % The |\kvt at rowcolorornot|\marg{color} expands to
 % |\rowcolor|\marg{color} if \meta{color} is nonempty and does have no
 % effect if \meta{color} is empty.
+% \begin{macro}{\kvt at rowcolorcmdornot}
+% The |\kvt at rowcolorcmdornot|\marg{cmd} expands to
+% |\rowcolor|\marg{color}, where \meta{color} is the (one-time)
+% expansion of \meta{cmd}, if \meta{cmd} is a defined macro whose
+% expansion is nonempty; its expansion is empty otherwise.
 %    \begin{macrocode}
 \newcommand\kvt at rowcolorornot[1]{\ifstrempty{#1}{}{\rowcolor{#1}}}
+\newcommand\kvt at rowcolorcmdornot[1]{\ifdefvoid{#1}{}{%
+  \expandafter\rowcolor\expandafter{#1}}}
 %    \end{macrocode}
 % \end{macro}
+% \end{macro}
 %
+% \begin{macro}{\kvt@@bodyrow}
+% The counter |\kvt@@bodyrow| is used internally in |KeyValTable|
+% environments for keeping track of rows for the background-coloring.
+% The difference between this counter and |\kvtRow| is that the former
+% also counts |uncounted| rows and is unaffected by the |resume| option.
+% The counter only counts rows produced by |\Row| and its corresponding
+% collecting counterparts. Header rows as well as manually inserted
+% rows, including those produced by macros like |\midrule| in a
+% |longtable| environment, are not counted (as opposed by the internal
+% counter of |\rowcolors|.
+%    \begin{macrocode}
+\newcount\kvt@@bodyrow
+%    \end{macrocode}
+% \end{macro}
+%
 % \begin{macro}{\kvt@@span}
 % The counter |\kvt@@span| is used temporarily in macros for counting
 % how many columns are spanned by column groups.
@@ -2354,18 +2577,19 @@
 %    \end{macrocode}
 % \end{macro}
 %
-% \begin{macro}{\kvt at concludecolumn}
-% The |\kvt at concludecolumn| macro appends a cell, potentially spanning
+% \begin{macro}{\kvt at concludehdcolumn}
+% The |\kvt at concludehdcolumn| macro appends a cell, potentially spanning
 % multiple columns, to the row under construction (which is in
 % |\kvt@@tmpgrphd|).
 %    \begin{macrocode}
-\newcommand\kvt at concludecolumn{%
+\newcommand\kvt at concludehdcolumn{%
   \kvt@@switchcol
   \ifdefvoid\kvt@@lasthd{}{%
     \eappto\kvt@@tmpgrphd{\noexpand\multicolumn
       {\the\kvt@@span}
       {\csexpandonce{kvt@@hdcell at align@\kvt@@lasthd}}
-      {\csexpandonce{kvt@@hdcell at head@\kvt@@lasthd}}}%
+      {\noexpand\cmdkvt at Table@headformat
+        {\csexpandonce{kvt@@hdcell at head@\kvt@@lasthd}}}}%
 %    \end{macrocode}
 % Mark the header cell as already used and concluded, such that another
 % use of the same header cell can be detected and raise an error.
@@ -2382,7 +2606,11 @@
 %    \begin{macrocode}
 \def\kvt at parsehdcolspec#1#2:#3:#4\@undefined{%
 %    \end{macrocode}
-% First link the individual columns of a header cell to the cell.
+% Catch syntax errors first.
+%    \begin{macrocode}
+  \kvt at checkcolspecempty{#4}{header cell}{#2}%
+%    \end{macrocode}
+% Next, link the individual columns of a header cell to the cell.
 % In this, ensure that no column is contained in more than one header
 % cell.
 %    \begin{macrocode}
@@ -2492,6 +2720,15 @@
 % \end{macro}
 %    \begin{macrocode}
   \kvt at SetOptions{#2}{#1}%
+%    \end{macrocode}
+% Save \meta{options} globally for a potential "|resume*|" option in the
+% immediately following |KeyValTable| environment.
+% If |resume*| is specified for the current environment, then the
+% previous options are not replaced. That is, |resume*| resumes the
+% options from the previous non-resuming environment.
+%    \begin{macrocode}
+  \ifbool{kvt at TableEnv@resume*}{}
+    {\gdef\kvt@@lastenvopt{#1}}%
   \csuse{kvt at StartTable@\cmdkvt at Table@shape}{#2}%
 }{%
   \csuse{kvt at EndTable@\cmdkvt at Table@shape}}
@@ -2503,225 +2740,19 @@
 % specific table options in the current environment, based on the
 % options for table type \meta{tname} and the specific \meta{options}.
 %    \begin{macrocode}
-\newcommand\kvt at SetOptions[2]{%
-  \begingroup\edef\kvt@@do{\endgroup\noexpand%
-    \kvt at setkeys{\csexpandonce{kvt at options@#1},\unexpanded{#2}}{Table}%
-  }\kvt@@do}
+\newcommand\kvt at SetOptions[2]{\expandafter
+  \kvt at SetOptions@i\expandafter{\csname kvt at options@#1\endcsname}{#2}}
 %    \end{macrocode}
-% \end{macro}
-%
-% \subsubsection{Table Environment Code}
-%
-% \begin{macro}{\kvt at StartTabularlike}
-% The
-% |\kvt at StartTabularlike|\marg{env}\marg{tname}
-% macro begins a table environment for the given table type \meta{tname}.
-% The \meta{env} parameter specifies the concrete environment name.
+% The auxiliary macro |\kvt at SetOptions@i|\marg{optcmd}\marg{options}
+% first sets the options in the expansion of \meta{optcmd} and then the
+% \meta{options}.
 %    \begin{macrocode}
-\newcommand\kvt at StartTabularlike[2]{%
+\newcommand\kvt at SetOptions@i[2]{\expandafter
+  \kvt at setkeys\expandafter{#1,#2}{Table,TableEnv}}
 %    \end{macrocode}
-% The |\kvt@@recenttable| allows the |\AfterEndEnvironment| hook for
-% |KeyValTable| to access the most recent table type.
-% \changes{v1.0}{2019/02/18}{Implemented \texttt{showrules} option}
-%    \begin{macrocode}
-  \gdef\kvt@@recenttable{#2}%
-  \metatblAtEnd{#1}{\kvt@@endhook}\let\kvt@@endhook\relax%
-  \ifbool{kvt at Table@showrules}
-    {\def\kvt@@rule##1{\csuse{##1rule}}}
-    {\def\kvt@@rule##1{}}%
-  \appto\kvt@@endhook{\kvt@@rule{bottom}}
-%    \end{macrocode}
-% The following saves the row counter value for the table type globally,
-% such that subsequent tables of the same \meta{tname} can start counting
-% from there.
-%    \begin{macrocode}
-  \appto\kvt@@endhook{%
-    \noalign{\csxdef{kvt at rowcount@#2}{\thekvtTypeRow}}}%
-%    \end{macrocode}
-% Adding caption and label, if given, to the end hook. This displays the
-% caption solely at the very end of the table.
-%    \begin{macrocode}
-  \ifdefempty\cmdkvt at Table@caption{}{%
-    \metatblHasCaption{#1}
-      {\appto\kvt@@endhook{\rowcolor{white}%
-        \caption{\cmdkvt at Table@caption}}%
-       \ifdefempty\cmdkvt at Table@label{}{%
-         \appto\kvt@@endhook{\expandafter%
-           \label\expandafter{\cmdkvt at Table@label}}}}
-      {\kvt at warn{Caption lost, table environment '#1'
-                 does not support captions.}}}%
-%    \end{macrocode}
-% The following lines perform some checks before the table environment
-% is started.
-%    \begin{macrocode}
-  \ifdefvoid{\cmdkvt at Table@valign}{}{\metatblCanVAlign{#1}{}
-    {\undef{\cmdkvt at Table@valign}%
-      \kvt at warn{Table environment '#1' of table '#2'
-        does not support the vertical alignment option (valign).
-        Ignoring the option}}}%
-  \ifdefvoid{\cmdkvt at Table@halign}{}{\metatblCanHAlign{#1}{}
-    {\undef{\cmdkvt at Table@halign}%
-      \kvt at warn{Table environment '#1' of table '#2'
-        does not support the horizontal alignment option (halign).
-        Ignoring the option}}}%
-%    \end{macrocode}
-% Initializing the row counters. The global counter |kvtTotalRow| needs
-% no local initialization.
-%    \begin{macrocode}
-  \setcounter{kvtRow}{0}%
-  \setcounter{kvtTypeRow}{\csuse{kvt at rowcount@#2}}%
-%    \end{macrocode}
-% In |\kvt@@do|, the start code for the environment, including the
-% header rows, is gathered, with expansion to fill in all the table
-% settings and options.
-% \changes{v0.3}{2016/06/05}{Added \texttt{showhead} option}
-% \changes{v1.0}{2019/03/09}{Added \texttt{width} option}
-% \changes{v2.1}{2020/01/19}{Added \texttt{valign} and \texttt{halign} options}
-%    \begin{macrocode}
-  \begingroup\edef\kvt@@do{\endgroup
-    \metatblIsTabu{#1}{}{\noexpand\kvt at dottedrowcolors
-      {\ifbool{kvt at Table@showhead}
-        {\the\numexpr\csuse{kvt at headrowcount@#2}+1\relax}
-        {1}}%
-      {\expandonce\cmdkvt at Table@rowbg}}%
-    \expandafter\noexpand\csname #1\endcsname
-%    \end{macrocode}
-% As background on the positions of the parameters below, here is the
-% syntax for beginning the supported environments:
-% \begin{itemize}[nosep]
-% \item|\begin{tabular}|\oarg{valign}\marg{preamble}
-% \item|\begin{tabularx}|\marg{width}\oarg{valign}\marg{preamble}
-% \item|\begin{longtable}|\oarg{halign}\marg{preamble}
-% \item|\begin{xltabular}|\oarg{halign}\marg{width}\marg{preamble}
-% \item|\begin{tabu}| to \meta{width}\oarg{valign}\marg{preamble}
-% \item|\begin{longtabu}| to \meta{width}\oarg{halign}\marg{preamble}
-% \end{itemize}
-% The above cases are covered in the following lines.
-%    \begin{macrocode}
-      \ifdefvoid{\cmdkvt at Table@halign}{}
-        {\metatblIsTabu{#1}{}{[\cmdkvt at Table@halign]}}%
-      \metatblHasWidth{#1}
-        {\metatblIsTabu{#1}
-          {to \expandonce\cmdkvt at Table@width}
-          {{\expandonce\cmdkvt at Table@width}}}
-        {}%
-      \ifdefvoid{\cmdkvt at Table@valign}{}{[\cmdkvt at Table@valign]}%
-      \ifdefvoid{\cmdkvt at Table@halign}{}
-        {\metatblIsTabu{#1}{[\cmdkvt at Table@halign]}{}}%
-      {\csexpandonce{kvt at alignments@#2}}%
-%    \end{macrocode}
-% The remainder below already starts the content of the table
-% environment.
-%    \begin{macrocode}
-    \noexpand\kvt@@rule{top}%
-    \ifbool{kvt at Table@showhead}
-      {\csuse{kvt at headings@#2}\noexpand\kvt@@rule{mid}}
-      {}%
-    \metatblIsTabu{#1}
-      {\noexpand\kvt at taburowcolors{\expandonce\cmdkvt at Table@rowbg}}{}%
-    \metatblIsLong{#1}{\noexpand\endhead}{}%
-  }\kvt@@do}
-%    \end{macrocode}
 % \end{macro}
 %
-% \begin{macro}{\kvt at dottedrowcolors}
-% The |\kvt at dottedrowcolors|\marg{start-row}\marg{colors} sets up row
-% colors using the |\rowcolors| macro of \pkgname{xcolor}.
-% The \marg{colors} parameter expects arguments of the form
-% "\meta{color1}|..|\meta{color2}" (the syntax used for the |rowbg|
-% option. The row colors then alternate between \meta{color1} and
-% \meta{color2}, starting with \meta{color1} in \meta{start-row}.
-% This macro substitutes |\taburowcolors| for non-\pkgname{tabu}
-% environments.
-% If \meta{colors} is empty, then no row colors are setup.
-%    \begin{macrocode}
-\newcommand\kvt at dottedrowcolors[2]{%
-  \ifstrempty{#2}{}{\kvt at dottedrowcolors@i{#1}#2\@nil}}
-\def\kvt at dottedrowcolors@i#1#2..#3\@nil{%
-%    \end{macrocode}
-% Since |\rowcolors| expects its color arguments to specify the odd and
-% even color, we swap arguments depending on the parity of
-% \meta{start-row} to ensure \meta{color1} is applied to
-% \meta{start-row}.
-%    \begin{macrocode}
-  \ifnumodd{#1}
-    {\rowcolors{#1}{#2}{#3}}
-    {\rowcolors{#1}{#3}{#2}}}
-%    \end{macrocode}
-% \end{macro}
 %
-% \begin{macro}{\kvt at taburowcolors}
-% The |\kvt at taburowcolors|\marg{colors} expands to
-% |\taburowcolors|\marg{colors} if \meta{colors} is nonempty and does
-% have no effect if \meta{color} is empty.
-%    \begin{macrocode}
-\newcommand\kvt at taburowcolors[1]{%
-  \ifstrempty{#1}{}{\taburowcolors{#1}}}
-%    \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}{\kvt at DefineStdTabEnv}
-% The |\kvt at DefineStdTabEnv|\oarg{shape}\marg{env}
-% macro defines the macros needed for the given \meta{shape} value.
-% If \meta{shape} is omitted, \meta{env} (the name of the environment to
-% use for the shape) is used as \meta{shape} value.
-%
-% Note: In the future, the macro could automatically add \meta{option}
-% to the list of possible values for the |shape| option.
-%    \begin{macrocode}
-\newcommand\kvt at DefineStdTabEnv{\@dblarg\kvt at DefineStdTabEnv@i}
-\newcommand\kvt at DefineStdTabEnv@i[2][]{%
-  \expandafter\newcommand\csname kvt at StartTable@#1\endcsname[1]{%
-    \kvt at StartTabularlike{#2}{##1}}%
-  \csedef{kvt at EndTable@#1}{%
-    \expandafter\noexpand\csname end#2\endcsname}}
-%    \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}{\kvt at DefineDualTabEnv}
-% The |\kvt at DefineDualTabEnv|\marg{shape}\marg{nonX-env}\marg{X-env}
-% macro defines the macros for the given \meta{shape} name.
-% The macros are defined in a way such that the table environment
-% \meta{nonX-env} is used for typesetting tables that do not use |X|
-% columns and that table environment \meta{X-env} is used for
-% typesetting tables that do use |X| columns.
-%    \begin{macrocode}
-\newcommand\kvt at DefineDualTabEnv[3]{%
-  \expandafter\newcommand\csname kvt at StartTable@#1\endcsname[1]{%
-    \kvt at ifhasXcolumns{##1}
-      {\csedef{kvt at EndTable@#1}{%
-         \expandafter\noexpand\csname end#3\endcsname}%
-       \kvt at StartTabularlike{#3}{##1}%
-      }{\csedef{kvt at EndTable@#1}{%
-         \expandafter\noexpand\csname end#2\endcsname}%
-       \kvt at StartTabularlike{#2}{##1}}}}
-%    \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}{\kvt at ifhasXcolumns}
-% The |\kvt at ifhasXcolumns|\marg{tname}\marg{iftrue}\marg{iffalse}
-% takes a table type \meta{tname} and checks whether the table type
-% contains an "|X|" column. If such a column is contained, the macro
-% expands to \meta{iftrue}. Otherwise, it expands to \meta{iffalse}.
-%    \begin{macrocode}
-\newcommand\kvt at ifhasXcolumns[1]{%
-  \expandafter\expandafter\expandafter\metatbl at ifhasXcolumns
-  \expandafter\expandafter\expandafter{%
-    \csname kvt at alignments@#1\endcsname}}
-%    \end{macrocode}
-% \end{macro}
-%
-% The following lines define the macros for the various table shapes /
-% environments.
-%    \begin{macrocode}
-\kvt at DefineStdTabEnv{tabular}
-\kvt at DefineStdTabEnv{longtable}
-\kvt at DefineStdTabEnv{tabularx}
-\kvt at DefineStdTabEnv{xltabular}
-\kvt at DefineStdTabEnv{tabu}
-\kvt at DefineStdTabEnv{longtabu}
-%    \end{macrocode}
-%
 % \subsubsection{Table Environment Properties}
 %
 % The following code maintains properties about known table
@@ -2759,6 +2790,7 @@
 %    \begin{macrocode}
 \newrobustcmd\metatblRegisterEnv[2]{%
   \edef\metatbl@@envname{#1}%
+  \csdef{metatbl@@registered@#1}{true}%
   \setkeys[metatbl]{EnvProp}{#2}}
 %    \end{macrocode}
 % \end{macro}
@@ -2786,6 +2818,7 @@
 %    \end{macrocode}
 % \end{macro}
 %
+% \begin{macro}{\metatblRegistered}
 % \begin{macro}{\metatblIsLong}
 % \begin{macro}{\metatblIsTabu}
 % \begin{macro}{\metatblHasWidth}
@@ -2792,23 +2825,17 @@
 % \begin{macro}{\metatblHasCaption}
 % \begin{macro}{\metatblCanVAlign}
 % \begin{macro}{\metatblCanHAlign}
+% All macros in the following block expect three arguments,
+%   \marg{env-name}\marg{iftrue}\marg{iffalse}.
 % The macro
-% |\metatblIsLong|\marg{env-name}\marg{iftrue}\marg{iffalse}
-% expands to \meta{iftrue} if \meta{env-name} is a "long" table
-% environment, i.e., one that can span multiple pages. Otherwise, the
-% macro expands to \meta{iffalse}.
-% The macro
-% |\metatblIsTabu|\marg{env-name}\marg{iftrue}\marg{iffalse}
-% expands to \meta{iftrue} if \meta{env-name} is a table environment
-% that inherits from |tabu| and expands to \meta{iffalse} otherwise.
-% The macro
-% |\metatblHasWidth|\marg{env-name}\marg{iftrue}\marg{iffalse}
-% expands to \meta{iftrue} if \meta{env-name} is a table environment
-% that expects a width argument and expands to \meta{iffalse} otherwise.
-% |\metatblHasCaption|\marg{env-name}\marg{iftrue}\marg{iffalse}
-% expands to \meta{iftrue} if \meta{env-name} is a table environment
-% that supports a caption and expands to \meta{iffalse} otherwise.
+% |\metatblRegistered|
+% expands to \meta{iftrue} if \meta{env-name} has been registered via
+% |\metatblRegisterEnv| and expands to \meta{iffalse} otherwise.
+% The remaining macros expand to \meta{iftrue}, if the respective
+% property has been set to |true| in when \meta{env-name} was registered
+% via |\metatblRegisterEnv|, and expand to \meta{iffalse} otherwise.
 %    \begin{macrocode}
+\newcommand\metatblRegistered[1]{\ifcsdef{metatbl@@registered@#1}}
 \newcommand\metatblIsLong[1]{\ifbool{metatbl at EnvProp@isLong@#1}}
 \newcommand\metatblIsTabu[1]{\ifbool{metatbl at EnvProp@isTabu@#1}}
 \newcommand\metatblHasWidth[1]{\ifbool{metatbl at EnvProp@hasWidth@#1}}
@@ -2822,6 +2849,7 @@
 % \end{macro}
 % \end{macro}
 % \end{macro}
+% \end{macro}
 %
 % \begin{macro}{\metatblUsePackage}
 % \begin{macro}{\metatblRequire}
@@ -2849,7 +2877,7 @@
 % \meta{code} for addition at the end of tables based on the
 % \meta{env-name} environment.
 %    \begin{macrocode}
-\newcommand\metatblAtEnd[2]{% #1=env-name, #2=code
+\newcommand\metatblAtEnd[2]{%
   \csname metatbl at EnvProp@atEnd@#1\endcsname{#2}}
 %    \end{macrocode}
 % \end{macro}
@@ -2956,6 +2984,305 @@
 % \end{macro}
 %
 %
+% \subsubsection{Table Environment Code}
+%
+% \begin{macro}{\kvt at StartTabularlike}
+% The
+% |\kvt at StartTabularlike|\marg{env}\marg{tname}
+% macro begins a table environment for the given table type \meta{tname}.
+% The \meta{env} parameter specifies the concrete environment name.
+%    \begin{macrocode}
+\newcommand\kvt at StartTabularlike[2]{%
+%    \end{macrocode}
+% \changes{v1.0}{2019/02/18}{Implemented \texttt{showrules} option}
+%    \begin{macrocode}
+  \metatblAtEnd{#1}{\kvt@@endhook}%
+  \let\kvt@@endhook\@empty
+  \let\kvt@@prehook\@empty
+  \ifbool{kvt at Table@showrules}
+    {\def\kvt@@rule##1{\csuse{##1rule}}}
+    {\def\kvt@@rule##1{}}%
+  \appto\kvt@@prehook{\kvt@@rule{top}}%
+  \appto\kvt@@endhook{\kvt@@rule{bottom}}%
+%    \end{macrocode}
+% The following saves the row counter value for the table type globally,
+% such that subsequent tables of the same \meta{tname} can start counting
+% from there. Moreover, it save the local row counter for the case that
+% the next table uses the "|resume|" option.
+%    \begin{macrocode}
+  \appto\kvt@@endhook{\noalign{%
+    \csxdef{kvt at rowcount@#2}{\thekvtTypeRow}%
+    \csxdef{kvt@@rowcountlast}{\thekvtRow}}}%
+%    \end{macrocode}
+% Adding caption and label.
+%    \begin{macrocode}
+  \ifdefvoid\cmdkvt at TableEnv@caption
+    {\let\kvt@@caption at main\@empty
+     \let\kvt@@caption at alt\@empty}
+    {\metatblHasCaption{#1}
+       {\edef\kvt@@caption at main{%
+         \csexpandonce{kvt at caption@\cmdkvt at Table@captionpos}%
+           \ifcsvoid{cmdkvt at TableEnv@caption/lot}{}
+             {[{\csexpandonce{cmdkvt at TableEnv@caption/lot}}]}%
+           {\expandonce\cmdkvt at TableEnv@caption
+              \ifdefvoid\cmdkvt at TableEnv@label{}{%
+                \noexpand\label{\expandonce\cmdkvt at TableEnv@label}}}%
+         \noexpand\\}%
+        \ifcsvoid{cmdkvt at TableEnv@caption/alt}
+          {\def\kvt@@caption at alt{}}
+          {\edef\kvt@@caption at alt{%
+            \csexpandonce{kvt at caption@\cmdkvt at Table@captionpos}[]%
+              {\csexpandonce{cmdkvt at TableEnv@caption/alt}}%
+            \noexpand\\}}%
+       }{\kvt at error
+         {Caption lost, table backend '#1' does not support captions}
+         {Consider placing the KeyValTable environment inside a 'table'
+          environment and use the \string\caption\space macro inside.}}}%
+  \ifdefstring{\cmdkvt at Table@captionpos}{t}
+    {\let\kvt@@caption at headmain\kvt@@caption at main\let\kvt@@caption at footmain\@empty
+     \let\kvt@@caption at headalt\kvt@@caption at alt  \let\kvt@@caption at footalt\@empty}
+    {\let\kvt@@caption at footmain\kvt@@caption at main\let\kvt@@caption at headmain\@empty
+     \let\kvt@@caption at footalt\kvt@@caption at alt  \let\kvt@@caption at headalt\@empty}%
+  \ifbool{kvt at Table@showhead}
+    {\eappto\kvt@@prehook{\csuse{kvt at headings@#2}\noexpand\kvt@@rule{mid}}}
+    {}%
+%    \end{macrocode}
+% The following lines perform some checks before the table environment
+% is started.
+%    \begin{macrocode}
+  \ifdefvoid{\cmdkvt at Table@valign}{}{\metatblCanVAlign{#1}{}
+    {\undef{\cmdkvt at Table@valign}%
+      \kvt at warn{Table environment '#1' of table '#2'
+        does not support the vertical alignment option (valign).
+        Ignoring the option}}}%
+  \ifdefvoid{\cmdkvt at Table@halign}{}{\metatblCanHAlign{#1}{}
+    {\undef{\cmdkvt at Table@halign}%
+      \kvt at warn{Table environment '#1' of table '#2'
+        does not support the horizontal alignment option (halign).
+        Ignoring the option}}}%
+%    \end{macrocode}
+% Initializing the row counters. The global counter |kvtTotalRow| needs
+% no local initialization.
+%    \begin{macrocode}
+  \global\kvt@@bodyrow=0\relax
+  \ifbool{kvt at TableEnv@resume}
+    {\setcounter{kvtRow}{\csuse{kvt@@rowcountlast}}}
+    {\setcounter{kvtRow}{0}}%
+  \setcounter{kvtTypeRow}{\csuse{kvt at rowcount@#2}}%
+%    \end{macrocode}
+% Initialize the background colors for the body rows.
+%    \begin{macrocode}
+  \expandafter\kvt at setrowcolors\expandafter{\cmdkvt at Table@rowbg}%
+%    \end{macrocode}
+% In |\kvt@@do|, the start code for the environment, including the
+% header rows, is gathered, with expansion to fill in all the table
+% settings and options.
+% \changes{v0.3}{2016/06/05}{Added \texttt{showhead} option}
+% \changes{v1.0}{2019/03/09}{Added \texttt{width} option}
+% \changes{v2.1}{2020/01/19}{Added \texttt{valign} and \texttt{halign} options}
+%    \begin{macrocode}
+  \begingroup\edef\kvt@@do{\endgroup
+    \expandafter\noexpand\csname #1\endcsname
+%    \end{macrocode}
+% As background on the positions of the parameters below, here is the
+% syntax for beginning the supported environments:
+% \begin{itemize}[nosep]
+% \item|\begin{tabular}|\oarg{valign}\marg{preamble}
+% \item|\begin{tabularx}|\marg{width}\oarg{valign}\marg{preamble}
+% \item|\begin{longtable}|\oarg{halign}\marg{preamble}
+% \item|\begin{xltabular}|\oarg{halign}\marg{width}\marg{preamble}
+% \item|\begin{tabu}| to \meta{width}\oarg{valign}\marg{preamble}
+% \item|\begin{longtabu}| to \meta{width}\oarg{halign}\marg{preamble}
+% \end{itemize}
+% The above cases are covered in the following lines.
+%    \begin{macrocode}
+      \ifdefvoid{\cmdkvt at Table@halign}{}
+        {\metatblIsTabu{#1}{}{[\cmdkvt at Table@halign]}}%
+      \metatblHasWidth{#1}
+        {\metatblIsTabu{#1}
+          {to \expandonce\cmdkvt at Table@width}
+          {{\expandonce\cmdkvt at Table@width}}}
+        {}%
+      \ifdefvoid{\cmdkvt at Table@valign}{}{[\cmdkvt at Table@valign]}%
+      \ifdefvoid{\cmdkvt at Table@halign}{}
+        {\metatblIsTabu{#1}{[\cmdkvt at Table@halign]}{}}%
+      {\csexpandonce{kvt at alignments@#2}}%
+%    \end{macrocode}
+% The remainder below already starts the content of the table
+% environment. It also sets the header and footer for multipage tables.
+%    \begin{macrocode}
+    \expandonce\kvt@@caption at headmain
+    \expandonce\kvt@@prehook
+    \metatblIsLong{#1}{%
+      \noexpand\endfirsthead
+      \expandonce\kvt@@caption at headalt
+      \expandonce\kvt@@prehook
+      \noexpand\endhead}{}%
+    \expandonce\kvt@@caption at footmain
+    \metatblIsLong{#1}{%
+      \noexpand\endlastfoot
+      \expandonce\kvt@@caption at footalt
+      \noexpand\endfoot}{}%
+  }\kvt@@do}
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\kvt at caption@b}
+% \begin{macro}{\kvt at caption@t}
+% The |\kvt at caption@b| and |\kvt at caption@t| macros behave like
+% |\caption| but add extra behavior depending on whether the caption is
+% displayed above (|\kvt at caption@t|) or below (|\kvt at caption@b|) the
+% table. Currently, |\kvt at caption@b| only fixes the spacing between the
+% table and the caption.
+%    \begin{macrocode}
+\newcommand\kvt at caption@t{\caption}
+\newcommand\kvt at caption@b{%
+%    \end{macrocode}
+% Fixme: The following |\baselineskip| before the caption compensates
+% that \pkgname{longtable} adds a |\baselineskip| below the caption (in
+% its macro |\LT at makecaption|) but not above. The \pkgname{ltcaption}
+% package replaces the hard-coded |\baselineskip| by |\LTcapskip| but
+% also only puts it below the caption. The code below could at least be
+% improved to use |\LTcapskip| if it is available.
+%    \begin{macrocode}
+  \noalign{\parbox{0pt}{\vskip\baselineskip}}%
+  \caption}
+%    \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\kvt at setrowcolors}
+% The |\kvt at setrowcolors|\marg{colors} sets up row
+% colors using the |\rowcolors| macro of \pkgname{xcolor}.
+% The \marg{colors} parameter expects arguments of the form
+% "\meta{color1}|..|\meta{color2}" (the syntax used for the |rowbg|
+% option. The row colors then alternate between \meta{color1} and
+% \meta{color2}, starting with \meta{color1} in the first row.
+% If \meta{colors} is empty, then no row colors are setup.
+%    \begin{macrocode}
+\newcommand\kvt at setrowcolors[1]{%
+  \ifstrempty{#1}{}{\kvt at setrowcolors@i#1\@nil}}
+\def\kvt at setrowcolors@i#1..#2\@nil{%
+  \def\kvt@@bgcolor at odd{#1}%
+  \def\kvt@@bgcolor at even{#2}}
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\kvt at userowcolors}
+% The |\kvt at userowcolors| macro macro expands to
+% |\rowcolor|\marg{color}, where \meta{color} is the background color
+% set via |\kvt at setrowcolors| for odd, respectively even rows, based on
+% |\kvt@@bodyrow|.
+%    \begin{macrocode}
+\newcommand\kvt at userowcolors{\ifnumodd{\the\kvt@@bodyrow}
+  {\kvt at rowcolorcmdornot{\kvt@@bgcolor at odd}}
+  {\kvt at rowcolorcmdornot{\kvt@@bgcolor at even}}}
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\kvt at RegisterBackend}
+% \begin{macro}{\kvt at RegisterShape}
+% The |\kvt at RegisterBackend|\marg{env} macro registers the table
+% environment \meta{env} as a table backend for use by \thispackage.
+% The |\kvt at RegisterShape|\marg{name}\marg{nonX-env}\marg{X-env}
+% registers a shape with the given \meta{name} and associates it with
+% the environment \meta{nonX-env} when the shape is used for a table
+% without |X| columns and with environment \meta{X-env} otherwise.
+%    \begin{macrocode}
+\newcommand\kvt at RegisterBackend[1]{%
+  \ifinlist{#1}{\kvt@@tablebackends}
+    {\kvt at error{Backend '#1' already registered}
+       {Internal error. Check use of \string\kvt at RegisterBackend.}}
+    {\kvt at CheckMetatblEnv{#1}%
+     \listadd{\kvt@@tablebackends}{#1}%
+     \kvt at DefineStdTabEnv{#1}{#1}}}
+\newcommand\kvt at RegisterShape[3]{%
+  \ifinlist{#1}{\kvt@@tableshapes}
+    {\kvt at error{Shape '#1' already registered}
+       {Internal error. Check use of \string\kvt at RegisterShape.}}
+    {\kvt at CheckMetatblEnv{#2}\kvt at CheckMetatblEnv{#3}%
+    \listadd{\kvt@@tableshapes}{#1}%
+     \ifstrequal{#2}{#3}
+       {\kvt at DefineStdTabEnv{#1}{#2}}
+       {\kvt at DefineDualTabEnv{#1}{#2}{#3}}}}
+\newcommand\kvt at CheckMetatblEnv[1]{\metatblRegistered{#1}{}
+   {\kvt at error{Environment '#1' not supported by keyvaltable}
+      {Check \string\metatblRegisterEnv\space for how to make it
+       supported.}}}
+%    \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \begin{macro}{\kvt at RegisterBackend}
+% \begin{macro}{\kvt at RegisterShape}
+% The macros |\kvt@@tablebackends| and |\kvt@@tableshapes| hold
+% \pkgname{etoolbox} lists of registered names of table backends and
+% table shapes.
+%    \begin{macrocode}
+\newcommand\kvt@@tablebackends{}
+\newcommand\kvt@@tableshapes{}
+%    \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\kvt at DefineStdTabEnv}
+% The |\kvt at DefineStdTabEnv|\marg{shape}\marg{env}
+% macro defines the macros needed for the given \meta{shape} value.
+% If \meta{shape} is omitted, \meta{env} (the name of the environment to
+% use for the shape) is used as \meta{shape} value.
+%    \begin{macrocode}
+\newcommand\kvt at DefineStdTabEnv[2]{%
+  \csdef{kvt at StartTable@#1}##1{%
+    \kvt at StartTabularlike{#2}{##1}}%
+  \csedef{kvt at EndTable@#1}{%
+    \expandafter\noexpand\csname end#2\endcsname}}
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\kvt at DefineDualTabEnv}
+% The |\kvt at DefineDualTabEnv|\marg{shape}\marg{nonX-env}\marg{X-env}
+% macro defines the macros for the given \meta{shape} name.
+% The macros are defined in a way such that the table environment
+% \meta{nonX-env} is used for typesetting tables that do not use |X|
+% columns and that table environment \meta{X-env} is used for
+% typesetting tables that do use |X| columns.
+%    \begin{macrocode}
+\newcommand\kvt at DefineDualTabEnv[3]{%
+  \expandafter\newcommand\csname kvt at StartTable@#1\endcsname[1]{%
+    \kvt at ifhasXcolumns{##1}
+      {\csedef{kvt at EndTable@#1}{%
+         \expandafter\noexpand\csname end#3\endcsname}%
+       \kvt at StartTabularlike{#3}{##1}%
+      }{\csedef{kvt at EndTable@#1}{%
+         \expandafter\noexpand\csname end#2\endcsname}%
+       \kvt at StartTabularlike{#2}{##1}}}}
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\kvt at ifhasXcolumns}
+% The |\kvt at ifhasXcolumns|\marg{tname}\marg{iftrue}\marg{iffalse}
+% takes a table type \meta{tname} and checks whether the table type
+% contains an "|X|" column. If such a column is contained, the macro
+% expands to \meta{iftrue}. Otherwise, it expands to \meta{iffalse}.
+%    \begin{macrocode}
+\newcommand\kvt at ifhasXcolumns[1]{%
+  \expandafter\expandafter\expandafter\metatbl at ifhasXcolumns
+  \expandafter\expandafter\expandafter{%
+    \csname kvt at alignments@#1\endcsname}}
+%    \end{macrocode}
+% \end{macro}
+%
+% The following lines define the macros for the various table 
+% environments.
+%    \begin{macrocode}
+\kvt at RegisterBackend{tabular}
+\kvt at RegisterBackend{longtable}
+\kvt at RegisterBackend{tabularx}
+\kvt at RegisterBackend{xltabular}
+\kvt at RegisterBackend{tabu}
+\kvt at RegisterBackend{longtabu}
+%    \end{macrocode}
+%
+%
 % \subsubsection{Environment-Independent Parts}
 %
 % \begin{macro}{\kvt at AddKeyValRow}
@@ -3012,10 +3339,12 @@
   \ifdefvoid\cmdkvt at Row@above{}{%
     \eappto\kvt@@row{\noexpand\noalign{\noexpand\vspace{%
       \expandonce\cmdkvt at Row@above}}}}%
-  \ifdefvoid\cmdkvt at Row@bg{}{%
-    \eappto\kvt@@row{\noexpand\rowcolor{\expandonce\cmdkvt at Row@bg}}}%
+  \appto\kvt@@row{\noalign{\global\advance\kvt@@bodyrow\@ne}}%
   \ifbool{kvt at Row@uncounted}{}{%
     \appto\kvt@@row{\noalign{\kvt at stepcounters}}}%
+  \ifdefvoid\cmdkvt at Row@bg
+    {\appto\kvt@@row{\kvt at userowcolors}}
+    {\eappto\kvt@@row{\noexpand\rowcolor{\expandonce\cmdkvt at Row@bg}}}%
 %    \end{macrocode}
 % If a row alignment is specified, a default |\multicolumn| display is
 % enabled for the row's cells.
@@ -3272,55 +3601,112 @@
 %    \end{macrocode}
 % \end{macro}
 %
-% \subsubsection{Row Styles}
+% \subsubsection{Table and Row Styles}
 %
+% The following are the user macros.
+%
 % \begin{macro}{\kvtNewRowStyle}
+% \changes{v2.0}{2019/03/25}{Added the macro}
+% \begin{macro}{\kvtRenewRowStyle}
+% \changes{v2.0}{2019/03/25}{Added the macro}
 % The |\kvtNewRowStyle|\marg{name}\marg{row-options} macro declares
 % \meta{name} as a row style and defines it to be equivalent to
 % specifying \meta{row-options} directly in the optional argument of
 % |\Row|. The macro fails if \meta{name} is already declared as a row
 % style.
-% \changes{v2.0}{2019/03/25}{Added the macro}
+% The |\kvtRenewRowStyle|\marg{name}\marg{row-options} macro re-defines
+% an already existing row style with new \meta{row-options}.
 %    \begin{macrocode}
-\newcommand\kvtNewRowStyle[2]{%
-  \ifcsundef{kvt@@rowstyle@#1}
-    {\csdef{kvt@@rowstyle@#1}{#2}}
-    {\kvt at error{Row style '#1' is already defined}{Use
-      \string\kvtRenewRowStyle\space to change an existing style.}}}
+\newcommand\kvtNewRowStyle{\kvt at NewStyle{row}{\kvtRenewRowStyle}}
+\newcommand\kvtRenewRowStyle{\kvt at RenewStyle{row}{\kvtNewRowStyle}}
 %    \end{macrocode}
 % \end{macro}
+% \end{macro}
 %
-% \begin{macro}{\kvtRenewRowStyle}
-% The |\kvtRenewRowStyle|\marg{name}\marg{row-options} macro re-defines
-% an already existing row style with new \meta{row-options}.
-% \changes{v2.0}{2019/03/25}{Added the macro}
+% \begin{macro}{\kvtNewTableStyle}
+% \changes{v2.2}{2020/02/24}{Added the macro}
+% \begin{macro}{\kvtRenewTableStyle}
+% \changes{v2.2}{2020/02/24}{Added the macro}
+% The |\kvtNewTableStyle|\marg{name}\marg{options} macro declares
+% \meta{name} as a table style and defines it to be equivalent to
+% specifying \meta{options} directly in the optional argument of
+% a |KeyValTable| environment or of a |\NewKeyValTable|. The macro fails
+% if \meta{name} is already declared as a table style.
+% The |\kvtRenewTableStyle|\marg{name}\marg{options} macro re-defines
+% an already existing table style with new \meta{options}.
 %    \begin{macrocode}
-\newcommand\kvtRenewRowStyle[2]{%
-  \ifcsundef{kvt@@rowstyle@#1}
-    {\kvt at error{Row style '#1' is not defined}
-      {Use \string\kvtNewRowStyle\space to define a new row style.}}
-    {\csdef{kvt@@rowstyle@#1}{#2}}}
+\newcommand\kvtNewTableStyle{\kvt at NewStyle{table}{\kvtRenewTableStyle}}
+\newcommand\kvtRenewTableStyle{\kvt at RenewStyle{table}{\kvtNewTableStyle}}
 %    \end{macrocode}
 % \end{macro}
+% \end{macro}
 %
-% \begin{macro}{\kvt at UseRowStyle}
-% The |\kvt at UseRowStyle|\marg{style} macro sets the row keys based on
-% the \meta{row-options} stored for the given \meta{style}.
+% The following are the internal macros that the style code shares.
+%
+% \begin{macro}{\kvt at NewStyle}
+% \begin{macro}{\kvt at RenewStyle}
+% The |\kvt at NewStyle|\marg{type}\marg{renewcmd}\marg{name}\marg{options}
+% macro defines a new style, \meta{name}, for \meta{type} (|table| or
+% |row|) to correspond to \meta{options}.
+% Analogously,
+% |\kvt at RenewStyle|\marg{type}\marg{newcmd}\marg{name}\marg{options}
+% macro re-defines a style.
 %    \begin{macrocode}
-\newcommand\kvt at UseRowStyle[1]{%
-  \ifcsundef{kvt@@rowstyle@#1}
-    {\kvt at error{Row style '#1' is not defined}
-      {Use \string\kvtNewRowStyle\space to define a new row style.}}
-    {\kvt at setcskeys{kvt@@rowstyle@#1}{Row}}}
+\newcommand\kvt at NewStyle[4]{%
+  \ifcsundef{kvt@@#1style@#3}
+    {\csdef{kvt@@#1style@#3}{#4}}
+    {\kvt at error{The #1 style '#3' is already defined}{Use
+      \string#2\space to change an existing style.}}}
+\newcommand\kvt at RenewStyle[4]{%
+  \ifcsundef{kvt@@#1style@#3}
+    {\kvt at error{A #1 style '#3' is not defined}
+      {Use \string#2\space to define a new #1 style.}}
+    {\csdef{kvt@@#1style@#3}{#4}}}
 %    \end{macrocode}
 % \end{macro}
+% \end{macro}
+%
 % \begin{macro}{\kvt at UseRowStyles}
-% The |\kvt at UseRowStyle|\marg{styles} macro sets the row keys based on
-% the \meta{row-options} for all styles in the comma-separated list
-% \meta{styles}.
+% \begin{macro}{\kvt at UseTableStyles}
+% \changes{v2.2}{2020/02/24}{Added the macro}
+% The |\kvt at UseRowStyles|\marg{styles} and
+% |\kvt at UseTableStyles|\marg{styles} macros set the keys for the given,
+% comma-separated list of \meta{styles}.
 %    \begin{macrocode}
 \newcommand\kvt at UseRowStyles[1]{%
+  \kvt at UseStyles{row}{Row}{\kvt at NewRowStyle}{#1}}
+\newcommand\kvt at UseTableStyles[1]{%
+  \kvt at UseStyles{table}{Table}{\kvt at NewTableStyle}{#1}}
 %    \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\kvt at UseStyle}
+% The |\kvt at UseStyle|\marg{type}\marg{fam}\marg{newcmd}\marg{style}
+% macro sets the keys for type \meta{type} based on the \meta{options}
+% stored for the given \meta{style}.
+% The \meta{fam} identifies the
+% \pkgname{xkeyval} family for \meta{type} and \meta{newcmd} is the
+% macro for defining new \meta{type} styles.
+%    \begin{macrocode}
+\newcommand\kvt at UseStyle[4]{%
+  \ifcsundef{kvt@@#1style@#4}
+    {\kvt at error{A #1 style '#4' is not defined}
+      {Use \string#3\space to define a new #1 style.}}
+    {\kvt at setcskeys{kvt@@#1style@#4}{#2}}}
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\kvt at UseStyles}
+% The |\kvt at UseStyles|\marg{type}\marg{fam}\marg{newcmd}\marg{styles}
+% macro sets the \meta{type} keys based on the \meta{options} for all
+% styles in the comma-separated list \meta{styles}.
+% The \meta{fam} identifies the
+% \pkgname{xkeyval} family for \meta{type} and \meta{newcmd} is the
+% macro for defining new \meta{type} styles.
+%    \begin{macrocode}
+\newcommand\kvt at UseStyles[4]{%
+%    \end{macrocode}
 % We use |\kvt at xkv@disablepreset| to eliminate undesired effects that
 % would otherwise be caused by preset values for keys.
 % For an example of such side-effect, consider a style "|vis|" that is
@@ -3334,8 +3720,8 @@
 % |\setkeys| would then again employ the presets for |Row| (e.g., from a
 % |\kvtSet{Row/bg=blue}|) and undesirably overwrite the |bg=red|.
 %    \begin{macrocode}
-  \kvt at xkv@disablepreset[kvt]{Row}{%
-    \forcsvlist\kvt at UseRowStyle{#1}}}
+  \kvt at xkv@disablepreset[kvt]{#2}{%
+    \forcsvlist{\kvt at UseStyle{#1}{#2}{#3}}{#4}}}
 %    \end{macrocode}
 % \end{macro}
 %
@@ -3737,12 +4123,12 @@
 %    \begin{macrocode}
 \kvt at IfVersion{<}{2.0}{%
   \metatblRequire{tabu,longtabu}
-  \kvt at DefineStdTabEnv[onepage]{tabu}
-  \kvt at DefineStdTabEnv[multipage]{longtabu}
+  \kvt at RegisterShape{onepage}{tabu}{tabu}
+  \kvt at RegisterShape{multipage}{longtabu}{longtabu}
 }{%
   \metatblRequire{tabularx,longtable,xltabular}
-  \kvt at DefineDualTabEnv{onepage}{tabular}{tabularx}
-  \kvt at DefineDualTabEnv{multipage}{longtable}{xltabular}
+  \kvt at RegisterShape{onepage}{tabular}{tabularx}
+  \kvt at RegisterShape{multipage}{longtable}{xltabular}
 }
 %    \end{macrocode}
 %

Modified: trunk/Master/texmf-dist/tex/latex/keyvaltable/keyvaltable.sty
===================================================================
--- trunk/Master/texmf-dist/tex/latex/keyvaltable/keyvaltable.sty	2020-04-11 22:49:53 UTC (rev 54676)
+++ trunk/Master/texmf-dist/tex/latex/keyvaltable/keyvaltable.sty	2020-04-11 22:50:13 UTC (rev 54677)
@@ -20,7 +20,8 @@
 %% 
 \NeedsTeXFormat{LaTeX2e}[1999/12/01]
 \ProvidesPackage{keyvaltable}
-    [2020/02/19 v2.1 Package for filling tables using key-value lists]
+    [2020/04/05 v2.2 Package for filling tables using key-value lists]
+
 \RequirePackage{etoolbox}
 \RequirePackage{xkeyval}
 \RequirePackage{trimspaces}
@@ -27,9 +28,23 @@
 \PassOptionsToPackage{table}{xcolor}
 \RequirePackage{xcolor}
 \RequirePackage{booktabs}
+\newcommand\kvt at DeclareTrimListParser{%
+  \@ifstar{\kvt at DeclareTrimListParser@i{*}}
+          {\kvt at DeclareTrimListParser@i{}}}
+\newcommand\kvt at DeclareTrimListParser@i[3]{%
+  \DeclareListParser#1{#2}{#3}\expandafter
+  \patchcmd\csname etb at lst@\expandafter\@gobble\string#2\endcsname
+    {\etb at listitem}{\kvt at etb@listitem}{}
+    {\kvt at warn{Failed to patch a command defined by the etoolbox
+      package, possibly because etoolbox internals have changed.
+      You might encounter superfluous spaces.}}}
+\newcommand\kvt at etb@listitem[2]{%
+  \expandafter\expandafter\expandafter\kvt at etb@listitem at i
+  \expandafter\expandafter\expandafter{\trim at post@space at noexp{#2}}{#1}}
+\newcommand\kvt at etb@listitem at i[2]{\etb at listitem{#2}{#1}}
 \DeclareListParser{\kvt at dossvlist}{;}
-\DeclareListParser*{\kvt at forpsvlist}{+}
-\DeclareListParser{\kvt at dobrklist}{\\}
+\kvt at DeclareTrimListParser*{\kvt at forpsvlist}{+}
+\kvt at DeclareTrimListParser{\kvt at dobrklist}{\\}
 \newcommand\kvt at error[2]{\PackageError{keyvaltable}{#1}{#2}}
 \newcommand\kvt at warn[1]{\PackageWarning{keyvaltable}{#1}}
 \newcommand\kvt at setkeys[2]{\setkeys[kvt]{#2}{#1}}
@@ -64,12 +79,13 @@
 \define at cmdkey[kvt]{Table}{width}{}
 \define at boolkey[kvt]{Table}{showhead}{}
 \define at boolkey[kvt]{Table}{showrules}{}
-\define at cmdkey[kvt]{Table}{caption}{}
-\define at cmdkey[kvt]{Table}{label}{}
+\define at choicekey[kvt]{Table}{captionpos}{t,b}
+  {\csdef{cmdkvt at Table@captionpos}{#1}}
 \define at choicekey[kvt]{Table}{valign}{t,c,b}
   {\csdef{cmdkvt at Table@valign}{#1}}
 \define at choicekey[kvt]{Table}{halign}{l,c,r}
   {\csdef{cmdkvt at Table@halign}{#1}}
+\define at key[kvt]{Table}{style}{\kvt at UseTableStyles{#1}}
 \define at boolkey[kvt]{Table}{norowbg}[true]{%
   \kvt at setkeys{rowbg={}}{Table}}
 \define at boolkey[kvt]{Table}{nobg}[true]{%
@@ -78,9 +94,36 @@
   \ifbool{#1}
     {\kvt at setkeys{showrules=false}{Table}}
     {\kvt at setkeys{showrules=true}{Table}}}
-\define at choicekey[kvt]{Table}{shape}
-  {multipage,onepage,tabular,longtable,tabularx,xltabular,tabu,longtabu}
+\define at key[kvt]{Table}{backend}{\ifinlist{#1}{\kvt@@tablebackends}
   {\csdef{cmdkvt at Table@shape}{#1}}
+  {\kvt at error{Table backend '#1' not known}
+     {Check for misspellings in '#1'}}}
+\define at key[kvt]{Table}{shape}{\ifinlist{#1}{\kvt@@tableshapes}
+  {\csdef{cmdkvt at Table@shape}{#1}}
+  {\ifinlist{#1}{\kvt@@tablebackends}
+    {\kvt at warn{Using a backend ('#1') as shape is deprecated.
+      Use the 'backend' option instead.}%
+     \csdef{cmdkvt at Table@shape}{#1}}
+    {\kvt at error{Table shape '#1' not known}
+       {Check for misspellings in '#1'}}}}
+\define at cmdkey[kvt]{TableEnv}{caption}{}
+\define at cmdkey[kvt]{TableEnv}{caption/lot}{}
+\define at cmdkey[kvt]{TableEnv}{caption/alt}{}
+\define at cmdkey[kvt]{TableEnv}{label}{}
+\define at boolkey[kvt]{TableEnv}{resume}[true]{%
+  \ifbool{#1}{\ifundef\kvt@@rowcountlast
+    {\kvt at error{No previous table whose counter could be resumed.}
+      {Check whether the "resume" is intentional and whether a
+       previously existing predecessor table has disappeared.}}{}}{}}
+\define at boolkey[kvt]{TableEnv}{resume*}[true]{%
+  \ifbool{#1}
+    {\ifundef\kvt@@lastenvopt
+       {\kvt at error{No previous table whose options could be resume*'d.}
+         {Check whether the "resume*" is intentional and whether a
+          previously existing predecessor table has disappeared.}}{}%
+     \kvt at setcmdkeys\kvt@@lastenvopt{Table}%
+     \kvt at setkeys{resume}{TableEnv}}
+    {}}
 \define at key[kvt]{Column}{default}{\kvt at colkeysetter{default}{#1}}
 \define at key[kvt]{Column}{format}{\kvt at colkeysetter{format}{#1}}
 \define at key[kvt]{Column}{align}{\kvt at colkeysetter{align}{#1}}
@@ -135,7 +178,7 @@
 \kvt at def@globalopts{Row}{
   bg,hidden,below,above,around,style,uncounted,
   expand,expandonce}
-\kvtSet{%
+\AtEndOfPackage{\kvtSet{%
   rowbg=white..black!10,
   headbg=black!14,
   showhead=true,
@@ -144,7 +187,7 @@
   headalign=,
   shape=multipage,
   width=\linewidth,
-  caption={}, label={},
+  captionpos=b,
   default=,
   format=\kvtStrutted,
   align=l,
@@ -160,7 +203,7 @@
   ColGroup/align=c,
   ColGroup/format=\kvtStrutted,
   HeadCell/align=c,
-}
+}}
 \newcommand\NewKeyValTable[3][]{%
   \@ifnextchar[%]
     {\kvt at NewKeyValTable{#1}{#2}{#3}}%
@@ -187,6 +230,7 @@
   \kvt at parselayout{#4}{#2}%
 }
 \def\kvt at parsecolspec#1#2:#3:#4\@undefined{%
+  \kvt at checkcolspecempty{#4}{column}{#2}%
   \def\kvt@@column{#2}%
   \trim at spaces@in\kvt@@column
   \expandafter\kvt at parsecolspec@i\expandafter{\kvt@@column}{#1}{#3}}
@@ -239,6 +283,7 @@
   \kvt at dossvlist{#2}%
   \expandafter\endgroup\kvt@@result}
 \def\kvt at parsecolgroup#1#2:#3:#4\@undefined{%
+  \kvt at checkcolspecempty{#4}{column group}{#2}%
   \ifinlistcs{#2}{kvt at allcolumns@#1}{\kvt at error
     {Name `#2' cannot be used for a column group in table type `#1',
      as it is already used for a column}
@@ -264,6 +309,11 @@
       }%
     }}%
     \listcsadd{kvt at grpcolkeys@#1}{#2}}
+\newcommand\kvt at checkcolspecempty[3]{%
+  \ifstrempty{#1}{}{\ifstrequal{#1}{:}{}{\kvt at error
+    {Too many ':' in definition of #2 '#3'}
+    {Check whether there is an accidental ':' that should actually be
+     a ',' or ';'.}}}}
 \newcommand\kvt at checkcolgroup[3]{%
   \def\kvt@@psvdo##1{%
     \ifinlistcs{##1}{kvt at allcolumns@#2}{}{\kvt at error
@@ -307,8 +357,7 @@
   \begingroup
   \def\kvt@@parseheadrows{}%
   \def\do##1{%
-    \def\kvt@@tmp{##1}\trim at post@space at in\kvt@@tmp%
-    \expandafter\ifstrequal\expandafter{\kvt@@tmp}{::}
+    \ifstrequal{##1}{::}
       {\appto\kvt@@parseheadrows{%
          \cseappto{kvt@@custheadrows@#2}{%
            \csexpandonce{kvt at headings@#2}}}}
@@ -329,7 +378,7 @@
   \def\do##1{\letcs\kvt@@curhd{kvt@@hdcellof@##1}%
     \ifdefequal\kvt@@curhd\kvt@@lasthd
       {\advance\kvt@@span\@ne}%
-      {\ifnum\kvt@@span>\z@ \expandafter\kvt at concludecolumn\fi
+      {\ifnum\kvt@@span>\z@ \expandafter\kvt at concludehdcolumn\fi
        \ifdefvoid\kvt@@curhd{}{\ifcsdef{kvt@@hdcelldone@\kvt@@curhd}{%
          \kvt at error{Header cell `\kvt@@curhd' must consist of only
             consecutive columns, but it is not}%
@@ -337,7 +386,7 @@
            specified in `\string\NewKeyValTable{#1}'}}{}}%
        \kvt@@span\@ne \let\kvt@@lasthd\kvt@@curhd}%
   }\dolistcsloop{kvt at displaycols@#1}%
-  \kvt at concludecolumn
+  \kvt at concludehdcolumn
   \appto\kvt@@tmpgrphd{\tabularnewline}%
   \edef\do{\noexpand\csappto{kvt@@custheadrows@#1}{%
     \unexpanded{\noexpand\kvt at rowcolorornot{\cmdkvt at Table@headbg}}%
@@ -344,16 +393,21 @@
     \noexpand\unexpanded{\expandonce{\kvt@@tmpgrphd}}}}%
   \expandafter\endgroup\do}
 \newcommand\kvt at rowcolorornot[1]{\ifstrempty{#1}{}{\rowcolor{#1}}}
+\newcommand\kvt at rowcolorcmdornot[1]{\ifdefvoid{#1}{}{%
+  \expandafter\rowcolor\expandafter{#1}}}
+\newcount\kvt@@bodyrow
 \newcount\kvt@@span
-\newcommand\kvt at concludecolumn{%
+\newcommand\kvt at concludehdcolumn{%
   \kvt@@switchcol
   \ifdefvoid\kvt@@lasthd{}{%
     \eappto\kvt@@tmpgrphd{\noexpand\multicolumn
       {\the\kvt@@span}
       {\csexpandonce{kvt@@hdcell at align@\kvt@@lasthd}}
-      {\csexpandonce{kvt@@hdcell at head@\kvt@@lasthd}}}%
+      {\noexpand\cmdkvt at Table@headformat
+        {\csexpandonce{kvt@@hdcell at head@\kvt@@lasthd}}}}%
     \cslet{kvt@@hdcelldone@\kvt@@lasthd}{\@ne}}}
 \def\kvt at parsehdcolspec#1#2:#3:#4\@undefined{%
+  \kvt at checkcolspecempty{#4}{header cell}{#2}%
   \def\kvt@@colreg##1{%
     \ifinlistcs{##1}{kvt at allcolumns@#1}{}
       {\kvt at error{Column `##1', referenced in header cell `#2', not
@@ -383,102 +437,15 @@
   \def\Row{\kvt at AddKeyValRow
     {\noalign\bgroup}{\expandafter\egroup\kvt@@row}{#2}}%
   \kvt at SetOptions{#2}{#1}%
+  \ifbool{kvt at TableEnv@resume*}{}
+    {\gdef\kvt@@lastenvopt{#1}}%
   \csuse{kvt at StartTable@\cmdkvt at Table@shape}{#2}%
 }{%
   \csuse{kvt at EndTable@\cmdkvt at Table@shape}}
-\newcommand\kvt at SetOptions[2]{%
-  \begingroup\edef\kvt@@do{\endgroup\noexpand%
-    \kvt at setkeys{\csexpandonce{kvt at options@#1},\unexpanded{#2}}{Table}%
-  }\kvt@@do}
-\newcommand\kvt at StartTabularlike[2]{%
-  \gdef\kvt@@recenttable{#2}%
-  \metatblAtEnd{#1}{\kvt@@endhook}\let\kvt@@endhook\relax%
-  \ifbool{kvt at Table@showrules}
-    {\def\kvt@@rule##1{\csuse{##1rule}}}
-    {\def\kvt@@rule##1{}}%
-  \appto\kvt@@endhook{\kvt@@rule{bottom}}
-  \appto\kvt@@endhook{%
-    \noalign{\csxdef{kvt at rowcount@#2}{\thekvtTypeRow}}}%
-  \ifdefempty\cmdkvt at Table@caption{}{%
-    \metatblHasCaption{#1}
-      {\appto\kvt@@endhook{\rowcolor{white}%
-        \caption{\cmdkvt at Table@caption}}%
-       \ifdefempty\cmdkvt at Table@label{}{%
-         \appto\kvt@@endhook{\expandafter%
-           \label\expandafter{\cmdkvt at Table@label}}}}
-      {\kvt at warn{Caption lost, table environment '#1'
-                 does not support captions.}}}%
-  \ifdefvoid{\cmdkvt at Table@valign}{}{\metatblCanVAlign{#1}{}
-    {\undef{\cmdkvt at Table@valign}%
-      \kvt at warn{Table environment '#1' of table '#2'
-        does not support the vertical alignment option (valign).
-        Ignoring the option}}}%
-  \ifdefvoid{\cmdkvt at Table@halign}{}{\metatblCanHAlign{#1}{}
-    {\undef{\cmdkvt at Table@halign}%
-      \kvt at warn{Table environment '#1' of table '#2'
-        does not support the horizontal alignment option (halign).
-        Ignoring the option}}}%
-  \setcounter{kvtRow}{0}%
-  \setcounter{kvtTypeRow}{\csuse{kvt at rowcount@#2}}%
-  \begingroup\edef\kvt@@do{\endgroup
-    \metatblIsTabu{#1}{}{\noexpand\kvt at dottedrowcolors
-      {\ifbool{kvt at Table@showhead}
-        {\the\numexpr\csuse{kvt at headrowcount@#2}+1\relax}
-        {1}}%
-      {\expandonce\cmdkvt at Table@rowbg}}%
-    \expandafter\noexpand\csname #1\endcsname
-      \ifdefvoid{\cmdkvt at Table@halign}{}
-        {\metatblIsTabu{#1}{}{[\cmdkvt at Table@halign]}}%
-      \metatblHasWidth{#1}
-        {\metatblIsTabu{#1}
-          {to \expandonce\cmdkvt at Table@width}
-          {{\expandonce\cmdkvt at Table@width}}}
-        {}%
-      \ifdefvoid{\cmdkvt at Table@valign}{}{[\cmdkvt at Table@valign]}%
-      \ifdefvoid{\cmdkvt at Table@halign}{}
-        {\metatblIsTabu{#1}{[\cmdkvt at Table@halign]}{}}%
-      {\csexpandonce{kvt at alignments@#2}}%
-    \noexpand\kvt@@rule{top}%
-    \ifbool{kvt at Table@showhead}
-      {\csuse{kvt at headings@#2}\noexpand\kvt@@rule{mid}}
-      {}%
-    \metatblIsTabu{#1}
-      {\noexpand\kvt at taburowcolors{\expandonce\cmdkvt at Table@rowbg}}{}%
-    \metatblIsLong{#1}{\noexpand\endhead}{}%
-  }\kvt@@do}
-\newcommand\kvt at dottedrowcolors[2]{%
-  \ifstrempty{#2}{}{\kvt at dottedrowcolors@i{#1}#2\@nil}}
-\def\kvt at dottedrowcolors@i#1#2..#3\@nil{%
-  \ifnumodd{#1}
-    {\rowcolors{#1}{#2}{#3}}
-    {\rowcolors{#1}{#3}{#2}}}
-\newcommand\kvt at taburowcolors[1]{%
-  \ifstrempty{#1}{}{\taburowcolors{#1}}}
-\newcommand\kvt at DefineStdTabEnv{\@dblarg\kvt at DefineStdTabEnv@i}
-\newcommand\kvt at DefineStdTabEnv@i[2][]{%
-  \expandafter\newcommand\csname kvt at StartTable@#1\endcsname[1]{%
-    \kvt at StartTabularlike{#2}{##1}}%
-  \csedef{kvt at EndTable@#1}{%
-    \expandafter\noexpand\csname end#2\endcsname}}
-\newcommand\kvt at DefineDualTabEnv[3]{%
-  \expandafter\newcommand\csname kvt at StartTable@#1\endcsname[1]{%
-    \kvt at ifhasXcolumns{##1}
-      {\csedef{kvt at EndTable@#1}{%
-         \expandafter\noexpand\csname end#3\endcsname}%
-       \kvt at StartTabularlike{#3}{##1}%
-      }{\csedef{kvt at EndTable@#1}{%
-         \expandafter\noexpand\csname end#2\endcsname}%
-       \kvt at StartTabularlike{#2}{##1}}}}
-\newcommand\kvt at ifhasXcolumns[1]{%
-  \expandafter\expandafter\expandafter\metatbl at ifhasXcolumns
-  \expandafter\expandafter\expandafter{%
-    \csname kvt at alignments@#1\endcsname}}
-\kvt at DefineStdTabEnv{tabular}
-\kvt at DefineStdTabEnv{longtable}
-\kvt at DefineStdTabEnv{tabularx}
-\kvt at DefineStdTabEnv{xltabular}
-\kvt at DefineStdTabEnv{tabu}
-\kvt at DefineStdTabEnv{longtabu}
+\newcommand\kvt at SetOptions[2]{\expandafter
+  \kvt at SetOptions@i\expandafter{\csname kvt at options@#1\endcsname}{#2}}
+\newcommand\kvt at SetOptions@i[2]{\expandafter
+  \kvt at setkeys\expandafter{#1,#2}{Table,TableEnv}}
 \define at boolkey[metatbl]{EnvProp}{isLong}{\metatbl at boolprop{isLong}{#1}}
 \define at boolkey[metatbl]{EnvProp}{isTabu}{\metatbl at boolprop{isTabu}{#1}}
 \define at boolkey[metatbl]{EnvProp}{hasWidth}{%
@@ -493,6 +460,7 @@
 \define at key[metatbl]{EnvProp}{atEnd}{\metatbl at setprop[1]{atEnd}{#1}}
 \newrobustcmd\metatblRegisterEnv[2]{%
   \edef\metatbl@@envname{#1}%
+  \csdef{metatbl@@registered@#1}{true}%
   \setkeys[metatbl]{EnvProp}{#2}}
 \newcommand\metatbl at setprop[3][0]{%
   \expandafter\newcommand
@@ -500,6 +468,7 @@
 \newcommand\metatbl at boolprop[2]{%
   \providebool{metatbl at EnvProp@#1@\metatbl@@envname}%
   \setbool{metatbl at EnvProp@#1@\metatbl@@envname}{#2}}
+\newcommand\metatblRegistered[1]{\ifcsdef{metatbl@@registered@#1}}
 \newcommand\metatblIsLong[1]{\ifbool{metatbl at EnvProp@isLong@#1}}
 \newcommand\metatblIsTabu[1]{\ifbool{metatbl at EnvProp@isTabu@#1}}
 \newcommand\metatblHasWidth[1]{\ifbool{metatbl at EnvProp@hasWidth@#1}}
@@ -514,7 +483,7 @@
   \def\do##1{%
     \metatbl at csnamearg\RequirePackage{metatbl at EnvProp@pkg@##1}}%
   \docsvlist{#1}}
-\newcommand\metatblAtEnd[2]{% #1=env-name, #2=code
+\newcommand\metatblAtEnd[2]{%
   \csname metatbl at EnvProp@atEnd@#1\endcsname{#2}}
 \newcommand\metatbl at csnamearg[2]{%
   \expandafter\expandafter\expandafter#1%
@@ -563,6 +532,148 @@
   \def\NC at rewrite@X{\def\metatbl@@branch{\@firstoftwo}\NC at find l}%
   \@mkpream{#1}%
   \expandafter\endgroup\metatbl@@branch}
+\newcommand\kvt at StartTabularlike[2]{%
+  \metatblAtEnd{#1}{\kvt@@endhook}%
+  \let\kvt@@endhook\@empty
+  \let\kvt@@prehook\@empty
+  \ifbool{kvt at Table@showrules}
+    {\def\kvt@@rule##1{\csuse{##1rule}}}
+    {\def\kvt@@rule##1{}}%
+  \appto\kvt@@prehook{\kvt@@rule{top}}%
+  \appto\kvt@@endhook{\kvt@@rule{bottom}}%
+  \appto\kvt@@endhook{\noalign{%
+    \csxdef{kvt at rowcount@#2}{\thekvtTypeRow}%
+    \csxdef{kvt@@rowcountlast}{\thekvtRow}}}%
+  \ifdefvoid\cmdkvt at TableEnv@caption
+    {\let\kvt@@caption at main\@empty
+     \let\kvt@@caption at alt\@empty}
+    {\metatblHasCaption{#1}
+       {\edef\kvt@@caption at main{%
+         \csexpandonce{kvt at caption@\cmdkvt at Table@captionpos}%
+           \ifcsvoid{cmdkvt at TableEnv@caption/lot}{}
+             {[{\csexpandonce{cmdkvt at TableEnv@caption/lot}}]}%
+           {\expandonce\cmdkvt at TableEnv@caption
+              \ifdefvoid\cmdkvt at TableEnv@label{}{%
+                \noexpand\label{\expandonce\cmdkvt at TableEnv@label}}}%
+         \noexpand\\}%
+        \ifcsvoid{cmdkvt at TableEnv@caption/alt}
+          {\def\kvt@@caption at alt{}}
+          {\edef\kvt@@caption at alt{%
+            \csexpandonce{kvt at caption@\cmdkvt at Table@captionpos}[]%
+              {\csexpandonce{cmdkvt at TableEnv@caption/alt}}%
+            \noexpand\\}}%
+       }{\kvt at error
+         {Caption lost, table backend '#1' does not support captions}
+         {Consider placing the KeyValTable environment inside a 'table'
+          environment and use the \string\caption\space macro inside.}}}%
+  \ifdefstring{\cmdkvt at Table@captionpos}{t}
+    {\let\kvt@@caption at headmain\kvt@@caption at main\let\kvt@@caption at footmain\@empty
+     \let\kvt@@caption at headalt\kvt@@caption at alt  \let\kvt@@caption at footalt\@empty}
+    {\let\kvt@@caption at footmain\kvt@@caption at main\let\kvt@@caption at headmain\@empty
+     \let\kvt@@caption at footalt\kvt@@caption at alt  \let\kvt@@caption at headalt\@empty}%
+  \ifbool{kvt at Table@showhead}
+    {\eappto\kvt@@prehook{\csuse{kvt at headings@#2}\noexpand\kvt@@rule{mid}}}
+    {}%
+  \ifdefvoid{\cmdkvt at Table@valign}{}{\metatblCanVAlign{#1}{}
+    {\undef{\cmdkvt at Table@valign}%
+      \kvt at warn{Table environment '#1' of table '#2'
+        does not support the vertical alignment option (valign).
+        Ignoring the option}}}%
+  \ifdefvoid{\cmdkvt at Table@halign}{}{\metatblCanHAlign{#1}{}
+    {\undef{\cmdkvt at Table@halign}%
+      \kvt at warn{Table environment '#1' of table '#2'
+        does not support the horizontal alignment option (halign).
+        Ignoring the option}}}%
+  \global\kvt@@bodyrow=0\relax
+  \ifbool{kvt at TableEnv@resume}
+    {\setcounter{kvtRow}{\csuse{kvt@@rowcountlast}}}
+    {\setcounter{kvtRow}{0}}%
+  \setcounter{kvtTypeRow}{\csuse{kvt at rowcount@#2}}%
+  \expandafter\kvt at setrowcolors\expandafter{\cmdkvt at Table@rowbg}%
+  \begingroup\edef\kvt@@do{\endgroup
+    \expandafter\noexpand\csname #1\endcsname
+      \ifdefvoid{\cmdkvt at Table@halign}{}
+        {\metatblIsTabu{#1}{}{[\cmdkvt at Table@halign]}}%
+      \metatblHasWidth{#1}
+        {\metatblIsTabu{#1}
+          {to \expandonce\cmdkvt at Table@width}
+          {{\expandonce\cmdkvt at Table@width}}}
+        {}%
+      \ifdefvoid{\cmdkvt at Table@valign}{}{[\cmdkvt at Table@valign]}%
+      \ifdefvoid{\cmdkvt at Table@halign}{}
+        {\metatblIsTabu{#1}{[\cmdkvt at Table@halign]}{}}%
+      {\csexpandonce{kvt at alignments@#2}}%
+    \expandonce\kvt@@caption at headmain
+    \expandonce\kvt@@prehook
+    \metatblIsLong{#1}{%
+      \noexpand\endfirsthead
+      \expandonce\kvt@@caption at headalt
+      \expandonce\kvt@@prehook
+      \noexpand\endhead}{}%
+    \expandonce\kvt@@caption at footmain
+    \metatblIsLong{#1}{%
+      \noexpand\endlastfoot
+      \expandonce\kvt@@caption at footalt
+      \noexpand\endfoot}{}%
+  }\kvt@@do}
+\newcommand\kvt at caption@t{\caption}
+\newcommand\kvt at caption@b{%
+  \noalign{\parbox{0pt}{\vskip\baselineskip}}%
+  \caption}
+\newcommand\kvt at setrowcolors[1]{%
+  \ifstrempty{#1}{}{\kvt at setrowcolors@i#1\@nil}}
+\def\kvt at setrowcolors@i#1..#2\@nil{%
+  \def\kvt@@bgcolor at odd{#1}%
+  \def\kvt@@bgcolor at even{#2}}
+\newcommand\kvt at userowcolors{\ifnumodd{\the\kvt@@bodyrow}
+  {\kvt at rowcolorcmdornot{\kvt@@bgcolor at odd}}
+  {\kvt at rowcolorcmdornot{\kvt@@bgcolor at even}}}
+\newcommand\kvt at RegisterBackend[1]{%
+  \ifinlist{#1}{\kvt@@tablebackends}
+    {\kvt at error{Backend '#1' already registered}
+       {Internal error. Check use of \string\kvt at RegisterBackend.}}
+    {\kvt at CheckMetatblEnv{#1}%
+     \listadd{\kvt@@tablebackends}{#1}%
+     \kvt at DefineStdTabEnv{#1}{#1}}}
+\newcommand\kvt at RegisterShape[3]{%
+  \ifinlist{#1}{\kvt@@tableshapes}
+    {\kvt at error{Shape '#1' already registered}
+       {Internal error. Check use of \string\kvt at RegisterShape.}}
+    {\kvt at CheckMetatblEnv{#2}\kvt at CheckMetatblEnv{#3}%
+    \listadd{\kvt@@tableshapes}{#1}%
+     \ifstrequal{#2}{#3}
+       {\kvt at DefineStdTabEnv{#1}{#2}}
+       {\kvt at DefineDualTabEnv{#1}{#2}{#3}}}}
+\newcommand\kvt at CheckMetatblEnv[1]{\metatblRegistered{#1}{}
+   {\kvt at error{Environment '#1' not supported by keyvaltable}
+      {Check \string\metatblRegisterEnv\space for how to make it
+       supported.}}}
+\newcommand\kvt@@tablebackends{}
+\newcommand\kvt@@tableshapes{}
+\newcommand\kvt at DefineStdTabEnv[2]{%
+  \csdef{kvt at StartTable@#1}##1{%
+    \kvt at StartTabularlike{#2}{##1}}%
+  \csedef{kvt at EndTable@#1}{%
+    \expandafter\noexpand\csname end#2\endcsname}}
+\newcommand\kvt at DefineDualTabEnv[3]{%
+  \expandafter\newcommand\csname kvt at StartTable@#1\endcsname[1]{%
+    \kvt at ifhasXcolumns{##1}
+      {\csedef{kvt at EndTable@#1}{%
+         \expandafter\noexpand\csname end#3\endcsname}%
+       \kvt at StartTabularlike{#3}{##1}%
+      }{\csedef{kvt at EndTable@#1}{%
+         \expandafter\noexpand\csname end#2\endcsname}%
+       \kvt at StartTabularlike{#2}{##1}}}}
+\newcommand\kvt at ifhasXcolumns[1]{%
+  \expandafter\expandafter\expandafter\metatbl at ifhasXcolumns
+  \expandafter\expandafter\expandafter{%
+    \csname kvt at alignments@#1\endcsname}}
+\kvt at RegisterBackend{tabular}
+\kvt at RegisterBackend{longtable}
+\kvt at RegisterBackend{tabularx}
+\kvt at RegisterBackend{xltabular}
+\kvt at RegisterBackend{tabu}
+\kvt at RegisterBackend{longtabu}
 \newcommand\kvt at AddKeyValRow[3]{%
   #1%
   \@ifnextchar[%]
@@ -579,10 +690,12 @@
   \ifdefvoid\cmdkvt at Row@above{}{%
     \eappto\kvt@@row{\noexpand\noalign{\noexpand\vspace{%
       \expandonce\cmdkvt at Row@above}}}}%
-  \ifdefvoid\cmdkvt at Row@bg{}{%
-    \eappto\kvt@@row{\noexpand\rowcolor{\expandonce\cmdkvt at Row@bg}}}%
+  \appto\kvt@@row{\noalign{\global\advance\kvt@@bodyrow\@ne}}%
   \ifbool{kvt at Row@uncounted}{}{%
     \appto\kvt@@row{\noalign{\kvt at stepcounters}}}%
+  \ifdefvoid\cmdkvt at Row@bg
+    {\appto\kvt@@row{\kvt at userowcolors}}
+    {\eappto\kvt@@row{\noexpand\rowcolor{\expandonce\cmdkvt at Row@bg}}}%
   \ifdefvoid\cmdkvt at Row@align
     {\let\kvt@@rowmkmulticolumn\@empty}
     {\edef\kvt@@rowmkmulticolumn{%
@@ -668,24 +781,32 @@
   \kvt@@span=#2\relax \advance\kvt@@span\m at ne
   \def\kvt@@cell{#3}%
   \def\kvt@@mkmulticolumn{\multicolumn{#2}{#1}}}
-\newcommand\kvtNewRowStyle[2]{%
-  \ifcsundef{kvt@@rowstyle@#1}
-    {\csdef{kvt@@rowstyle@#1}{#2}}
-    {\kvt at error{Row style '#1' is already defined}{Use
-      \string\kvtRenewRowStyle\space to change an existing style.}}}
-\newcommand\kvtRenewRowStyle[2]{%
-  \ifcsundef{kvt@@rowstyle@#1}
-    {\kvt at error{Row style '#1' is not defined}
-      {Use \string\kvtNewRowStyle\space to define a new row style.}}
-    {\csdef{kvt@@rowstyle@#1}{#2}}}
-\newcommand\kvt at UseRowStyle[1]{%
-  \ifcsundef{kvt@@rowstyle@#1}
-    {\kvt at error{Row style '#1' is not defined}
-      {Use \string\kvtNewRowStyle\space to define a new row style.}}
-    {\kvt at setcskeys{kvt@@rowstyle@#1}{Row}}}
+\newcommand\kvtNewRowStyle{\kvt at NewStyle{row}{\kvtRenewRowStyle}}
+\newcommand\kvtRenewRowStyle{\kvt at RenewStyle{row}{\kvtNewRowStyle}}
+\newcommand\kvtNewTableStyle{\kvt at NewStyle{table}{\kvtRenewTableStyle}}
+\newcommand\kvtRenewTableStyle{\kvt at RenewStyle{table}{\kvtNewTableStyle}}
+\newcommand\kvt at NewStyle[4]{%
+  \ifcsundef{kvt@@#1style@#3}
+    {\csdef{kvt@@#1style@#3}{#4}}
+    {\kvt at error{The #1 style '#3' is already defined}{Use
+      \string#2\space to change an existing style.}}}
+\newcommand\kvt at RenewStyle[4]{%
+  \ifcsundef{kvt@@#1style@#3}
+    {\kvt at error{A #1 style '#3' is not defined}
+      {Use \string#2\space to define a new #1 style.}}
+    {\csdef{kvt@@#1style@#3}{#4}}}
 \newcommand\kvt at UseRowStyles[1]{%
-  \kvt at xkv@disablepreset[kvt]{Row}{%
-    \forcsvlist\kvt at UseRowStyle{#1}}}
+  \kvt at UseStyles{row}{Row}{\kvt at NewRowStyle}{#1}}
+\newcommand\kvt at UseTableStyles[1]{%
+  \kvt at UseStyles{table}{Table}{\kvt at NewTableStyle}{#1}}
+\newcommand\kvt at UseStyle[4]{%
+  \ifcsundef{kvt@@#1style@#4}
+    {\kvt at error{A #1 style '#4' is not defined}
+      {Use \string#3\space to define a new #1 style.}}
+    {\kvt at setcskeys{kvt@@#1style@#4}{#2}}}
+\newcommand\kvt at UseStyles[4]{%
+  \kvt at xkv@disablepreset[kvt]{#2}{%
+    \forcsvlist{\kvt at UseStyle{#1}{#2}{#3}}{#4}}}
 \newcommand\kvt at xkv@disablepreset[3][KV]{%
   \ifnumgreater{\XKV at depth}{1}
     {#3}
@@ -795,12 +916,12 @@
   \ifdimcomp{\kvt@@pkg at compat pt}{#1}{#2pt}}
 \kvt at IfVersion{<}{2.0}{%
   \metatblRequire{tabu,longtabu}
-  \kvt at DefineStdTabEnv[onepage]{tabu}
-  \kvt at DefineStdTabEnv[multipage]{longtabu}
+  \kvt at RegisterShape{onepage}{tabu}{tabu}
+  \kvt at RegisterShape{multipage}{longtabu}{longtabu}
 }{%
   \metatblRequire{tabularx,longtable,xltabular}
-  \kvt at DefineDualTabEnv{onepage}{tabular}{tabularx}
-  \kvt at DefineDualTabEnv{multipage}{longtable}{xltabular}
+  \kvt at RegisterShape{onepage}{tabular}{tabularx}
+  \kvt at RegisterShape{multipage}{longtable}{xltabular}
 }
 \kvt at IfVersion{<}{2.0}{%
   \renewcommand\kvt at parselayout[2]{\kvt at parseheadrows{#2}{#1}}%



More information about the tex-live-commits mailing list.