% \iffalse meta-comment
%
% Copyright (C) 2016-2020 by Richard Grewe <r-g+tex@posteo.net>
% -------------------------------------------------------
%
% Thie file may be distributed and/or modified under the
% conditions of the LaTeX Project Public License, either version 1.3c
% of this license or (at your option) any later version.
% The latest version of this license is in
%    https://www.latex-project.org/lppl.txt
% and version 1.3c or later is part of all distributions of LaTeX
% version 2008 or later.
%
% This file has the LPPL maintenance status "maintained".
%
% \fi
%
% \iffalse
%<*driver>
\ProvidesFile{keyvaltable.dtx}
%</driver>
%<package>\NeedsTeXFormat{LaTeX2e}[1999/12/01]
%<package>\ProvidesPackage{keyvaltable}
%<*package>
    [2020/08/09 v2.3 Package for filling tables using key-value lists]
%</package>
%
%<*driver>
\documentclass[svgnames]{ltxdoc}
\usepackage{rgltxdoc}[2019/12/21 v1.3]
\usepackage{etoc}
\usepackage{amssymb}% \checkmark
\EnableCrossrefs
\CodelineIndex
\RecordChanges
\usepackage{xspace}
\newcommand\thispackage{\pkgname{keyvaltable}\xspace}
% the following packages are additional for the examples
\usepackage{xintexpr}
\usepackage{makecell,cellspace}
\usepackage{gensymb}% for \degree
\usepackage{tabularx,longtable,xltabular,tabu}
\usepackage{filecontents}
\usepackage{keyvaltable}
\usepackage{datatool,csvsimple}
\NewKeyValTable[
    showhead=false,headformat={\bfseries\footnotesize},
    rowbg=black!7!white..black!3!white,
    showrules=false,
    backend=tabu]{GoalApproach}{
  id: align=r, default=(\alph{kvtRow}), head=\#;
  goal: align=X[l];
  approach: align={X[2,l]};
}
\newcommand\RecipePreset{%
  \NewKeyValTable{Recipe}{amount:align=r;ingredient:align=l;step:align=X}}
%
\usepackage{fontawesome}
\makeatletter
\newenvironment{NiceText}[2]{%
  \medskip\par\noindent
  \rgltxdoc@inmargin{\smash{\textcolor{#1}{\large#2}}}{\quad}%
  \ignorespaces}{\medskip\par\noindent}
\newenvironment{NiceNote}{\NiceText{DarkBlue}{\faInfoCircle}}{\endNiceText}
\newenvironment{NiceTipp}{\NiceText{DarkBlue}{\faLightbulbO}}{\endNiceText}
\newenvironment{NiceWarn}{\NiceText{DarkBlue}{\faWarning}}{\endNiceText}
%    \end{macrocode}
\makeatother
%
\begin{filecontents*}{recipes.csv}
id,amount,ingredient,step
snowman,3,balls of snow,staple all 3 balls
snowman,1,carrot,stick into top ball
snowman,2,coffee beans,put diagonally above carrot
cherries,150g,ice cream,put into bowl
cherries,50g,cherries,heat up and add to bowl
\end{filecontents*}
%
\begin{document}
  \DocInput{keyvaltable.dtx}
  \PrintChanges
  \PrintIndex
\end{document}
%</driver>
% \fi
%
% \CheckSum{0}
%
% \CharacterTable
%  {Upper-case    \A\B\C\D\E\F\G\H\I\J\K\L\M\N\O\P\Q\R\S\T\U\V\W\X\Y\Z
%   Lower-case    \a\b\c\d\e\f\g\h\i\j\k\l\m\n\o\p\q\r\s\t\u\v\w\x\y\z
%   Digits        \0\1\2\3\4\5\6\7\8\9
%   Exclamation   \!     Double quote  \"     Hash (number) \#
%   Dollar        \$     Percent       \%     Ampersand     \&
%   Acute accent  \'     Left paren    \(     Right paren   \)
%   Asterisk      \*     Plus          \+     Comma         \,
%   Minus         \-     Point         \.     Solidus       \/
%   Colon         \:     Semicolon     \;     Less than     \<
%   Equals        \=     Greater than  \>     Question mark \?
%   Commercial at \@     Left bracket  \[     Backslash     \\
%   Right bracket \]     Circumflex    \^     Underscore    \_
%   Grave accent  \`     Left brace    \{     Vertical bar  \|
%   Right brace   \}     Tilde         \~}
%
% \changes{v0.1}{2016/03/13}{Initial version}
% \changes{v0.3b}{2018/11/01}{Package author's name change}
%
% \GetFileInfo{keyvaltable.dtx}
%
% \DoNotIndex{\newcommand,\newenvironment,\def,\gdef,\edef}
%
%
% \title{The \thispackage package\thanks{This document
%   corresponds to \thispackage~\fileversion, dated \filedate.
%   The package is available online at
%   \url{http://www.ctan.org/pkg/keyvaltable} and
%   \url{https://github.com/Ri-Ga/keyvaltable}.}}
% \author{Richard Grewe \\ \texttt{r-g+tex@posteo.net}}
%
% \maketitle
%
% \begin{abstract}\noindent
% The \thispackage package's main goal is to facilitate
% typesetting tables\ldots\medskip\\
% \begin{KeyValTable}{GoalApproach}
%   \Row{
%     goal={\ldots easily and yet still looking rather nicely},
%     approach={through horizontal rules and alternating row background
%       colors by default;}}
%   \Row{
%     goal={\ldots in a way that separates content from presentation},
%     approach={by table rows that are specified as lists of key-value
%       pairs, where the keys are column names and the corresponding
%       values are the content of the cell in this row in the respective
%       column;}}
%   \Row{
%     goal={\ldots with re-usable layout for tables of the same type},
%     approach={through named table types, of which each has a list of
%       columns as well as further properties such as the background
%       colors of rows; each column, in turn, has a name as well as
%       further properties such as the heading of the column and the
%       alignment of the column's content.}}
% \end{KeyValTable}
% \end{abstract}
%
% \etocsetnexttocdepth{1}
% \etocmulticol[2]{\section*{Contents}}
% \clearpage
%
% \section{Basic Usage}\label{sec:basic}
%
% We start with a basic usage example. An explanation of the involved
% macros follows afterwards.\medskip
%
% \begin{LTXexample}[morekeywords={NewKeyValTable,Row,KeyValTable}]
% \NewKeyValTable{Recipe}{
%   amount:     align=r;
%   ingredient: align=l;
%   step:       align=X;
% }
% \begin{KeyValTable}{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}
% The example code first defines a new table type, |Recipe|, along with
% the columns that belong to this type. There are three columns
% (|amount|, |ingredient|, and |step|), whose specifications are separated
% with semicolons. After the separating |:|, for each column, the macro
% configures the column alignment using the |align| key. The alignments
% |r| (right) and |l| (left) are the standard |tabular| alignments; the
% |X| alignment is provided by the \pkgname{tabularx} package (see the
% documentation there).
%
% After defining the table type, the example creates a table of
% the newly defined type. For this, the example uses the |KeyValTable|
% environment and the |\Row| macro, once for each row. The parameter
% |Recipe| of the |KeyValTable| identifies the type of the table.
% In the parameter of the |\Row| macro, the content of the individual
% cells can be specified by key-value pairs such as |amount=150g|, which
% puts ``150g'' into the |amount| column of the respective row.
%
% The example above already shows that producing a rather nice-looking
% table -- including alternating row colors as well as horizontal rules
% -- without further ado. How the \thispackage package can be
% used in the general case and how its visual appearance can be
% customized is subject of the remainder of this documentation.
%
% \begin{NiceTipp}
%   To quickly sketch a table type, one can even omit properties
%   of columns and just list their names, separated by semicolons, as the
%   following example shows. All columns then get the default alignment:
%   |l|.
% \end{NiceTipp}
% \begin{LTXexample}
% \NewKeyValTable{Recipe}{amount;ingredient;step}
% \begin{KeyValTable}{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}
%
%
% \section{Defining Table Types}
%
% As the example in \cref{sec:basic} shows,
% |\NewKeyValTable| defines a table type.
%
% \NiceDescribeMacro{\NewKeyValTable}{\oarg{options}\marg{tname}\marg{colspecs}\oarg{layout}}
% The macro defines a table type with name \meta{tname} whose columns
% are specified by \meta{colspecs}.
% The \meta{colspecs} parameter must be a semicolon-separated list.
% Each column specification is of the form
% \begin{center}
%   \meta{colname}|:| \meta{property}|=|\meta{value}|,|
%   \meta{property}|=|\meta{value}|,|\ldots
% \end{center}
% In such a specification, \meta{colname} represents the name of the
% column. The \meta{property}|=|\meta{value} pairs configure certain
% properties of the column. The \meta{property} can be one of the
% following:
%
% \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.\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
%   column, i.e., in case that a \cmd{\Row} does not provide content for
%   the cell.  Initially (i.e., if unset for a column), this is an
%   empty string.
%
% \NiceDescribeKey{format}{vals=\vmeta{single argument macro}, init=\vmeta{"identity"}}
%   This property specifies a formatting macro for content of the cell.
%   The macro can take one argument and is provided with the content of
%   the cell as its argument. Initially, the format is defined to take
%   the content as is.\footnote{Prior to version~2.3 of \thispackage,
%   the initial format setting was to put \cmd{\strut} before and after
%   the content to yield a better vertical row spacing in some
%   situations. See also \cref{sec:VertSpacing}.}
%
% \NiceDescribeKey{head}{vals=\vmeta{content}, init=\vmeta{colname}}
%   This property specifies the \meta{content} of the column's header
%   row. The initial value for this property is the name of the column.
%
% \NiceDescribeKey{hidden}{vals={true,false}, init=false, def=true}
%   This property specifies whether a table column shall be displayed or
%   not. The \meta{value} for this property can be |true| (to hide the
%   cell) or |false| (to display the cell). Using |hidden| without
%   \meta{value} is equivalent to specifying |hidden=true|.
%
% The following example shows all of the above column properties in
% action.
%
% \begin{LTXexample}[morekeywords={align,default,format,head,hidden}]
% \NewKeyValTable{ShoppingList}{
%   what:   head=article, format=\textbf;
%   amount: align=r, default=1;
%   why:    hidden;
% }
% \begin{KeyValTable}{ShoppingList}
% \Row{what=melon}
% \Row{what=apples, amount=6}
% \Row{what=bicycle, why=Bob's birthday}
% \end{KeyValTable}
% \end{LTXexample}
%
% The \meta{options} and \meta{layout} parameters of |\NewKeyValTable|
% are described in \cref{sec:TableAppearance} and, respectively,
% \cref{sec:CustomHeaders} of this documentation.
%
%
% \section{Typesetting Tables}\label{sec:typesetting-tables}
%
% The \thispackage package offers three possibilities for typesetting
% tables.
% The first is in the traditional \hologo{LaTeX} form, in which there is
% an environment that encloses the individual row specifications.
% The second possibility is to specify rows throughout the document, bind
% them to a name, and finally typeset a table from all rows bound to
% the particular name.
% The third possibility is to source the row specifications from a
% file.
%
% \subsection{Specifying Rows in a Table Environment}
%
% The first possibility for typesetting a table using the
% \thispackage package, is via the |KeyValTable| environment.
% \cref{sec:basic} presents an example of this possibility.
%
% \NiceDescribeEnv{KeyValTable}{\oarg{options}\marg{tname}}
% The |KeyValTable| environment creates a table of type \meta{tname}.
% The type \meta{tname} must have been created using |\NewKeyValTable|
% before. The environment itself already produces a table with the
% columns specified for the table type, produces a header row and some
% horizontal lines, and sets up background colors of rows.
% The \meta{options} are described in \cref{sec:TableAppearance}.
%
% \NiceDescribeMacro{\Row}{\oarg{options}\marg{content}}
% A table row is produced by the |\Row| macro. The
% \meta{content} must be a comma-separated list of
% \meta{cname}|=|\meta{text} pairs. The \meta{cname} identifies a column
% that was registered for the table type \meta{tname}. The \meta{text}
% specifies the content of the cell in the respective column. Each
% column for which no \meta{text} is provided in \meta{content}, will
% result in a cell that is filled with the column's default value.
% The \meta{options} argument customizes row properties and is further
% explained in \cref{sec:RowOptions}.
%
%
% \subsection{Tables of Collected Rows}\label{sec:collected}
%
% The content of a table's rows might logically belong to locations that
% are scattered throughout a document, e.g., to individual sections of
% the document. In this situation, it can be convenient to have the rows
% specified close to the locations their contents belong to, instead of
% specified in the table environment.
%
% The following example illustrates the use of this feature for taking
% and collecting notes in a document:
% \begin{LTXexample}[width=0.475\hsize,morekeywords={NewCollectedTable,CollectRow,ShowCollectedTable}]
% \NewKeyValTable{Notes}{type; text}
% \NewCollectedTable{notes}{Notes}
%
% \subsection*{Notes}
% \ShowCollectedTable{notes}
%
% \section{Introduction}
% \CollectRow{notes}{type=remark, text=intro too long}
% Lorem ipsum dolor sit amet, \ldots
%
% \section{Analysis}
% \CollectRow{notes}{type=task, text=proofread Analysis}
% Lorem ipsum dolor sit amet, \ldots
% \end{LTXexample}
% See \cref{sec:referencing} on how to (automatically) include
% references to, e.g., section or page numbers in tables.
% The key macros (highlighted in bold font) used in the example are the
% following three.
%
% \NiceDescribeMacro{\NewCollectedTable}{\marg{cname}\marg{tname}}
% This macro defines the name \meta{cname} for a new collection of
% rows. The collection is associated with the table type \meta{tname}.
% This macro must be used before |\CollectRow| for a \meta{cname}.
%
% \NiceDescribeMacro{\CollectRow}{\oarg{options}\marg{cname}\marg{content}}
% This macro adds the row content \meta{content} and row options
% \meta{options} to the row collection \meta{cname}.
%
% \NiceDescribeMacro{\ShowCollectedTable}{\oarg{options}\marg{cname}}
% This macro typesets a table of the row collection \meta{cname}, with
% the table options \meta{options}.
% The table includes rows that are collected only afterwards in the
% document. For this, \hologo{LaTeX} must be run at least two times.
%
%
% \subsection{Sourcing Rows From a File}
%
% Rather than specifying the rows of a table inside a |KeyValTable|
% environment, the rows can also be sourced from a file.
% More concretely, this file must consist of the |\Row| macros that
% specify the content of the rows.
% For information on how to source rows from CSV files, see
% \cref{sec:CSV}.
%
% \NiceDescribeMacro{\ShowKeyValTableFile}{\oarg{options}\marg{tname}\marg{filename}}
% This macro produces a |KeyValTable| environment of type \meta{tname}
% whose content is taken from the file \meta{filename}.
% The \meta{options} specify the table options, which are directly
% passed to the options argument of the |KeyValTable| environment.
%
% \begin{LTXexample}[morepreset=\RecipePreset,morekeywords={ShowKeyValTableFile}]
% \begin{filecontents}{snowman.kvt}
% \Row{amount=3, ingredient=balls of snow,
%      step=staple all 3 balls}
% \Row{amount=1, ingredient=carrot,
%      step=stick into top ball}
% \Row{amount=2, ingredient=coffee beans,
%      step=put diagonally above carrot}
% \end{filecontents}
% \ShowKeyValTableFile{Recipe}{snowman.kvt}
% \end{LTXexample}
%
%
% \subsection{Tables of Collected Rows (Legacy Interface)}
%
% This section documents legacy functionality of \thispackage, that is
% now superseded by the functionality described in \cref{sec:collected}.
% The legacy functionality compares to the new functionality as follows:
% \begin{itemize}[noitemsep]
% \item Rows must be collected \emph{before} the place in the document
%   where they are displayed in a table.
% \item For each table type, there can be only one collection of rows.
%   After the collection has been typeset in a table the collection is
%   emptied again.
% \item Row content is not written into the aux file. This might be
%   relevant for very large tables.
% \end{itemize}
% The following macros and environments implement the functionality.
%
% \NiceDescribeMacro{\AddKeyValRow}{\marg{tname}\oarg{options}\marg{content}}
% A table row is produced by the
% |\AddKeyValRow| macro. The \meta{tname}
% identifies the table type and the \meta{content} provides the content
% of the cells in the row. The format of the \meta{content} is the same
% as for the |\Row| macro described in
% Section~\ref{sec:typesetting-tables}.
%
% \NiceDescribeMacro{\ShowKeyValTable}{\oarg{options}\marg{tname}}
% A table of all the rows defined via |\AddKeyValRow| can be displayed
% by the |\ShowKeyValTable| macro. The
% parameters have the same meaning as for the |KeyValTable| environment.
% This macro resets the list of rows for the specified table type.
%
% \NiceDescribeEnv{KeyValTableContent}{\marg{tname}}
% For simplifying the addition of rows, the
% |KeyValTableContent| environment can be used. In this
% environment, the |\Row| macro can be used just like in the
% |KeyValTable| environment. The only difference is that the
% |KeyValTableContent| environment does not cause the table to be
% displayed. For displaying the content collected in
% |KeyValTableContent| environments, the |\ShowKeyValTable| macro can be
% used.
%
% The following example demonstrates the use, based on the previously
% defined |Recipe| table type.
% \begin{LTXexample}[morepreset=\RecipePreset,morekeywords={AddKeyValRow,KeyValTableContent,ShowKeyValTable}]
% \AddKeyValRow{Recipe}{amount=3,
%      ingredient=balls of snow,
%      step=staple all 3 balls}
% \begin{KeyValTableContent}{Recipe}
% \Row{amount=1, ingredient=carrot,
%      step=stick into top ball}
% \Row{amount=2, ingredient=coffee beans,
%      step=put diagonally above carrot}
% \end{KeyValTableContent}
% \ShowKeyValTable{Recipe}
% \end{LTXexample}
%
%
% \section{Row Numbering\,\&\,Labeling}\label{sec:row-numbering}
%
% The mechanism of default column values enables a simple means for
% automatic row numbering, labeling, and referencing document entities.
%
% \subsection{Row Numbering}
%
% For row numbering, one can use one of three row counters provided by
% the \thispackage package: |kvtRow|, |kvtTypeRow|, and |kvtTotalRow|.
% The counters are explained after the following example, which
% demonstrates the use for the case of the |kvtRow| counter.
%
% \begin{LTXexample}[morekeywords={thekvtRow,thekvtTypeRow}]
% \NewKeyValTable[headformat=\textbf]{Numbered}{
%   line: align=r, head=\#,
%         format=\textbf,
%         default=\thekvtRow;
%   text: align=l, head=Text}
% \begin{KeyValTable}{Numbered}
% \Row{text=First row}
% \Row{text=Second row}
% \end{KeyValTable}
% \end{LTXexample}
%
% \NiceDescribeCounter{kvtRow}{}
% The |kvtRow| counter counts the row in the \emph{current} table. The
% row number excludes the header row of the table. If the table spans
% multiple pages, the row number also excludes the repeated headings on
% subsequent pages.
%
% \NiceDescribeCounter{kvtTypeRow}{}
% The |kvtTypeRow| counter counts the rows in the current table and
% includes the number of rows of all previous tables of the same type.
%
% \NiceDescribeCounter{kvtTotalRow}{}
% The |kvtTotalRow| counter counts the rows in the current table and
% includes the number of rows of all previous tables produced using the
% \thispackage package.
%
% By default, all rows are counted by the aforementioned counters.
% However, this default can be changed.
%
% \NiceDescribeKey{uncounted}{vals={true,false}, init=false, def=true}
%   This row option specifies whether the row shall not be counted
%   (|true|) or shall be counted (|false|).
%   If only |uncounted| is used without a value, this is equivalent to
%   |uncounted=true|.
% The following example illustrates the option.
%
% \begin{LTXexample}[morekeywords={uncounted},
%   morepreset={\NewKeyValTable[headformat=\textbf]{Numbered}{
%     line: align=r,head=\#,format=\textbf,default=\thekvtRow;
%     text: align=l,head=Text}}]
% \begin{KeyValTable}{Numbered}
% \Row{text=First row}
% \Row[uncounted]{line={--}, text=interlude}
% \Row{text=Second row}
% \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.
% The following example shows how the |format| column property can be
% used for this purpose.
% \begin{LTXexample}[morekeywords={kvtLabel}]
% \NewKeyValTable{Labeled}{
%   label: align=r, head=\textbf{\#},
%          format=\kvtLabel{kvtRow};
%   text:  align=l, head=\textbf{Text}}
% \begin{KeyValTable}{Labeled}
% \Row{text=First row, label=first}
% \Row{text=After row \ref{first}}
% \end{KeyValTable}
% \end{LTXexample}
%
% \NiceDescribeMacro{\kvtLabel}{\oarg{labelopts}\marg{counter}\marg{label}}
% The |\kvtLabel| macro shows the current value of the \meta{counter} --
% in particular |kvtRow|, |kvtTypeRow|, and |kvtTotalRow| -- and sets
% the \meta{label} to the value of \meta{counter}. When using the macro
% with the |format| property, only the first argument (\meta{counter})
% must be provided, as the above example shows. The second argument
% (\meta{label}) is provided by the respective cell content.
%
% The |\kvtLabel| macro should work well with packages that change the
% referencing, like \pkgname{cleveref} or \pkgname{varioref}. When using a
% package that adds an optional argument to the |\label| command (like
% \pkgname{cleveref} does), the \meta{labelopts} can be used to pass an
% optional argument to |\label|. This feature is demonstrated in
% \cref{sec:package-cleveref}.
%
% \subsection{Referencing in Collected Rows}\label{sec:referencing}
%
% The previous sections show examples of referencing row numbers.
% In tables of collected rows, it may be desirable to reference the
% point in the document at which a row was collected.
% The example in \cref{sec:collected} illustrates such a situation.
% In the following, we augment that example by references to section and
% page numbers.
%
% \begin{LTXexample}[width=0.5\hsize,morekeywords={NewCollectedTable,CollectRow,ShowCollectedTable}]
% \NewKeyValTable{Notes2}{
%   id: default=\thekvtRow.;
%   type; text;
%   where: default={\S\thesection\ (p.\@\thepage)};}
% \NewCollectedTable{notes2}{Notes2}
%
% \subsection*{Notes}
% \ShowCollectedTable{notes2}
%
% \section{Introduction}
% \CollectRow{notes2}{type=remark, text=intro too long}
% Lorem ipsum dolor sit amet, \ldots
%
% \section{Analysis}
% \CollectRow{notes2}{type=task, text=proofread!}
% Lorem ipsum dolor sit amet, \ldots
% \end{LTXexample}
%
% The above example demonstrates that the correct section number is
% referenced. Since the whole example is contained on a single page, the
% example does not demonstrate that the page number (|\thepage|) in the
% "where" column actually references the page in the document on which
% the |\CollectRow| takes place. Note that the correct page will be
% produced even when the |\CollectRow| is placed in a float, such as a
% figure or table.
% \begin{NiceWarn}
%   \hologo{LaTeX} internally implements a special treatment of
%   |\thepage| to make page references possible. For this reason, using
%   something like |\arabic{page}| to produce the page number will
%   presumably not work correctly.
% \end{NiceWarn}
%
% The \thispackage package
% \begin{itemize}[nosep]
% \item takes the values of row counters (like |\thekvtRow|) from the
%   position of \emph{the row in the table}
%   but
% \item takes the values of other counters such as the page counter and
%   the section counter from the \emph{point in the document where
%   \cmd{\CollectRow} is used}.
% \end{itemize}
% This takes into account that counter values can be obtained via
% \cmd{\the\meta{ctrname}} (like |\thekvtRow| or |\thepage|) as well as
% via macros like |\arabic|, |\roman| etc.
% The following macros allow for declaring additional counters and
% formatting macros to be taken into account by \thispackage.
%
% \NiceDescribeMacros{2}
%   {\kvtDeclareTableMacros}{\marg{macro-list}}
%   {\kvtDeclareTableCounters}{\marg{counter-list}}
% These macros take a comma-separated list of macros (respectively
% counters) and declares these as "table macros" ("table counters").
% A macro or counter declared this way is expanded only inside the table
% environment and not at the point where |\CollectRow| is used.
% The \thispackage already declares |\thekvtRow|, |\thekvtTypeRow|, and
% |\thekvtTotalRow| as table macros and declares |kvtRow|, |kvtTypeRow|,
% and |kvtTotalRow| as table counters.
%
% \NiceDescribeMacro{\kvtDeclareCtrFormatters}{\marg{macro-list}}
% This macro takes a comma-separated list of macros and declares them as
% macros for formatting counter values. Examples for such macros are
% |\arabic|, |\alph|, |\Alph|, |\roman|, |\Roman|, |\fnsymbol|, which
% \thispackage already declares.
% When other counter-formatting macros shall be used in the |default|
% value of a column, such as |\ordinal| of the \pkgname{fmtcount}
% package, they have to be passed to |\kvtDeclareCtrFormatters| first.
%
%
% \section{Changing the Appearance}
%
% The appearance (e.g., colors, rules) of a table can be changed at
% the level of the overall table as well as for individual rows,
% columns, and cells.
%
% \subsection{Table Appearance}\label{sec:TableAppearance}
%
% The appearance of a table can be configured through the \meta{options}
% parameters of
% \begin{itemize}[nosep]
% \item |KeyValTable|, |\ShowKeyValTable|, and |\ShowKeyValTableFile|
%   (affecting the particular table),
% \item |\NewKeyValTable| (affecting all tables of the table type), and
% \item |\kvtSet| (affecting all tables).
% \end{itemize}
% In this list, the former take precedence over the latter. That is,
% table options override table type options and table type options
% override global options for all tables.
%
% In each case, \meta{options} must be specified as a comma-separated
% list of \meta{property}|=|\meta{value} pairs.
% The following \meta{property} keys can be configured.
%
% \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|/|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|/|backend| 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|
% specifies that the header row is shown and |false| specifies that the
% header row is not shown.
%
% \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|,
% |\midrule|, or |\MidRule| (see Section~\ref{sec:rules}) 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
% empty, each header cell receives the same alignment as the respective
% column.
%
% \NiceDescribeKey{headbg}{vals=\vmeta{color}, init={black!14}}
% This property specifies the background color of the header rows.  The
% \meta{color} must be a single color specification that is understood
% by the \pkgname{xcolor} package. The \meta{color} is passed directly
% to the \cs{rowcolor} macro. If \meta{color} is empty, then no
% background color is produced for the header row.
%
% \NiceDescribeKey{headformat}{vals=\vmeta{single argument macro}, init=\vmeta{"identity"}}
% This property specifies a format to be applied to all header cells.
% The value specified for the |headformat| key is used to format each
% header. The value can be a macro that takes once argument, through
% which it is provided the header (as specified in the column's |head|
% property).  Initially, an "identity" macro is used, meaning that each
% |head| is taken without change.
%
% \NiceDescribeKey{rowbg}{vals=\vmeta{color}, init={white..black!10}}
% This property specifies the background colors of content rows. The
% \meta{value} for this property must be of the format
% \meta{oddcolor}|..|\meta{evencolor}. The first row after the header is
% colored with \meta{oddcolor}, the second row with \meta{evencolor},
% and so forth. Both colors must be understood by the \pkgname{xcolor}
% package. If \meta{color} is empty, then no background color is
% produced for content rows.
%
% \NiceDescribeKeys{2}
%   {norowbg}{vals={true,false}, init=false, def=true}
%   {nobg}{vals={true,false}, init=false, def=true}
% These properties are shorthands for |rowbg={}| (turning off
% background colors for content rows) and, respectively, for
% |rowbg={},headbg={}| (turning off background colors for header rows
% and for content rows). Using these options without a value is
% equivalent to using |true| for the value. For instance, |nobg| is
% equivalent to |nobg=true|.
%
% \vref{fig:TableOptionExamples} demonstrates the \meta{options} in
% examples.
% \begin{figure}
% \begin{LTXexample}[morekeywords={showhead,rowbg}]
% \kvtSet{format=\texttt}
% \NewKeyValTable[showhead=false,
%     rowbg=blue!10..blue!15,
%   ]{TabOptions}{opt; val}
% \begin{KeyValTable}{TabOptions}
%   \Row{opt=showhead, val=false}
%   \Row{opt=rowbg,  val=blue!10..blue!15}
% \end{KeyValTable}
% \end{LTXexample}
% \begin{LTXexample}[morepreset={\kvtSet{format=\texttt}},morekeywords={showrules,headbg,headalign,headformat,halign,norowbg}]
% \NewKeyValTable[showrules=false,headbg=blue!25,
%     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=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}
%
% \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}
%
% \begin{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.
% \end{NiceNote}
%
% 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|,
% |head|, |format|, and |default| of columns in |\NewKeyValTable|.
%
%
% \subsection{Row Appearance}\label{sec:RowOptions}
%
% Through the \meta{options} argument of the
%   |\Row|
% and the
%   |\KeyValRow|
% macros, the appearance of rows can be configured.
% As with other option arguments of the \thispackage package, the
% options must be a comma-separated list of key-value pairs.
% The following options are supported.
%
% \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
%   explicitly), the background color is determined by the |rowbg|
%   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.
%
% \begin{NiceNote}
%   Initial values for all row options can be set with
%   |\kvtSet{Row/|\meta{option}|=|\meta{value}|}| (see also
%   \cref{sec:kvtSet}).
% \end{NiceNote}
%
% 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}
% \Row{amount= 50g, ingredient=cherries,
%   step=heat up and add to bowl}
% \Row[hidden]{amount=25g, ingredient=cream,
%   step=decorate on top}
% \Row[above=1ex,bg=Gold,format=\textit]{
%   step=serve with a smile}
% \end{KeyValTable}
% \end{LTXexample}
%
%
% \subsubsection{Vertical Row Size \& Spacing}\label{sec:VertSpacing}
%
% When rows are narrow or appear to be narrow, extra spacing above and
% below can be configured. There are (at least) three options for this.
%
% The first option is to use the following |\Row| options.
% \NiceDescribeKeys{3}
%   {above}{vals=\vmeta{dimension}, init=\vmeta{empty}}
%   {below}{vals=\vmeta{dimension}, init=\vmeta{empty}}
%   {around}{vals=\vmeta{dimension}, init=\vmeta{empty}}
%   These properties specify extra vertical space above and,
%   respectively, below the row. The |around| property is a short-hand
%   for setting both, |above| and |below|, to the same value.
%     Note that the vertical space is currently not colored with the
%     row's background color but with the page's background color.
%     The argument, if provided, is directly passed to |\vspace|.
%
% The second option is to use the row |format| or a column's |format|
% property to insert |\strut| macros around cell content.
% For the |format|, the following macro exists.
%
% \NiceDescribeMacro{\kvtStrutted}{\oarg{inner}\marg{arg}}
% This macro places a |\strut| before \meta{arg} and a |\strut| after
% \meta{arg}. This has the effect that the first and last row of
% \meta{arg} obtain a "natural" height and depth even if their content
% is smaller.
% The second |\strut| is omitted when it would cause a new line to be
% produced.
% See \cref{sec:row-numbering} for an example.
%
% The third option is using the \pkgname{cellspace} package and its
% column alignments (e.g., |Sl| instead of |l|) along with the configurable dimensions |\cellspacetoplimit| and |\cellspacebottomlimit|.
% The following example shows the second and the third option.
%
% \begin{LTXexample}[morekeywords={cellspace,kvtStrutted,cellspacetoplimit}]
% \usepackage{cellspace}
% \setlength{\cellspacetoplimit}{3pt}
% \NewKeyValTable{VertSpacing}{
%   normal;
%   struts: format=\kvtStrutted;
%   cellspace: align=Sl;
% }
% \begin{KeyValTable}{VertSpacing}
% \Row{normal=normal size}
% \Row{normal=\large Large}
% \Row{struts=\large Large}
% \Row{cellspace=\large Large}
% \end{KeyValTable}
% \end{LTXexample}
%
%
% \subsubsection{Row Styles}
%
% Rather than specifying properties for individual rows, \thispackage
% also supports named \emph{row styles}.
%
% \NiceDescribeKey{style}{vals=\vmeta{list of style names}, init=\vmeta{empty}}
% Through this property of rows, a list of styles can be applied to the
% row. Each style must have been defined with |\kvtNewRowStyle| before.
%
% \NiceDescribeMacro{\kvtNewRowStyle}{\marg{name}\marg{row-options}}
% This macro declares a new row style with the given \meta{name} and
% defines it to be equivalent to using the given \meta{row-options}.
% The \meta{name} must not already be defined.
%
% \NiceDescribeMacro{\kvtRenewRowStyle}{\marg{name}\marg{row-options}}
% This macro re-defines an existing row style \meta{name} with new
% \meta{row-options}.
%
% The following example produces the same output as the previous
% example, but uses row styles.
%
% \begin{LTXexample}[morepreset=\RecipePreset,morekeywords={style,kvtNewRowStyle}]
% \kvtNewRowStyle{optional}{hidden}
% \kvtNewRowStyle{highlight}{above=1ex,bg=Gold}
% \begin{KeyValTable}{Recipe}
% \Row{amount=150g, ingredient=ice cream,
%   step=put into bowl}
% \Row{amount= 50g, ingredient=cherries,
%   step=heat up and add to bowl}
% \Row[style=optional]{amount=25g,
%   ingredient=cream, step=decorate on top}
% \Row[style=highlight]{step=serve with a smile}
% \end{KeyValTable}
% \end{LTXexample}
%
% \begin{NiceNote}
%   The \meta{row-options} in |\kvtNewRowStyle| can be left empty.
%   In this case, the row style does not have any effect on the appearance
%   of rows. However, the style can already be used for "tagging" rows and
%   the final options for the style can be configured at a later point in
%   time.
% \end{NiceNote}
%
%
% \subsubsection{Rules Between Rows}\label{sec:rules}
%
% For placing additional horizontal rules between rows, the
% \thispackage package provides the following two macros that are
% available in |KeyValTable| environments.
%
% \NiceDescribeMacro{\MidRule}{\oarg{width}}
% This macro puts a horizontal rule over the full width of the table,
% with line width \meta{width}. The macro puts the same vertical
% spacing above and below the rule, just like |\midrule| of the
% \pkgname{booktabs} package. The difference to |\midrule| is that row
% colors (as specified by the |rowbg| property) are respected.
% The following example demonstrates the use of |\MidRule|.
%
% \begin{LTXexample}[morepreset=\RecipePreset,morekeywords={MidRule}]
% \begin{KeyValTable}{Recipe}
% \Row{amount=150g, ingredient=ice cream,
%   step=put into bowl}
% \Row{amount= 50g, ingredient=cherries,
%   step=heat up and add to bowl}
% \MidRule
% \Row{step=serve with a smile}
% \end{KeyValTable}
% \end{LTXexample}
%
% \NiceDescribeMacro{\CMidRule}{\oarg{width}\marg{columns}}
% This macro puts horizontal rules below each of the columns in the
% comma-separated list \meta{columns}. This comma-separated list can
% also contain names of column groups. The rules all have line width
% \meta{width}. The outcome is similar to what a set of |\cmidrule|'s
% would produce, except that row colors are respected and that column
% indexes need not be counted.
% The following example demonstrates the use of |\CMidRule|.
%
% \begin{LTXexample}[morekeywords={CMidRule}]
% \NewKeyValTable[headformat=\textbf]{Prices}{
%   part; min: align=r; max: align=r}[
%   headers={min+max: head=price},
%   colgroups={price: span=min+max}]
% \begin{KeyValTable}{Prices}
% \Row{part=engine, min=2500\$, max=3000\$}
% \Row{part=tires, min=500\$, max=700\$}
% \CMidRule[2pt]{price}
% \Row{part=$\Sigma$, min=3000\$, max=3700\$}
% \end{KeyValTable}
% \end{LTXexample}
%
% The following macros are provided for general use, in
% normal table environments.
% \newcommand\kvtparg[1]{\texttt{(}\meta{#1}\texttt{)}}%
% \NiceDescribeMacros{4}
%   {\kvtRuleTop}{\oarg{width}\marg{color2}}
%   {\kvtRuleBottom}{\oarg{width}\marg{color1}}
%   {\kvtRuleMid}{\oarg{width}\marg{color1}\marg{color2}}
%   {\kvtRuleCMid}{\oarg{width}\kvtparg{trim}\marg{a-b}\marg{color1}\marg{color2}}
% These macros are replacements for the macros |\toprule|,
% |\bottomrule|, |\midrule|, and |\cmidrule| of the \pkgname{booktabs}
% package, which do not integrate well with background colors of rows.
% The arguments \meta{color1} and \meta{color2} take the background
% color above and, respectively, below the rule.
%
% Note that while multiple |\cmidrule|s can follow each other and
% produce rules at the same horizontal position, this is not possible
% with |\kvtRuleCMid|. Instead, if multiple |\kvtRuleCMid|s are desired,
% one can use the following macro:
% \NiceDescribeMacro{\kvtRulesCMid}{\oarg{width}\marg{rlist}\marg{color1}\marg{color2}}
% In this macro, \meta{rlist} is a comma-separated list of
% "\kvtparg{trim}\marg{a-b}" pairs, where each \meta{trim} is optional.
% Consider the \pkgname{booktabs} documentation for more information
% about \meta{trim}.
%
%
% \subsection{Cell Appearance}
%
% Individual cells can be formatted by using the respective
% \hologo{LaTeX} code directly in the value of the cell.
% 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.
%
% \begin{LTXexample}
% \usepackage{url}\urlstyle{sf}
% \NewKeyValTable{Links}{
%   service;
%   url: format=\url }
% \begin{KeyValTable}{Links}
%   \Row{service=CTAN,
%     url=ctan.org/pkg/keyvaltable}
%   \Row{service=github,
%     url=github.com/Ri-Ga/keyvaltable}
%   \Row{service=Google Play, url*=none}
% \end{KeyValTable}
% \end{LTXexample}
%
% \subsection{Setting Global Defaults}\label{sec:kvtSet}
%
% \NiceDescribeMacro{\kvtSet}{\marg{options}}
% The \thispackage package allows changing the default values
% globally for the parameters of tables and columns. This can be done by
% using the |\kvtSet| macro.
%
% \begin{LTXexample}[morekeywords={kvtSet}]
% \kvtSet{headbg=red,default=?,align=r}
% \NewKeyValTable{Defaults}{x; y}
% \begin{KeyValTable}{Defaults}
% \Row{x=1}
% \Row{y=4}
% \end{KeyValTable}
% \end{LTXexample}
%
%
% \section{Customizing the Layout}
%
% The \thispackage package provides some means for altering tables
% beyond those described in the previous sections.
% Those means are described in the following.
%
% \subsection{Custom Table Headers}\label{sec:CustomHeaders}
%
% By default, a table type defined by |\NewKeyValTable| includes a
% single header row and each column of the table type has a header cell
% in this row.
% Through the optional \meta{layout} parameter of |\NewKeyValTable|,
% one can define multiple header rows and can define header cells that
% span multiple columns.
%
% The following two examples illustrate how the |headers| key in the
% \meta{layout} parameter can be used for specifying custom
% headers.\footnote{In \thispackage v1.0, the \meta{layout}
% parameter specified \emph{only} the headers and did not use a
% \texttt{headers} key for this. For compatibility, this can be enabled
% with the \texttt{compat=1.0} package option.}
% The first example produces a single header row in which two columns
% are grouped with a single header, one column has a normal header, and
% in which one column is not provided with a header.
% \begin{LTXexample}
% \NewKeyValTable{Headers1}{
%   id:     align=r, default=\thekvtRow.;
%   amount: align=r; ingredient: align=l;
%   step:   align=X;
% }[headers={
%     amount+ingredient: head=\textbf{ingredient};
%     step: head=\textbf{step}, align=l;
%   }
% ]
% \begin{KeyValTable}{Headers1}
% \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}
%
% The second example shows how multiple header rows can be specified
% and, particularly, how the normal column headers can be displayed
% through the use of "|::|".
% \begin{LTXexample}[width=0.5\hsize]
% \NewKeyValTable[headformat=\textbf,headalign=c]
%   {Headers2}{
%     date: align=r, head=date;
%     Berlin/min: align=r, head=min;
%     Berlin/max: align=r, head=max;
%     Paris/min:  align=r, head=min;
%     Paris/max:  align=r, head=max;
%   }[headers={
%     Berlin/min+Berlin/max+Paris/min+Paris/max:
%       head=temperature\\
%     Paris/min+Paris/max: head=Paris, underline;
%     Berlin/min+Berlin/max: head=Berlin, underline\\
%     ::}]
% \begin{KeyValTable}{Headers2}
% \Row{date=01.01.1970,
%      Berlin/min=0\degree C, Berlin/max=...}
% \end{KeyValTable}
% \end{LTXexample}
%
% The syntax for a \meta{value} of the |headers| key in the
% \meta{layout} parameter is as follows:
% \begin{itemize}[noitemsep]
% \item \meta{value} is a list, separated by "|\\|", where each
%   element in the list specifies the columns of a single header
%   \meta{row}.
% \item Each \meta{row}, in turn, is also a
%   list. The elements of this list are separated by "|;|" (as in the
%   columns specification of |\NewKeyValTable|) and each element
%   specifies a header \meta{cell}.
% \item Each \meta{cell} is of the form
%   \begin{center}
%     \meta{col}|+|\ldots|+|\meta{col}|:| \meta{property}|=|\meta{value}|,|
%     \meta{property}|=|\meta{value}|,|\ldots
%   \end{center}
%   where each \meta{col} is the name of a column.
%   The specified header cell then spans each of the listed columns.
%   The columns must be displayed consecutively, though not necessarily
%   in the same order in which they are specified in \meta{cell}.
% \end{itemize}
% The \meta{property}|=|\meta{value} pairs configure properties of the
% header cell. Supported \meta{property} keys are the following.
%
% \NiceDescribeKey{align}{vals={\vmeta{alignment-letter},\vmeta{empty}}, init=c}
%   This property specifies the alignment of content in the header cell.
%   The \meta{value} can be set to any column alignment understood by
%   the underlying table environment used (see \cref{sec:AltTabEnv}).
%   This particularly includes |l|, |c|, |r|, and |p|, as well as |X|
%   for some of the table environments.
%   The initial value can be modified with
%   |\kvtSet{HeadCell/align=...}|.
%
% \NiceDescribeKey{head}{vals=\vmeta{text}, init=\vmeta{colspec}}
%   This property specifies the content of the header cell.
%   The initial value for this property is the column specification,
%   i.e., "\meta{col}|+|\ldots|+|\meta{col}".
%
% \NiceDescribeKey{underline}{vals={true,false}, init=false, def=true}
%   This property specifies whether the header cell shall be underlined,
%   to visually indicate that the columns in the header cell form a
%   logical group.
%
%
% \subsection{Column Spanning}
%
% The \thispackage package supports column spanning via "column
% groups". A column group is a collection of adjacent columns, has
% its own name, and can be assigned a value just like "normal" columns
% can be.
% The following example demonstrates how column groups can be defined
% and be used.
%
% \begin{LTXexample}[morekeywords={colgroups}]
% \NewKeyValTable{AltRecipe}{
%   amount:     align=r, format=\textbf;
%   ingredient: align=l;
%   step:       align=X;
% }[colgroups={
%   all: span=step+amount+ingredient
% }]
% \begin{KeyValTable}{AltRecipe}
% \Row{amount=150g, ingredient=ice cream,
%   step=put into bowl}
% \Row{amount= 50g, ingredient=cherries,
%   step=heat up and add to bowl}
% \MidRule
% \Row{all=serve with a smile}
% \end{KeyValTable}
% \end{LTXexample}
%
% As the example shows, column groups are defined through the
% |colgroups| key of the second optional argument of |\NewKeyValTable|.
% This key expects a semicolon-separated list of individual column
% groups definitions.
% Each such definition takes the same shape as a normal column
% definition -- that is, first the name of the column group, then a
% colon, and then a comma-separated list of column properties.
% The properties that can be set are the following.
%
% \NiceDescribeKey{span}{vals=\vmeta{plus-separated columns}}
% This property specifies which columns the column group shall span, as
% a plus-separated list of column names. Some or all of the columns can
% be hidden. All the displayed columns must be adjacent in the table,
% though.
%
% \NiceDescribeKeys{2}
%   {align}{vals={\vmeta{alignment-letter},\vmeta{empty}}, init=c}
%   {format}{vals=\vmeta{single argument macro}, init=\vmeta{"identity"}}
% These properties are analogous to the respective properties of normal
% columns. The only difference is that the initial column alignment of
% column groups is "|c|" while the alignment of normal columns is "|l|".
%
% \begin{NiceNote}
%   Initial values for all the |align| and |format| options can be
%   set with |\kvtSet|, via the |ColGroup/align| and, respectively
%   |ColGroup/format| keys (see also \cref{sec:kvtSet}).
% \end{NiceNote}
%
%
% \subsubsection{Manual Column Spanning}
%
% The |\multicolumn| macro can be used for the content of a cell.
% The effect of this is that a number of subsequent cells are spanned
% over with the content of the cell. The following example demonstrates
% the use.
% \begin{LTXexample}[width=0.475\hsize,morekeywords={multicolumn}]
% \NewKeyValTable{MultiCol}{
%   col1: align=l;
%   col2: align=l;
%   col3: align=l;}
% \begin{KeyValTable}{MultiCol}
%   \Row{col1=1, col2=\multicolumn{1}{r}{2}, col3=3}
%   \Row{col1=1, col2=\multicolumn{2}{c}{2+3}}
%   \Row{col1=\multicolumn{2}{c}{1+2}, col3=3}
%   \Row{col1=\multicolumn{3}{c}{1+2+3}}
% \end{KeyValTable}
% \end{LTXexample}
% A word of warning:
% The |\multicolumn| macro implicitly constrains the ordering of
% columns. For instance, in the above example, switching columns 2 and 3
% would lead to an error in the second row (because |col2| is the
% rightmost column and therefore cannot span two columns) and also in
% the third row (because |col1| spans two columns but the second, |col3|
% is not empty). Thus, column spanning via |\multicolumn| should be used
% with care.
%
%
% \subsection{Captions}
%
% 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 the backends
% |tabular|, |tabularx|, and |tabu| (see \cref{sec:AltTabEnv}).
%
% \begin{LTXexample}[morepreset=\RecipePreset,morekeywords={caption,label,ref}]
% \begin{table}
%   \begin{KeyValTable}[shape=onepage]{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}
%   \caption{Cherries++}
%   \label{Cherries}
% \end{table}
% Table~\ref{Cherries} shows the recipe.
% \end{LTXexample}
%
% The second way to add captions is through the |caption| option of
% \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{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.
% 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\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}
% \Row{amount= 50g, ingredient=cherries,
%   step=heat up and add to bowl}
% \end{KeyValTable}
% Table~\ref{Cherries2} shows the recipe.
% \end{LTXexample}
%
%
% \subsection{Alternative Table Environments}
% \label{sec:AltTabEnv}
% 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 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 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[backend=tabular,headformat=\sffamily\textbf]{ShapeProps}{
%   shape: format=\small\texttt;
%   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;
%   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, 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, align=v, packages=tabu}
% \Row{shape=multipage, env=longtabu,  multipage=yes, caption=yes, Xcols=yes, width=yes, align=h, packages={tabu, longtable}}
% \MidRule
% \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 and backends}
% \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}]
% \NewKeyValTable[showrules=false]{ShapeNoX}{
%   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}[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}[backend=longtable]{ShapeNoX}
%   \Row{l=left,   c=center,     r=right}
%   \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}{
%   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}[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}[backend=xltabular]{ShapeWithX}
%   \Row{l=left,   X=expandable,   r=right}
%   \Row{l=left-2, X=expandable-2, r=2-right}
% \end{KeyValTable}
% \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}[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 backend option}
% \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}
%
% The |\kvtLabel| feature of the \thispackage package can be
% used together with named references, as provided by the
% \pkgname{cleveref} package. A name to a row label can be given by using
% the optional first argument to the |\kvtLabel| formatting macro and
% specifying the name to use using |\crefname|. The following example
% uses ``row'' for the optional argument and ``line'' for the displayed
% name of the reference.
% \begin{LTXexample}
% \usepackage{cleveref}
% \crefname{row}{line}{lines}
% \NewKeyValTable[headformat=\textbf]{NamedRef}{
%   label: align=r, head=Line,
%          format=\kvtLabel[row]{kvtRow};
%   text:  align=l, head=Text}
% \begin{KeyValTable}{NamedRef}
% \Row{text=First row, label=one}
% \Row{text=After \cref{one}}
% \end{KeyValTable}
% \end{LTXexample}
%
%
% \subsection{Tables from CSV Files (\pkgname{datatool} and \pkgname{csvsimple})}\label{sec:CSV}
%
% The \thispackage package itself does not offer its own functionality
% for generating tables from CSV files. However, together with existing
% CSV packages, table content can be sourced from CSV files.
% The remainder of this section shows how this can be achieved by
% example. The following CSV file serves as the data file in the
% examples. We use the same |Recipe| table type as previously.
%
% \lstinputlisting[caption=recipes.csv]{recipes.csv}
%
% \paragraph{\pkgname{datatool}}
% The package provides a variety of macros for loading and also
% displaying CSV database content. The following shows how the macros
% |\DTLloaddb| and |\DTLforeach*| can be used, together with
% |\AddKeyValRow| and |\ShowKeyValTable|.
% The example also shows how a simple filter can be applied to the rows
% via |\DTLforeach*|.
%
% \begin{LTXexample}[morepreset=\RecipePreset,morekeywords={DTLloaddb,DTLforeach,expandonce}]
% \usepackage{datatool}
% \DTLloaddb{recipes}{recipes.csv}
% \DTLforeach*[\equal{\Id}{snowman}]{recipes}
%   {\Id=id,
%    \Amount=amount,\Ingr=ingredient,\Step=step}
%   {\AddKeyValRow{Recipe}[expandonce]{
%    amount=\Amount,ingredient=\Ingr,step=\Step}}
% \ShowKeyValTable{Recipe}
% \end{LTXexample}
%
% Two aspects shall be noted.
% Firstly, we use |\AddKeyValRow| rather than |KeyValTable|,
% because |\DTLforeach*| interferes with how |KeyValTable| constructs
% its rows and yields "misplaced |\noalign|" errors. We do not use
% |\CollectRow| here, because it requires two runs and we do not need
% the feature to show the table before the rows are specified.
% Secondly, we use the row option |expandonce| to ensure that the macros
% |\Amount|, |\Ingr|, and |\Step| are expanded (i.e., replaced by their
% values). Without this option, all rows would only carry the three
% macros and display the value that these macros have at the time of the
% |\ShowKeyValTable|.
%
% \NiceDescribeKeys{2}
%    {expandonce}{vals={true,false}, init=false, def=true}
%    {expand}{vals={true,false}, init=false, def=true}
% These row options can be used when programmatically constructing the
% rows of a table, particularly with |KeyValTableContent| and
% |\CollectRow|.
% The |expandonce| option expands all the cell values
% given to a row (default values not included) exactly once before
% including it in the respective row.
% The |expand| option fully expands the cell values, in |protect|'ed
% mode (i.e., robust commands are not expanded).
%
%
% \paragraph{\pkgname{csvsimple}}
% For the sake of our example, using this package is very similar to
% using \pkgname{datatool}.
%
% \begin{LTXexample}[morepreset=\RecipePreset,morekeywords={csvreader,expand}]
% \usepackage{csvsimple}
% \csvreader[head to column names,
%   filter equal={\id}{cherries}]{recipes.csv}{}
%   {\AddKeyValRow{Recipe}[expand]{
%      amount=\amount,ingredient=\ingredient,
%      step=\step}}
% \ShowKeyValTable{Recipe}
% \end{LTXexample}
%
% Two differences are noteworthy here:
% First, we can avoid specifying macro names for the columns through the
% |head to column names|, which uses the column names as macro names.
% Second, we have to use the |expand| option rather than |expandonce|
% here, because \pkgname{csvsimple} apparently does not directly store
% the column value in the respective macro.
%
%
% \subsection{Computational Cells (\pkgname{xint})}
%
% The mechanism of cell formatting macros enables a simple means for
% automatically computing formulas contained in a column. This can be
% done, for instance using the \pkgname{xint} package and defining a
% custom format macro (here |\Math|) that takes over the computation.
% \begin{LTXexample}
% \usepackage{xintexpr}
% \newcommand\Math[1]{%
%    \xinttheexpr trunc(#1, 1)\relax}
% \NewKeyValTable{Calculating}{
%    type; value: align=r,format=\Math}
% \begin{KeyValTable}{Calculating}
% \Row{type=simple,   value=10+5.5}
% \Row{type=advanced, value=0.2*(9+2^8)}
% \end{KeyValTable}
% \end{LTXexample}
%
%
% \subsection{Cell Formatting (\pkgname{makecell})}
%
% The \thispackage package can be used together with the
% \pkgname{makecell} package in at least two ways:
% \begin{enumerate}[noitemsep]
% \item formatting header cells using the |head| property of columns;
% \item formatting content cells using the |format| property of columns.
% \end{enumerate}
% The following example gives an impression.
% \begin{LTXexample}
% \usepackage{makecell}
% \renewcommand\theadfont{\bfseries}
% \renewcommand\theadalign{lt}
% \NewKeyValTable{Header}{
%    first:  head=\thead{short};
%    second: head=\thead{two\\ lines};}
% \begin{KeyValTable}{Header}
% \Row{first=just a, second=test}
% \end{KeyValTable}
% \end{LTXexample}
%
%
% \clearpage
% \section{Related Packages}
%
% I'm not aware of any \LaTeX{} packages that pursue similar goals or
% provide similar functionality. The following \LaTeX{} packages provide
% loosely related functionalities to the \thispackage package.
%
% \begin{description}
% \item[\pkgname{tablestyles}:]
%   This package simplifies typesetting tables with common and/or more
%   appealing appearances than default \hologo{LaTeX} tables.
%   This corresponds to what \thispackage supports with the various
%   coloring and formatting options to |\kvtSet|, |\NewKeyValTable|, and
%   individual tables.
%   The \pkgname{tablestyles} package builds on the default
%   \hologo{LaTeX} environments and syntax for typesetting tables (with
%   column alignments specified in an argument to the table environment,
%   and columns separated by |&| in the body of the environment).
% \item[\pkgname{ctable}:]
%   This package focuses on typesetting tables with captions and notes.
%   With this package, the specification of table content is quite
%   close to normal |tabular| environments, except that the package's
%   table creation is done via a macro, |\ctable|.
% \item[\pkgname{easytable}:]
%   This package provides an environment |TAB| which simplifies the
%   creation of tables with particular horizontal and vertical cell
%   alignments, rules around cells, and cell width distributions. In
%   that sense, the package aims at simpler table creation, like
%   \thispackage. However, the package does not pursue
%   separation of content from presentation or re-use of table layouts.
% \item[\pkgname{tabularkv}:]
%   Despite the similarity in the name, this package pursues a different
%   purpose. Namely, this package provides means for specifying table
%   options such as width and height through an optional key-value
%   argument to the |tabularkv| environment. This package does not use
%   a key-value like specification for the content of tables.
% \end{description}
%
% \section{Future Work}
%
% \begin{itemize}
% \item support for different headers on the first page vs.\@ on
%   subsequent pages of a multipage table; support configurable spacing
%   between and above/below header rows
% \item support for more flexibility with regards to specifying
%   distinct captions on first/middle/last page of the table.
% \item improved row coloring that makes sure that the alternation
%   re-starts on continued pages of a table that spans several pages
% \item rerun detection for recorded rows (possibly via
%   \pkgname{rerunfilecheck})
% \item nesting of |KeyValTable| environments (this is so far not tested
%   by the package author and might not work or work only to a limited
%   extent)
% \end{itemize}
%
% \clearpage
%
% \StopEventually{}
%\iffalse
%<*package>
%\fi
%
% \section{Implementation}
% \etocsetnexttocdepth{2}
% \etoclocalmulticol[2]{\subsection*{Content}}
%
% \subsection{Package Dependencies}
%
% We use \pkgname{etoolbox} for some convenience macros that make the
% code more easily maintainable and use \pkgname{xkeyval} for options
% in key--value form. The \pkgname{trimspaces} package is used once for
% trimming spaces before a string comparison.
%    \begin{macrocode}
\RequirePackage{etoolbox}
\RequirePackage{xkeyval}
\RequirePackage{trimspaces}
%    \end{macrocode}
% We use \pkgname{booktabs} for nice horizontal lines,
% \pkgname{colortbl} for row coloring, and \pkgname{xcolor} for color
% names. To avoid package option clashes with \pkgname{xcolor}, we
% load it at the end of the preamble..
% \changes{v2.3}{2020/06/13}{Delayed loading of \pkgname{xcolor}}
%    \begin{macrocode}
\RequirePackage{colortbl}
\AtBeginDocument{\@ifpackageloaded{xcolor}{}{\RequirePackage{xcolor}}}
\RequirePackage{booktabs}
%    \end{macrocode}
%
% \subsection{Auxiliary Code}
%
% \subsubsection{List Parsing}
%
% \begin{macro}{\kvt@DeclareTrimListParser}
% The |\kvt@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@DeclareTrimListParser{%
  \@ifstar{\kvt@DeclareTrimListParser@i{*}}
          {\kvt@DeclareTrimListParser@i{}}}
\newcommand\kvt@DeclareTrimListParser@i[3]{%
  \DeclareListParser#1{#2}{#3}\expandafter
  \patchcmd\csname etb@lst@\expandafter\@gobble\string#2\endcsname
    {\etb@listitem}{\kvt@etb@listitem}{}
    {\kvt@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@etb@listitem[2]{%
  \expandafter\expandafter\expandafter\kvt@etb@listitem@i
  \expandafter\expandafter\expandafter{\trim@post@space@noexp{#2}}{#1}}
\newcommand\kvt@etb@listitem@i[2]{\etb@listitem{#2}{#1}}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\kvt@dossvlist}
% The |\kvt@dossvlist|\marg{list} macro parses a semicolon-separated
% list and runs |\do|\meta{item} for every element of the list.
%    \begin{macrocode}
\DeclareListParser{\kvt@dossvlist}{;}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\kvt@forpsvlist}
% The |\kvt@forpsvlist|\marg{handler}\marg{list} parses a `+'-separated list.
%    \begin{macrocode}
\kvt@DeclareTrimListParser*{\kvt@forpsvlist}{+}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\kvt@dobrklist}
% The |\kvt@dobrklist|\marg{list} parses a `|\\|'-separated list.
%    \begin{macrocode}
\kvt@DeclareTrimListParser{\kvt@dobrklist}{\\}
%    \end{macrocode}
% \end{macro}
%
% \subsubsection{Errors and Warnings}
%
% \begin{macro}{\kvt@error}
% \begin{macro}{\kvt@warn}
% These macros produce error and warning messages.
%    \begin{macrocode}
\newcommand\kvt@error[2]{\PackageError{keyvaltable}{#1}{#2}}
\newcommand\kvt@warn[1]{\PackageWarning{keyvaltable}{#1}}
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \subsubsection{Setting Keys}
%
% \begin{macro}{\kvt@setkeys}
% \begin{macro}{\kvt@setcmdkeys}
% \begin{macro}{\kvt@setcskeys}
% The |\kvt@setkeys|\marg{keys}\marg{fam} macro abbreviates
% |\setkeys[kvt]|\meta{fam}\meta{keys} (note the reverse order of
% arguments).
% The |\kvt@setcmdkeys|\marg{keycmd}\marg{fam} and
% |\kvt@setcskeys|\marg{keycs}\marg{fam} abbreviate the cases where
% \meta{keys} are stored in macro \meta{keycmd} or, respectively,
% stored in a macro with name \meta{keycs}.
%    \begin{macrocode}
\newcommand\kvt@setkeys[2]{\setkeys[kvt]{#2}{#1}}
\newcommand\kvt@setcmdkeys[2]{%
  \expandafter\kvt@setkeys\expandafter{#1}{#2}}
\newcommand\kvt@setcskeys[2]{%
  \expandafter\kvt@setcmdkeys\expandafter{\csname #1\endcsname}{#2}}
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\kvt@setkeys@nopresets}
% The
% |\kvt@setkeys@nopresets|\marg{keys}\marg{family} macro
% expands to a |\kvt@setkeys| in which no presets are active.
%    \begin{macrocode}
\newcommand\kvt@setkeys@nopresets[2]{%
  \kvt@xkv@disablepreset[kvt]{#2}{\kvt@setkeys{#1}{#2}}}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\kvt@colsetkeys}
% \begin{macro}{\kvt@colsetcmdkeys}
% \begin{macro}{\kvt@colsetcskeys}
% The |\kvt@colsetkeys|\marg{fam}\marg{keys} macro abbreviates
% |\setkeys[KeyValTable]| with the same arguments.
% The |\kvt@colsetcmdkeys|\marg{famcmd}\marg{keys} and
% |\kvt@colsetcskeys|\marg{famcs}\marg{keys} abbreviate the cases where
% \meta{fam} is stored in macro \meta{famcmd} or, respectively,
% stored in a macro with name \meta{famcs}.
%    \begin{macrocode}
\newcommand\kvt@colsetkeys[2]{\setkeys[KeyValTable]{#1}{#2}}
\newcommand\kvt@colsetcmdkeys[2]{%
  \expandafter\kvt@colsetkeys\expandafter{#1}{#2}}
\newcommand\kvt@colsetcskeys[2]{%
  \expandafter\kvt@colsetcmdkeys\expandafter{\csname #1\endcsname}{#2}}
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\kvtStrutted}
% The |\kvtStrutted|\oarg{inner}\marg{arg} macro prefixes and suffixes
% the argument \meta{arg} with a |\strut|. When used for formatting
% cell content, this makes sure that there is some vertical space
% between the content of a cell and the top and bottom of the row.
% The optional \oarg{inner} argument, if provided, should be a macro
% that takes one argument. In this case, instead of \meta{arg},
% \meta{inner}|{|\meta{arg}|}| is prefixed and sufficed with |\strut|.
% \changes{v0.3}{2016/06/06}{Fix for cells with vertical material}
% \changes{v2.0}{2019/03/22}{Added optional argument}
%    \begin{macrocode}
\newcommand\kvtStrutted[2][\@firstofone]{%
  \strut#1{#2}\ifhmode\expandafter\strut\fi}
%    \end{macrocode}
% \end{macro}
%
%
% \subsection{Setting Options}
%
% \begin{macro}{\kvtSet}
% The |\kvtSet|\marg{options} set the default options, which apply
% to all tables typeset with the package.
%    \begin{macrocode}
\newcommand\kvtSet[1]{%
  \kvt@setkeys{#1}{global,Table,Column}%
  \ifdefvoid\kvt@@presetqueue{}
    {\kvt@@presetqueue\undef\kvt@@presetqueue}}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\kvt@lazypreset}
% The |\kvt@@lazypreset|\marg{family}\marg{head keys} macro collects a
% request for pre-setting \meta{head keys} in family
% key \meta{family}. Using this macro, one can avoid causing problems
% with using \pkgname{xkeyval}'s |\presetkeys| inside the \meta{function}
% defined for a key (e.g., via |\define@key|). The collected requests
% can be performed by expanding the |\kvt@@presetqueue| macro.
%    \begin{macrocode}
\newcommand\kvt@lazypreset[2]{%
  \appto\kvt@@presetqueue{\presetkeys[kvt]{#1}{#2}{}}}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\kvt@keysetter}
% The
% |\kvt@keysetter|\marg{macro}\marg{fam}\marg{key}\marg{value}\marg{func}
% macro is an auxiliary macro that can be used inside the "func"
% argument of |\define@...key| macros.
% If \meta{macro} is not defined, |\kvt@keysetter| expands to an
% instance of |\kvt@lazypreset| in order to set a global default.
% Otherwise, |\kvt@keysetter| expands to \meta{func}, which is supposed
% to set a key for the specific context referenced by \meta{macro}.
%    \begin{macrocode}
\newcommand\kvt@keysetter[5]{%
  \ifdefvoid{#1}
    {\kvt@lazypreset{#2}{#3=#4}}
    {#5}}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\kvtTableOpt}
% The |\kvtTableOpt|\marg{optname} macro, inside a |KeyValTable|
% environment, expands to the value of the table option \meta{optname}.
%    \begin{macrocode}
\newcommand\kvtTableOpt[1]{\csname cmdkvt@Table@#1\endcsname}
%    \end{macrocode}
% \end{macro}
%
% \subsubsection{Table Options}
%
% 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.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@cmdkey[kvt]{Table}{rowbg}{}
\define@cmdkey[kvt]{Table}{headbg}{}
\define@cmdkey[kvt]{Table}{headalign}{}
\define@cmdkey[kvt]{Table}{headformat}{}
\define@cmdkey[kvt]{Table}{width}{}
\define@boolkey[kvt]{Table}{showhead}{}
\define@boolkey[kvt]{Table}{showrules}{}
\define@choicekey[kvt]{Table}{captionpos}{t,b}
  {\csdef{cmdkvt@Table@captionpos}{#1}}
\define@choicekey[kvt]{Table}{valign}{t,c,b}
  {\csdef{cmdkvt@Table@valign}{#1}}
\define@choicekey[kvt]{Table}{halign}{l,c,r}
  {\csdef{cmdkvt@Table@halign}{#1}}
\define@key[kvt]{Table}{style}{\kvt@UseTableStyles{#1}}
%    \end{macrocode}
% The following options only abbreviate options defined above.
% \changes{v2.1}{2020/01/14}{added abbreviation option "norules"}
%    \begin{macrocode}
\define@boolkey[kvt]{Table}{norowbg}[true]{%
  \kvt@setkeys{rowbg={}}{Table}}
\define@boolkey[kvt]{Table}{nobg}[true]{%
  \kvt@setkeys{rowbg={},headbg={}}{Table}}
\define@boolkey[kvt]{Table}{norules}[true]{%
  \ifbool{#1}
    {\kvt@setkeys{showrules=false}{Table}}
    {\kvt@setkeys{showrules=true}{Table}}}
\define@key[kvt]{Table}{backend}{\ifinlist{#1}{\kvt@@tablebackends}
  {\csdef{cmdkvt@Table@shape}{#1}}
  {\kvt@error{Table backend '#1' not known}
     {Check for misspellings in '#1'}}}
\define@key[kvt]{Table}{shape}{\ifinlist{#1}{\kvt@@tableshapes}
  {\csdef{cmdkvt@Table@shape}{#1}}
  {\ifinlist{#1}{\kvt@@tablebackends}
    {\kvt@warn{Using a backend ('#1') as shape is deprecated.
      Use the 'backend' option instead.}%
     \csdef{cmdkvt@Table@shape}{#1}}
    {\kvt@error{Table shape '#1' not known}
       {Check for misspellings in '#1'}}}}
%    \end{macrocode}
%
% 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@cmdkey[kvt]{TableEnv}{caption}{}
\define@cmdkey[kvt]{TableEnv}{caption/lot}{}
\define@cmdkey[kvt]{TableEnv}{caption/alt}{}
\define@cmdkey[kvt]{TableEnv}{label}{}
\define@boolkey[kvt]{TableEnv}{resume}[true]{%
  \ifbool{#1}{\ifundef\kvt@@rowcountlast
    {\kvt@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@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@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@setcmdkeys\kvt@@lastenvopt{Table}%
     \kvt@setkeys{resume}{TableEnv}}
    {}}
%    \end{macrocode}
%
%
% \subsubsection{Column Options}
%
% The following code defines the possible column options.
%
% \changes{v1.0}{2018/12/30}{Enabled default ``true'' for ``hidden''}
%    \begin{macrocode}
\define@key[kvt]{Column}{default}{\kvt@colkeysetter{default}{#1}}
\define@key[kvt]{Column}{format}{\kvt@colkeysetter{format}{#1}}
\define@key[kvt]{Column}{align}{\kvt@colkeysetter{align}{#1}}
\define@key[kvt]{Column}{head}{\kvt@colkeysetter{head}{#1}}
\define@boolkey[kvt]{Column}{hidden}[true]{%
  \kvt@colkeysetter{hidden}{#1}}
%    \end{macrocode}
%
% \begin{macro}{\kvt@colkeysetter}
% The |\kvt@colkeysetter|\marg{key}\marg{value} specializes
% |\kvt@keysetter| for column options.
%    \begin{macrocode}
\newcommand\kvt@colkeysetter[2]{%
  \kvt@keysetter{\kvt@@column}{Column}{#1}{#2}{%
    \csdef{kvt@col@#1@\kvt@@column}{#2}}}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\kvt@def@globalopt}
% \begin{macro}{\kvt@def@globalopts}
% The |\kvt@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@def@globalopts|\marg{family}{keys} macro extends the former
% macro to comma-separated lists of \meta{keys} within a single
% \meta{family}.
%    \begin{macrocode}
\newcommand\kvt@def@globalopt[2]{%
  \define@key[kvt]{global}{#1/#2}{\kvt@lazypreset{#1}{#2={##1}}}}
\newcommand\kvt@def@globalopts[2]{%
  \forcsvlist{\kvt@def@globalopt{#1}}{#2}}
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
%    \begin{macrocode}
\define@cmdkey[kvt]{ColGroup}{span}{%
  \csgdef{kvt@colgrp@span@\kvt@@tname @\kvt@@colgrp}{#1}}
\define@cmdkey[kvt]{ColGroup}{align}{%
  \csgdef{kvt@colgrp@align@\kvt@@tname @\kvt@@colgrp}{#1}}
\define@cmdkey[kvt]{ColGroup}{format}{%
  \csgdef{kvt@colgrp@format@\kvt@@tname @\kvt@@colgrp}{#1}}
\kvt@def@globalopts{ColGroup}{align, format}
%    \end{macrocode}
%
%
% \subsubsection{Layout Customization Options}
%
% 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@cmdkey[kvt]{Layout}{headers}{%
  \expandafter\kvt@parseheadrows\expandafter{\kvt@@tname}{#1}}
\define@cmdkey[kvt]{Layout}{colgroups}{%
  \expandafter\kvt@parsecolgroups\expandafter{\kvt@@tname}{#1}}
%    \end{macrocode}
%
% The following defines the options for header cells.
%    \begin{macrocode}
\define@key[kvt]{HeadCell}{head}{%
  \csdef{kvt@@hdcell@head@\kvt@@hdcell}{#1}}
\define@key[kvt]{HeadCell}{align}{%
  \csdef{kvt@@hdcell@align@\kvt@@hdcell}{#1}}
\define@boolkey[kvt]{HeadCell}{underline}[true]{%
  \csdef{kvt@@hdcell@underline@\kvt@@hdcell}{#1}}
\kvt@def@globalopts{HeadCell}{align}
%    \end{macrocode}
%
%
% \subsubsection{Row Options}
%
% The following block declares the known row options.
% Note that these are not enabled for |\kvtSet|.
% \changes{v2.0}{2019/05/11}{added row options "expand" and "expandonce"}
% \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@cmdkey[kvt]{Row}{bg}{}
\define@cmdkey[kvt]{Row}{format}{}
\define@cmdkey[kvt]{Row}{format*}{}
\define@cmdkey[kvt]{Row}{format!}{}
\define@cmdkey[kvt]{Row}{align}{}
\define@boolkey[kvt]{Row}{headlike}[true]{%
  \ifbool{#1}{%
    \edef\kvt@@opts{%
      bg={\expandonce\cmdkvt@Table@headbg},%
      format!={\expandonce\cmdkvt@Table@headformat},%
      align={\expandonce\cmdkvt@Table@headalign}}%
    \expandafter\kvt@setkeys@nopresets\expandafter{\kvt@@opts}{Row}%
  }{}}
\define@boolkey[kvt]{Row}{hidden}[true]{}
\define@cmdkey[kvt]{Row}{below}{}
\define@cmdkey[kvt]{Row}{above}{}
\define@key[kvt]{Row}{around}{%
  \kvt@setkeys@nopresets{below={#1},above={#1}}{Row}}
\define@key[kvt]{Row}{style}{\kvt@UseRowStyles{#1}}
\define@boolkey[kvt]{Row}{uncounted}[true]{}
\define@boolkey[kvt]{Row}{expand}[true]{}
\define@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@def@globalopts{Row}{
  bg,hidden,below,above,around,style,uncounted,
  expand,expandonce}
%    \end{macrocode}
%
%
% \subsubsection{Option Defaults}
%
% 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.
% \changes{v2.3}{2020/07/30}{Removed \cmd{\kvtStrutted} from default format}
%    \begin{macrocode}
\AtEndOfPackage{\kvtSet{%
  rowbg=white..black!10,
  headbg=black!14,
  showhead=true,
  showrules=true,
  headformat=\@firstofone,
  headalign=,
  shape=multipage,
  width=\linewidth,
  captionpos=b,
%    \end{macrocode}
% Column options
%    \begin{macrocode}
  default=,
  format=\@firstofone,
  align=l,
  head=,
  hidden=false,
  Row/bg={},
  Row/hidden=false,
  Row/above={},
  Row/below={},
  Row/uncounted=false,
  Row/expand=false,
  Row/expandonce=false,
  ColGroup/align=c,
  ColGroup/format=\@firstofone,
  HeadCell/align=c,
}}
%    \end{macrocode}
%
%
% \subsection{Declaring Key-Value Tables}
%
% \begin{macro}{\NewKeyValTable}
% The
% |\NewKeyValTable|\oarg{options}\marg{tname}\marg{colspecs}\oarg{layout}
% declares a new key-value table type, identified by the given
% \meta{tname}. The columns of the table type are specified by
% \meta{colspecs}. The optional \meta{options}, if given, override the
% default table options for tables of type \meta{tname}.
% \changes{v0.2}{2016/05/21}{Added table-type options}
% \changes{v1.0}{2019/02/03}{Added optional headers argument}
% \changes{v2.0}{2019/04/28}{Changed headers argument to layout argument}
%    \begin{macrocode}
\newcommand\NewKeyValTable[3][]{%
  \@ifnextchar[%]
    {\kvt@NewKeyValTable{#1}{#2}{#3}}%
    {\kvt@NewKeyValTable{#1}{#2}{#3}[]}}
%    \end{macrocode}
% The
% |\kvt@NewKeyValTable|\marg{options}\marg{tname}\marg{colspecs}\oarg{layout}
% macro is an auxiliary macro used for parsing the fourth, optional
% argument of |\NewKeyValTable|.
%    \begin{macrocode}
\def\kvt@NewKeyValTable#1#2#3[#4]{%
%    \end{macrocode}
% Before doing anything, check whether \meta{tname} has already been
% defined.
%    \begin{macrocode}
  \ifinlist{#2}{\kvt@alltables}
    {\kvt@error{Table type with name '#2' already defined}
      {Check '#2' for typos and check other uses of
      \string\NewKeyValTable}}{}%
%    \end{macrocode}
% First initialize the ``variables''.
%    \begin{macrocode}
  \csdef{kvt@options@#2}{#1}%
  \csdef{kvt@headings@#2}{}%
%    \end{macrocode}
% The following adds a zero-width column to the left of every table.
% This column serves the purpose of "holding" the code that
% \thispackage uses for formatting a row (e.g., parsing |\Row|
% arguments). This code is partly not expandable.
% The reason for not putting this code into the first actual colum of
% 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}}
% \changes{v2.1}{2020/02/16}{Removed zero-width column again}
%    \begin{macrocode}
  \csdef{kvt@alignments@#2}{}%
  \csdef{kvt@allcolumns@#2}{}%
  \csdef{kvt@displaycols@#2}{}%
  \csdef{kvt@ndisplaycols@#2}{0}%
  \csdef{kvt@rowcount@#2}{0}%
  \csdef{kvt@rows@#2}{}%
  \csdef{kvt@headings@#2}{\kvt@defaultheader}%
  \listadd\kvt@alltables{#2}%
%    \end{macrocode}
% Now parse \meta{colspecs}, a semicolon-separated list of individual
% column specifications, and add the columns to the table. Each
% |\do|\marg{colspec} takes the specification for a single column.
%    \begin{macrocode}
  \def\do##1{%
    \kvt@parsecolspec{#2}##1::\@undefined}%
  \kvt@dossvlist{#3}%
%    \end{macrocode}
% By default, a single header row is constructed.
%    \begin{macrocode}
  \csdef{kvt@headrowcount@#2}{1}%
%    \end{macrocode}
% The following terminates the argument list of |\kvt@defaultheader|.
%    \begin{macrocode}
  \csappto{kvt@headings@#2}{{\@nil}}%
%    \end{macrocode}
% Finally, parse \meta{layout}.
%    \begin{macrocode}
  \kvt@parselayout{#4}{#2}%
}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\kvt@parsecolspec}
% The
% |\kvt@parsecolspec|\marg{tname}\meta{cname}|:|\meta{config}|:|\meta{empty}|\@undefined|
% takes a configuration \meta{config} for a column \meta{cname} in table
% \meta{tname} and adds the column with the configuration to the table.
%    \begin{macrocode}
\def\kvt@parsecolspec#1#2:#3:#4\@undefined{%
%    \end{macrocode}
% Catch syntax errors first.
%    \begin{macrocode}
  \kvt@checkcolspecempty{#4}{column}{#2}%
  \def\kvt@@column{#2}%
  \trim@spaces@in\kvt@@column
  \expandafter\kvt@parsecolspec@i\expandafter{\kvt@@column}{#1}{#3}}
\newcommand\kvt@parsecolspec@i[3]{\kvt@parsecolspec@ii{#2}{#1}{#3}}
\newcommand\kvt@parsecolspec@ii[3]{%
  \def\kvt@@column{#1@#2}%
%    \end{macrocode}
% Check and record the column name first.
%    \begin{macrocode}
  \ifinlistcs{#2}{kvt@allcolumns@#1}
    {\kvt@error{Column name '#2' declared more than once in table type
      '#1'}{Check '#2' for typos; column names declared so far:%
      \forlistcsloop{ }{kvt@allcolumns@#1}}}{}%
  \listcsadd{kvt@allcolumns@#1}{#2}%
  \kvt@setkeys{#3}{Column}%
%    \end{macrocode}
% The following stores the column's properties. The column is only added
% if the |hidden| option is not set to |true|.
%    \begin{macrocode}
  \ifcsstring{kvt@col@hidden@#1@#2}{true}{}{%
    \cseappto{kvt@alignments@#1}{\csexpandonce{kvt@col@align@#1@#2}}%
%    \end{macrocode}
% Append the column heading to \cs{kvt@headings@\meta{tname}}, which
% collects arguments to |\kvt@defaultheader|. Hence, the appended tokens
% are enclosed in curly braces. If no |head| is specified for the
% column, \meta{cname} is used for the column header. Otherwise, the
% |head| value is used.
%    \begin{macrocode}
    \ifcsvoid{kvt@col@head@#1@#2}%
      {\csappto{kvt@headings@#1}{{#2}}}%
      {\cseappto{kvt@headings@#1}{{\csexpandonce{kvt@col@head@#1@#2}}}}%
    \listcsadd{kvt@displaycols@#1}{#2}%
    \csedef{kvt@ndisplaycols@#1}{%
      \the\numexpr\csuse{kvt@ndisplaycols@#1}+1\relax}%
  }%
%    \end{macrocode}
% The following creates the column key that can be used by the row
% macros to set the content of the column's content in that row.
% The starred variant of the key disables the column's |format| for the
% cell.
%    \begin{macrocode}
  \define@cmdkey[KeyValTable]{#1}{#2}[]{}%
  \define@key[KeyValTable]{#1}{#2*}{%
    \csdef{cmdKeyValTable@#1@#2}{##1}%
    \csdef{kvt@@noformat@#1@#2}{1}}%
  \presetkeys[KeyValTable]{#1}{#2}{}%
%    \end{macrocode}
% The |\kvt@parsecolspec| macro is not necessarily enclosed in a group.
% To avoid leaking a local |\kvt@@column| value to the outer (global)
% scope, we explicitly undefine it.
%    \begin{macrocode}
  \undef\kvt@@column}
%    \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\kvt@defaultheader}
% The |\kvt@defaultheader|\marg{head1}\ldots\marg{headn}|\@nil| macro,
% 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@defaultheader| yields
% "\meta{rowcolor}\meta{fmthead1}| & |\ldots| & |\meta{fmtheadn}|\tabularnewline|".
% In the above, \meta{rowcolor}=|\rowcolor{|\meta{headbg}|}|.
%    \begin{macrocode}
\newcommand\kvt@defaultheader{%
  \noexpand\kvt@rowcolorornot{\cmdkvt@Table@headbg}%
  \kvt@defaultheader@i{}}
\newcommand\kvt@defaultheader@i[2]{%
  \kvt@ifnil{#2}{\noexpand\tabularnewline}{%
    \unexpanded{#1}%
    \ifdefvoid\cmdkvt@Table@headalign
      {\expandonce\cmdkvt@Table@headformat{\unexpanded{#2}}}
      {\noexpand\multicolumn{1}{\expandonce\cmdkvt@Table@headalign}
        {\expandonce\cmdkvt@Table@headformat{\unexpanded{#2}}}}%
    \kvt@defaultheader@i{&}}}
%    \end{macrocode}
% \begin{macro}{\kvt@ifnil}
% The |\kvt@ifnil|\marg{val}\marg{iftrue}\marg{iffalse} macro expands to
% \meta{iftrue} if \meta{val} is |\@nil|, and expands to \meta{iffalse}
% otherwise.
% Fixme: The |\relax| in the following is not fully ideal as it is not
% swallowed by the |\ifx| and therefore remains in the macro's
% expansion.
%    \begin{macrocode}
\newcommand\kvt@ifnil[1]{%
  \ifx\@nil#1\relax
    \expandafter\@firstoftwo\else
    \expandafter\@secondoftwo\fi}
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\kvt@alltables}
% The |\kvt@alltables| is an \pkgname{etoolbox} list containing the names
% of all tables declared by |\NewKeyValTable|.
%    \begin{macrocode}
\newcommand\kvt@alltables{}
%    \end{macrocode}
% \end{macro}
%
%
% \subsection{Custom Layout Parameters}
%
% \begin{macro}{\kvt@parselayout}
% The |\kvt@parselayout|\marg{layout-opts}\marg{tname} macro parses the
% layout options, \meta{layout-opts}, for table type \meta{tname},
%    \begin{macrocode}
\newcommand\kvt@parselayout[2]{%
  \def\kvt@@tname{#2}%
%    \end{macrocode}
% Now parse the \meta{layout-opts}. The keys are defined such that their
% handlers already do the parsing.
%    \begin{macrocode}
  \kvt@setkeys{#1}{Layout}%
  \undef\kvt@@tname}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\kvt@parsecolgroups}
% The |\kvt@parsecolgroups|\marg{tname}\marg{spec} macro parses the
% specification, \meta{spec}, of column groups for table type
% \meta{tname}.
%    \begin{macrocode}
\newcommand\kvt@parsecolgroups[2]{%
  \begingroup
%    \end{macrocode}
% |\kvt@@result| collects the parsing outcome code that shall escape the
% group started above.
%    \begin{macrocode}
  \def\kvt@@result{}%
  \def\do##1{\kvt@parsecolgroup{#1}##1::\@undefined}%
  \kvt@dossvlist{#2}%
  \expandafter\endgroup\kvt@@result}
%    \end{macrocode}
% The
% |\kvt@parsecolgroup|\marg{tname}\marg{cgname}\marg{cgopts}\marg{empty}
% macro parses a single column group, \meta{cgname} with options
% \meta{cgopts}.
%    \begin{macrocode}
\def\kvt@parsecolgroup#1#2:#3:#4\@undefined{%
%    \end{macrocode}
% Catch syntax errors first.
%    \begin{macrocode}
  \kvt@checkcolspecempty{#4}{column group}{#2}%
%    \end{macrocode}
% Next, check for a valid \meta{cgname}.
%    \begin{macrocode}
  \ifinlistcs{#2}{kvt@allcolumns@#1}{\kvt@error
    {Name `#2' cannot be used for a column group in table type `#1',
     as it is already used for a column}
    {Check the \string\NewKeyValTable{#1} for
     the names of known columns and check `#2' for a typo.}}{}%
  \ifinlistcs{#2}{kvt@grpcolkeys@#1}{\kvt@error
    {Name `#2' is used twice in table type `#1'}
    {Check the \string\NewKeyValTable{#1} for typos in the names of
     columns groups.}}{}%
  \def\kvt@@colgrp{#2}%
  \kvt@setkeys{#3}{ColGroup}%
  \kvt@checkcolgroupcs{kvt@colgrp@span@#1@#2}{#1}{#2}%
%    \end{macrocode}
% Store the result of |\kvt@checkcolgroupcs| for later use.
%    \begin{macrocode}
  \csxdef{kvt@colgrp@first@#1@#2}{\kvt@@colgrp@first}%
  \csxdef{kvt@colgrp@count@#1@#2}{\kvt@@colgrp@n}%
%    \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@first| to a |\multicolumn| that spans the
% "right" number of columns).
%    \begin{macrocode}
  \eappto\kvt@@result{%
    \noexpand\define@cmdkey[KeyValTable]{#1}{#2}{%
%    \end{macrocode}
% The following |\ifdefvoid| check ensures that if \meta{cgname} is a
% hidden column group (i.e., a column group of which all spanned columns
% are hidden), then setting \meta{cgname} to a value has no effect.
%    \begin{macrocode}
      \ifdefvoid\kvt@@colgrp@first{}{%
%    \end{macrocode}
% The "abbreviation" is implemented via |\setkeys|. The letter normally
% employs the defined |\presetkeys|, but we disable this through
% |\kvt@xkv@disablepreset| to avoid that column keys that are set before
% a colgroup key are overwritten by their preset values.
%    \begin{macrocode}
        \noexpand\kvt@xkv@disablepreset[KeyValTable]{#1}{%
          \noexpand\setkeys[KeyValTable]{#1}{%
%    \end{macrocode}
% Notice the "*" after |\kvt@@colgrp@first|,
% which disables the first column's default formatting to replace it by
% the formatting of \meta{cgname}.
%    \begin{macrocode}
            \expandonce\kvt@@colgrp@first=\noexpand\kvt@@@colgroup
              {\unexpanded{#2}}%
              {\expandonce\kvt@@colgrp@n}%
              {\csexpandonce{kvt@colgrp@align@#1@#2}}%
              {\unexpanded{##1}}}}%
      }%
    }}%
    \listcsadd{kvt@grpcolkeys@#1}{#2}}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\kvt@checkcolspecempty}
% The |\kvt@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@checkcolspecempty[3]{%
  \ifstrempty{#1}{}{\ifstrequal{#1}{:}{}{\kvt@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@checkcolgroup}
% The |\kvt@checkcolgroup|\marg{span-psv}\marg{tname}\marg{cgname} macro
% performs some checks on \meta{span-psv} as a specification of which
% columns shall be spanned by a group column of name \meta{cgname}.
% The checks are
% \begin{itemize}
% \item whether all column names are indeed columns of \meta{tname},
% \item whether each column appears at most once in the column group,
%   and
% \item whether the (displayed) columns from \meta{span-psv} appear
%   consecutively in \meta{tname}.
% \end{itemize}
% The macro returns the number of spanned (displayed!) columns in
% |\kvt@@colgrp@n| and the name of the first column in
% |\kvt@@colgrp@first|.
%
% Fixme: There can probably be some code sharing with
% |\kvt@parseheadrow| and |\kvt@parsecolgroup|.
%    \begin{macrocode}
\newcommand\kvt@checkcolgroup[3]{%
%    \end{macrocode}
% First, check individual colums in \meta{span-psv} and transfer them
% into a "map", |kvt@@incolgrp@| that simply records which column names
% occur in \meta{span-psv}.
%    \begin{macrocode}
  \def\kvt@@psvdo##1{%
    \ifinlistcs{##1}{kvt@allcolumns@#2}{}{\kvt@error
      {Column `##1' referenced in column group `#3' not known
       in table type `#2'}
      {Check the \string\NewKeyValTable{#2} for
       the names of known columns and check `##1' for a typo.}}%
    \ifcsvoid{kvt@@incolgrp@##1}{}{\kvt@error
      {Column `##1' used more than once in column group `#3' of table
       type `#2'}
      {Check `##1' for a typo.}}%
    \csdef{kvt@@incolgrp@##1}{#2}%
  }\kvt@forpsvlist{\kvt@@psvdo}{#1}%
%    \end{macrocode}
% The following two macros are the "return values".
%    \begin{macrocode}
  \def\kvt@@colgrp@n{0}%
  \let\kvt@@colgrp@first\relax
%    \end{macrocode}
% Second, iterate over the displayed columns of \meta{tname} to check
% whether the columns in \meta{span-psv} are consecutive.
% For this, use |\kvt@@status| to track
% whether no column of \meta{span-psv} has yet been visited (value 0,
% the initial value),
% whether the current column is part of \meta{span-psv} (value 1), and
% whether columns of \meta{span-psv} have been visited but the current
% column is not part of \meta{span-psv} (value 2).
%    \begin{macrocode}
  \def\kvt@@status{0}%
%    \end{macrocode}
% |\kvt@@coldo|\marg{column} is applied to each displayed column, in
% order.
%    \begin{macrocode}
  \def\kvt@@coldo##1{%
    \ifcsvoid{kvt@@incolgrp@##1}
%    \end{macrocode}
% If \meta{column} is \emph{not} in \meta{span-psv}, then change
% |\kvt@@status| from 1 to 2, but do not change it when it is 0 or 2.
%    \begin{macrocode}
      {\expandafter\ifcase\kvt@@status \or
        \def\kvt@@status{2}\fi}%
%    \end{macrocode}
% If \meta{column} is in \meta{span-psv}, then change |\kvt@@status|
% from 0 to 1 and record \meta{column} as |\kvt@@colgrp@first|; if
% |\kvt@@status| is previously 2, then the columns in \meta{span-psv}
% would not be consecutively displayed and, hence, an error is raised.
%    \begin{macrocode}
      {\expandafter\ifcase\kvt@@status
        \def\kvt@@status{1}\def\kvt@@colgrp@first{##1}%
        \or\or
        \kvt@error{Column group `\kvt@@colgrp' must consist of only
           consecutive columns, but it is not}%
          {Compare `\string\kvt@@curgrp' to the column ordering as
           specified in `\string\NewKeyValTable{#1}'}%
        \fi
        \edef\kvt@@colgrp@n{\the\numexpr\kvt@@colgrp@n+1\relax}%
%    \end{macrocode}
% Since this macro is not encapsulated in a group (in order to return
% |\kvt@@colgrp@n| and |\kvt@@colgrp@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@displaycols@#2}}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\kvt@checkcolgroupcs}
% The |\kvt@checkcolgroupcs|\marg{span-psv-cs}\marg{tname}\marg{cgname}
% macro is the same as |\kvt@checkcolgroup| except that it takes a
% control sequence name as its first argument rather than a
% plus-separated list directly.
%    \begin{macrocode}
\newcommand\kvt@checkcolgroupcs[3]{%
  \expandafter\expandafter\expandafter
  \kvt@checkcolgroup
  \expandafter\expandafter\expandafter{\csname #1\endcsname}{#2}{#3}}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\kvt@parseheadrows}
% The |\kvt@parseheadrows|\marg{tname}\marg{headers}
% macro parses the values of the |headers| key in the \meta{layout}
% argument of |\NewKeyValTable|. The values are |\\|-separated lists of
% header rows, and the rows are semicolon-separated lists of header
% cells. Each header cell can span zero, one, or more visible columns.
% If the |headers| key is not set (or empty), then the default header
% (based on the column specification alone) is used, as set by
% |\kvt@NewKeyValTable|.
%    \begin{macrocode}
\newcommand\kvt@parseheadrows[2]{%
  \ifstrempty{#2}{}{\kvt@parseheadrows@i{#2}{#1}}}
\newcommand\kvt@parseheadrows@i[2]{%
  \csdef{kvt@@custheadrows@#2}{}%
  \csdef{kvt@headrowcount@#2}{0}%
  \begingroup
  \def\kvt@@parseheadrows{}%
%    \end{macrocode}
% Now loop over \meta{headers} to split \meta{headers} by |\\|.
% Append each item, which specifies a single header row, to
% |\kvt@@parseheadrows| for subsequent parsing by |\kvt@parseheadrow|.
% If an item equals the special sequence "|::|", then the original
% header for the columns is added as header row.
%    \begin{macrocode}
  \def\do##1{%
    \ifstrequal{##1}{::}
      {\appto\kvt@@parseheadrows{%
         \cseappto{kvt@@custheadrows@#2}{%
           \csexpandonce{kvt@headings@#2}}}}
      {\appto\kvt@@parseheadrows{\kvt@parseheadrow{#2}{##1}}}%
%    \end{macrocode}
% Increment the header row counter for each |\\|-separated item of
% \meta{headers}.
%    \begin{macrocode}
    \appto\kvt@@parseheadrows{\csedef{kvt@headrowcount@#2}{%
      \the\numexpr\csuse{kvt@headrowcount@#2}+1\relax}}%
  }\kvt@dobrklist{#1}%
%    \end{macrocode}
% Finally, escape the inner group and overwrite the headings
% with the result of the parsing.
%    \begin{macrocode}
  \expandafter\endgroup\kvt@@parseheadrows
  \csletcs{kvt@headings@#2}{kvt@@custheadrows@#2}}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\kvt@parseheadrow}
% The |\kvt@parseheadrow|\marg{tname}\marg{colspec} macro parses a
% single header row and appends the resulting table code to
% \cs{kvt@@custheadrows@\meta{tname}}.
%    \begin{macrocode}
\newcommand\kvt@parseheadrow[2]{%
  \begingroup
%    \end{macrocode}
% First parse \meta{colspec}, populating the
% \cs{kvt@@hdcellof@\meta{colname}} macros that associate each column
% with the header cell to which the column belongs (in this row).
%    \begin{macrocode}
  \def\do##1{\kvt@parsehdcolspec{#1}##1::\@undefined}%
  \kvt@dossvlist{#2}%
%    \end{macrocode}
% Initialize variables for the subsequent loop.
% The |\kvt@@tmpgrphd| macro collects the code for the cells of the
% current header row.
% The |\kvt@@tmpunderline| macro collects the rules (|\cmidrule|-like)
% from header cells, in an \pkgname{etoolbox} list.
% The |\kvt@@span| counter specifies how many columns the current cell
% shall span.
% Finally, |\kvt@@curhd| and |\kvt@@lasthd| hold the name of the
% header cell in which the current column and, respectively, previous
% column are in.  Each of the two macros is undefined if there is no
% such header cell.
%    \begin{macrocode}
  \let\kvt@@tmpgrphd\@empty
  \let\kvt@@tmpunderlines\@empty
  \letcs\kvt@@tmpncols{kvt@ndisplaycols@#1}%
  \kvt@@span\z@ \kvt@@coln\@ne
  \undef\kvt@@curhd \undef\kvt@@lasthd
  \kvt@def@atseconduse\kvt@@switchcol{\appto\kvt@@tmpgrphd{&}}%
%    \end{macrocode}
% Next, loop over all displayed columns, stored in
% \cs{kvt@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
% columns are stored in |\kvt@@tmpgrphd|.
%    \begin{macrocode}
  \def\do##1{\letcs\kvt@@curhd{kvt@@hdcellof@##1}%
    \ifdefequal\kvt@@curhd\kvt@@lasthd
%    \end{macrocode}
% If the header cell has not changed, simply increase the spanning
% counter.
%    \begin{macrocode}
      {\advance\kvt@@span\@ne}%
%    \end{macrocode}
% Otherwise, i.e., if the header cell has changed, then conclude the
% previous column (if there was one) and reset the span to 1 (to count
% for the column in |\kvt@@curhd|) and set |\kvt@@lasthd| to the
% current one.
%    \begin{macrocode}
      {\ifnum\kvt@@span>\z@ \expandafter\kvt@concludehdcolumn\fi
       \ifdefvoid\kvt@@curhd{}{\ifcsdef{kvt@@hdcelldone@\kvt@@curhd}{%
         \kvt@error{Header cell `\kvt@@curhd' must consist of only
            consecutive columns, but it is not}%
           {Compare `\string\kvt@@curhd' to the column ordering as
           specified in `\string\NewKeyValTable{#1}'}}{}}%
       \advance\kvt@@coln\kvt@@span\relax
       \kvt@@span\@ne \let\kvt@@lasthd\kvt@@curhd}%
  }\dolistcsloop{kvt@displaycols@#1}%
  \kvt@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}},
% while ending the current \hologo{TeX} group.
%    \begin{macrocode}
  \appto\kvt@@tmpgrphd{\tabularnewline}%
  \ifdefempty\kvt@@tmpunderlines{}{%
    \eappto\kvt@@tmpgrphd{%
      \noexpand\kvtRule@cmid{\noexpand\cmidrulewidth}
        {\expandonce\kvt@@tmpunderlines}
        {\expandonce\cmdkvt@Table@headbg}
        {\expandonce\cmdkvt@Table@headbg}}}%
  \edef\do{\noexpand\csappto{kvt@@custheadrows@#1}{%
    \unexpanded{\noexpand\kvt@rowcolorornot{\cmdkvt@Table@headbg}}%
    \noexpand\unexpanded{\expandonce{\kvt@@tmpgrphd}}}}%
  \expandafter\endgroup\do}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\kvt@rowcolorornot}
% The |\kvt@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@rowcolorcmdornot}
% The |\kvt@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@rowcolorornot[1]{\ifstrempty{#1}{}{\rowcolor{#1}}}
\newcommand\kvt@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.
% The counter |\kvt@@coln| is used temporarily in macros for counting
% column indexes.
%    \begin{macrocode}
\newcount\kvt@@span
\newcount\kvt@@coln
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\kvt@concludehdcolumn}
% The |\kvt@concludehdcolumn| macro appends a cell, potentially spanning
% multiple columns, to the row under construction (which is in
% |\kvt@@tmpgrphd|).
%    \begin{macrocode}
\newcommand\kvt@concludehdcolumn{%
  \kvt@@switchcol
  \ifdefvoid\kvt@@lasthd{}{%
    \eappto\kvt@@tmpgrphd{\noexpand\multicolumn
      {\the\kvt@@span}
      {\csexpandonce{kvt@@hdcell@align@\kvt@@lasthd}}
      {\noexpand\cmdkvt@Table@headformat
        {\csexpandonce{kvt@@hdcell@head@\kvt@@lasthd}}}}%
%    \end{macrocode}
% The following adds a pair of trim and spanned columns to
% |\kvt@@tmpunderlines| for later drawing all the horizontal rules that
% underline column groups.
% A rule is trimmed left if it's not the first column and
% a rule is trimmed right if it's not the last column.
%    \begin{macrocode}
    \ifcsstring{kvt@@hdcell@underline@\kvt@@lasthd}{true}
      {\listeadd\kvt@@tmpunderlines{%
        {\ifnumgreater{\kvt@@coln}{1}{l}{}%
          \ifnumless{\kvt@@coln+\kvt@@span-1}{\kvt@@tmpncols}{r}{}}%
        {\the\kvt@@coln-\the\numexpr\kvt@@coln+\kvt@@span-1\relax}}}{}%
%    \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.
%    \begin{macrocode}
    \cslet{kvt@@hdcelldone@\kvt@@lasthd}{\@ne}}}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\kvt@parsehdcolspec}
% The |\kvt@parsehdcolspec|\marg{tname}\meta{cname}|:|\meta{config}|:|\meta{empty}|\@undefined|
% macro parses a single header cell (resp. column group), \meta{cname}.
% For a header cell, \meta{cname} can consist of multiple,
% "+"-separated column names.
%    \begin{macrocode}
\def\kvt@parsehdcolspec#1#2:#3:#4\@undefined{%
%    \end{macrocode}
% Catch syntax errors first.
%    \begin{macrocode}
  \kvt@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}
  \def\kvt@@colreg##1{%
    \ifinlistcs{##1}{kvt@allcolumns@#1}{}
      {\kvt@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@error{Column `##1' used in more than one header cell}
         {Check the fourth, optional argument of \string\NewKeyValTable
         and eliminate multiple occurrences of column `##1'.}}
      {\csdef{kvt@@hdcellof@##1}{#2}}%
  }\kvt@forpsvlist{\kvt@@colreg}{#2}%
%    \end{macrocode}
% Now parse the \meta{config} of the header cell.
%    \begin{macrocode}
  \def\kvt@@hdcell{#2}%
  \kvt@setkeys{#3}{HeadCell}}
%    \end{macrocode}
% \end{macro}
%
%
% \subsection{Row Numbering and Labeling}
%
% The following counters simplify row numbering in key-value tables.
% One can use a table-local counter (|kvtRow|), a table-type local
% counter (|kvtTypeRow|), and a global counter (|kvtTotalRow|).
%
% \begin{macro}{kvtRow}
% The |kvtRow| counter can be used by cells to get the current row
% number. This row number (in contrast to |taburow|) does not count
% table headers. That is, |kvtRow| provides the current \emph{content}
% row number, even in tables that are spread over multiple pages.
%    \begin{macrocode}
\newcounter{kvtRow}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{kvtTypeRow}
% The |kvtTypeRow| counter can be used by cells to get the current row
% number, including all previous rows of tables of the same type. This
% counter works together with the \cs{kvt@rowcount@\meta{tname}} macro,
% which keeps track of the individual row counts of the \meta{tname}
% type.
%    \begin{macrocode}
\newcounter{kvtTypeRow}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{kvtTotalRow}
% The |kvtTotalRow| counter can be used by cells to get the current row
% number, including all previous |KeyValTable| tables.
%    \begin{macrocode}
\newcounter{kvtTotalRow}
\setcounter{kvtTotalRow}{0}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\kvtLabel}
% The |\kvtLabel|\oarg{labelopts}\marg{counter}\marg{label} macro sets
% a label, named \meta{label}, for the current value of the \LaTeX{}
% counter named \meta{counter}.
% \changes{v0.2}{2016/05/22}{Added macro for row labeling}
% \changes{v0.3}{2016/06/09}{Robustified for use with, e.g., \pkgname{cleveref}}
%    \begin{macrocode}
\newcommand\kvtLabel[3][]{%
%    \end{macrocode}
% The following imitates a |\refstepcounter| in the sense of setting the
% current label, but it does not touch the \meta{counter} (in case
% someone added some custom hooks to them).
%    \begin{macrocode}
  \setcounter{kvt@LabelCtr}{\value{#2}}%
  \addtocounter{kvt@LabelCtr}{-1}%
  \refstepcounter{kvt@LabelCtr}%
%    \end{macrocode}
% Next, define the \meta{label} (if provided) and show the value of
% \meta{counter}.
%    \begin{macrocode}
  \ifstrempty{#3}{}{%
    \ifstrempty{#1}{\label{#3}}{\label[#1]{#3}}}%
  \csuse{the#2}}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{kvt@LabelCtr}
% The |kvt@LabelCtr| counter is an auxiliary counter for setting labels,
% used by |\kvtLabel|.
%    \begin{macrocode}
\newcounter{kvt@LabelCtr}
%    \end{macrocode}
% \end{macro}
%
%
% \subsection{Rules}
%
% This section exists because drawing rules with proper spacing and
% proper consideration of row background colors requires some effort.
% \changes{v2.3}{2020/08/09}{Made rules aware of row background colors}
%
% \begin{macro}{\kvt@RuleTop}
% The |\kvt@RuleTop| macro produces a |\kvtRuleTop| rule that fits with
% the header background color or, if no headers are shown, the
% alternating row background colors.
%    \begin{macrocode}
\newcommand\kvt@RuleTop{\noalign{%
  \edef\kvt@@do{\noexpand\kvtRuleTop{\ifbool{kvt@Table@showhead}
    {\expandonce\cmdkvt@Table@headbg}{\expandonce\kvt@@bgcolor@odd}}}%
  \expandafter}\kvt@@do}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\kvt@RuleBottom}
% The |\kvt@RuleBottom| macro produces a |\kvtRuleBottom| rule that fits
% with the alternating row background colors.
%    \begin{macrocode}
\newcommand\kvt@RuleBottom{\noalign{%
  \edef\kvt@@do{\noexpand\kvtRuleBottom{\ifnumodd{\the\kvt@@bodyrow}
    {\expandonce\kvt@@bgcolor@odd}{\expandonce\kvt@@bgcolor@even}}}%
  \expandafter}\kvt@@do}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\kvt@RuleMid}
% The |\kvt@RuleMid|\oarg{wd} macro produces a |\kvtRuleMid| rule that
% fits with the alternating row background colors.
%    \begin{macrocode}
\newcommand\kvt@RuleMid{\noalign{\ifnum0=`}\fi
  \@ifnextchar[{\kvt@RuleMid@i}{\kvt@RuleMid@i[\lightrulewidth]}}
\long\def\kvt@RuleMid@i[#1]{%
  \edef\kvt@@do{\unexpanded{\ifnum0=`{\fi}\kvtRuleMid[{#1}]}%
    \ifnumodd{\the\kvt@@bodyrow}
    {{\expandonce\kvt@@bgcolor@odd}{\expandonce\kvt@@bgcolor@even}}
    {{\expandonce\kvt@@bgcolor@even}{\expandonce\kvt@@bgcolor@odd}}}%
  \kvt@@do}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\kvt@RuleSubHead}
% The |\kvt@RuleSubHead| macro is very similar to |\kvt@RuleMid|.
% The latter is to be placed between body rows of a table.
% The former is to be placed between the header row(s) and the body
% rows.
%    \begin{macrocode}
\newcommand\kvt@RuleSubHead{\noalign{%
  \edef\kvt@@do{\noexpand\kvtRuleMid
    {\expandonce\cmdkvt@Table@headbg}{\expandonce\kvt@@bgcolor@odd}}%
  \expandafter}\kvt@@do}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\kvt@RuleCMid}
% The |\kvt@RuleCMid|\marg{tname}\oarg{wd}\marg{cglist} macro draws a
% set of horizontal rules for a given comma-separated list of names of
% columns and/or column groups, \meta{cglist}.
%    \begin{macrocode}
\newcommand\kvt@RuleCMid[1]{\noalign{\ifnum0=`}\fi
  \@ifnextchar[{\kvt@RuleCMid@i{#1}}
               {\kvt@RuleCMid@i{#1}[\cmidrulewidth]}}
\long\def\kvt@RuleCMid@i#1[#2]#3{%
  \let\kvt@@rules\@empty
  \def\kvt@@do##1{%
    \ifcsdef{kvt@colgrp@first@#1@##1}
      {\kvt@RuleCMid@cg{#1}{##1}}
      {\kvt@RuleCMid@cc{#1}{##1}{1}}}%
  \forcsvlist\kvt@@do{#3}%
%    \end{macrocode}
% The above collected the second argument of |\kvtRule@cmid| in
% |\kvt@@rules|. The remaining lines now add the remaining arguments.
%    \begin{macrocode}
  \edef\kvt@@rules{\unexpanded{\ifnum0=`{\fi}\kvtRule@cmid}%
    {\unexpanded{#2}}%
    {\expandonce\kvt@@rules}
    \ifnumodd{\the\kvt@@bodyrow}
      {{\expandonce\kvt@@bgcolor@odd}{\expandonce\kvt@@bgcolor@even}}
      {{\expandonce\kvt@@bgcolor@even}{\expandonce\kvt@@bgcolor@odd}}}%
  \kvt@@rules}
%    \end{macrocode}
% The |\kvt@RuleCMid@cg|\marg{tname}\marg{colgrp} macro
% takes the first column of \meta{colgrp} and column count of this
% column group and passes them on to |\kvt@RuleCMid@c|.
%    \begin{macrocode}
\newcommand\kvt@RuleCMid@cg[2]{\bgroup%
  \edef\kvt@@do{\egroup
    \unexpanded{\kvt@RuleCMid@c{#1}}%
      {\csuse{kvt@colgrp@first@#1@#2}}
      {\csuse{kvt@colgrp@count@#1@#2}}}%
  \kvt@@do}
%    \end{macrocode}
% The |\kvt@RuleCMid@c|\marg{tname}\marg{cname}\marg{count}
% macro determines the index $a$ of column \meta{cname} and adds a rule
% from this column to $a+\meta{count}-1$.
% The |\kvt@RuleCMid@cc| macro takes the same arguments but additionally
% checks whether \meta{cname} is a valid column name.
%    \begin{macrocode}
\newcommand\kvt@RuleCMid@cc[3]{%
  \ifinlistcs{#2}{kvt@allcolumns@#1}
    {\ifinlistcs{#2}{kvt@displaycols@#1}
      {\kvt@RuleCMid@c{#1}{#2}{#3}}
%    \end{macrocode}
% Rules below known but hidden columns are silently skipped by the below
% line.
%    \begin{macrocode}
      {}}
    {\kvt@error
      {Column or column group `#2' for `\string\CMidRule'
       not known in table type `#1'}
      {Check the \string\NewKeyValTable{#1} for
       the names of known columns and check `#2' for a typo.}}}
\newcommand\kvt@RuleCMid@c[3]{%
%    \end{macrocode}
% Find index of column \meta{cname} and store it in |\@tempcnta|.
% Fixme: Column indexes could also be precomputed.
%    \begin{macrocode}
  \@tempcnta\z@
  \def\do##1{\advance\@tempcnta\@ne
    \ifstrequal{#2}{##1}{\listbreak}{}}%
  \dolistcsloop{kvt@displaycols@#1}%
%    \end{macrocode}
% Now add new rule pair (trim and columns) to the list stored in
% |\kvt@@rules|.
%    \begin{macrocode}
  \listeadd\kvt@@rules{%
    {\ifnumgreater{\@tempcnta}{1}{l}{}%
     \ifnumless{\@tempcnta+#3-1}{\csuse{kvt@ndisplaycols@#1}}{r}{}}%
    {\the\@tempcnta-\the\numexpr\@tempcnta+#3-1\relax}}}
%    \end{macrocode}
% \end{macro}
%
% \paragraph{Candidate for separate package.}
% The following macros are independent of the remaining \thispackage
% macros and could be factored out into their own small macro package
% (|kvtrule|?) as a solution to reoccurring questions about row colors
% with \pkgname{booktabs} (e.g.,
% \url{https://tex.stackexchange.com/questions/177202/booktabs-and-row-color}).
%
% The macros below act as alternatives to rule macros of the
% \pkgname{booktabs} package.
% The \pkgname{booktabs} rule macros draw horizontal rules with some
% spacing above and below the rule. Their spacing does not take into
% account row colors.
% The replacement macro allow specifying the row color above
% (\meta{c-above}) and below (\meta{c-below}) of rule.
%
% \begin{macro}{\kvtRuleTop}
% The |\kvtRuleTop|\oarg{wd}\marg{c-below} macro acts as a replacement
% macro for \pkgname{booktabs}'s |\toprule|\oarg{wd} macro.
%    \begin{macrocode}
\newcommand\kvtRuleTop{\noalign{\ifnum0=`}\fi
  \@ifnextchar[{\kvtRuleTop@i}{\kvtRuleTop@i[\heavyrulewidth]}}
\long\def\kvtRuleTop@i[#1]#2{\ifnum0=`{\fi}%
  \specialrule{#1}{\abovetopsep}{0pt}%
  \kvtRule@ColorRule{#2}{2\belowrulesep}{0pt}{-\belowrulesep}}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\kvtRuleBottom}
% The |\kvtRuleBottom|\oarg{wd}\marg{c-above} macro acts as a
% replacement for \pkgname{booktabs}'s |\bottomrule|\oarg{wd} macro.
%    \begin{macrocode}
\newcommand\kvtRuleBottom{\noalign{\ifnum0=`}\fi
  \@ifnextchar[{\kvtRuleBottom@i}{\kvtRuleBottom@i[\heavyrulewidth]}}
\long\def\kvtRuleBottom@i[#1]#2{\ifnum0=`{\fi}%
  \kvtRule@ColorRule{#2}{\aboverulesep}{0pt}{0pt}%
  \specialrule{#1}{0pt}{\belowbottomsep}}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\kvtRuleMid}
% The |\kvtRuleMid|\oarg{wd}\marg{c-above}\marg{c-below} macro acts as a
% replacement for \pkgname{booktabs}'s |\midrule|\oarg{wd} macro.
%    \begin{macrocode}
\newcommand\kvtRuleMid{\noalign{\ifnum0=`}\fi
  \@ifnextchar[{\kvtRuleMid@i}{\kvtRuleMid@i[\lightrulewidth]}}
\long\def\kvtRuleMid@i[#1]#2#3{\ifnum0=`{\fi}%
  \kvtRule@ColorRule{#2}{\aboverulesep}{0pt}{0pt}%
  \specialrule{#1}{0pt}{0pt}%
%    \end{macrocode}
% For some reason, without the doubling of |\belowrulesep| below,
% there is a white space below the |\specialrule|. (Fixme?)
%    \begin{macrocode}
  \kvtRule@ColorRule{#3}{2\belowrulesep}{0pt}{-\belowrulesep}}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\kvtRuleCMid}
% The
% |\kvtRuleCMid|\oarg{wd}|(|\meta{trim}|)|\marg{a-b}\marg{c-above}\marg{c-below}
% macro acts as a replacement for \pkgname{booktabs}'s
% |\cmidrule|\oarg{wd}|(|\meta{trim}|)|\marg{a-b} macro.
%    \begin{macrocode}
\newcommand\kvtRuleCMid{\noalign{\ifnum0=`}\fi
  \@ifnextchar[{\kvtRuleCMid@i}{\kvtRuleCMid@i[\cmidrulewidth]}}
\long\def\kvtRuleCMid@i[#1]{%
  \@ifnextchar({\kvtRuleCMid@ii{#1}}{\kvtRuleCMid@ii{#1}()}}
\long\def\kvtRuleCMid@ii#1(#2)#3{\ifnum0=`{\fi}%
  \kvtRule@cmid{#1}{{#2}{#3}}}
%    \end{macrocode}
% The
% |\kvtRule@cmid|\marg{wd}\marg{r-list}\marg{c-above}\marg{c-below}
% macro does the actual work.
% The \meta{r-list} parameter is a \pkgname{etoolbox} list of pairs
% "\marg{trim}\marg{a-b}".
%    \begin{macrocode}
\newcommand\kvtRule@cmid[4]{%
%    \end{macrocode}
% The "\meta{wd}/2" (i.e., |#1/2|) occurring twice below "splits" the
% later rule vertically into the upper half (on \meta{c-above}
% background) and the lower half (on \meta{c-below} background).
%    \begin{macrocode}
  \kvtRule@ColorRule{#3}
    {\the\dimexpr\aboverulesep+#1/2\relax}
    {0pt}
    {\the\dimexpr-#1/2\relax}%
%    \end{macrocode}
% Draw the "below" color already here such that the rule can be drawn in
% the middle on top of the "above" and "below" color.
%    \begin{macrocode}
  \kvtRule@ColorRule{#4}
    {\the\dimexpr\belowrulesep+#1/2\relax}{0pt}
    {\the\dimexpr-\belowrulesep-#1\relax}%
%    \end{macrocode}
% Now collect the rules to be drawn in a single macro |\kvt@@rules|.
%    \begin{macrocode}
  \noalign{%
    \let\kvt@@rules\@empty%
    \def\kvt@@do##1{\appto\kvt@@rules{\kvtRule@cmid@i{#1}##1}}%
    \forlistloop\kvt@@do{#2}%
    \expandafter}%
  \kvt@@rules
%    \end{macrocode}
% In the spacing below, cancel out the negative spacing from
% |\kvtRule@cmid@i|.
%    \begin{macrocode}
  \noalign{\vskip\dimexpr\belowrulesep+#1\relax}}
%    \end{macrocode}
%
% The |\kvtRule@cmid@i|\marg{wd}\marg{trim}\marg{a-b} macro produces a
% single |\cmidrule|-like rule from a set of such rules. The arguments
% are the same as for |\cmidrule|.
%    \begin{macrocode}
\newcommand\kvtRule@cmid@i[3]{%
%    \end{macrocode}
% The following three lines locally inject zero |\aboverulesep| into
% |\cmidrule|. Due to grouping within |\@cmidrule|, this is not possible
% for |\belowrulesep|; hence, we have to fix |\belowrulesep| in the
% |\vskip| later in this macro.
% Note that the |\noalign| started below is ended within |\@cmidrule|.
%    \begin{macrocode}
  \noalign{\ifnum0=`}\fi
    \aboverulesep=0pt\relax
    \@cmidrule[#1](#2){#3}%
%    \end{macrocode}
% The imitates the code from |\xcmidrule| for when further |\cmidrule|s
% follow. It additionally cancels out the superfluous |\belowrulesep| as
% described before.
%    \begin{macrocode}
  \noalign{%
    \vskip-\dimexpr #1+\belowrulesep\relax
    \global\@lastruleclass\@ne}}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\kvtRulesCMid}
% The |\kvtRulesCMid|\oarg{width}\marg{r-list}\marg{color1}\marg{color2}
% macro is the user interface for |\kvtRule@cmid| with multiple rules.
% Here, \meta{r-list} is a comma-separated list of optional trim (in
% parentheses) and column range -- and the code below essentially just
% transforms this syntax into the syntax expected by |\kvtRule@cmid|.
%    \begin{macrocode}
\newcommand\kvtRulesCMid{\noalign{\ifnum0=`}\fi
  \@ifnextchar[{\kvtRulesCMid@i}{\kvtRulesCMid@i[\cmidrulewidth]}}
\long\def\kvtRulesCMid@i[#1]#2#3#4{%
  \let\kvt@@rules\@empty
  \forcsvlist\kvtRulesCMid@ii{#2}%
  \ifnum0=`{\fi\expandafter}\expandafter
  \kvtRulesCMid@v\expandafter{\kvt@@rules}{#1}{#3}{#4}}
\newcommand\kvtRulesCMid@ii[1]{\kvtRulesCMid@iii#1\@undefined}
\newcommand\kvtRulesCMid@iii{%
  \@ifnextchar({\kvtRulesCMid@iv}{\kvtRulesCMid@iv()}}
\long\def\kvtRulesCMid@iv(#1)#2\@undefined{%
  \listadd\kvt@@rules{{#1}{#2}}}
\newcommand\kvtRulesCMid@v[4]{\kvtRule@cmid{#2}{#1}{#3}{#4}}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\kvtRule@ColorRule}
% The |\kvtRule@ColorRule|\marg{color}\marg{wd}\marg{above}\marg{below}
% macro draws a full-width horizontal table rule of width \meta{wd} in
% color \meta{color} and spacing \meta{above} above and \meta{below}
% below the rule.
% If \meta{color} is empty, the current background color is used.
%    \begin{macrocode}
\newcommand\kvtRule@ColorRule[4]{%
  \ifstrempty{#1}
    {\noalign{\expandafter\vskip\the\dimexpr #2+#3+#4\relax}}
    {\kvtRule@SaveRuleColor
     \arrayrulecolor{#1}%
     \specialrule{#2}{#3}{#4}%
     \kvtRule@RestoreRuleColor}}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\kvtRule@SaveRuleColor}
% \begin{macro}{\kvtRule@RestoreRuleColor}
% These macros save and, respectively, restore the current rule color,
% as provided by the \pkgname{colortbl} package in |\CT@arc@|.
%    \begin{macrocode}
\newcommand\kvtRule@SaveRuleColor{%
  \noalign{\global\let\kvt@@ctarc\CT@arc@}}
\newcommand\kvtRule@RestoreRuleColor{%
  \noalign{\global\let\CT@arc@\kvt@@ctarc}}
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
%
% \subsection{Key-Value Table Content}
%
% \begin{environment}{KeyValTable}
% The |KeyValTable|\oarg{options}\marg{tname} environment encloses a new
% table whose type is identified by the given \meta{tname}. Table options
% can be overridden by providing \meta{options}.
%    \begin{macrocode}
\newenvironment{KeyValTable}[2][]{%
%    \end{macrocode}
% \begin{macro}{\Row}
% The |\Row|\oarg{options}\marg{content} macro is made available locally
% in the |KeyValTable| environment.
%    \begin{macrocode}
  \def\Row{\kvt@AddKeyValRow
    {\noalign\bgroup}{\expandafter\egroup\kvt@@row}{#2}}%
  \def\MidRule{\kvt@RuleMid}%
  \def\CMidRule{\kvt@RuleCMid{#2}}%
%    \end{macrocode}
% \end{macro}
%    \begin{macrocode}
  \kvt@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@TableEnv@resume*}{}
    {\gdef\kvt@@lastenvopt{#1}}%
  \csuse{kvt@StartTable@\cmdkvt@Table@shape}{#2}%
}{%
  \csuse{kvt@EndTable@\cmdkvt@Table@shape}}
%    \end{macrocode}
% \end{environment}
%
% \begin{macro}{\kvt@SetOptions}
% The |\kvt@SetOptions|\marg{tname}\marg{options} macro sets the
% 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@SetOptions[2]{\expandafter
  \kvt@SetOptions@i\expandafter{\csname kvt@options@#1\endcsname}{#2}}
%    \end{macrocode}
% The auxiliary macro |\kvt@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@SetOptions@i[2]{\expandafter
  \kvt@setkeys\expandafter{#1,#2}{Table,TableEnv}}
%    \end{macrocode}
% \end{macro}
%
%
% \subsubsection{Table Environment Properties}
%
% The following code maintains properties about known table
% environments. This code does not depend on other code of the
% \thispackage package but is only used by \thispackage.
%
% The following properties can be maintained about table environments.
%    \begin{macrocode}
\define@boolkey[metatbl]{EnvProp}{isLong}{\metatbl@boolprop{isLong}{#1}}
\define@boolkey[metatbl]{EnvProp}{isTabu}{\metatbl@boolprop{isTabu}{#1}}
\define@boolkey[metatbl]{EnvProp}{hasWidth}{%
  \metatbl@boolprop{hasWidth}{#1}}
\define@boolkey[metatbl]{EnvProp}{hasCaption}{%
  \metatbl@boolprop{hasCaption}{#1}}
\define@boolkey[metatbl]{EnvProp}{canVAlign}{%
  \metatbl@boolprop{canVAlign}{#1}}
\define@boolkey[metatbl]{EnvProp}{canHAlign}{%
  \metatbl@boolprop{canHAlign}{#1}}
\define@cmdkey[metatbl]{EnvProp}{packages}{\metatbl@setprop{pkg}{#1}}
%    \end{macrocode}
% The |atEnd| property shall be set to \hologo{TeX} code with one
% argument (i.e., using the positional argument |#1|) that adds its
% argument to the end of the active table environment's final content.
% Finding such code is not obvious for table environments that collect
% the content of the environment, like |tabularx| does, for instance.
%    \begin{macrocode}
\define@key[metatbl]{EnvProp}{atEnd}{\metatbl@setprop[1]{atEnd}{#1}}
%    \end{macrocode}
%
% \begin{macro}{\metatblRegisterEnv}
% The |\metatblRegisterEnv|\marg{env-name}\marg{properties} macro
% registers a table environment with name \meta{env-name} and sets its
% properties according to \meta{properties}, a comma-separated key-value
% list.
%    \begin{macrocode}
\newrobustcmd\metatblRegisterEnv[2]{%
  \edef\metatbl@@envname{#1}%
  \csdef{metatbl@@registered@#1}{true}%
  \setkeys[metatbl]{EnvProp}{#2}}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\metatbl@setprop}
% The |\metatbl@setprop|\oarg{n}\marg{key}\marg{value}
% macro defines a macro with \meta{n} arguments ($0$ by default) for the
% environment stored in |\metatbl@@envname| and the given
% \meta{key}. This macro then expands to \meta{value}.
%    \begin{macrocode}
\newcommand\metatbl@setprop[3][0]{%
  \expandafter\newcommand
    \csname metatbl@EnvProp@#2@\metatbl@@envname\endcsname[#1]{#3}}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\metatbl@boolprop}
% The |\metatbl@boolprop|\marg{prop}\marg{value} macro stores the
% Boolean value \meta{value} in a property \meta{prop} for the
% environment stored in |\metatbl@@envname|.
%    \begin{macrocode}
\newcommand\metatbl@boolprop[2]{%
  \providebool{metatbl@EnvProp@#1@\metatbl@@envname}%
  \setbool{metatbl@EnvProp@#1@\metatbl@@envname}{#2}}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\metatblRegistered}
% \begin{macro}{\metatblIsLong}
% \begin{macro}{\metatblIsTabu}
% \begin{macro}{\metatblHasWidth}
% \begin{macro}{\metatblHasCaption}
% \begin{macro}{\metatblCanVAlign}
% \begin{macro}{\metatblCanHAlign}
% The following macros all expect the three arguments
%   \marg{env-name}\marg{iftrue}\marg{iffalse}.
% The macro
% |\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@EnvProp@isLong@#1}}
\newcommand\metatblIsTabu[1]{\ifbool{metatbl@EnvProp@isTabu@#1}}
\newcommand\metatblHasWidth[1]{\ifbool{metatbl@EnvProp@hasWidth@#1}}
\newcommand\metatblHasCaption[1]{\ifbool{metatbl@EnvProp@hasCaption@#1}}
\newcommand\metatblCanVAlign[1]{\ifbool{metatbl@EnvProp@canVAlign@#1}}
\newcommand\metatblCanHAlign[1]{\ifbool{metatbl@EnvProp@canHAlign@#1}}
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\metatblUsePackage}
% \begin{macro}{\metatblRequire}
% 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
% package developers.
%    \begin{macrocode}
\newcommand\metatblUsePackage[1]{%
  \def\do##1{%
    \metatbl@csnamearg\usepackage{metatbl@EnvProp@pkg@##1}}%
  \docsvlist{#1}}
\newcommand\metatblRequire[1]{%
  \def\do##1{%
    \metatbl@csnamearg\RequirePackage{metatbl@EnvProp@pkg@##1}}%
  \docsvlist{#1}}
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\metatblAtEnd}
% The |\metatblAtEnd|\marg{env-name}\marg{code} macro registers
% \meta{code} for addition at the end of tables based on the
% \meta{env-name} environment.
%    \begin{macrocode}
\newcommand\metatblAtEnd[2]{%
  \csname metatbl@EnvProp@atEnd@#1\endcsname{#2}}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\metatbl@csnamearg}
% The auxiliary macro
% |\metatbl@csnamearg|\marg{command}\marg{csname}
% passes the expansion of the macro with name \meta{csname} as the first
% argument to \meta{command}.
%    \begin{macrocode}
\newcommand\metatbl@csnamearg[2]{%
  \expandafter\expandafter\expandafter#1%
  \expandafter\expandafter\expandafter{\csname#2\endcsname}}
%    \end{macrocode}
% \end{macro}
%
% The following are the properties of some basic table environments.
%    \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}
% Of the following two lines, the latter is for the case that the
% \pkgname{xltabular} package is loaded, and the former is for the case
% that the package is not loaded.
%    \begin{macrocode}
    \preto\TX@endtabularx{\toks@\expandafter{\the\toks@#1}}%
    \preto\XLT@i@TX@endtabularx{\toks@\expandafter{\the\toks@#1}}},
}
\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@ii@TX@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
% |\def\endtabu{\endtabular}| at the beginning of a |tabu| environment.
%    \begin{macrocode}
  atEnd={\preto\endtabular{#1}},
}
\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
% |\def\endlongtabu{\endlongtable}| at the beginning of a |longtabu|
% environment.
%    \begin{macrocode}
  atEnd={\preto\endlongtable{#1}},
}
%    \end{macrocode}
%
% \begin{macro}{\metatbl@ifhasXcolumns}
% The |\metatbl@ifhasXcolumns|\marg{preamble}\marg{iftrue}\marg{iffalse}
% takes a \meta{preamble} (the argument of a |tabular| environment that
% specifies the columns of the table) and checks, whether this preamble
% contains an "|X|" column. If such a column is contained, the macro
% expands to \meta{iftrue}. Otherwise, it expands to \meta{iffalse}.
%    \begin{macrocode}
\newrobustcmd\metatbl@ifhasXcolumns[1]{%
  \begingroup
%    \end{macrocode}
% The |\metatbl@@branch| macro is used at the end of the macro to select
% \meta{iftrue} or \meta{iffalse} for expansion. Initially, the macro is
% defined to select \meta{iffalse}.
%    \begin{macrocode}
  \def\metatbl@@branch{\@secondoftwo}%
%    \end{macrocode}
% The code uses the |\@mkpream| macro of the \pkgname{array} package to
% create an |\halign| preamble from the |tabular| \meta{preamble}.
% The result of |\@mkpream| is in |\@preamble| afterwards, but this
% result is not used, but rather discarded at the |\endgroup| below.
% Rather, we hook into |\@mkpream| via |\NC@rewrite@X|, which is used
% when an |X| column was encountered in \meta{preamble}.\footnote{This
% hooking into \cmd{\@mkpream} is inspired by how |tabularx| replaces |X|
% columns by |p| columns as part of its measuring.}
% When an |X| column is encountered, |\metatbl@@branch| is redefined to
% expand to \meta{iftrue} in the end.
%    \begin{macrocode}
  \def\NC@rewrite@X{\def\metatbl@@branch{\@firstoftwo}\NC@find l}%
  \@mkpream{#1}%
  \expandafter\endgroup\metatbl@@branch}
%    \end{macrocode}
% \end{macro}
%
%
% \subsubsection{Table Environment Code}
%
% \begin{macro}{\kvt@StartTabularlike}
% The
% |\kvt@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@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@Table@showrules}
    {\def\kvt@@rule##1{\csuse{kvt@Rule##1}}}
    {\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@rowcount@#2}{\thekvtTypeRow}%
    \csxdef{kvt@@rowcountlast}{\thekvtRow}}}%
%    \end{macrocode}
% Adding caption and label.
%    \begin{macrocode}
  \ifdefvoid\cmdkvt@TableEnv@caption
    {\let\kvt@@caption@main\@empty
     \let\kvt@@caption@alt\@empty}
    {\metatblHasCaption{#1}
       {\edef\kvt@@caption@main{%
         \csexpandonce{kvt@caption@\cmdkvt@Table@captionpos}%
           \ifcsvoid{cmdkvt@TableEnv@caption/lot}{}
             {[{\csexpandonce{cmdkvt@TableEnv@caption/lot}}]}%
           {\expandonce\cmdkvt@TableEnv@caption
              \ifdefvoid\cmdkvt@TableEnv@label{}{%
                \noexpand\label{\expandonce\cmdkvt@TableEnv@label}}}%
         \noexpand\\}%
        \ifcsvoid{cmdkvt@TableEnv@caption/alt}
          {\def\kvt@@caption@alt{}}
          {\edef\kvt@@caption@alt{%
            \csexpandonce{kvt@caption@\cmdkvt@Table@captionpos}[]%
              {\csexpandonce{cmdkvt@TableEnv@caption/alt}}%
            \noexpand\\}}%
       }{\kvt@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@Table@captionpos}{t}
    {\let\kvt@@caption@headmain\kvt@@caption@main
     \let\kvt@@caption@footmain\@empty
     \let\kvt@@caption@headalt\kvt@@caption@alt
     \let\kvt@@caption@footalt\@empty}
    {\let\kvt@@caption@footmain\kvt@@caption@main
     \let\kvt@@caption@headmain\@empty
     \let\kvt@@caption@footalt\kvt@@caption@alt
     \let\kvt@@caption@headalt\@empty}%
  \ifbool{kvt@Table@showhead}
    {\eappto\kvt@@prehook{\csuse{kvt@headings@#2}%
      \noexpand\kvt@@rule{SubHead}}}
    {}%
%    \end{macrocode}
% The following lines perform some checks before the table environment
% is started.
%    \begin{macrocode}
  \ifdefvoid{\cmdkvt@Table@valign}{}{\metatblCanVAlign{#1}{}
    {\undef{\cmdkvt@Table@valign}%
      \kvt@warn{Table environment '#1' of table '#2'
        does not support the vertical alignment option (valign).
        Ignoring the option}}}%
  \ifdefvoid{\cmdkvt@Table@halign}{}{\metatblCanHAlign{#1}{}
    {\undef{\cmdkvt@Table@halign}%
      \kvt@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@TableEnv@resume}
    {\setcounter{kvtRow}{\csuse{kvt@@rowcountlast}}}
    {\setcounter{kvtRow}{0}}%
  \setcounter{kvtTypeRow}{\csuse{kvt@rowcount@#2}}%
%    \end{macrocode}
% Initialize the background colors for the body rows.
%    \begin{macrocode}
  \expandafter\kvt@setrowcolors\expandafter{\cmdkvt@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@Table@halign}{}
        {\metatblIsTabu{#1}{}{[\cmdkvt@Table@halign]}}%
      \metatblHasWidth{#1}
        {\metatblIsTabu{#1}
          {to \expandonce\cmdkvt@Table@width}
          {{\expandonce\cmdkvt@Table@width}}}
        {}%
      \ifdefvoid{\cmdkvt@Table@valign}{}{[\cmdkvt@Table@valign]}%
      \ifdefvoid{\cmdkvt@Table@halign}{}
        {\metatblIsTabu{#1}{[\cmdkvt@Table@halign]}{}}%
      {\csexpandonce{kvt@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@headmain
    \expandonce\kvt@@prehook
    \metatblIsLong{#1}{%
      \noexpand\endfirsthead
      \expandonce\kvt@@caption@headalt
      \expandonce\kvt@@prehook
      \noexpand\endhead}{}%
    \expandonce\kvt@@caption@footmain
    \metatblIsLong{#1}{%
      \noexpand\endlastfoot
      \expandonce\kvt@@caption@footalt
      \noexpand\endfoot}{}%
  }\kvt@@do}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\kvt@caption@b}
% \begin{macro}{\kvt@caption@t}
% The |\kvt@caption@b| and |\kvt@caption@t| macros behave like
% |\caption| but add extra behavior depending on whether the caption is
% displayed above (|\kvt@caption@t|) or below (|\kvt@caption@b|) the
% table. Currently, |\kvt@caption@b| only fixes the spacing between the
% table and the caption.
%    \begin{macrocode}
\newcommand\kvt@caption@t{\caption}
\newcommand\kvt@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@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@setrowcolors}
% The |\kvt@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@setrowcolors[1]{%
  \ifstrempty{#1}{\kvt@setrowcolors@ii{}{}}
                 {\kvt@setrowcolors@i#1\@nil}}
\def\kvt@setrowcolors@i#1..#2\@nil{%
  \kvt@setrowcolors@ii{#1}{#2}}
\newcommand\kvt@setrowcolors@ii[2]{%
  \def\kvt@@bgcolor@odd{#1}%
  \def\kvt@@bgcolor@even{#2}}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\kvt@userowcolors}
% The |\kvt@userowcolors| macro macro expands to
% |\rowcolor|\marg{color}, where \meta{color} is the background color
% set via |\kvt@setrowcolors| for odd, respectively even rows, based on
% |\kvt@@bodyrow|.
%    \begin{macrocode}
\newcommand\kvt@userowcolors{\ifnumodd{\the\kvt@@bodyrow}
  {\kvt@rowcolorcmdornot{\kvt@@bgcolor@odd}}
  {\kvt@rowcolorcmdornot{\kvt@@bgcolor@even}}}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\kvt@RegisterBackend}
% \begin{macro}{\kvt@RegisterShape}
% The |\kvt@RegisterBackend|\marg{env} macro registers the table
% environment \meta{env} as a table backend for use by \thispackage.
% The |\kvt@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@RegisterBackend[1]{%
  \ifinlist{#1}{\kvt@@tablebackends}
    {\kvt@error{Backend '#1' already registered}
       {Internal error. Check use of \string\kvt@RegisterBackend.}}
    {\kvt@CheckMetatblEnv{#1}%
     \listadd{\kvt@@tablebackends}{#1}%
     \kvt@DefineStdTabEnv{#1}{#1}}}
\newcommand\kvt@RegisterShape[3]{%
  \ifinlist{#1}{\kvt@@tableshapes}
    {\kvt@error{Shape '#1' already registered}
       {Internal error. Check use of \string\kvt@RegisterShape.}}
    {\kvt@CheckMetatblEnv{#2}\kvt@CheckMetatblEnv{#3}%
    \listadd{\kvt@@tableshapes}{#1}%
     \ifstrequal{#2}{#3}
       {\kvt@DefineStdTabEnv{#1}{#2}}
       {\kvt@DefineDualTabEnv{#1}{#2}{#3}}}}
\newcommand\kvt@CheckMetatblEnv[1]{\metatblRegistered{#1}{}
   {\kvt@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@RegisterBackend}
% \begin{macro}{\kvt@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@DefineStdTabEnv}
% The |\kvt@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@DefineStdTabEnv[2]{%
  \csdef{kvt@StartTable@#1}##1{%
    \kvt@StartTabularlike{#2}{##1}}%
  \csedef{kvt@EndTable@#1}{%
    \expandafter\noexpand\csname end#2\endcsname}}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\kvt@DefineDualTabEnv}
% The |\kvt@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@DefineDualTabEnv[3]{%
  \expandafter\newcommand\csname kvt@StartTable@#1\endcsname[1]{%
    \kvt@ifhasXcolumns{##1}
      {\csedef{kvt@EndTable@#1}{%
         \expandafter\noexpand\csname end#3\endcsname}%
       \kvt@StartTabularlike{#3}{##1}%
      }{\csedef{kvt@EndTable@#1}{%
         \expandafter\noexpand\csname end#2\endcsname}%
       \kvt@StartTabularlike{#2}{##1}}}}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\kvt@ifhasXcolumns}
% The |\kvt@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@ifhasXcolumns[1]{%
  \expandafter\expandafter\expandafter\metatbl@ifhasXcolumns
  \expandafter\expandafter\expandafter{%
    \csname kvt@alignments@#1\endcsname}}
%    \end{macrocode}
% \end{macro}
%
% The following lines define the macros for the various table
% environments.
%    \begin{macrocode}
\kvt@RegisterBackend{tabular}
\kvt@RegisterBackend{longtable}
\kvt@RegisterBackend{tabularx}
\kvt@RegisterBackend{xltabular}
\kvt@RegisterBackend{tabu}
\kvt@RegisterBackend{longtabu}
%    \end{macrocode}
%
%
% \subsubsection{Environment-Independent Parts}
%
% \begin{macro}{\kvt@AddKeyValRow}
% The
% |\kvt@AddKeyValRow|\marg{pre}\marg{post}\marg{tname}\oarg{options}\marg{content}
% macro composes a row for the table of type \meta{tname} from the given
% \meta{content} and \meta{options}. The \meta{content} is a
% key-value list that specifies the content of the individual cells in
% the row. The result is returned in macro |\kvt@@row|.
% The arguments \meta{pre} and \meta{post} are expanded at the very
% beginning, resp.\@ end of the macro.
% They allow to control grouping (|\begingroup| and |\endgroup|) as well
% as table placement via |\noalign|.
% \changes{v1.0}{2019/03/17}{Added \oarg{options}}
%    \begin{macrocode}
\newcommand\kvt@AddKeyValRow[3]{%
  #1%
%    \end{macrocode}
% It's essential that \meta{pre} above comes even before |\@ifnextchar|
% and, therefore, cannot be moved into |\kvt@AddKeyValRow@i|:
% The |\@ifnextchar| is not fully expandable and therefore any
% |\noalign| (in \meta{pre}) following |\@ifnextchar| would lead to
% "misplaced |\noalign|" errors.
%    \begin{macrocode}
  \@ifnextchar[%]
    {\kvt@AddKeyValRow@i{#2}{#3}}
    {\kvt@AddKeyValRow@i{#2}{#3}[]}}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\kvt@AddKeyValRow@i}
% The
% |\kvt@AddKeyValRow@i|\marg{post}\marg{tname}\oarg{options}\marg{content}
% macro parses \meta{options} and evaluates the |hidden| option.
%    \begin{macrocode}
\def\kvt@AddKeyValRow@i#1#2[#3]#4{%
  \kvt@setkeys{#3}{Row}%
  \ifbool{kvt@Row@hidden}
    {\let\kvt@@row\@empty #1}
    {\kvt@AddKeyValRow@ii{#1}{#2}{#4}}}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\kvt@AddKeyValRow@ii}
% The
% |\kvt@AddKeyValRow@ii|\marg{post}\marg{tname}\marg{content}
% macro mainly processes \meta{content} as well as \meta{options}
% that have already been parsed by |\kvt@AddKeyValRow@i|.
%    \begin{macrocode}
\def\kvt@AddKeyValRow@ii#1#2#3{%
  \setkeys[KeyValTable]{#2}{#3}%
%    \end{macrocode}
% Initialize and first add the |\noalign| material to the row.
%    \begin{macrocode}
  \def\kvt@@row{}%
  \ifdefvoid\cmdkvt@Row@above{}{%
    \eappto\kvt@@row{\noexpand\noalign{\noexpand\vspace{%
      \expandonce\cmdkvt@Row@above}}}}%
  \appto\kvt@@row{\noalign{\global\advance\kvt@@bodyrow\@ne}}%
  \ifbool{kvt@Row@uncounted}{}{%
    \appto\kvt@@row{\noalign{\kvt@stepcounters}}}%
  \ifdefvoid\cmdkvt@Row@bg
    {\appto\kvt@@row{\kvt@userowcolors}}
    {\eappto\kvt@@row{\noexpand\rowcolor{\expandonce\cmdkvt@Row@bg}}}%
%    \end{macrocode}
% If a row alignment is specified, a default |\multicolumn| display is
% enabled for the row's cells.
%    \begin{macrocode}
  \ifdefvoid\cmdkvt@Row@align
    {\def\kvt@@rowmkmulticolumn{\kvt@unicolumn}}
    {\edef\kvt@@rowmkmulticolumn{%
       \noexpand\kvt@multicolumn{1}{\expandonce\cmdkvt@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@Row@format!}
    {\edef\kvt@@cellfmtbuilder##1##2{%
       \noexpand\edef##1####1{%
         \noexpand\kvt@expandonce@onearg\noexpand\kvt@@mkmulticolumn
         {\ifcsvoid{cmdkvt@Row@format*}{\@firstofone}
           {\noexpand\unexpanded{\csexpandonce{cmdkvt@Row@format*}}}%
         {\noexpand\csexpandonce{##2}{%
             \ifdefvoid\cmdkvt@Row@format{\@firstofone}
               {\noexpand\unexpanded{\expandonce\cmdkvt@Row@format}}%
              {####1}}}}}}}%
    {\edef\kvt@@cellfmtbuilder##1##2{%
      \noexpand\edef##1####1{%
        \noexpand\kvt@expandonce@onearg\noexpand\kvt@@mkmulticolumn{%
          \noexpand\unexpanded{\csexpandonce{cmdkvt@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
% \cs{cmdKeyValTable@\meta{tname}@\meta{cname}}.
% Note that currently the default value is formatted using the given
% format macro -- a design decision.
% \changes{v1.0}{2019/02/03}{Added \cs{multicolumn} support}
%    \begin{macrocode}
  \kvt@@span=0\relax
  \kvt@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@ne
       \ifcsvoid{cmdKeyValTable@#2@##1}{}
         {\ifdefvoid\kvt@@curcgname
           {\kvt@error{Column '##1' nonempty inside a
                       \string\multicolumn}{}}
           {\kvt@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@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@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@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@Row@expandonce}
            {\expandafter\let\expandafter\kvt@@cell\kvt@@cell}{}%
          \ifbool{kvt@Row@expand}
            {\protected@edef\kvt@@cell{\kvt@@cell}}{}}%
%    \end{macrocode}
% Separately also already create the content -- with formatting unless
% the user explicitly requested no cell formatting.
%    \begin{macrocode}
       \ifcsvoid{kvt@@noformat@#2@##1}
         {\kvt@@cellfmtbuilder\kvt@@formatter{kvt@@curcolformat}}%
         {\let\kvt@@formatter\kvt@unicolumn}%
       \csundef{kvt@@noformat@#2@##1}%
       \edef\kvt@@fmtcell{\expandafter\expandonce\expandafter{%
         \expandafter\kvt@@formatter\expandafter{%
           \kvt@@cell}}}%
%    \end{macrocode}
% Finally, append the cell to the row.
%    \begin{macrocode}
       \expandafter\appto\expandafter\kvt@@row\expandafter{%
         \kvt@@fmtcell}}%
  }\dolistcsloop{kvt@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.
%    \begin{macrocode}
  \appto\kvt@@row{\tabularnewline}%
  \ifdefvoid\cmdkvt@Row@below{}{%
    \eappto\kvt@@row{\noexpand\noalign{\noexpand\vspace{%
      \expandonce\cmdkvt@Row@below}}}}%
%    \end{macrocode}
% At the very end of the expansion text, put \meta{post}.
%    \begin{macrocode}
  #1}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\kvt@def@atseconduse}
% The |\kvt@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@def@atseconduse[2]{\def#1{\def#1{#2}}}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\kvt@expandonce@onearg}
% The |\kvt@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@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:
% \begin{itemize}[nosep]
% \item Using `|\expandonce|\marg{cmd}\marg{arg}' would, by definition
%   of |\expandonce|, expand to
%   `|\unexpanded\expandafter{\@firstofone}|' and produces the error
%   `Argument of |\@firstofone| has an extra |}|'.
% \item Using `|\expandonce{|\meta{cmd}\marg{arg}|}|' would expand to
%   `|\unexpanded|\marg{arg}' and, thus, prevent expansion of
%   \meta{arg}.
% \end{itemize}
% \end{macro}
%
% \begin{macro}{\kvt@stepcounters}
% The |\kvt@stepcounters|\oarg{delta} macro increments all row counters
% by \meta{delta}. If \meta{delta} is omitted, \meta{delta}=1.
%    \begin{macrocode}
\newcommand\kvt@stepcounters[1][1]{%
  \addtocounter{kvtRow}{#1}%
  \addtocounter{kvtTypeRow}{#1}%
  \addtocounter{kvtTotalRow}{#1}}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\kvt@CheckMulticolumn}
% The
% |\kvt@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}
\newcommand\kvt@CheckMulticolumn[2]{%
%    \end{macrocode}
% For parsing \meta{content}, the macro uses |\kvt@CheckMulticolumn@i|
% and adds 5 |\relax| after \meta{content} for the case that
% \meta{content} is empty or too short.
%    \begin{macrocode}
  \kvt@CheckMulticolumn@i{#2}#1%
    \relax\relax\relax\relax\relax\kvt@@undefined}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\kvt@CheckMulticolumn@i}
% The
% |\kvt@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@CheckMulticolumn|.
%    \begin{macrocode}
\def\kvt@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@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@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@Row@align
        {\kvt@SetMulticolumn{#5}{#4}{#6}}
        {\expandafter
         \kvt@SetMulticolumn\expandafter{\cmdkvt@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@CheckMulticolumn@i|.
%    \begin{macrocode}
\newcommand\kvt@@@colgroup{kvt@@@colgroup}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\kvt@SetMulticolumn}
% The |\kvt@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@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@ne
%    \end{macrocode}
% 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}
  \def\kvt@@cell{#3}%
  \def\kvt@@mkmulticolumn{\kvt@multicolumn{#2}{#1}}}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\kvt@unicolumn}
% \begin{macro}{\kvt@multicolumn}
% The |\kvt@unicolumn|\marg{content} macro is the central macro for
% creating a "normal" (non-multicolumn) cell holding the given
% \meta{content}.
% Analogously, the macro
% |\kvt@multicolumn|\marg{align}\marg{n}\marg{content}
% is the central macro for creating a multi-column cell with
% \meta{content}.
% The two macros are only meant to improve code legibility and to
% simplify certain future modifications.
%    \begin{macrocode}
\newcommand\kvt@unicolumn[1]{#1}
\newcommand\kvt@multicolumn[3]{\multicolumn{#1}{#2}{#3}}
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \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.
%    \begin{macrocode}
\newcommand\kvtNewRowStyle{\kvt@NewStyle{row}{\kvtRenewRowStyle}}
%    \end{macrocode}
% The |\kvtRenewRowStyle|\marg{name}\marg{row-options} macro re-defines
% an already existing row style with new \meta{row-options}.
%    \begin{macrocode}
\newcommand\kvtRenewRowStyle{\kvt@RenewStyle{row}{\kvtNewRowStyle}}
%    \end{macrocode}
% \end{macro}
% \end{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.
%    \begin{macrocode}
\newcommand\kvtNewTableStyle{\kvt@NewStyle{table}{\kvtRenewTableStyle}}
%    \end{macrocode}
% The |\kvtRenewTableStyle|\marg{name}\marg{options} macro re-defines
% an already existing table style with new \meta{options}.
%    \begin{macrocode}
\newcommand\kvtRenewTableStyle{\kvt@RenewStyle{table}{\kvtNewTableStyle}}
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% The following are the internal macros that the style code shares.
%
% \begin{macro}{\kvt@NewStyle}
% \begin{macro}{\kvt@RenewStyle}
% The |\kvt@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@RenewStyle|\marg{type}\marg{newcmd}\marg{name}\marg{options}
% macro re-defines a style.
%    \begin{macrocode}
\newcommand\kvt@NewStyle[4]{%
  \ifcsundef{kvt@@#1style@#3}
    {\csdef{kvt@@#1style@#3}{#4}}
    {\kvt@error{The #1 style '#3' is already defined}{Use
      \string#2\space to change an existing style.}}}
\newcommand\kvt@RenewStyle[4]{%
  \ifcsundef{kvt@@#1style@#3}
    {\kvt@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@UseRowStyles}
% \begin{macro}{\kvt@UseTableStyles}
% \changes{v2.2}{2020/02/24}{Added the macro}
% The |\kvt@UseRowStyles|\marg{styles} and
% |\kvt@UseTableStyles|\marg{styles} macros set the keys for the given,
% comma-separated list of \meta{styles}.
%    \begin{macrocode}
\newcommand\kvt@UseRowStyles[1]{%
  \kvt@UseStyles{row}{Row}{\kvt@NewRowStyle}{#1}}
\newcommand\kvt@UseTableStyles[1]{%
  \kvt@UseStyles{table}{Table}{\kvt@NewTableStyle}{#1}}
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\kvt@UseStyle}
% The |\kvt@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@UseStyle[4]{%
  \ifcsundef{kvt@@#1style@#4}
    {\kvt@error{A #1 style '#4' is not defined}
      {Use \string#3\space to define a new #1 style.}}
    {\kvt@setcskeys{kvt@@#1style@#4}{#2}}}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\kvt@UseStyles}
% The |\kvt@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@UseStyles[4]{%
%    \end{macrocode}
% We use |\kvt@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 undesirably overwrite the |bg=red|.
%    \begin{macrocode}
  \kvt@xkv@disablepreset[kvt]{#2}{%
    \forcsvlist{\kvt@UseStyle{#1}{#2}{#3}}{#4}}}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\kvt@xkv@disablepreset}
% The |\kvt@xkv@disablepreset|\oarg{prefix}\marg{family}\marg{code}
% disables head presets and tail presets for \meta{family} during the
% expansion of \meta{code}.
%    \begin{macrocode}
\newcommand\kvt@xkv@disablepreset[3][KV]{%
  \ifnumgreater{\XKV@depth}{1}
    {#3}
    {\kvt@xkv@savepreset{#1}{#2}{h}%
     \kvt@xkv@savepreset{#1}{#2}{t}%
     #3%
     \kvt@xkv@restorepreset{#1}{#2}{h}%
     \kvt@xkv@restorepreset{#1}{#2}{t}}}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\kvt@xkv@savepreset}
% \begin{macro}{\kvt@xkv@restorepreset}
% The auxiliary macro
% |\kvt@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@xkv@restorepreset|\marg{prefix}\marg{family}\marg{h/t}
% restores the preset keys saved via |\kvt@xkv@savepreset|.
%    \begin{macrocode}
\newcommand\kvt@xkv@savepreset[3]{%
  \csletcs{kvt@@saved@preset#3}{XKV@#1@#2@preset#3}%
  \csundef{XKV@#1@#2@preset#3}}
\newcommand\kvt@xkv@restorepreset[3]{%
  \csletcs{XKV@#1@#2@preset#3}{kvt@@saved@preset#3}}
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \subsection{Collecting Key-Value Table Content}
%
% \begin{macro}{\NewCollectedTable}
% The |\NewCollectedTable|\marg{cname}\marg{tname} macro registers a new
% table for recorded rows under name \meta{cname} for table type
% \meta{tname}. The macro can only be used when
% \meta{cname} is not already defined. It's function is not more than
% memorizing \meta{tname} for \meta{cname}.
% \changes{v2.0}{2019/04/10}{Added the macro}
%    \begin{macrocode}
\newcommand\NewCollectedTable[2]{%
  \ifcsvoid{kvt@@tnameof@#1}
    {\csgdef{kvt@@tnameof@#1}{#2}}
    {\kvt@error{Name '#1' for a row collection is already defined}
      {Check for other \string\NewCollectedTable{#1}.}}}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\CollectRow}
% The |\CollectRow|\oarg{options}\marg{cname}\marg{content} writes a
% |\kvt@RecordedRow| entry to the aux file, protecting fragile parts of
% \meta{content} through |\protected@write|.
% \changes{v2.0}{2019/04/09}{Added the macro}
%    \begin{macrocode}
\newcommand\CollectRow[3][]{%
  \ifcsvoid{kvt@@tnameof@#2}
    {\kvt@error{No row collection with name '#2' defined}
      {Use \string\NewCollectedTable in the preamble to define it.}}
    {%
%    \end{macrocode}
% First check in a local group whether the passed \meta{content} and
% \meta{options} are of a proper syntax.
%    \begin{macrocode}
     \begingroup
     \kvt@setkeys{#1}{Row}%
     \kvt@colsetcskeys{kvt@@tnameof@#2}{#3}%
     \endgroup
%    \end{macrocode}
% Next, write to |\@auxout|.
%    \begin{macrocode}
     \kvt@protected@write\@auxout{\string\kvt@RecordedRow{#1}{#2}{%
%    \end{macrocode}
% In the following, the columns' default values are explicitly added to
% the row. This ensures that defaults are expanded (via the |\write|) at
% the point at which a row is recorded rather than when the row is
% displayed. This allows using |\thepage| as the default value for a
% column with the intuitively expected outcome.
%    \begin{macrocode}
        \kvt@coldefaults{#2}%
        #3}}%
    }}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\kvt@protected@write}
% The |\kvt@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]
% \item protects ordinarily |\protect|'ed parts via |\protected@write|;
%    \begin{macrocode}
\newcommand\kvt@protected@write[2]{\protected@write{#1}
%    \end{macrocode}
% \item protects table macros -- like |\thekvtRow| --, which are stored
%   in the \pkgname{etoolbox} list |\kvt@@writeprotected@cmds|, by
%   defining them to expand to their own name -- delaying the actual
%   expansion until when the file's contents is expanded;
%    \begin{macrocode}
    {\def\do##1{\def##1{\string##1}}%
     \dolistloop{\kvt@@writeprotected@cmds}%
%    \end{macrocode}
% \item protects table counters like |kvtRow| by adapting the
%   counter-formatting macros to treat table counters differently from
%   other counters.
%    \begin{macrocode}
     \forlistloop{\kvt@writeprotect@fmt}{\kvt@@numberformatters}}
    {#2}}
%    \end{macrocode}
% \end{enumerate}
% \end{macro}
%
% \begin{macro}{\kvt@writeprotect@fmt}
% The |\kvt@writeprotect@fmt|\marg{fmt-csname} macro takes the name of a
% counter-formatting macro (e.g., the name "arabic" for the macro|\arabic|)
% and redefines it such that counters declared via
% |\kvtDeclareTableCounters| are not expanded while all other counters
% are treated normally.
%    \begin{macrocode}
\newcommand\kvt@writeprotect@fmt[1]{%
%    \end{macrocode}
% First, save a copy of \meta{fmt-csname} and then redefine
% \meta{fmt-csname}.
%    \begin{macrocode}
  \csletcs{kvt@@fmt@#1}{#1}%
  \csdef{#1}##1{%
%    \end{macrocode}
% The |kvt@@c@##1| in the following condition is a csname that is
% defined by |\kvtDeclareTableCounters| if |##1| (the counter to be
% formatted) has been declared as a table counter. If the macro is
% defined, then \meta{fmt-csname} expands to its name with its argument.
% Otherwise, the saved copy of \meta{fmt-csname} is expanded, producing
% the actual counter value.
%    \begin{macrocode}
    \ifcsdef{kvt@@c@##1}
      {\expandafter\string\csname#1\endcsname{##1}}
      {\csname kvt@@fmt@#1\endcsname{##1}}}}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\kvtDeclareTableMacros}
% The |\kvtDeclareTableMacros|\marg{macro-list} macro declares all
% the macros in \meta{macro-list} to be "table macros", i.e.,
% macros that should be expanded inside the |KeyValTable| environment
% rather than in a |\CollectRow|.
% The macro records the \meta{macro-list} by appending its elements to
% |\kvt@@writeprotected@cmds|. The actual expansion control is performed
% by |\kvt@protected@write|.
%    \begin{macrocode}
\newcommand\kvtDeclareTableMacros[1]{%
  \forcsvlist{\listadd\kvt@@writeprotected@cmds}{#1}}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\kvt@@writeprotected@cmds}
% Initially empty \pkgname{etoolbox} list of table macros.
%    \begin{macrocode}
\newcommand\kvt@@writeprotected@cmds{}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\kvtDeclareTableCounters}
% The |\kvtDeclareTableCounters|\marg{counter-list} macro declares all
% the counters in \meta{counter-list} to be "table counters", i.e.,
% counters that should be expanded inside the |KeyValTable| environment
% rather than in a |\CollectRow|.
% The macro only marks the counters by defining
% \cs{kvt@@c@\meta{counter}}. The actual expansion control is performed
% by |\kvt@writeprotect@fmt|.
%    \begin{macrocode}
\newcommand\kvtDeclareTableCounters[1]{%
  \def\do##1{\cslet{kvt@@c@##1}\@ne}%
  \docsvlist{#1}}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\kvtDeclareCtrFormatters}
% The |\kvtDeclareCtrFormatters|\marg{macro-list} macro declares all the
% macros in \meta{macro-list} to be counter-formatting macros, i.e.,
% macros that take a \hologo{LaTeX} counter as their argument and format
% the counter's value, e.g., arabic, alphabetic, or as a roman number.
% The macro records the \meta{macro-list} by appending the csnames of
% its elements to |\kvt@@numberformatters|. The actual expansion
% control for the macros in \meta{macro-list} is performed by
% |\kvt@writeprotect@fmt|.
%    \begin{macrocode}
\newcommand\kvtDeclareCtrFormatters[1]{%
  \def\do##1{\listeadd\kvt@@numberformatters{%
    \expandafter\@gobble\string##1}}%
  \docsvlist{#1}}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\kvt@@writeprotected@cmds}
% Initially empty \pkgname{etoolbox} list of counter-formatting macros.
%    \begin{macrocode}
\newcommand\kvt@@numberformatters{}
%    \end{macrocode}
% \end{macro}
%
% The following registers the row counter macros as well as the row
% counters themselves as macros/counters that shall only be expanded
% inside the respective table.
%    \begin{macrocode}
\kvtDeclareTableMacros{\thekvtRow,\thekvtTypeRow,\thekvtTotalRow}
\kvtDeclareTableCounters{kvtRow,kvtTypeRow,kvtTotalRow}
%    \end{macrocode}
% The following registers macros that format counter values. This
% registering is necessary such that |\kvt@writeprotect@fmt| can protect
% table counters from expansion.
%    \begin{macrocode}
\kvtDeclareCtrFormatters{\arabic,\alph,\Alph,\roman,\Roman,\fnsymbol}
%    \end{macrocode}
%
% \begin{macro}{\kvt@coldefault}
% \begin{macro}{\kvt@coldefaults}
% \begin{macro}{\kvt@coldefaults@i}
% The |\kvt@coldefault|\marg{tname}\marg{cname} macro expands to
% "\meta{cname}|={|\meta{default}|},|", where \meta{default} is the
% default value of column \meta{cname} in table type \meta{tname}. If
% \meta{default} is empty, then the macro expands to the empty string.
% The |\kvt@coldefaults@i|\marg{tname} macro expands to the
% comma-separated list of the |\kvt@coldefault| for all \emph{displayed}
% columns of table type \meta{tname}.
% Finally, the |\kvt@coldefaults|\marg{cname} macro expands to
% |\kvt@coldefaults| for the table type assigned to \meta{cname} via
% |\NewCollectedTable|.
%    \begin{macrocode}
\newcommand\kvt@coldefaults[1]{%
  \kvt@coldefaults@i{\csuse{kvt@@tnameof@#1}}}
\newcommand\kvt@coldefaults@i[1]{%
  \forlistcsloop{\kvt@coldefault{#1}}{kvt@displaycols@#1}}
\newcommand\kvt@coldefault[2]{\ifcsvoid{kvt@col@default@#1@#2}{}{%
  #2={\csuse{kvt@col@default@#1@#2}},}}
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\kvt@RecordedRow}
% The |\kvt@RecordedRow|\marg{options}\marg{cname}\marg{content}
% appends a |\Row| with \meta{options} and \meta{content} to a global
% macro for \meta{cname}.
%    \begin{macrocode}
\newcommand\kvt@RecordedRow[3]{%
  \csgappto{kvt@@rowsof@#2}{\Row[{#1}]{#3}}}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\ShowCollectedTable}
% The |\ShowCollectedTable|\oarg{options}\marg{cname}
% produces a |KeyValTable| table for the rows stored under the given
% \meta{cname}, table options \meta{options}.
% \changes{v2.0}{2019/04/09}{Added the macro}
%    \begin{macrocode}
\newcommand\ShowCollectedTable[2][]{%
  \ifcsvoid{kvt@@tnameof@#2}
    {\kvt@error{No row collection with name '#2' defined}
      {Use \string\NewCollectedTable in the preamble to define it.}}
    {\ifcsvoid{kvt@@rowsof@#2}
      {\kvt@warn{No row data available for name '#2'.
        A LaTeX rerun might be needed^^M
        for the row data to be available}%
       \kvt@tableofcname{#2}{#1}{???\tabularnewline}}%
      {\kvt@tableofcname{#2}{#1}{\csuse{kvt@@rowsof@#2}}}}}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\kvt@tableof}
% \begin{macro}{\kvt@tableofcname}
% \begin{macro}{\kvt@tableofcname@i}
% The |\kvt@tableof|\marg{tname}\marg{options}\marg{content} expands to
% a |KeyValTable| environment for table type \meta{tname} with
% \meta{options} and environment body \meta{content}.
% The |\kvt@tableofcname|\marg{cname}\marg{options}\marg{content}
% expands to a |\kvt@tableof| where \meta{tname} is the table type
% assigned to \meta{cname}.
% Finally, |\kvt@tableofcname@i| is an auxiliary macro for expansion
% control.
%    \begin{macrocode}
\newcommand\kvt@tableof[3]{%
  \begin{KeyValTable}[{#2}]{#1}%
    #3%
  \end{KeyValTable}}
\newcommand\kvt@tableofcname[1]{\expandafter
  \kvt@tableofcname@i\expandafter{\csname kvt@@tnameof@#1\endcsname}}
\newcommand\kvt@tableofcname@i[1]{\expandafter
  \kvt@tableof\expandafter{#1}}
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
%
% \subsubsection{Table Content from Files}
%
% \begin{macro}{\ShowKeyValTableFile}
% The |\ShowKeyValTableFile|\oarg{options}\marg{tname}\marg{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][]{%
  \IfFileExists{#3}
    {\begin{KeyValTable}[{#1}]{#2}\@@input#3 \end{KeyValTable}}%
    {\kvt@error{No KeyValTable file '#3'}
      {Check whether the file really exists or whether there is a
       typo in the argument '#3'}}}
%    \end{macrocode}
% \end{macro}
%
% \subsubsection{Legacy Variant}
%
% \begin{macro}{\ShowKeyValTable}
% The |\ShowKeyValTable|\oarg{options}\marg{tname} macro shows a table
% of type \meta{tname} with given \meta{options}. The rows must have
% been collected using |\Row| in |KeyValTableContent| environments or
% using |\AddKeyValRow|.
%    \begin{macrocode}
\newcommand\ShowKeyValTable[2][]{%
  \begin{KeyValTable}[#1]{#2}%
    \csuse{kvt@rows@#2}%
  \end{KeyValTable}%
  \csdef{kvt@rows@#2}{}}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\AddKeyValRow}
% The |\AddKeyValRow|\marg{tname}\oarg{options}\marg{content} adds a row
% with a given \meta{content} to the existing content for the next table
% of type \meta{tname} that is displayed with |\ShowKeyValTable|. The
% \meta{content} and \meta{options} parameters are the same as with
% |\kvt@AddKeyValRow|.
% The resulting row (|\kvt@@row|) is globally appended to
% \cs{kvt@rows@\meta{tname}}.
%    \begin{macrocode}
\newcommand\AddKeyValRow[1]{%
  \kvt@AddKeyValRow
    {\begingroup}
    {\csxappto{kvt@rows@#1}{\expandonce{\kvt@@row}}\endgroup}
    {#1}}
%    \end{macrocode}
% \end{macro}
%
% \begin{environment}{KeyValTableContent}
% The |KeyValTableContent|\marg{tname} environment acts as a container
% in which rows can be specified without automatically being displayed.
% In this environment, rows can be specified via the
% |\Row|\marg{content} macro, which is supposedly shorter than using
% |\AddKeyValRow|\meta{tname}\meta{content}.
%    \begin{macrocode}
\newenvironment{KeyValTableContent}[1]{%
  \def\Row{\AddKeyValRow{#1}}}{}%
%    \end{macrocode}
% \end{environment}
%
%
% \subsection{Package Options}
%
% The following option allows specifying a version for (hopefully)
% compatibility with the respective old version.
% \changes{v2.0}{2019/05/11}{added package option "compat"}
%    \begin{macrocode}
\define@cmdkey[kvt]{PackageOptions}[kvt@@pkg@]{compat}{}
%    \end{macrocode}
%
% Next, set default package options and process them.
%    \begin{macrocode}
\ExecuteOptionsX[kvt]<PackageOptions>{%
  compat=2.0,
}
\ProcessOptionsX[kvt]<PackageOptions>\relax
%    \end{macrocode}
%
%
% \subsection{Compatibility}
%
% \begin{macro}{\kvt@NewCompat}
% The
% |\kvt@IfVersion|\marg{relation}\marg{version}\marg{iftrue}\marg{iffalse}
% macro expands to \meta{iftrue} if the requested package version is in
% the given \meta{relation} ($<$, $<$, or $=$) to \meta{version}.
% Otherwise, the macro expands to \meta{iffalse}.
% Package versions are requested via the |compat| package option. If no
% version is explicitly requested, the newest version is implicitly
% assumed to be requested.
% \meta{code} as
%    \begin{macrocode}
\newcommand\kvt@IfVersion[2]{%
  \ifdimcomp{\kvt@@pkg@compat pt}{#1}{#2pt}}
%    \end{macrocode}
% \end{macro}
%
% Before v2.0, \pkgname{tabu} was the default table environment.
%    \begin{macrocode}
\kvt@IfVersion{<}{2.0}{%
  \metatblRequire{tabu,longtabu}
  \kvt@RegisterShape{onepage}{tabu}{tabu}
  \kvt@RegisterShape{multipage}{longtabu}{longtabu}
}{%
  \metatblRequire{tabularx,longtable,xltabular}
  \kvt@RegisterShape{onepage}{tabular}{tabularx}
  \kvt@RegisterShape{multipage}{longtable}{xltabular}
}
%    \end{macrocode}
%
% Before v2.0, the second optional argument of |\NewKeyValTable|
% specified the header rows only. Only afterwards, that argument
% received a key-value syntax.
%    \begin{macrocode}
\kvt@IfVersion{<}{2.0}{%
  \renewcommand\kvt@parselayout[2]{\kvt@parseheadrows{#2}{#1}}%
}{}
%    \end{macrocode}
%
%\iffalse
%</package>
%\fi
% \Finale
\endinput