texlive[53861] Master/texmf-dist: keyvaltable (21feb20)

commits+karl at tug.org commits+karl at tug.org
Fri Feb 21 23:54:25 CET 2020


Revision: 53861
          http://tug.org/svn/texlive?view=revision&revision=53861
Author:   karl
Date:     2020-02-21 23:54:25 +0100 (Fri, 21 Feb 2020)
Log Message:
-----------
keyvaltable (21feb20)

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

Modified: trunk/Master/texmf-dist/doc/latex/keyvaltable/README.md
===================================================================
--- trunk/Master/texmf-dist/doc/latex/keyvaltable/README.md	2020-02-21 22:54:05 UTC (rev 53860)
+++ trunk/Master/texmf-dist/doc/latex/keyvaltable/README.md	2020-02-21 22:54:25 UTC (rev 53861)
@@ -1,7 +1,7 @@
 The keyvaltable Package
 =======================
 
-Copyright (C) 2016-2018 Richard Grewe
+Copyright (C) 2016-2020 Richard Grewe
 
 Released under the [LaTeX Project Public License](http://www.latex-project.org/lppl/) version 1.2 or later
 

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-02-21 22:54:05 UTC (rev 53860)
+++ trunk/Master/texmf-dist/source/latex/keyvaltable/keyvaltable.dtx	2020-02-21 22:54:25 UTC (rev 53861)
@@ -1,6 +1,6 @@
 % \iffalse meta-comment
 %
-% Copyright (C) 2016-2019 by Richard Grewe <r-g+tex at posteo.net>
+% Copyright (C) 2016-2020 by Richard Grewe <r-g+tex at posteo.net>
 % -------------------------------------------------------
 %
 % This file may be distributed and/or modified under the
@@ -22,12 +22,12 @@
 %<package>\NeedsTeXFormat{LaTeX2e}[1999/12/01]
 %<package>\ProvidesPackage{keyvaltable}
 %<*package>
-    [2019/05/11 v2.0 Package for filling tables using key-value lists]
+    [2020/02/19 v2.1 Package for filling tables using key-value lists]
 %</package>
 %
 %<*driver>
 \documentclass[svgnames]{ltxdoc}
-\usepackage{rgltxdoc}[2019/05/04 v1.2]
+\usepackage{rgltxdoc}[2019/12/21 v1.3]
 \usepackage{etoc}
 \usepackage{amssymb}% \checkmark
 \EnableCrossrefs
@@ -624,6 +624,13 @@
 % This property specifies the width of the table, if the selected
 % |shape| 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
+% \cref{sec:AltTabEnv}).
+%
 % \NiceDescribeKey{showhead}{vals={true,false}, init=true}
 % This property specifies whether the header row shall be shown.  The
 % \meta{value} must be a Boolean (i.e., |true| or |false|), where |true|
@@ -630,9 +637,17 @@
 % specifies that the header row is shown and |false| specifies that the
 % header row is not shown.
 %
-% \NiceDescribeKey{showrules}{vals={true,false}, init=true}
-% This property specifies whether top and bottom rules as well
-% as a rule below the header row are drawn (|true|) or not (|false|).
+% \NiceDescribeKeys{2}
+%   {showrules}{vals={true,false}, init=true}
+%   {norules}{vals={true,false}, init=false, def=true}
+% The |showrules| property specifies whether top and bottom rules as
+% well as a rule below the header row are drawn (|true|) or not
+% (|false|). The |norules| property serves the same purpose, but the
+% value |true| hides the rules and the value |false| causes the rules to
+% be drawn.
+% Note that both properties only affect the rules that \thispackage
+% produces automatically; rules manually added, e.g., via |\hline| or
+% |\midrule| are not affected by the properties.
 %
 % \NiceDescribeKey{headalign}{vals={\vmeta{empty} or \vmeta{coltype}}, init=\vmeta{empty}}
 % This property specifies the alignment for header cells.  If left
@@ -676,36 +691,44 @@
 % \vref{fig:TableOptionExamples} demonstrates the \meta{options} in
 % examples.
 % \begin{figure}
-% \begin{LTXexample}[morekeywords={shape,showhead,rowbg}]
-% \NewKeyValTable[shape=onepage,
-%     showhead=false,
+% \begin{LTXexample}[morekeywords={showhead,rowbg}]
+% \kvtSet{format=\texttt}
+% \NewKeyValTable[showhead=false,
 %     rowbg=blue!10..blue!15,
-%   ]{TabOptions}{
-%     opt: align=l, format=\texttt;
-%     val: align=l, format=\texttt;}
-% \begin{table}\centering
+%   ]{TabOptions}{opt; val}
 % \begin{KeyValTable}{TabOptions}
-% \Row{opt=shape,  val=onepage}
-% \Row{opt=showhead, val=false}
-% \Row{opt=rowbg,  val=blue!10..blue!15}
+%   \Row{opt=showhead, val=false}
+%   \Row{opt=rowbg,  val=blue!10..blue!15}
 % \end{KeyValTable}
-% \caption{table options demo}
-% \end{table}
 % \end{LTXexample}
-% \begin{LTXexample}[morekeywords={showrules,headbg,headalign,headformat,norowbg}]
+% \begin{LTXexample}[morepreset={\kvtSet{format=\texttt}},morekeywords={showrules,headbg,headalign,headformat,halign,norowbg}]
 % \NewKeyValTable[showrules=false,headbg=blue!25,
-%     headalign=c,headformat=\textbf,norowbg
-%   ]{TabOptions2}{
-%     opt: align=l, format=\texttt;
-%     val: align=l, format=\texttt;}
+%     headalign=c,headformat=\textbf,norowbg,
+%     halign=r,
+%   ]{TabOptions2}{opt; val}
 % \begin{KeyValTable}{TabOptions2}
-% \Row{opt=showrules, val=false}
-% \Row{opt=headbg, val=blue!25}
-% \Row{opt=headalign, val=c}
-% \Row{opt=headformat, val=\string\textbf}
-% \Row{opt=norowbg, val=true}
+%   \Row{opt=showrules, val=false}
+%   \Row{opt=headbg, val=blue!25}
+%   \Row{opt=headalign, val=c}
+%   \Row{opt=headformat, val=\string\textbf}
+%   \Row{opt=norowbg, val=true}
+%   \Row{opt=halign, val=r}
 % \end{KeyValTable}
 % \end{LTXexample}
+% \begin{LTXexample}[morepreset={\kvtSet{format=\texttt}},morekeywords={nobg,norules,valign,shape,width}]
+% \NewKeyValTable[valign=t,nobg,norules,
+%     shape=onepage,width=3cm,headformat=\textbf,
+%   ]{TabOptions3}{opt: align=X;}
+% \begin{KeyValTable}{TabOptions3}
+%   \Row{opt=nobg}
+%   \Row{opt=norules}
+% \end{KeyValTable}
+% \begin{KeyValTable}{TabOptions3}
+%   \Row{opt={shape=onepage}}
+%   \Row{opt={valign=t}}
+%   \Row{opt={width=3cm}}
+% \end{KeyValTable}
+% \end{LTXexample}
 % \caption{Examples for table options}
 % \label{fig:TableOptionExamples}
 % \end{figure}
@@ -739,11 +762,19 @@
 % options must be a comma-separated list of key-value pairs.
 % The following options are supported.
 %
-% \NiceDescribeKey{hidden}{vals={true,false}, init=false}
+% \NiceDescribeKey{hidden}{vals={true,false}, init=false, def=true}
 %   This property specifies whether the row shall be hidden (|true|) or
 %   not (|false|). If only |hidden| is used without a value, this is
 %   equivalent to |hidden=true|.
 %
+% \NiceDescribeKey{align}{vals={\vmeta{empty} or \vmeta{coltype}}, init=\vmeta{empty}}
+%   This property specifies the alignment of the cells in the row.
+%   If this property is not specified, the respective columns' alignment
+%   is used. The alignment applies to normal cells as well as to cells
+%   in column groups.\footnote{Note that the alignment does not override
+%   the alignment specified in any \cs{multicolumn} if it is assigned to
+%   a cell in the row.}
+%
 % \NiceDescribeKey{bg}{vals=\vmeta{color}, init=\vmeta{empty}}
 %   This property specifies the background color for the particular row.
 %   If this option is not specified (or set to an empty value
@@ -751,6 +782,27 @@
 %   option of the table.
 %
 % \NiceDescribeKeys{3}
+%   {format}{vals=\vmeta{single argument macro}, init=\vmeta{"identity"}}
+%   {format*}{vals=\vmeta{single argument macro}, init=\vmeta{"identity"}}
+%   {format!}{vals=\vmeta{single argument macro}, init=\vmeta{none}}
+%   These properties specify formatting for all cells of the particular
+%   row. The difference between the three properties is how they
+%   interact with the column formats of the respective cells in the row.
+%   The |format| property is applied to the cell content \emph{before}
+%   the column format, and the |format*| property is applied
+%   \emph{after} the column format.
+%   The |format!| property overrides any column formats in the
+%   respective row and also renders the |format| and |format*|
+%   properties ineffective.
+%
+% \NiceDescribeKey{headlike}{vals={true,false}, init=false, def=true}
+%   This property, when used without a value or with value |true|,
+%   specifies that the row shall be formatted like a header row.
+%   Concretely, the alignment, background color, and format of the row's
+%   cells is then set to the values of the table's |headalign|,
+%   |headbg|, and |headformat| properties.
+%
+% \NiceDescribeKeys{3}
 %   {above}{vals=\vmeta{dimension}, init=\vmeta{empty}}
 %   {below}{vals=\vmeta{dimension}, init=\vmeta{empty}}
 %   {around}{vals=\vmeta{dimension}, init=\vmeta{empty}}
@@ -765,8 +817,8 @@
 %   |\kvtSet{Row/|\meta{option}|=|\meta{value}|}| (see also
 %   \cref{sec:kvtSet}).}
 %
-% The following example demonstrates the options.
-% \begin{LTXexample}[morepreset=\RecipePreset,morekeywords={hidden,above,bg}]
+% The following example demonstrates some of the options.
+% \begin{LTXexample}[morepreset=\RecipePreset,morekeywords={hidden,above,bg,format}]
 % \begin{KeyValTable}{Recipe}
 % \Row{amount=150g, ingredient=ice cream,
 %   step=put into bowl}
@@ -774,7 +826,7 @@
 %   step=heat up and add to bowl}
 % \Row[hidden]{amount=25g, ingredient=cream,
 %   step=decorate on top}
-% \Row[above=1ex,bg=Gold]{
+% \Row[above=1ex,bg=Gold,format=\textit]{
 %   step=serve with a smile}
 % \end{KeyValTable}
 % \end{LTXexample}
@@ -842,7 +894,7 @@
 %
 % Individual cells can be formatted by using the respective
 % \hologo{LaTeX} code directly in the value of the cell.
-% One can disabled column's configured |format| for the cell by
+% One can disable the column's configured |format| for the cell by
 % using the starred column name in |\Row|.
 % The following example demonstrates starred column names.
 %
@@ -1115,14 +1167,18 @@
 % 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 whether they support
-% tables that span multiple pages, whether they support |X|-type
-% (variable-width) columns, and whether their width can be specified
-% (through the |width| option). Finally, the table also displays the
+% used by \thispackage tables 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).
+% \end{itemize}
+% Finally, the table also displays the
 % package(s) that must be loaded manually when the respective shapes are
 % used.
-% Examples can be found in \vref{fig:TableTypes}.
 % \begin{table}\centering
 %   \newcommand\RHead[1]{\rotatebox{90}{\small\varwidth{\linewidth}#1\endvarwidth}}%
 %   \newcommand\YesNo[1]{\ifstrequal{#1}{yes}{\checkmark}{}}%
@@ -1129,30 +1185,32 @@
 % \NewKeyValTable[shape=tabular,headformat=\sffamily\textbf]{ShapeProps}{
 %   shape: format=\small\texttt;
 %   env: format=\small\texttt, head=environment;
-%   multipage: align=c, head=\RHead{multi-\\[-3pt] page}, format=\YesNo;
+%   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;
 %   width:     align=c, head=\RHead{width}, format=\YesNo;
+%   align:     align=c, head=\RHead{align}, format=\textsf;
 %   packages: align=l,  format=\pkgnames}%
 % \begin{KeyValTable}{ShapeProps}
-% \Row{shape=onepage,   env=tabular/tabularx,   multipage=no,  caption=no,  Xcols=yes, width=yes, packages=tabularx}
-% \Row{shape=multipage, env=longtabu/xltabular, multipage=yes, caption=yes, Xcols=yes, width=yes, packages={longtable, xltabular}}
+% \Row{shape=onepage,   env=tabular/tabularx,    multipage=no,  caption=no,  Xcols=yes, width=yes, align=v, packages=tabularx}
+% \Row{shape=multipage, env=longtable/xltabular, multipage=yes, caption=yes, Xcols=yes, width=yes, align=h, packages={longtable, xltabular}}
 % \midrule
 % \noalign{\footnotesize with package option |compat=1.0|:}
-% \Row{shape=onepage,   env=tabu,      multipage=no,  caption=no,  Xcols=yes, width=yes, packages=tabu}
-% \Row{shape=multipage, env=longtabu,  multipage=yes, caption=yes, Xcols=yes, width=yes, packages={tabu, longtable}}
+% \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}
-% \Row{shape=tabularx,  env=tabularx,  multipage=no,  caption=no,  Xcols=yes, width=yes, packages={tabularx}}
-% \Row{shape=longtable, env=longtable, multipage=yes, caption=yes, Xcols=no,  width=no,  packages={longtable}}
-% \Row{shape=xltabular, env=xltabular, multipage=yes, caption=yes, Xcols=yes, width=yes, packages={xltabular}}
-% \Row{shape=tabu,      env=tabu,      multipage=no,  caption=no,  Xcols=yes, width=yes, packages={tabu}}
-% \Row{shape=longtabu,  env=longtabu,  multipage=yes, caption=yes, Xcols=yes, width=yes, packages={tabu,longtable}}
+% \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}}
 % \end{KeyValTable}
 % \caption{Comparison of table shapes / environments}
 % \label{tab:TabEnv}
 % \end{table}
 %
+% Examples can be found in \vref{fig:TableTypes}.
 % \begin{figure}[p]
 % \begin{LTXexample}[width=0.475\hsize,
 %    morekeywords={tabular,longtable}]
@@ -1160,6 +1218,7 @@
 %   id: align=l, default=\thekvtTypeRow;
 %   l: align=l; c: align=c; r: align=r;}[headers={
 %   l+c+r: head=\textbf{\kvtTableOpt{shape} shape}\\ ::}]
+%
 % \begin{KeyValTable}[shape=tabular]{ShapeNoX}
 %   \Row{l=left,   c=center,     r=right}
 %   \Row{l=left-2, c=2-center-2, r=2-right}
@@ -1169,6 +1228,7 @@
 %   \Row{l=left-2, c=2-center-2, r=2-right}
 % \end{KeyValTable}
 % \end{LTXexample}
+%
 % \begin{LTXexample}[width=0.475\hsize,
 %    morekeywords={tabularx,xltabular,tabu,longtabu}]
 % \NewKeyValTable[showrules=false]{ShapeWithX}{
@@ -1175,6 +1235,7 @@
 %   id: align=l, default=\thekvtTypeRow;
 %   l: align=l; X: align=X; r: align=r;}[headers={
 %   l+X+r: head=\textbf{\kvtTableOpt{shape} shape}\\ ::}]
+%
 % \begin{KeyValTable}[shape=tabularx]{ShapeWithX}
 %   \Row{l=left,   X=expandable,   r=right}
 %   \Row{l=left-2, X=expandable-2, r=2-right}
@@ -1196,7 +1257,10 @@
 % \label{fig:TableTypes}
 % \end{figure}
 %
-%
+% ^^M The following \clearpage is a hack! It fixes the page breaking
+% ^^M that is messed up because of the longtable/xltabular/longtabu
+% ^^M in fig:TableTypes.
+% \clearpage
 % \section{Use with Other Packages}
 %
 % \subsection{Named References (\pkgname{cleveref})}\label{sec:package-cleveref}
@@ -1481,11 +1545,21 @@
 % \end{macro}
 % \end{macro}
 %
+% \begin{macro}{\kvt at setkeys@nopresets}
+% The
+% |\kvt at setkeys@nopresets|\marg{keys}\marg{family} macro
+% expands to a |\kvt at setkeys| in which no presets are active.
+%    \begin{macrocode}
+\newcommand\kvt at setkeys@nopresets[2]{%
+  \kvt at xkv@disablepreset[kvt]{#2}{\kvt at setkeys{#1}{#2}}}
+%    \end{macrocode}
+% \end{macro}
+%
 % \begin{macro}{\kvt at colsetkeys}
 % \begin{macro}{\kvt at colsetcmdkeys}
 % \begin{macro}{\kvt at colsetcskeys}
 % The |\kvt at colsetkeys|\marg{fam}\marg{keys} macro abbreviates
-% |\setkeys[KeyValTable]|\meta{fam}\meta{keys}.
+% |\setkeys[KeyValTable]| with the same arguments.
 % The |\kvt at colsetcmdkeys|\marg{famcmd}\marg{keys} and
 % |\kvt at colsetcskeys|\marg{famcs}\marg{keys} abbreviate the cases where
 % \meta{fam} is stored in macro \meta{famcmd} or, respectively,
@@ -1575,13 +1649,10 @@
 %
 % \changes{v0.2}{2016/05/21}{Added ``shape'' table option}
 % \changes{v2.0}{2019/05/11}{added table options "caption" and "label"}
+% \changes{v2.1}{2020/01/18}{Added ``valign'' and ``halign'' table options}
 %    \begin{macrocode}
 \define at cmdkey[kvt]{Table}{rowbg}{}
 \define at cmdkey[kvt]{Table}{headbg}{}
-\define at boolkey[kvt]{Table}{norowbg}[true]{%
-  \kvt at setkeys{rowbg={}}{Table}}
-\define at key[kvt]{Table}{nobg}[true]{%
-  \kvt at setkeys{rowbg={},headbg={}}{Table}}
 \define at cmdkey[kvt]{Table}{headalign}{}
 \define at cmdkey[kvt]{Table}{headformat}{}
 \define at cmdkey[kvt]{Table}{width}{}
@@ -1589,8 +1660,23 @@
 \define at boolkey[kvt]{Table}{showrules}{}
 \define at cmdkey[kvt]{Table}{caption}{}
 \define at cmdkey[kvt]{Table}{label}{}
-
+\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}}
 %    \end{macrocode}
+% The following options only abbreviate options defined above.
+% \changes{v2.1}{2020/01/14}{added abbreviation option "norules"}
+%    \begin{macrocode}
+\define at boolkey[kvt]{Table}{norowbg}[true]{%
+  \kvt at setkeys{rowbg={}}{Table}}
+\define at boolkey[kvt]{Table}{nobg}[true]{%
+  \kvt at setkeys{rowbg={},headbg={}}{Table}}
+\define at boolkey[kvt]{Table}{norules}[true]{%
+  \ifbool{#1}
+    {\kvt at setkeys{showrules=false}{Table}}
+    {\kvt at setkeys{showrules=true}{Table}}}
+%    \end{macrocode}
 % When adding further |shape| options below, ensure to also add a
 % corresponding |\kvt at DefineStdTabEnv| counterpart further below in the
 % code.
@@ -1627,9 +1713,9 @@
 %
 % \begin{macro}{\kvt at def@globalopt}
 % \begin{macro}{\kvt at def@globalopts}
-% The |\kvt at def@globalopt|\marg{family}{key} macro creates an option key
-% "\meta{family}/\meta{key}" for |\kvtSet| that set the preset value for
-% the \meta{key} in \meta{family}.
+% The |\kvt at def@globalopt|\marg{family}{key} macro creates the option key
+% "\meta{family}/\meta{key}". When used in |\kvtSet|, this key sets the preset
+% value for the \meta{key} in \meta{family}.
 % The |\kvt at def@globalopts|\marg{family}{keys} macro extends the former
 % macro to comma-separated lists of \meta{keys} within a single
 % \meta{family}.
@@ -1644,11 +1730,11 @@
 %
 %    \begin{macrocode}
 \define at cmdkey[kvt]{ColGroup}{span}{%
-  \csdef{kvt at colgrp@span@\kvt@@colgrp}{#1}}
+  \csgdef{kvt at colgrp@span@\kvt@@tname @\kvt@@colgrp}{#1}}
 \define at cmdkey[kvt]{ColGroup}{align}{%
-  \csdef{kvt at colgrp@align@\kvt@@colgrp}{#1}}
+  \csgdef{kvt at colgrp@align@\kvt@@tname @\kvt@@colgrp}{#1}}
 \define at cmdkey[kvt]{ColGroup}{format}{%
-  \csdef{kvt at colgrp@format@\kvt@@colgrp}{#1}}
+  \csgdef{kvt at colgrp@format@\kvt@@tname @\kvt@@colgrp}{#1}}
 \kvt at def@globalopts{ColGroup}{align, format}
 %    \end{macrocode}
 %
@@ -1655,9 +1741,9 @@
 %
 % \subsubsection{Layout Customization Options}
 %
-% The following defines the options for the second optional argument to
-% |\NewKeyValTable|. These options intentionally do not support setting
-% global defaults via |\kvtSet|.
+% The following defines the option keys for the second optional argument
+% to |\NewKeyValTable|. These options intentionally do not support
+% setting global defaults via |\kvtSet|.
 %    \begin{macrocode}
 \define at cmdkey[kvt]{Layout}{headers}{%
   \expandafter\kvt at parseheadrows\expandafter{\kvt@@tname}{#1}}
@@ -1683,17 +1769,37 @@
 % \changes{v2.0}{2019/05/11}{added row options "nobg" and "norowbg"}
 % \changes{v2.0}{2019/05/11}{added row option "style"}
 % \changes{v2.0}{2019/05/11}{added row option "uncounted"}
+% \changes{v2.1}{2020/02/15}{added row options "format", "format*",
+%                            "format!", "align", and "headlike"}
 %    \begin{macrocode}
 \define at cmdkey[kvt]{Row}{bg}{}
+\define at cmdkey[kvt]{Row}{format}{}
+\define at cmdkey[kvt]{Row}{format*}{}
+\define at cmdkey[kvt]{Row}{format!}{}
+\define at cmdkey[kvt]{Row}{align}{}
+\define at boolkey[kvt]{Row}{headlike}[true]{%
+  \ifbool{#1}{%
+    \edef\kvt@@opts{%
+      bg={\expandonce\cmdkvt at Table@headbg},%
+      format!={\expandonce\cmdkvt at Table@headformat},%
+      align={\expandonce\cmdkvt at Table@headalign}}%
+    \expandafter\kvt at setkeys@nopresets\expandafter{\kvt@@opts}{Row}%
+  }{}}
 \define at boolkey[kvt]{Row}{hidden}[true]{}
 \define at cmdkey[kvt]{Row}{below}{}
 \define at cmdkey[kvt]{Row}{above}{}
 \define at key[kvt]{Row}{around}{%
-  \kvt at setkeys{below={#1},above={#1}}{Row}}
+  \kvt at setkeys@nopresets{below={#1},above={#1}}{Row}}
 \define at key[kvt]{Row}{style}{\kvt at UseRowStyles{#1}}
 \define at boolkey[kvt]{Row}{uncounted}[true]{}
 \define at boolkey[kvt]{Row}{expand}[true]{}
 \define at boolkey[kvt]{Row}{expandonce}[true]{}
+%    \end{macrocode}
+% The following specifies which row options can be specified globally,
+% i.e. via a |Row/option| key. Not contained in the list are the
+% |format| options and the |headlike| option, as setting these globally
+% appears strange.
+%    \begin{macrocode}
 \kvt at def@globalopts{Row}{
   bg,hidden,below,above,around,style,uncounted,
   expand,expandonce}
@@ -1782,16 +1888,14 @@
 % tables is that this code would prevent |\multicolumn| to be used in
 % the first column.
 % \changes{v1.0}{2019/02/03}{Added zero-width column for \cs{multicolumn}}
-% Fixme: Ideally, the whole extra column should be removed through
-% sufficient use of |\noalign| in headers and rows, such that even the
-% presence of |\multicolumn| does not produce errors.
+% \changes{v2.1}{2020/02/16}{Removed zero-width column again}
 %    \begin{macrocode}
-  \csedef{kvt at alignments@#2}{p{0pt}\expandonce\kvt at HackIntercolSpace}%
+  \csdef{kvt at alignments@#2}{}%
   \csdef{kvt at allcolumns@#2}{}%
   \csdef{kvt at displaycols@#2}{}%
   \csdef{kvt at rowcount@#2}{0}%
   \csdef{kvt at rows@#2}{}%
-  \csdef{kvt at headings@#2}{\kvt at defaultheader}
+  \csdef{kvt at headings@#2}{\kvt at defaultheader}%
   \listadd\kvt at alltables{#2}%
 %    \end{macrocode}
 % Now parse \meta{colspecs}, a semicolon-separated list of individual
@@ -1883,20 +1987,20 @@
 % takes $n$ header cell titles, \meta{head1} to \meta{headn} and formats
 % them based on the |headformat| and |headalign| options.
 % More precisely, when fully expanded, |\kvt at defaultheader| yields
-% "\meta{rowcolor}|& |\meta{fmthead1}| & |\ldots| & |\meta{fmtheadn}|\tabularnewline|".
+% "\meta{rowcolor}\meta{fmthead1}| & |\ldots| & |\meta{fmtheadn}|\tabularnewline|".
 % In the above, \meta{rowcolor}=|\rowcolor{|\meta{headbg}|}|.
 %    \begin{macrocode}
 \newcommand\kvt at defaultheader{%
   \noexpand\kvt at rowcolorornot{\cmdkvt at Table@headbg}%
-  \kvt at defaultheader@i}
-\newcommand\kvt at defaultheader@i[1]{%
-  \kvt at ifnil{#1}{\noexpand\tabularnewline}{%
-    \unexpanded{&}%
+  \kvt at defaultheader@i{}}
+\newcommand\kvt at defaultheader@i[2]{%
+  \kvt at ifnil{#2}{\noexpand\tabularnewline}{%
+    \unexpanded{#1}%
     \ifdefvoid\cmdkvt at Table@headalign
-      {\expandonce\cmdkvt at Table@headformat{\unexpanded{#1}}}
+      {\expandonce\cmdkvt at Table@headformat{\unexpanded{#2}}}
       {\noexpand\multicolumn{1}{\expandonce\cmdkvt at Table@headalign}
-        {\expandonce\cmdkvt at Table@headformat{\unexpanded{#1}}}}%
-    \kvt at defaultheader@i}}
+        {\expandonce\cmdkvt at Table@headformat{\unexpanded{#2}}}}%
+    \kvt at defaultheader@i{&}}}
 %    \end{macrocode}
 % \begin{macro}{\kvt at ifnil}
 % The |\kvt at ifnil|\marg{val}\marg{iftrue}\marg{iffalse} macro expands to
@@ -1914,16 +2018,6 @@
 % \end{macro}
 % \end{macro}
 %
-% \begin{macro}{\kvt at HackIntercolSpace}
-% The |\kvt at HackIntercolSpace| macro captures the negative space that
-% cancels out the spacing otherwise caused by the extra column that the
-% package adds.
-%    \begin{macrocode}
-\newcommand\kvt at HackIntercolSpace{%
-  @{\hspace{-.5\arrayrulewidth}}}
-%    \end{macrocode}
-% \end{macro}
-%
 % \begin{macro}{\kvt at alltables}
 % The |\kvt at alltables| is an \pkgname{etoolbox} list containing the names
 % of all tables declared by |\NewKeyValTable|.
@@ -1983,16 +2077,14 @@
      columns groups.}}{}%
   \def\kvt@@colgrp{#2}%
   \kvt at setkeys{#3}{ColGroup}%
-  \kvt at checkcolgroupcs{kvt at colgrp@span@\kvt@@colgrp}{#1}{#2}%
-  \eappto\kvt@@result{%
+  \kvt at checkcolgroupcs{kvt at colgrp@span@#1@#2}{#1}{#2}%
 %    \end{macrocode}
 % The following defines the |\Row| key for \meta{cgname}, as an
 % abbreviation for setting the value of the first displayed column of
 % \meta{cgname} (|\kvt@@colgrp at first| to a |\multicolumn| that spans the
-% "right" number of columns. Notice the "*" after |\kvt@@colgrp at first|,
-% which disables the first column's default formatting to replace it by
-% the formatting of \meta{cgname}.
+% "right" number of columns).
 %    \begin{macrocode}
+  \eappto\kvt@@result{%
     \noexpand\define at cmdkey[KeyValTable]{#1}{#2}{%
 %    \end{macrocode}
 % The following |\ifdefvoid| check ensures that if \meta{cgname} is a
@@ -2000,14 +2092,27 @@
 % are hidden), then setting \meta{cgname} to a value has no effect.
 %    \begin{macrocode}
       \ifdefvoid\kvt@@colgrp at first{}{%
-        \noexpand\setkeys[KeyValTable]{#1}{%
-          \expandonce\kvt@@colgrp at first*=\noexpand\multicolumn
-            {\expandonce\kvt@@colgrp at n}%
-            {\csexpandonce{kvt at colgrp@align@#2}}%
-            {\csexpandonce{kvt at colgrp@format@#2}{\unexpanded{##1}}}}%
+%    \end{macrocode}
+% The "abbreviation" is implemented via |\setkeys|. The letter normally
+% employs the defined |\presetkeys|, but we disable this through
+% |\kvt at xkv@disablepreset| to avoid that column keys that are set before
+% a colgroup key are overwritten by their preset values.
+%    \begin{macrocode}
+        \noexpand\kvt at xkv@disablepreset[KeyValTable]{#1}{%
+          \noexpand\setkeys[KeyValTable]{#1}{%
+%    \end{macrocode}
+% Notice the "*" after |\kvt@@colgrp at first|,
+% which disables the first column's default formatting to replace it by
+% the formatting of \meta{cgname}.
+%    \begin{macrocode}
+            \expandonce\kvt@@colgrp at first=\noexpand\kvt@@@colgroup
+              {\unexpanded{#2}}%
+              {\expandonce\kvt@@colgrp at n}%
+              {\csexpandonce{kvt at colgrp@align@#1@#2}}%
+              {\unexpanded{##1}}}}%
       }%
-    }%
-    \noexpand\listcsadd{kvt at grpcolkeys@#1}{#2}}}
+    }}%
+    \listcsadd{kvt at grpcolkeys@#1}{#2}}
 %    \end{macrocode}
 % \end{macro}
 %
@@ -2090,7 +2195,14 @@
           {Compare `\string\kvt@@curgrp' to the column ordering as
            specified in `\string\NewKeyValTable{#1}'}%
         \fi
-        \edef\kvt@@colgrp at n{\the\numexpr\kvt@@colgrp at n+1\relax}}%
+        \edef\kvt@@colgrp at n{\the\numexpr\kvt@@colgrp at n+1\relax}%
+%    \end{macrocode}
+% Since this macro is not encapsulated in a group (in order to return
+% |\kvt@@colgrp at n| and |\kvt@@colgrp at first|), we finally prevent the
+% local \cs{kvt@@incolgrp@\meta{column}} from leaking outside this
+% macro.
+%    \begin{macrocode}
+        \csundef{kvt@@incolgrp@##1}}%
   }\forlistcsloop{\kvt@@coldo}{kvt at displaycols@#2}}
 %    \end{macrocode}
 % \end{macro}
@@ -2182,8 +2294,9 @@
   \let\kvt@@tmpgrphd\@empty
   \kvt@@span\z@
   \undef\kvt@@curhd \undef\kvt@@lasthd
+  \kvt at def@atseconduse\kvt@@switchcol{\appto\kvt@@tmpgrphd{&}}%
 %    \end{macrocode}
-% Next, loop over all displayed (non-hidden) columns stored in
+% Next, loop over all displayed columns, stored in
 % \cs{kvt at displaycols@\meta{tname}}. The following |\do|\marg{colname}
 % macro collects (spanned) columns as specified in \meta{colspec}, in the
 % ordering in which the table's columns are displayed. The spanned
@@ -2247,21 +2360,11 @@
 % |\kvt@@tmpgrphd|).
 %    \begin{macrocode}
 \newcommand\kvt at concludecolumn{%
-%    \end{macrocode}
-% The following conditional checks whether this is the first header cell
-% in the header row. If this is the case, then the
-% |\kvt@@extraalign| macro is set to |\kvt at HackIntercolSpace|, such that
-% the |\multicolumn| below does not throw away this spacing.
-%    \begin{macrocode}
-  \ifdefequal\kvt@@tmpgrphd\@empty
-    {\let\kvt@@extraalign\kvt at HackIntercolSpace}
-    {\let\kvt@@extraalign\@empty}%
-  \appto\kvt@@tmpgrphd{&}%
+  \kvt@@switchcol
   \ifdefvoid\kvt@@lasthd{}{%
     \eappto\kvt@@tmpgrphd{\noexpand\multicolumn
       {\the\kvt@@span}
-      {\expandonce\kvt@@extraalign
-       \csexpandonce{kvt@@hdcell at align@\kvt@@lasthd}}
+      {\csexpandonce{kvt@@hdcell at align@\kvt@@lasthd}}
       {\csexpandonce{kvt@@hdcell at head@\kvt@@lasthd}}}%
 %    \end{macrocode}
 % Mark the header cell as already used and concluded, such that another
@@ -2285,9 +2388,9 @@
 %    \begin{macrocode}
   \def\kvt@@colreg##1{%
     \ifinlistcs{##1}{kvt at allcolumns@#1}{}
-      {\kvt at error{Column `##1', referenced in header cell `#2', not known
-        in table type `#1'}{Check the \string\NewKeyValTable{#1} for
-        the names of known columns and check `##1' for a typo.}}%
+      {\kvt at error{Column `##1', referenced in header cell `#2', not
+        known in table type `#1'}{Check the \string\NewKeyValTable{#1}
+        for the names of known columns and check `##1' for a typo.}}%
     \ifcsmacro{kvt@@hdcellof@##1}
       {\kvt at error{Column `##1' used in more than one header cell}
          {Check the fourth, optional argument of \string\NewKeyValTable
@@ -2393,12 +2496,6 @@
 }{%
   \csuse{kvt at EndTable@\cmdkvt at Table@shape}}
 %    \end{macrocode}
-% The following saves the row counter value outside the table
-% environment but still in the then-local scope.
-%    \begin{macrocode}
-\AfterEndEnvironment{KeyValTable}{%
-  \csdef{kvt at rowcount@\kvt@@recenttable}{\thekvtTypeRow}}
-%    \end{macrocode}
 % \end{environment}
 %
 % \begin{macro}{\kvt at SetOptions}
@@ -2434,6 +2531,13 @@
     {\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}
@@ -2447,6 +2551,20 @@
       {\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}
@@ -2458,6 +2576,7 @@
 % 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
@@ -2466,12 +2585,34 @@
         {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}}
@@ -2595,6 +2736,10 @@
   \metatbl at boolprop{hasWidth}{#1}}
 \define at boolkey[metatbl]{EnvProp}{hasCaption}{%
   \metatbl at boolprop{hasCaption}{#1}}
+\define at boolkey[metatbl]{EnvProp}{canVAlign}{%
+  \metatbl at boolprop{canVAlign}{#1}}
+\define at boolkey[metatbl]{EnvProp}{canHAlign}{%
+  \metatbl at boolprop{canHAlign}{#1}}
 \define at cmdkey[metatbl]{EnvProp}{packages}{\metatbl at setprop{pkg}{#1}}
 %    \end{macrocode}
 % The |atEnd| property shall be set to \hologo{TeX} code with one
@@ -2645,6 +2790,8 @@
 % \begin{macro}{\metatblIsTabu}
 % \begin{macro}{\metatblHasWidth}
 % \begin{macro}{\metatblHasCaption}
+% \begin{macro}{\metatblCanVAlign}
+% \begin{macro}{\metatblCanHAlign}
 % The macro
 % |\metatblIsLong|\marg{env-name}\marg{iftrue}\marg{iffalse}
 % expands to \meta{iftrue} if \meta{env-name} is a "long" table
@@ -2666,16 +2813,20 @@
 \newcommand\metatblIsTabu[1]{\ifbool{metatbl at EnvProp@isTabu@#1}}
 \newcommand\metatblHasWidth[1]{\ifbool{metatbl at EnvProp@hasWidth@#1}}
 \newcommand\metatblHasCaption[1]{\ifbool{metatbl at EnvProp@hasCaption@#1}}
+\newcommand\metatblCanVAlign[1]{\ifbool{metatbl at EnvProp@canVAlign@#1}}
+\newcommand\metatblCanHAlign[1]{\ifbool{metatbl at EnvProp@canHAlign@#1}}
 %    \end{macrocode}
 % \end{macro}
 % \end{macro}
 % \end{macro}
 % \end{macro}
+% \end{macro}
+% \end{macro}
 %
 % \begin{macro}{\metatblUsePackage}
 % \begin{macro}{\metatblRequire}
-% The |\metatblUsePackage|\marg{env-names} and
-% |\metatblRequire|\marg{env-names} macros load the packages required
+% Macros |\metatblUsePackage|\marg{env-names} and
+% |\metatblRequire|\marg{env-names} load the packages required
 % for typesetting |KeyValTable| tables based on the table environments
 % listed in \meta{env-names}.
 % The former aims more at normal document use, the second at use by
@@ -2682,10 +2833,12 @@
 % package developers.
 %    \begin{macrocode}
 \newcommand\metatblUsePackage[1]{%
-  \def\do##1{\metatbl at csnamearg\usepackage{metatbl at EnvProp@pkg@##1}}%
+  \def\do##1{%
+    \metatbl at csnamearg\usepackage{metatbl at EnvProp@pkg@##1}}%
   \docsvlist{#1}}
 \newcommand\metatblRequire[1]{%
-  \def\do##1{\metatbl at csnamearg\RequirePackage{metatbl at EnvProp@pkg@##1}}%
+  \def\do##1{%
+    \metatbl at csnamearg\RequirePackage{metatbl at EnvProp@pkg@##1}}%
   \docsvlist{#1}}
 %    \end{macrocode}
 % \end{macro}
@@ -2717,11 +2870,13 @@
 %    \begin{macrocode}
 \metatblRegisterEnv{tabular}{%
   isLong=false, hasWidth=false, isTabu=false, hasCaption=false,
+  canVAlign=true, canHAlign=false,
   packages={},
   atEnd={\preto\endtabular{#1}},
 }
 \metatblRegisterEnv{tabularx}{%
   isLong=false, hasWidth=true, isTabu=false, hasCaption=false,
+  canVAlign=true, canHAlign=false,
   packages=tabularx,
   atEnd={%
 %    \end{macrocode}
@@ -2734,16 +2889,19 @@
 }
 \metatblRegisterEnv{longtable}{%
   isLong=true, hasWidth=false, isTabu=false, hasCaption=true,
+  canVAlign=false, canHAlign=true,
   packages={longtable},
   atEnd={\preto\endlongtable{#1}},
 }
 \metatblRegisterEnv{xltabular}{%
   isLong=true, hasWidth=true, isTabu=false, hasCaption=true,
+  canVAlign=false, canHAlign=true,
   packages=xltabular,
   atEnd={\preto\XLT at ii@TX at endtabularx{\toks@\expandafter{\the\toks@#1}}},
 }
 \metatblRegisterEnv{tabu}{%
   isLong=false, hasWidth=true, isTabu=true, hasCaption=false,
+  canVAlign=true, canHAlign=false,
   packages={tabu},
 %    \end{macrocode}
 % The following is not a mistake: |tabu| does
@@ -2753,6 +2911,7 @@
 }
 \metatblRegisterEnv{longtabu}{%
   isLong=true, hasWidth=true, isTabu=true, hasCaption=true,
+  canVAlign=false, canHAlign=true,
   packages={tabu,longtable},
 %    \end{macrocode}
 % The following is not a mistake: |tabu| does
@@ -2790,7 +2949,7 @@
 % When an |X| column is encountered, |\metatbl@@branch| is redefined to
 % expand to \meta{iftrue} in the end.
 %    \begin{macrocode}
-  \def\NC at rewrite@X{\def\metatbl@@branch{\@firstoftwo}\NC at find}%
+  \def\NC at rewrite@X{\def\metatbl@@branch{\@firstoftwo}\NC at find l}%
   \@mkpream{#1}%
   \expandafter\endgroup\metatbl@@branch}
 %    \end{macrocode}
@@ -2858,6 +3017,39 @@
   \ifbool{kvt at Row@uncounted}{}{%
     \appto\kvt@@row{\noalign{\kvt at stepcounters}}}%
 %    \end{macrocode}
+% If a row alignment is specified, a default |\multicolumn| display is
+% enabled for the row's cells.
+%    \begin{macrocode}
+  \ifdefvoid\cmdkvt at Row@align
+    {\let\kvt@@rowmkmulticolumn\@empty}
+    {\edef\kvt@@rowmkmulticolumn{%
+       \noexpand\multicolumn{1}{\expandonce\cmdkvt at Row@align}}}%
+%    \end{macrocode}
+% The following defines a macro
+% |\kvt@@cellfmtbuilder|\marg{cmd}\marg{csname}.
+% This macro defines the macro \meta{cmd}\marg{cell} to format the cell
+% content, \meta{cell}, based on the column format \meta{csname} and the
+% row formatting options.
+% Through this "builder" macro, the row format options need only be
+% considered once and the column format options can then be included
+% when the displayed columns are iterated over. 
+%    \begin{macrocode}
+  \ifcsvoid{cmdkvt at Row@format!}
+    {\edef\kvt@@cellfmtbuilder##1##2{%
+       \noexpand\edef##1####1{%
+         \noexpand\kvt at expandonce@onearg\noexpand\kvt@@mkmulticolumn
+         {\ifcsvoid{cmdkvt at Row@format*}{\@firstofone}
+           {\noexpand\unexpanded{\csexpandonce{cmdkvt at Row@format*}}}%
+         {\noexpand\csexpandonce{##2}{%
+             \ifdefvoid\cmdkvt at Row@format{\@firstofone}
+               {\noexpand\unexpanded{\expandonce\cmdkvt at Row@format}}%
+              {####1}}}}}}}%
+    {\edef\kvt@@cellfmtbuilder##1##2{%
+      \noexpand\edef##1####1{%
+        \noexpand\kvt at expandonce@onearg\noexpand\kvt@@mkmulticolumn{%
+          \noexpand\unexpanded{\csexpandonce{cmdkvt at Row@format!}}%
+            {####1}}}}}%
+%    \end{macrocode}
 % The following loop uses |\do|\marg{cname} to append the content of
 % all displayed columns (in the given format and using the given default
 % value), where each column value is in
@@ -2867,50 +3059,70 @@
 % \changes{v1.0}{2019/02/03}{Added \cs{multicolumn} support}
 %    \begin{macrocode}
   \kvt@@span=0\relax
+  \kvt at def@atseconduse\kvt@@switchcol{\appto\kvt@@row{&}}%
   \def\do##1{%
 %    \end{macrocode}
+% First, check whether a column-spanning cell is active
+% ($\cs{kvt@@span}>0$). If this is the case, ensure that if the raw cell
+% content in the current column is empty, then the column is simply
+% ignored and otherwise an error is produced.
+%    \begin{macrocode}
+    \ifnumgreater\kvt@@span{0}
+      {\advance\kvt@@span\m at ne
+       \ifcsvoid{cmdKeyValTable@#2@##1}{}
+         {\ifdefvoid\kvt@@curcgname
+           {\kvt at error{Column '##1' nonempty inside a
+                       \string\multicolumn}{}}
+           {\kvt at error{Column '##1' nonempty inside column group
+                       '\kvt@@curcgname'}{}}}}
+      {\kvt@@switchcol
+%    \end{macrocode}
+% Initialize the multicolumn display to the row's default.
+%    \begin{macrocode}
+       \let\kvt@@mkmulticolumn\kvt@@rowmkmulticolumn
+       \letcs\kvt@@curcolformat{kvt at col@format@#2@##1}%
+%    \end{macrocode}
 % First recover the cell content (either the specified value for the row
 % or, if no value is specified for the row, the cell's default value)
 % without formatting.
 %    \begin{macrocode}
-    \ifcsvoid{cmdKeyValTable@#2@##1}
-      {\letcs\kvt@@cell{kvt at col@default@#2@##1}}
-      {\letcs\kvt@@cell{cmdKeyValTable@#2@##1}%
+       \ifcsvoid{cmdKeyValTable@#2@##1}
+         {\letcs\kvt@@cell{kvt at col@default@#2@##1}}
+         {\letcs\kvt@@cell{cmdKeyValTable@#2@##1}%
 %    \end{macrocode}
+% Unless the default cell value is used, first check for a multicolumn
+% value. Default cell values should not need this. The check is done
+% before the expansion code afterwards, in order for applying the
+% expansion to the code in the cell value rather than to the multicolumn
+% code.
+%    \begin{macrocode}
+          \expandafter\kvt at CheckMulticolumn\expandafter{\kvt@@cell}{#2}%
+%    \end{macrocode}
 % Apply expansion control options, but only to manually supplied cell
 % values, not to default values.
 %    \begin{macrocode}
-       \ifbool{kvt at Row@expandonce}
-         {\expandafter\let\expandafter\kvt@@cell\kvt@@cell}{}%
-       \ifbool{kvt at Row@expand}
-         {\protected at edef\kvt@@cell{\kvt@@cell}}{}}%
+          \ifbool{kvt at Row@expandonce}
+            {\expandafter\let\expandafter\kvt@@cell\kvt@@cell}{}%
+          \ifbool{kvt at Row@expand}
+            {\protected at edef\kvt@@cell{\kvt@@cell}}{}}%
 %    \end{macrocode}
-% Separately also already create the formatted content.
+% Separately also already create the content -- with formatting unless
+% the user explicitly requested no cell formatting.
 %    \begin{macrocode}
-    \ifcsvoid{kvt@@noformat@#2@##1}
-      {\edef\kvt@@formatter{\expandonce{\csname kvt at col@format@#2@##1\endcsname}}}%
-      {\def\kvt@@formatter{\@firstofone}}%
-    \edef\kvt@@fmtcell{\expandonce\kvt@@formatter{%
-      \expandonce\kvt@@cell}}%
-    \csundef{kvt@@noformat@#2@##1}%
+       \ifcsvoid{kvt@@noformat@#2@##1}
+         {\kvt@@cellfmtbuilder\kvt@@formatter{kvt@@curcolformat}}%
+         {\let\kvt@@formatter\@firstofone}%
+       \csundef{kvt@@noformat@#2@##1}%
+       \edef\kvt@@fmtcell{\expandafter\expandonce\expandafter{%
+         \expandafter\kvt@@formatter\expandafter{%
+           \kvt@@cell}}}%
 %    \end{macrocode}
-% Next, check whether a column-spanning cell is active
-% ($\cs{kvt@@span}>0$). If this is the case, ensure that if the raw cell
-% content in the current column is empty, then formatting does not make
-% the cell non-empty and, thereby, cause errors with the active
-% column-spanning cell.
+% Finally, append the cell to the row.
 %    \begin{macrocode}
-    \ifnumgreater\kvt@@span{0}
-      {\advance\kvt@@span\m at ne
-       \ifstrempty\kvt@@cell{\def\kvt@@fmtcell{}}{}}
-      {\appto\kvt@@row{&}}%
-%    \end{macrocode}
-% Now check whether the cell itself spans multiple columns.
-%    \begin{macrocode}
-    \expandafter\kvt at CheckMulticolumn\kvt@@cell
-      \relax\relax\relax\relax\@undefined
-    \expandafter\appto\expandafter\kvt@@row\expandafter{\kvt@@fmtcell}%
+       \expandafter\appto\expandafter\kvt@@row\expandafter{%
+         \kvt@@fmtcell}}%
   }\dolistcsloop{kvt at displaycols@#2}%
+  \undef\kvt@@cellfmtbuilder
 %    \end{macrocode}
 % Finally, add the concluding newline for the row as well as
 % the vertical space after the row, if requested.
@@ -2926,6 +3138,36 @@
 %    \end{macrocode}
 % \end{macro}
 %
+% \begin{macro}{\kvt at def@atseconduse}
+% The |\kvt at def@atseconduse|\marg{cmd}\marg{code} defines the macro
+% \meta{cmd} to expand to \meta{code} but only from its second use
+% onwards. At its first use, \meta{cmd} only redefines itself to
+% \meta{code} but does not do anything else.
+%    \begin{macrocode}
+\newcommand\kvt at def@atseconduse[2]{\def#1{\def#1{#2}}}
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\kvt at expandonce@onearg}
+% The |\kvt at expandonce@onearg|\marg{cmd}\marg{arg} macro expands to
+% \meta{arg} if \meta{cmd} is empty and expands to an |\expandonce| on
+% \meta{cmd} with \meta{arg} as argument otherwise.
+% This macro is for an |\edef| context in which an empty \meta{cmd}
+% should not leave any parentheses around the \meta{arg}.
+%    \begin{macrocode}
+\newcommand\kvt at expandonce@onearg[2]{%
+  \ifdefequal{#1}{\@empty}{#2}{\expandonce{#1}{#2}}}
+%    \end{macrocode}
+% Note that the alternative of avoiding the conditional (|\ifdefequal|)
+% in the above code and using |\@firstofone| instead of |\@empty| for a
+% noop in \meta{cmd} does not work:
+% Using `|\expandonce|\marg{cmd}\marg{arg}' would expand to
+% `|\unexpanded\expandafter{\@firstofone}|' and produces the error
+% `Argument of |\@firstofone| has an extra |}|'.
+% Using `|\expandonce{|\meta{cmd}\marg{arg}|}|' would expand to
+% `|\unexpanded|\marg{arg}' and, thus, prevent expansion of \meta{arg}.
+% \end{macro}
+%
 % \begin{macro}{\kvt at stepcounters}
 % The |\kvt at stepcounters|\oarg{delta} macro increments all row counters
 % by \meta{delta}. If \meta{delta} is omitted, \meta{delta}=1.
@@ -2939,30 +3181,94 @@
 %
 % \begin{macro}{\kvt at CheckMulticolumn}
 % The
-% |\kvt at CheckMulticolumn|\marg{arg1}\marg{arg2}\marg{arg3}\marg{arg4}|\@undefined|
-% macro checks whether a cell's initial content (captured by \meta{arg1}
-% to \meta{arg4}, starts a multi-column cell. If this is the case, the
-% macro records the arguments to |\multicolumn| for use by
-% |\kvt at AddKeyValRow|.
-% In this case, \meta{arg1}=|\multicolumn|, \meta{arg2}=\meta{n} (number
-% of columns to span), \meta{arg3}=\meta{format} (column alignment), and
-% \meta{arg4}=\meta{item} (the content of the cell).
+% |\kvt at CheckMulticolumn|\marg{content}\marg{tname} macro
+% checks whether a cell's \meta{content} in a table of type \meta{tname}
+% spans multiple columns in one of two ways:
+% \begin{enumerate}[nosep]
+% \item \meta{content} = |\multicolumn|\marg{n}\marg{align}\marg{content} or
+% \item \meta{content} = |\kvt@@@colgroup|\marg{cgname}\marg{n}\marg{align}\marg{content}
+% \end{enumerate}
+% The first way corresponds to the case that a user of the package
+% explicitly assigns a |\multicolumn| expression to a cell in a row.
+% The second way is generated by the package when a user assigns a
+% normal cell value to a column group key.
 %    \begin{macrocode}
-\def\kvt at CheckMulticolumn#1#2#3#4\@undefined{%
-  \ifx#1\multicolumn
+\newcommand\kvt at CheckMulticolumn[2]{%
 %    \end{macrocode}
+% For parsing \meta{content}, the macro uses |\kvt at CheckMulticolumn@i|
+% and adds 5 |\relax| after \meta{content} for the case that
+% \meta{content} is empty or too short.
+%    \begin{macrocode}
+  \kvt at CheckMulticolumn@i{#2}#1%
+    \relax\relax\relax\relax\relax\kvt@@undefined}
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\kvt at CheckMulticolumn@i}
+% The
+% |\kvt at CheckMulticolumn@i|\marg{tname}\marg{c1}$\cdots$\marg{c5}\marg{ign}|\@undefined|
+% macro checks \meta{content} when split into \meta{c1}$\cdots$\meta{c5}
+% for one of the two multicolumn cases listed in the description of
+% |\kvt at CheckMulticolumn|.
+%    \begin{macrocode}
+\def\kvt at CheckMulticolumn@i#1#2#3#4#5#6#7\kvt@@undefined{%
+  \ifdefmacro{#2}{%
+%    \end{macrocode}
+% First case: \meta{c1}=|\multicolumn|. In this case, we have
+% \meta{c2}=\meta{n}, \meta{c3}=\meta{align}, and
+% \meta{c4}=\meta{content}.
+%    \begin{macrocode}
+    \ifx#2\multicolumn
+      \kvt at SetMulticolumn{#4}{#3}{#5}%
+      \let\kvt@@curcgname\@empty
+%    \end{macrocode}
+% Second case: \meta{c1}=|\kvt@@@colgroup|. In this case, we have
+% \meta{c3}=\meta{n}, \meta{c4}=\meta{align}, and
+% \meta{c5}=\meta{content}. Moreover, \meta{c2} holds \meta{cgname}.
+%    \begin{macrocode}
+    \else\ifx#2\kvt@@@colgroup
+      \letcs\kvt@@curcolformat{kvt at colgrp@format@#1@#3}%
+      \def\kvt@@curcgname{#3}%
+%    \end{macrocode}
+% If a row alignment is defined, it overrides the alignment of the
+% column group:
+%    \begin{macrocode}
+      \ifdefvoid\cmdkvt at Row@align
+        {\kvt at SetMulticolumn{#5}{#4}{#6}}
+        {\expandafter
+         \kvt at SetMulticolumn\expandafter{\cmdkvt at Row@align}{#4}{#6}}%
+    \fi\fi}{}}
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\kvt@@@colgroup}
+% The |\kvt@@@colgroup| macro is not used as an actual macro but only as
+% an identifier for |\kvt at CheckMulticolumn@i|.
+%    \begin{macrocode}
+\newcommand\kvt@@@colgroup{kvt@@@colgroup}
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\kvt at SetMulticolumn}
+% The |\kvt at SetMulticolumn|\marg{align}\marg{n}\marg{content} records
+% that \meta{n} cells, starting from the current cell, belong to a
+% multicolumn cell with alignment \meta{align} and the given
+% \meta{content}.
+%    \begin{macrocode}
+\newcommand\kvt at SetMulticolumn[3]{%
+%    \end{macrocode}
 % First, record \meta{n} in |\kvt@@span|. The subtraction of $-1$ is
 % already in preparation for the next column, in which one spanning has
 % already been reduced.
 %    \begin{macrocode}
-    \kvt@@span=#2\relax \advance\kvt@@span\m at ne
+  \kvt@@span=#2\relax \advance\kvt@@span\m at ne
 %    \end{macrocode}
-% Second, move the defined cell format to inside of the \meta{item}
-% argument of |\multicolumn| rather than around the |\multicolumn|.
+% Next, unwrap the cell's \meta{content} to |\kvt@@cell| and record the
+% |\kvt@@mkmulticolumn| for re-wrapping the content later, after all
+% cell formatting has been applied.
 %    \begin{macrocode}
-    \edef\kvt@@fmtcell{\unexpanded{\multicolumn{#2}{#3}}%
-      {\expandonce\kvt@@formatter{\expandonce{#4}}}}%
-  \fi}
+  \def\kvt@@cell{#3}%
+  \def\kvt@@mkmulticolumn{\multicolumn{#2}{#1}}}
 %    \end{macrocode}
 % \end{macro}
 %
@@ -3015,12 +3321,18 @@
 %    \begin{macrocode}
 \newcommand\kvt at UseRowStyles[1]{%
 %    \end{macrocode}
-% We use |\kvt at xkv@disablepreset| to eliminate undesired effects from
-% presets. When, for example, using |\Row[bg=red,style=abc]{...}|, this
-% causes a |\setkeys[kvt]{Row}{xyz}| (if |xyz| is how the style |abc| is
-% defined) inside the |\setkeys[kvt]{Row}{bg=red,style=abc}|. The former
+% 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
+% defined as "|hidden=false|". Then,
+%   |\Row[bg=red,style=vis]{...}|
+% causes a
+%   |\setkeys[kvt]{Row}{hidden=false}|
+% to be processed inside the |\setkeys[kvt]{Row}{bg=red,style=vis}|,
+% after the |bg=red| is processed.
+% The former
 % |\setkeys| would then again employ the presets for |Row| (e.g., from a
-% |\kvtSet{Row/bg=blue}| and overwrite the |bg=red|.
+% |\kvtSet{Row/bg=blue}|) and undesirably overwrite the |bg=red|.
 %    \begin{macrocode}
   \kvt at xkv@disablepreset[kvt]{Row}{%
     \forcsvlist\kvt at UseRowStyle{#1}}}
@@ -3028,17 +3340,9 @@
 % \end{macro}
 %
 % \begin{macro}{\kvt at xkv@disablepreset}
-% \begin{macro}{\kvt at xkv@savepreset}
-% \begin{macro}{\kvt at xkv@restorepreset}
 % The |\kvt at xkv@disablepreset|\oarg{prefix}\marg{family}\marg{code}
-% disables presets (head and tail) for \meta{family} during the
+% disables head presets and tail presets for \meta{family} during the
 % expansion of \meta{code}.
-% The auxiliary macros
-% |\kvt at xkv@savepreset|\marg{prefix}\marg{family}\marg{h/t}
-% and
-% |\kvt at xkv@restorepreset|\marg{prefix}\marg{family}\marg{h/t}
-% save+unset and, respectively, restore the preset keys for
-% \meta{family} -- head keys for \meta{h/t}=h and tail keys otherwise.
 %    \begin{macrocode}
 \newcommand\kvt at xkv@disablepreset[3][KV]{%
   \ifnumgreater{\XKV at depth}{1}
@@ -3048,6 +3352,17 @@
      #3%
      \kvt at xkv@restorepreset{#1}{#2}{h}%
      \kvt at xkv@restorepreset{#1}{#2}{t}}}
+%    \end{macrocode}
+% \end{macro}
+% \begin{macro}{\kvt at xkv@savepreset}
+% \begin{macro}{\kvt at xkv@restorepreset}
+% The auxiliary macro
+% |\kvt at xkv@savepreset|\marg{prefix}\marg{family}\marg{h/t}
+% saves and unsets the preset keys (head keys for \meta{h/t}=h and tail
+% keys otherwise) for \meta{family}. The macro
+% |\kvt at xkv@restorepreset|\marg{prefix}\marg{family}\marg{h/t}
+% restores the preset keys saved via |\kvt at xkv@savepreset|.
+%    \begin{macrocode}
 \newcommand\kvt at xkv@savepreset[3]{%
   \csletcs{kvt@@saved at preset#3}{XKV@#1@#2 at preset#3}%
   \csundef{XKV@#1@#2 at preset#3}}
@@ -3056,7 +3371,6 @@
 %    \end{macrocode}
 % \end{macro}
 % \end{macro}
-% \end{macro}
 %
 % \subsection{Collecting Key-Value Table Content}
 %
@@ -3113,7 +3427,7 @@
 % \end{macro}
 %
 % \begin{macro}{\kvt at protected@write}
-% The |\kvt at protected@write|\marg{file}{content} macro writes
+% The |\kvt at protected@write|\marg{file}\marg{content} macro writes
 % \meta{content} to \meta{file}. The write ensures that \meta{content}
 % is written in a particularly protected form that
 % \begin{enumerate}[noitemsep]
@@ -3322,9 +3636,10 @@
 %
 % \begin{macro}{\ShowKeyValTableFile}
 % The |\ShowKeyValTableFile|\oarg{options}\marg{tname}\marg{filename}
-% macro typesets a |KeyValTable| environment of type \meta{tname} with
-% the given \meta{options}. The body of the environment (i.e., the rows
-% of the table) are read from the file \meta{filename}.
+% loads the content of the file with name \meta{filename} and places it
+% inside the body of a |KeyValTable| environment of type \meta{tname} with
+% the given \meta{options}. That is, the filename should contain the rows
+% of the table.
 % \changes{v2.0}{2019/03/25}{Added the macro}
 %    \begin{macrocode}
 \newcommand\ShowKeyValTableFile[3][]{%
@@ -3436,7 +3751,7 @@
 % received a key-value syntax.
 %    \begin{macrocode}
 \kvt at IfVersion{<}{2.0}{%
-  \let\kvt at parselayout=\kvt at parseheadrows
+  \renewcommand\kvt at parselayout[2]{\kvt at parseheadrows{#2}{#1}}%
 }{}
 %    \end{macrocode}
 %

Modified: trunk/Master/texmf-dist/source/latex/keyvaltable/keyvaltable.ins
===================================================================
--- trunk/Master/texmf-dist/source/latex/keyvaltable/keyvaltable.ins	2020-02-21 22:54:05 UTC (rev 53860)
+++ trunk/Master/texmf-dist/source/latex/keyvaltable/keyvaltable.ins	2020-02-21 22:54:25 UTC (rev 53861)
@@ -1,5 +1,5 @@
 %%
-%% Copyright (C) 2016-2018 by Richard Grewe <r-g+tex at posteo.net>
+%% Copyright (C) 2016-2020 by Richard Grewe <r-g+tex at posteo.net>
 %%
 %% This file may be distributed and/or modified under the conditions of
 %% the LaTeX Project Public License, either version 1.2 of this license
@@ -17,7 +17,7 @@
 \usedir{tex/latex/keyvaltable}
 \preamble
 
-Copyright (C) 2016-2018 by Richard Grewe <r-g+tex at posteo.net>
+Copyright (C) 2016-2020 by Richard Grewe <r-g+tex at posteo.net>
 
 This file may be distributed and/or modified under the conditions of
 the LaTeX Project Public License, either version 1.2 of this license

Modified: trunk/Master/texmf-dist/tex/latex/keyvaltable/keyvaltable.sty
===================================================================
--- trunk/Master/texmf-dist/tex/latex/keyvaltable/keyvaltable.sty	2020-02-21 22:54:05 UTC (rev 53860)
+++ trunk/Master/texmf-dist/tex/latex/keyvaltable/keyvaltable.sty	2020-02-21 22:54:25 UTC (rev 53861)
@@ -6,7 +6,7 @@
 %%
 %% keyvaltable.dtx  (with options: `package')
 %% 
-%% Copyright (C) 2016-2018 by Richard Grewe <r-g+tex at posteo.net>
+%% Copyright (C) 2016-2020 by Richard Grewe <r-g+tex at posteo.net>
 %% 
 %% This file may be distributed and/or modified under the conditions of
 %% the LaTeX Project Public License, either version 1.2 of this license
@@ -20,7 +20,7 @@
 %% 
 \NeedsTeXFormat{LaTeX2e}[1999/12/01]
 \ProvidesPackage{keyvaltable}
-    [2019/05/11 v2.0 Package for filling tables using key-value lists]
+    [2020/02/19 v2.1 Package for filling tables using key-value lists]
 \RequirePackage{etoolbox}
 \RequirePackage{xkeyval}
 \RequirePackage{trimspaces}
@@ -37,6 +37,8 @@
   \expandafter\kvt at setkeys\expandafter{#1}{#2}}
 \newcommand\kvt at setcskeys[2]{%
   \expandafter\kvt at setcmdkeys\expandafter{\csname #1\endcsname}{#2}}
+\newcommand\kvt at setkeys@nopresets[2]{%
+  \kvt at xkv@disablepreset[kvt]{#2}{\kvt at setkeys{#1}{#2}}}
 \newcommand\kvt at colsetkeys[2]{\setkeys[KeyValTable]{#1}{#2}}
 \newcommand\kvt at colsetcmdkeys[2]{%
   \expandafter\kvt at colsetkeys\expandafter{#1}{#2}}
@@ -57,10 +59,6 @@
 \newcommand\kvtTableOpt[1]{\csname cmdkvt at Table@#1\endcsname}
 \define at cmdkey[kvt]{Table}{rowbg}{}
 \define at cmdkey[kvt]{Table}{headbg}{}
-\define at boolkey[kvt]{Table}{norowbg}[true]{%
-  \kvt at setkeys{rowbg={}}{Table}}
-\define at key[kvt]{Table}{nobg}[true]{%
-  \kvt at setkeys{rowbg={},headbg={}}{Table}}
 \define at cmdkey[kvt]{Table}{headalign}{}
 \define at cmdkey[kvt]{Table}{headformat}{}
 \define at cmdkey[kvt]{Table}{width}{}
@@ -68,7 +66,18 @@
 \define at boolkey[kvt]{Table}{showrules}{}
 \define at cmdkey[kvt]{Table}{caption}{}
 \define at cmdkey[kvt]{Table}{label}{}
-
+\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 boolkey[kvt]{Table}{norowbg}[true]{%
+  \kvt at setkeys{rowbg={}}{Table}}
+\define at boolkey[kvt]{Table}{nobg}[true]{%
+  \kvt at setkeys{rowbg={},headbg={}}{Table}}
+\define at boolkey[kvt]{Table}{norules}[true]{%
+  \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}
   {\csdef{cmdkvt at Table@shape}{#1}}
@@ -86,11 +95,11 @@
 \newcommand\kvt at def@globalopts[2]{%
   \forcsvlist{\kvt at def@globalopt{#1}}{#2}}
 \define at cmdkey[kvt]{ColGroup}{span}{%
-  \csdef{kvt at colgrp@span@\kvt@@colgrp}{#1}}
+  \csgdef{kvt at colgrp@span@\kvt@@tname @\kvt@@colgrp}{#1}}
 \define at cmdkey[kvt]{ColGroup}{align}{%
-  \csdef{kvt at colgrp@align@\kvt@@colgrp}{#1}}
+  \csgdef{kvt at colgrp@align@\kvt@@tname @\kvt@@colgrp}{#1}}
 \define at cmdkey[kvt]{ColGroup}{format}{%
-  \csdef{kvt at colgrp@format@\kvt@@colgrp}{#1}}
+  \csgdef{kvt at colgrp@format@\kvt@@tname @\kvt@@colgrp}{#1}}
 \kvt at def@globalopts{ColGroup}{align, format}
 \define at cmdkey[kvt]{Layout}{headers}{%
   \expandafter\kvt at parseheadrows\expandafter{\kvt@@tname}{#1}}
@@ -102,11 +111,23 @@
   \csdef{kvt@@hdcell at align@\kvt@@hdcell}{#1}}
 \kvt at def@globalopts{HeadCell}{align}
 \define at cmdkey[kvt]{Row}{bg}{}
+\define at cmdkey[kvt]{Row}{format}{}
+\define at cmdkey[kvt]{Row}{format*}{}
+\define at cmdkey[kvt]{Row}{format!}{}
+\define at cmdkey[kvt]{Row}{align}{}
+\define at boolkey[kvt]{Row}{headlike}[true]{%
+  \ifbool{#1}{%
+    \edef\kvt@@opts{%
+      bg={\expandonce\cmdkvt at Table@headbg},%
+      format!={\expandonce\cmdkvt at Table@headformat},%
+      align={\expandonce\cmdkvt at Table@headalign}}%
+    \expandafter\kvt at setkeys@nopresets\expandafter{\kvt@@opts}{Row}%
+  }{}}
 \define at boolkey[kvt]{Row}{hidden}[true]{}
 \define at cmdkey[kvt]{Row}{below}{}
 \define at cmdkey[kvt]{Row}{above}{}
 \define at key[kvt]{Row}{around}{%
-  \kvt at setkeys{below={#1},above={#1}}{Row}}
+  \kvt at setkeys@nopresets{below={#1},above={#1}}{Row}}
 \define at key[kvt]{Row}{style}{\kvt at UseRowStyles{#1}}
 \define at boolkey[kvt]{Row}{uncounted}[true]{}
 \define at boolkey[kvt]{Row}{expand}[true]{}
@@ -151,12 +172,12 @@
       \string\NewKeyValTable}}{}%
   \csdef{kvt at options@#2}{#1}%
   \csdef{kvt at headings@#2}{}%
-  \csedef{kvt at alignments@#2}{p{0pt}\expandonce\kvt at HackIntercolSpace}%
+  \csdef{kvt at alignments@#2}{}%
   \csdef{kvt at allcolumns@#2}{}%
   \csdef{kvt at displaycols@#2}{}%
   \csdef{kvt at rowcount@#2}{0}%
   \csdef{kvt at rows@#2}{}%
-  \csdef{kvt at headings@#2}{\kvt at defaultheader}
+  \csdef{kvt at headings@#2}{\kvt at defaultheader}%
   \listadd\kvt at alltables{#2}%
   \def\do##1{%
     \kvt at parsecolspec{#2}##1::\@undefined}%
@@ -193,21 +214,19 @@
   \undef\kvt@@column}
 \newcommand\kvt at defaultheader{%
   \noexpand\kvt at rowcolorornot{\cmdkvt at Table@headbg}%
-  \kvt at defaultheader@i}
-\newcommand\kvt at defaultheader@i[1]{%
-  \kvt at ifnil{#1}{\noexpand\tabularnewline}{%
-    \unexpanded{&}%
+  \kvt at defaultheader@i{}}
+\newcommand\kvt at defaultheader@i[2]{%
+  \kvt at ifnil{#2}{\noexpand\tabularnewline}{%
+    \unexpanded{#1}%
     \ifdefvoid\cmdkvt at Table@headalign
-      {\expandonce\cmdkvt at Table@headformat{\unexpanded{#1}}}
+      {\expandonce\cmdkvt at Table@headformat{\unexpanded{#2}}}
       {\noexpand\multicolumn{1}{\expandonce\cmdkvt at Table@headalign}
-        {\expandonce\cmdkvt at Table@headformat{\unexpanded{#1}}}}%
-    \kvt at defaultheader@i}}
+        {\expandonce\cmdkvt at Table@headformat{\unexpanded{#2}}}}%
+    \kvt at defaultheader@i{&}}}
 \newcommand\kvt at ifnil[1]{%
   \ifx\@nil#1\relax
     \expandafter\@firstoftwo\else
     \expandafter\@secondoftwo\fi}
-\newcommand\kvt at HackIntercolSpace{%
-  @{\hspace{-.5\arrayrulewidth}}}
 \newcommand\kvt at alltables{}
 \newcommand\kvt at parselayout[2]{%
   \def\kvt@@tname{#2}%
@@ -231,18 +250,20 @@
      columns groups.}}{}%
   \def\kvt@@colgrp{#2}%
   \kvt at setkeys{#3}{ColGroup}%
-  \kvt at checkcolgroupcs{kvt at colgrp@span@\kvt@@colgrp}{#1}{#2}%
+  \kvt at checkcolgroupcs{kvt at colgrp@span@#1@#2}{#1}{#2}%
   \eappto\kvt@@result{%
     \noexpand\define at cmdkey[KeyValTable]{#1}{#2}{%
       \ifdefvoid\kvt@@colgrp at first{}{%
-        \noexpand\setkeys[KeyValTable]{#1}{%
-          \expandonce\kvt@@colgrp at first*=\noexpand\multicolumn
-            {\expandonce\kvt@@colgrp at n}%
-            {\csexpandonce{kvt at colgrp@align@#2}}%
-            {\csexpandonce{kvt at colgrp@format@#2}{\unexpanded{##1}}}}%
+        \noexpand\kvt at xkv@disablepreset[KeyValTable]{#1}{%
+          \noexpand\setkeys[KeyValTable]{#1}{%
+            \expandonce\kvt@@colgrp at first=\noexpand\kvt@@@colgroup
+              {\unexpanded{#2}}%
+              {\expandonce\kvt@@colgrp at n}%
+              {\csexpandonce{kvt at colgrp@align@#1@#2}}%
+              {\unexpanded{##1}}}}%
       }%
-    }%
-    \noexpand\listcsadd{kvt at grpcolkeys@#1}{#2}}}
+    }}%
+    \listcsadd{kvt at grpcolkeys@#1}{#2}}
 \newcommand\kvt at checkcolgroup[3]{%
   \def\kvt@@psvdo##1{%
     \ifinlistcs{##1}{kvt at allcolumns@#2}{}{\kvt at error
@@ -271,7 +292,8 @@
           {Compare `\string\kvt@@curgrp' to the column ordering as
            specified in `\string\NewKeyValTable{#1}'}%
         \fi
-        \edef\kvt@@colgrp at n{\the\numexpr\kvt@@colgrp at n+1\relax}}%
+        \edef\kvt@@colgrp at n{\the\numexpr\kvt@@colgrp at n+1\relax}%
+        \csundef{kvt@@incolgrp@##1}}%
   }\forlistcsloop{\kvt@@coldo}{kvt at displaycols@#2}}
 \newcommand\kvt at checkcolgroupcs[3]{%
   \expandafter\expandafter\expandafter
@@ -303,6 +325,7 @@
   \let\kvt@@tmpgrphd\@empty
   \kvt@@span\z@
   \undef\kvt@@curhd \undef\kvt@@lasthd
+  \kvt at def@atseconduse\kvt@@switchcol{\appto\kvt@@tmpgrphd{&}}%
   \def\do##1{\letcs\kvt@@curhd{kvt@@hdcellof@##1}%
     \ifdefequal\kvt@@curhd\kvt@@lasthd
       {\advance\kvt@@span\@ne}%
@@ -323,23 +346,19 @@
 \newcommand\kvt at rowcolorornot[1]{\ifstrempty{#1}{}{\rowcolor{#1}}}
 \newcount\kvt@@span
 \newcommand\kvt at concludecolumn{%
-  \ifdefequal\kvt@@tmpgrphd\@empty
-    {\let\kvt@@extraalign\kvt at HackIntercolSpace}
-    {\let\kvt@@extraalign\@empty}%
-  \appto\kvt@@tmpgrphd{&}%
+  \kvt@@switchcol
   \ifdefvoid\kvt@@lasthd{}{%
     \eappto\kvt@@tmpgrphd{\noexpand\multicolumn
       {\the\kvt@@span}
-      {\expandonce\kvt@@extraalign
-       \csexpandonce{kvt@@hdcell at align@\kvt@@lasthd}}
+      {\csexpandonce{kvt@@hdcell at align@\kvt@@lasthd}}
       {\csexpandonce{kvt@@hdcell at head@\kvt@@lasthd}}}%
     \cslet{kvt@@hdcelldone@\kvt@@lasthd}{\@ne}}}
 \def\kvt at parsehdcolspec#1#2:#3:#4\@undefined{%
   \def\kvt@@colreg##1{%
     \ifinlistcs{##1}{kvt at allcolumns@#1}{}
-      {\kvt at error{Column `##1', referenced in header cell `#2', not known
-        in table type `#1'}{Check the \string\NewKeyValTable{#1} for
-        the names of known columns and check `##1' for a typo.}}%
+      {\kvt at error{Column `##1', referenced in header cell `#2', not
+        known in table type `#1'}{Check the \string\NewKeyValTable{#1}
+        for the names of known columns and check `##1' for a typo.}}%
     \ifcsmacro{kvt@@hdcellof@##1}
       {\kvt at error{Column `##1' used in more than one header cell}
          {Check the fourth, optional argument of \string\NewKeyValTable
@@ -367,8 +386,6 @@
   \csuse{kvt at StartTable@\cmdkvt at Table@shape}{#2}%
 }{%
   \csuse{kvt at EndTable@\cmdkvt at Table@shape}}
-\AfterEndEnvironment{KeyValTable}{%
-  \csdef{kvt at rowcount@\kvt@@recenttable}{\thekvtTypeRow}}
 \newcommand\kvt at SetOptions[2]{%
   \begingroup\edef\kvt@@do{\endgroup\noexpand%
     \kvt at setkeys{\csexpandonce{kvt at options@#1},\unexpanded{#2}}{Table}%
@@ -380,6 +397,8 @@
     {\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}%
@@ -389,6 +408,16 @@
            \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
@@ -398,11 +427,16 @@
         {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}
@@ -451,6 +485,10 @@
   \metatbl at boolprop{hasWidth}{#1}}
 \define at boolkey[metatbl]{EnvProp}{hasCaption}{%
   \metatbl at boolprop{hasCaption}{#1}}
+\define at boolkey[metatbl]{EnvProp}{canVAlign}{%
+  \metatbl at boolprop{canVAlign}{#1}}
+\define at boolkey[metatbl]{EnvProp}{canHAlign}{%
+  \metatbl at boolprop{canHAlign}{#1}}
 \define at cmdkey[metatbl]{EnvProp}{packages}{\metatbl at setprop{pkg}{#1}}
 \define at key[metatbl]{EnvProp}{atEnd}{\metatbl at setprop[1]{atEnd}{#1}}
 \newrobustcmd\metatblRegisterEnv[2]{%
@@ -466,11 +504,15 @@
 \newcommand\metatblIsTabu[1]{\ifbool{metatbl at EnvProp@isTabu@#1}}
 \newcommand\metatblHasWidth[1]{\ifbool{metatbl at EnvProp@hasWidth@#1}}
 \newcommand\metatblHasCaption[1]{\ifbool{metatbl at EnvProp@hasCaption@#1}}
+\newcommand\metatblCanVAlign[1]{\ifbool{metatbl at EnvProp@canVAlign@#1}}
+\newcommand\metatblCanHAlign[1]{\ifbool{metatbl at EnvProp@canHAlign@#1}}
 \newcommand\metatblUsePackage[1]{%
-  \def\do##1{\metatbl at csnamearg\usepackage{metatbl at EnvProp@pkg@##1}}%
+  \def\do##1{%
+    \metatbl at csnamearg\usepackage{metatbl at EnvProp@pkg@##1}}%
   \docsvlist{#1}}
 \newcommand\metatblRequire[1]{%
-  \def\do##1{\metatbl at csnamearg\RequirePackage{metatbl at EnvProp@pkg@##1}}%
+  \def\do##1{%
+    \metatbl at csnamearg\RequirePackage{metatbl at EnvProp@pkg@##1}}%
   \docsvlist{#1}}
 \newcommand\metatblAtEnd[2]{% #1=env-name, #2=code
   \csname metatbl at EnvProp@atEnd@#1\endcsname{#2}}
@@ -479,11 +521,13 @@
   \expandafter\expandafter\expandafter{\csname#2\endcsname}}
 \metatblRegisterEnv{tabular}{%
   isLong=false, hasWidth=false, isTabu=false, hasCaption=false,
+  canVAlign=true, canHAlign=false,
   packages={},
   atEnd={\preto\endtabular{#1}},
 }
 \metatblRegisterEnv{tabularx}{%
   isLong=false, hasWidth=true, isTabu=false, hasCaption=false,
+  canVAlign=true, canHAlign=false,
   packages=tabularx,
   atEnd={%
     \preto\TX at endtabularx{\toks@\expandafter{\the\toks@#1}}%
@@ -491,21 +535,25 @@
 }
 \metatblRegisterEnv{longtable}{%
   isLong=true, hasWidth=false, isTabu=false, hasCaption=true,
+  canVAlign=false, canHAlign=true,
   packages={longtable},
   atEnd={\preto\endlongtable{#1}},
 }
 \metatblRegisterEnv{xltabular}{%
   isLong=true, hasWidth=true, isTabu=false, hasCaption=true,
+  canVAlign=false, canHAlign=true,
   packages=xltabular,
   atEnd={\preto\XLT at ii@TX at endtabularx{\toks@\expandafter{\the\toks@#1}}},
 }
 \metatblRegisterEnv{tabu}{%
   isLong=false, hasWidth=true, isTabu=true, hasCaption=false,
+  canVAlign=true, canHAlign=false,
   packages={tabu},
   atEnd={\preto\endtabular{#1}},
 }
 \metatblRegisterEnv{longtabu}{%
   isLong=true, hasWidth=true, isTabu=true, hasCaption=true,
+  canVAlign=false, canHAlign=true,
   packages={tabu,longtable},
   atEnd={\preto\endlongtable{#1}},
 }
@@ -512,7 +560,7 @@
 \newrobustcmd\metatbl at ifhasXcolumns[1]{%
   \begingroup
   \def\metatbl@@branch{\@secondoftwo}%
-  \def\NC at rewrite@X{\def\metatbl@@branch{\@firstoftwo}\NC at find}%
+  \def\NC at rewrite@X{\def\metatbl@@branch{\@firstoftwo}\NC at find l}%
   \@mkpream{#1}%
   \expandafter\endgroup\metatbl@@branch}
 \newcommand\kvt at AddKeyValRow[3]{%
@@ -535,44 +583,91 @@
     \eappto\kvt@@row{\noexpand\rowcolor{\expandonce\cmdkvt at Row@bg}}}%
   \ifbool{kvt at Row@uncounted}{}{%
     \appto\kvt@@row{\noalign{\kvt at stepcounters}}}%
+  \ifdefvoid\cmdkvt at Row@align
+    {\let\kvt@@rowmkmulticolumn\@empty}
+    {\edef\kvt@@rowmkmulticolumn{%
+       \noexpand\multicolumn{1}{\expandonce\cmdkvt at Row@align}}}%
+  \ifcsvoid{cmdkvt at Row@format!}
+    {\edef\kvt@@cellfmtbuilder##1##2{%
+       \noexpand\edef##1####1{%
+         \noexpand\kvt at expandonce@onearg\noexpand\kvt@@mkmulticolumn
+         {\ifcsvoid{cmdkvt at Row@format*}{\@firstofone}
+           {\noexpand\unexpanded{\csexpandonce{cmdkvt at Row@format*}}}%
+         {\noexpand\csexpandonce{##2}{%
+             \ifdefvoid\cmdkvt at Row@format{\@firstofone}
+               {\noexpand\unexpanded{\expandonce\cmdkvt at Row@format}}%
+              {####1}}}}}}}%
+    {\edef\kvt@@cellfmtbuilder##1##2{%
+      \noexpand\edef##1####1{%
+        \noexpand\kvt at expandonce@onearg\noexpand\kvt@@mkmulticolumn{%
+          \noexpand\unexpanded{\csexpandonce{cmdkvt at Row@format!}}%
+            {####1}}}}}%
   \kvt@@span=0\relax
+  \kvt at def@atseconduse\kvt@@switchcol{\appto\kvt@@row{&}}%
   \def\do##1{%
-    \ifcsvoid{cmdKeyValTable@#2@##1}
-      {\letcs\kvt@@cell{kvt at col@default@#2@##1}}
-      {\letcs\kvt@@cell{cmdKeyValTable@#2@##1}%
-       \ifbool{kvt at Row@expandonce}
-         {\expandafter\let\expandafter\kvt@@cell\kvt@@cell}{}%
-       \ifbool{kvt at Row@expand}
-         {\protected at edef\kvt@@cell{\kvt@@cell}}{}}%
-    \ifcsvoid{kvt@@noformat@#2@##1}
-      {\edef\kvt@@formatter{\expandonce{\csname kvt at col@format@#2@##1\endcsname}}}%
-      {\def\kvt@@formatter{\@firstofone}}%
-    \edef\kvt@@fmtcell{\expandonce\kvt@@formatter{%
-      \expandonce\kvt@@cell}}%
-    \csundef{kvt@@noformat@#2@##1}%
     \ifnumgreater\kvt@@span{0}
       {\advance\kvt@@span\m at ne
-       \ifstrempty\kvt@@cell{\def\kvt@@fmtcell{}}{}}
-      {\appto\kvt@@row{&}}%
-    \expandafter\kvt at CheckMulticolumn\kvt@@cell
-      \relax\relax\relax\relax\@undefined
-    \expandafter\appto\expandafter\kvt@@row\expandafter{\kvt@@fmtcell}%
+       \ifcsvoid{cmdKeyValTable@#2@##1}{}
+         {\ifdefvoid\kvt@@curcgname
+           {\kvt at error{Column '##1' nonempty inside a
+                       \string\multicolumn}{}}
+           {\kvt at error{Column '##1' nonempty inside column group
+                       '\kvt@@curcgname'}{}}}}
+      {\kvt@@switchcol
+       \let\kvt@@mkmulticolumn\kvt@@rowmkmulticolumn
+       \letcs\kvt@@curcolformat{kvt at col@format@#2@##1}%
+       \ifcsvoid{cmdKeyValTable@#2@##1}
+         {\letcs\kvt@@cell{kvt at col@default@#2@##1}}
+         {\letcs\kvt@@cell{cmdKeyValTable@#2@##1}%
+          \expandafter\kvt at CheckMulticolumn\expandafter{\kvt@@cell}{#2}%
+          \ifbool{kvt at Row@expandonce}
+            {\expandafter\let\expandafter\kvt@@cell\kvt@@cell}{}%
+          \ifbool{kvt at Row@expand}
+            {\protected at edef\kvt@@cell{\kvt@@cell}}{}}%
+       \ifcsvoid{kvt@@noformat@#2@##1}
+         {\kvt@@cellfmtbuilder\kvt@@formatter{kvt@@curcolformat}}%
+         {\let\kvt@@formatter\@firstofone}%
+       \csundef{kvt@@noformat@#2@##1}%
+       \edef\kvt@@fmtcell{\expandafter\expandonce\expandafter{%
+         \expandafter\kvt@@formatter\expandafter{%
+           \kvt@@cell}}}%
+       \expandafter\appto\expandafter\kvt@@row\expandafter{%
+         \kvt@@fmtcell}}%
   }\dolistcsloop{kvt at displaycols@#2}%
+  \undef\kvt@@cellfmtbuilder
   \appto\kvt@@row{\tabularnewline}%
   \ifdefvoid\cmdkvt at Row@below{}{%
     \eappto\kvt@@row{\noexpand\noalign{\noexpand\vspace{%
       \expandonce\cmdkvt at Row@below}}}}%
   #1}
+\newcommand\kvt at def@atseconduse[2]{\def#1{\def#1{#2}}}
+\newcommand\kvt at expandonce@onearg[2]{%
+  \ifdefequal{#1}{\@empty}{#2}{\expandonce{#1}{#2}}}
 \newcommand\kvt at stepcounters[1][1]{%
   \addtocounter{kvtRow}{#1}%
   \addtocounter{kvtTypeRow}{#1}%
   \addtocounter{kvtTotalRow}{#1}}
-\def\kvt at CheckMulticolumn#1#2#3#4\@undefined{%
-  \ifx#1\multicolumn
-    \kvt@@span=#2\relax \advance\kvt@@span\m at ne
-    \edef\kvt@@fmtcell{\unexpanded{\multicolumn{#2}{#3}}%
-      {\expandonce\kvt@@formatter{\expandonce{#4}}}}%
-  \fi}
+\newcommand\kvt at CheckMulticolumn[2]{%
+  \kvt at CheckMulticolumn@i{#2}#1%
+    \relax\relax\relax\relax\relax\kvt@@undefined}
+\def\kvt at CheckMulticolumn@i#1#2#3#4#5#6#7\kvt@@undefined{%
+  \ifdefmacro{#2}{%
+    \ifx#2\multicolumn
+      \kvt at SetMulticolumn{#4}{#3}{#5}%
+      \let\kvt@@curcgname\@empty
+    \else\ifx#2\kvt@@@colgroup
+      \letcs\kvt@@curcolformat{kvt at colgrp@format@#1@#3}%
+      \def\kvt@@curcgname{#3}%
+      \ifdefvoid\cmdkvt at Row@align
+        {\kvt at SetMulticolumn{#5}{#4}{#6}}
+        {\expandafter
+         \kvt at SetMulticolumn\expandafter{\cmdkvt at Row@align}{#4}{#6}}%
+    \fi\fi}{}}
+\newcommand\kvt@@@colgroup{kvt@@@colgroup}
+\newcommand\kvt at SetMulticolumn[3]{%
+  \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}}
@@ -708,7 +803,7 @@
   \kvt at DefineDualTabEnv{multipage}{longtable}{xltabular}
 }
 \kvt at IfVersion{<}{2.0}{%
-  \let\kvt at parselayout=\kvt at parseheadrows
+  \renewcommand\kvt at parselayout[2]{\kvt at parseheadrows{#2}{#1}}%
 }{}
 \endinput
 %%



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