texlive[50471] Master/texmf-dist: keyvaltable (19mar19)

commits+karl at tug.org commits+karl at tug.org
Tue Mar 19 22:28:17 CET 2019


Revision: 50471
          http://tug.org/svn/texlive?view=revision&revision=50471
Author:   karl
Date:     2019-03-19 22:28:17 +0100 (Tue, 19 Mar 2019)
Log Message:
-----------
keyvaltable (19mar19)

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

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

Modified: trunk/Master/texmf-dist/source/latex/keyvaltable/keyvaltable.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/keyvaltable/keyvaltable.dtx	2019-03-19 21:27:58 UTC (rev 50470)
+++ trunk/Master/texmf-dist/source/latex/keyvaltable/keyvaltable.dtx	2019-03-19 21:28:17 UTC (rev 50471)
@@ -1,6 +1,6 @@
 % \iffalse meta-comment
 %
-% Copyright (C) 2016-2018 by Richard Grewe <r-g+tex at posteo.net>
+% Copyright (C) 2016-2019 by Richard Grewe <r-g+tex at posteo.net>
 % -------------------------------------------------------
 % 
 % This file may be distributed and/or modified under the
@@ -22,54 +22,35 @@
 %<package>\NeedsTeXFormat{LaTeX2e}[1999/12/01]
 %<package>\ProvidesPackage{keyvaltable}
 %<*package>
-    [2018/11/01 v0.3b Package for filling tables using key-value lists]
+    [2019/03/17 v1.0 Package for filling tables using key-value lists]
 %</package>
 %
 %<*driver>
 \documentclass{ltxdoc}
-\usepackage[columns=2]{idxlayout}
-\usepackage[table]{xcolor}
-\usepackage{enumitem}
-\usepackage{showexpl}
-\lstset{gobble=2,frame=trbl,backgroundcolor=\color{black!5!white}}
-\lstset{explpreset={numbers=none,columns=fixed,basicstyle=\footnotesize\ttfamily}}
-\lstset{preset={\small\sffamily},overhang=2cm,pos=r}
-\usepackage{pbox}
-\newcommand\NiceDescribeStuff[2]{% #1=margin text, #2=body text
-  \medskip\par\noindent\leavevmode%
-  \marginpar{\hfill\pbox[t]{2\marginparwidth}{\ttfamily #1}%
-    \hspace*{-\marginparsep}}%
-  \ifstrempty{#2}{}{#2\smallskip\\}}
-\newcommand\NiceDescribeEnv[2]{% #1=envname, #2=parameters
-  \NiceDescribeStuff{%
-    \textcolor{gray}{\cs{begin}}\string{#1\string}\\
-    \textcolor{gray}{\cs{end}}\string{#1\string}}{#2}}
-\newcommand\NiceDescribeMacro[2]{% #1=macro, #2=parameters
-  \NiceDescribeStuff{\hbox to 0pt{\hss\string#1}}{#2}}
-\newcommand\NiceDescribeConstant[1]{% #1=constant
-  \NiceDescribeStuff{\hbox to 0pt{\hss #1\quad}}{}\ignorespaces}
-% The following macro simulates labels and references, assuming
-% labels are only referenced after they have been defined. This
-% is used in LTXexample environments, in which the normal label
-% and ref mechanism is otherwise disabled.
-\newcommand\FakeRefs{%
-  \def\ref##1{\csuse{fakelabel@##1}}%
-  \def\cref##1{\csuse{cref@\csuse{fakelname@##1}@name}\ \ref{##1}}%
-  \renewcommand\label[2][]{%
-    \csgdef{fakelname@##2}{##1}%
-    \global\csletcs{fakelabel@##2}{@currentlabel}}%
-  \let\marginpar=\origmarginpar
-}
-\let\origmarginpar=\marginpar
-\usepackage{keyvaltable}
-\usepackage{hypdoc}
+\usepackage{rgltxdoc}
+\usepackage{etoc}
+\setcounter{tocdepth}{2}
 \EnableCrossrefs
 \CodelineIndex
 \RecordChanges
-% the following packages are for the examples
-\usepackage{cleveref}
+% the following packages are additional for the examples
 \usepackage{xintexpr}
 \usepackage{makecell}
+\usepackage{gensymb}% for \degree
+\usepackage{tabularx}
+\usepackage{longtable}
+\usepackage{xspace}
+\newcommand\thispackage{\pkgname{keyvaltable}\xspace}
+\usepackage{keyvaltable}
+\NewKeyValTable[
+    showhead=false,headfmt={\bfseries\footnotesize},
+    rowbg=black!7!white..black!3!white,
+    showrules=false,
+    shape=onepage]{GoalApproach}{
+  id: align=r, default=(\alph{kvtRow}), head=\#;
+  goal: align=X[l];
+  approach: align={X[2,l]};
+}
 \begin{document}
   \DocInput{keyvaltable.dtx}
   \PrintChanges
@@ -104,8 +85,8 @@
 % \DoNotIndex{\newcommand,\newenvironment,\def,\gdef,\edef}
 %
 %
-% \title{The \textsf{keyvaltable} package\thanks{This document
-%   corresponds to \textsf{keyvaltable}~\fileversion, dated \filedate.
+% \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}.}}
@@ -113,32 +94,33 @@
 %
 % \maketitle
 %
-% \section{Introduction}
+% \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}
 %
-% The main goal of the \textsf{keyvaltable} package is to offer means
-% for typesetting tables
-% \begin{enumerate}[nosep]
-% \item easily and yet still looking rather nicely,
-% \item in a way that separates content from presentation,
-%   and
-% \item with re-usable layout for tables of the same type.
-% \end{enumerate}
-% For this purpose, the package essentially builds on two concepts:
-% \begin{description}[noitemsep]
-% \item[table types:]
-%   A table type is identified by a table name, \meta{tname}, and has a
-%   list of columns as well as further properties such as the background
-%   colors of rows. Each column also has a name, \meta{cname}, as well as
-%   further properties such as the heading of the column and the alignment
-%   of the column's content.
-% \item[key-value rows:]
-%   A table row is specified by a list 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.
-% \end{description}
-% The the display of the tables, the \textsf{keyvaltable} package builds
-% on the packages \textsf{tabu}, \textsf{longtable}, and
-% \textsf{booktabs}.
+% \etocmulticolstyle[2]{\section*{Contents}}
+% \tableofcontents
+% \clearpage
 %
 % \section{Usage}
 %
@@ -145,7 +127,7 @@
 % We start with a basic usage example. An explanation of the involved
 % macros follows afterwards.\medskip
 %
-% \begin{LTXexample}
+% \begin{LTXexample}[morekeywords={NewKeyValTable,Row,KeyValTable}]
 % \NewKeyValTable{Recipe}{
 %   amount:     align=r;
 %   ingredient: align=l;
@@ -153,9 +135,9 @@
 % }
 % \begin{KeyValTable}{Recipe}
 % \Row{amount=150g, ingredient=ice cream,
-%      step=put into bowl}
+%   step=put into bowl}
 % \Row{amount= 50g, ingredient=cherries,
-%      step=heat up and add to bowl}
+%   step=heat up and add to bowl}
 % \end{KeyValTable}
 % \end{LTXexample}
 % The example code first defines a new table type, |Recipe|, along with
@@ -164,8 +146,9 @@
 % 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[l]| alignment is provided by the \textsf{tabu} package (see the
-% documentation there).
+% |X[l]| alignment is provided by the \pkgname{tabu} package (see the
+% documentation there), which is used by default for creating the
+% tables.
 %
 % After the definition of the table type, the example creates a table of
 % the newly defined type. For this, the example uses the |KeyValTable|
@@ -178,13 +161,13 @@
 %
 % 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 \textsf{keyvaltable} package can be
+% -- 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 section.
 %
 % \subsection{Table Type Definition}
 %
-% \NiceDescribeMacro{\NewKeyValTable}{\oarg{options}\marg{tname}\marg{colspecs}}
+% \NiceDescribeMacro{\NewKeyValTable}{\oarg{options}\marg{tname}\marg{colspecs}\oarg{headers}}
 % Table types are defined via the |\NewKeyValTable| macro, where
 % \begin{itemize}[noitemsep]
 % \item \meta{tname} is the name of the table type,
@@ -196,6 +179,11 @@
 %   comma-separated list of \meta{property}|=|\meta{value} pairs;
 %   the list of table options can be found at the introduction of the
 %   |KeyValTable| environment on page~\pageref{page:table-options}.
+% \item \meta{headers}, if provided, specifies custom table header rows.
+%   This argument is further described in \cref{sec:colspan}.
+%   If this argument is omitted, a single header row is produced
+%   (unless |showhead=false| is provided as an option) and the
+%   individual headers in this row are determined by \meta{colspec}.
 % \end{itemize}
 % Each column specification is of the form
 % \begin{center}
@@ -206,36 +194,44 @@
 % column. The \meta{property}|=|\meta{value} pairs configure certain
 % properties of the column. The \meta{property} can be one of the
 % following:
-% \begin{description}
-% \item[|align|:]
-%   This property specifies the alignment of content in the column.
-%   The \meta{value} can be set to any column alignment understood by
-%   the |tabu| environment of the \textsf{tabu} package. This
-%   particularly includes |l|, |c|, |r|, |p|, and |X|. By default (i.e.,
-%   if this property is not set explicitly), this property is set
-%   to~|l|.
-% \item[|default|:]
-%   This property specifies the default value of a cell in this column,
-%   i.e., in case that a |\Row| does not provide content for the cell.
-%   By default (i.e., if unset for a column), this is an empty string.
-% \item[|format|:]
-%   This property specifies a formatting macro for content of the cell.
-%   By default, the formatting macro takes the content as is but puts a
-%   |\strut| before and after the content (to yield a better vertical
-%   spacing).
-% \item[|head|:]
-%   This property specifies the content of the column's header row. The
-%   default value for this property is the name of the column.
-% \item[|hidden|:]
-%   This property specifies whether a table column shall be displayed or
-%   not. The \meta{value} for this property can be |true| (to display
-%   the cell; the default) or |false| (to not display the cell).
-% \end{description}
+% \begin{KeyValTable}{KeyDesc}
+% \Row{key=align,
+%   desc={This property specifies the alignment of content in the
+%     column.  The \meta{value} can be set to any column alignment
+%     understood by the |tabu| environment of the \pkgname{tabu} package.
+%     This particularly includes |l|, |c|, |r|, |p|, and |X|.},
+%   default=l}
+% \Row{key=default,
+%   desc={This property specifies the default value of a cell in this
+%     column, i.e., in case that a \cmd{\Row} does not provide content
+%     for the cell.  By default (i.e., if unset for a column), this is
+%     an empty string.},
+%   default={\normalfont\itshape(empty)}}
+% \Row{key=format,
+%   desc={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.
+%     By default, the formatting macro takes the content as is
+%     but puts a \cmd{\strut} before and after the content (to yield a
+%     better vertical spacing).},
+%   default=\cmd{\kvtStrutted}}
+% \Row{key=head,
+%   desc={This property specifies the content of the column's header
+%     row. The default value for this property is the name of the
+%     column.},
+%   default={\normalfont\meta{colname}}}
+% \Row{key=hidden,
+%   desc={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; the default) or |false| (to display the
+%     cell).},
+%   default=false}
+% \end{KeyValTable}
 %
 % \subsection{Typesetting Tables}\label{sec:typesetting-tables}
 %
 % The first possibility for typesetting a table using the
-% \textsf{keyvaltable} package, is via the |KeyValTable| environment,
+% \thispackage package, is via the |KeyValTable| environment,
 % which the example at the beginning of this section shows.
 % The second possibility is described in
 % Section~\ref{sec:collected-tables}.
@@ -250,35 +246,63 @@
 % The \meta{options} override default configurations, if provided, and
 % must then be a comma-separated list of \meta{property}|=|\meta{value}
 % pairs. The following \meta{property} names are available:
-% \begin{description}\label{page:table-options}
-% \item[|shape|:]
-%   This property specifies the table's shape. For \meta{value}, the
-%   package currently supports |multipage| (the default) and |onepage|.
-%   In case of |multipage|, the table may span multiple pages and on
-%   each page, the column header is repeated. In case of |onepage|, the
-%   table does not split into multiple pages.
-% \item[|showhead|:]
-%   This property specifies whether the head row shall be shown. The
-%   \meta{value} must be a Boolean (i.e., |true| or |false|), where
-%   |true| (the default) specifies that the head row is shown and
-%   |false| specifies that the head row is not shown.
-% \item[|headbg|:]
-%   This property specifies the background color of the head row. The
-%   \meta{value} must be a single color specification that is understood
-%   by the \textsf{xcolor} package.\footnote{The \meta{value} is passed
-%   directly to the \cs{rowcolor} macro.} The default is |black!14|.
-% \item[|rowbg|:]
-%   This property specifies the background colors of content rows. The
-%   format of the \meta{value} for this property must be
-%   \meta{oddcolor}|..|\meta{evencolor}.\footnote{The \meta{value} is
-%   passed directly to \cs{taburowcolors} of the \textsf{tabu} package.}
-%   The default is |white..black!10|, i.e., alternatingly white and light
-%   very gray.
-% \end{description}
-% The following example shows the \meta{options} in action.
-% \begin{LTXexample}
+% \begin{KeyValTable}{KeyDesc}
+% \Row{key=shape\label{page:table-options},
+%   desc={This property specifies the table's shape. For \meta{value},
+%     the package currently supports |multipage| and |onepage| as well
+%     as |tabular|, |tabularx|, and |longtable|.
+%     In case of |multipage|, the table may span multiple pages and on
+%     each page, the column header is repeated. In case of |onepage|,
+%     the table does not split into multiple pages.
+%     The remaining three values use the respective environment for
+%     producing the table (see \cref{sec:AltTabEnv} for the effect).},
+%   default=multipage}
+% \Row{key=width,
+%   desc={This property specifies the width of the table, if the
+%     selected |shape| supports it (see \cref{sec:AltTabEnv}).},
+%   default={\string\linewidth}}
+% \Row{key=showhead,
+%   desc={This property specifies whether the head row shall be shown.
+%     The \meta{value} must be a Boolean (i.e., |true| or |false|),
+%     where |true| specifies that the head row is shown and |false|
+%     specifies that the head row is not shown.},
+%   default=true}
+% \Row{key=showrules,
+%   desc={This property specifies whether top and bottom rules as well
+%     as a rule below the head row are drawn (|true|) or not (|false|).},
+%   default=true}
+% \Row{key=headalign,
+%   desc={This property specifies the alignment for header cells.
+%     If left empty, each header cell receives the same alignment as the
+%     respective column.},
+%   default={\normalfont\itshape(empty)}}
+% \Row{key=headfmt,
+%   desc={This property specifies a format to be applied to all header
+%     cells. By default, the property is empty, meaning that header
+%     cells are formatted. Otherwise, the code provided as value to this
+%     key is prepended to the text of the header cells.},
+%   default={\normalfont\itshape(empty)}}
+% \Row{key=headbg,
+%   desc={This property specifies the background color of the head row.
+%     The \meta{value} must be a single color specification that is
+%     understood by the \pkgname{xcolor} package. The \meta{value} is
+%     passed directly to the \cs{rowcolor} macro.},
+%   default={black!14}}
+% \Row{key=rowbg,
+%   desc={This property specifies the background colors of content rows.
+%     The format of the \meta{value} for this property must be
+%     \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.},
+%   default={white..black!10}}
+% \end{KeyValTable}
+% \vref{fig:TableOptionExamples} demonstrates the \meta{options} in
+% examples.
+% \begin{figure}
+% \begin{LTXexample}[morekeywords={shape,showhead,rowbg}]
 % \NewKeyValTable[shape=onepage,
-%     showhead=false, headbg=blue!25,
+%     showhead=false,
 %     rowbg=blue!10..blue!15,
 %   ]{TabOptions}{
 %     opt: align=l, format=\texttt;
@@ -287,15 +311,30 @@
 % \begin{KeyValTable}{TabOptions}
 % \Row{opt=shape,  val=onepage}
 % \Row{opt=showhead, val=false}
-% \Row{opt=headbg, val=blue!25}%invisible
 % \Row{opt=rowbg,  val=blue!10..blue!15}
 % \end{KeyValTable}
 % \caption{table options demo}
 % \end{table}
 % \end{LTXexample}
+% \begin{LTXexample}[morekeywords={showrules,headbg,headalign,headfmt}]
+% \NewKeyValTable[showrules=false,headbg=blue!25,
+%     headalign=c,headfmt=\bfseries,
+%   ]{TabOptions2}{
+%     opt: align=l, format=\texttt;
+%     val: align=l, format=\texttt;}
+% \begin{KeyValTable}{TabOptions2}
+% \Row{opt=showrules, val=false}
+% \Row{opt=headbg, val=blue!25}
+% \Row{opt=headalign, val=c}
+% \Row{opt=headfmt, val=\string\bfseries}
+% \end{KeyValTable}
+% \end{LTXexample}
+% \caption{Examples for table options}
+% \label{fig:TableOptionExamples}
+% \end{figure}
 %
 %
-% \NiceDescribeMacro{\Row}{\marg{content}}
+% \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
@@ -304,10 +343,13 @@
 % 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-tables}
 %
 % As an alternative to producing a table within a single environment,
-% the \textsf{keyvaltable} package offers a way to scatter individual
+% the \thispackage package offers a way to scatter individual
 % rows throughout a document and display the full table later. This
 % method can be useful when table rows are strongly connected to
 % portions of text outside of the table. The method then allows
@@ -342,7 +384,7 @@
 %
 % The following example demonstrates the use, based on the previously
 % defined |Recipe| table type.
-% \begin{LTXexample}[preset=\NewKeyValTable{Recipe}{amount:align=r;ingredient:align=l;step:align=X[l]}]
+% \begin{LTXexample}[morepreset=\NewKeyValTable{Recipe}{amount:align=r;ingredient:align=l;step:align=X[l]},morekeywords={AddKeyValRow,KeyValTableContent,ShowKeyValTable}]
 % \AddKeyValRow{Recipe}{amount=3,
 %      ingredient=balls of snow,
 %      step=staple all 3 balls}
@@ -358,11 +400,11 @@
 % \subsection{Setting Global Defaults}
 %
 % \NiceDescribeMacro{\kvtSet}{\marg{options}}
-% The \textsf{keyvaltable} package allows changing the default values
+% 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}
+% \begin{LTXexample}[morekeywords={kvtSet}]
 % \kvtSet{headbg=red,default=?,align=r}
 % \NewKeyValTable{Defaults}{x; y}
 % \begin{KeyValTable}{Defaults}
@@ -379,12 +421,12 @@
 %
 % The mechanism of default column values enables a simple means for
 % automatic row numbering. For this, one can use one of three row
-% counters provided by the \textsf{keyvaltable} package: |kvtRow|,
+% 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}
+% \begin{LTXexample}[morekeywords={thekvtRow,thekvtTypeRow}]
 % \NewKeyValTable{Numbered1}{
 %   line: align=r, head=\#,
 %         default=\thekvtRow;
@@ -395,25 +437,25 @@
 % \end{KeyValTable}
 % \end{LTXexample}
 %
-% \NiceDescribeConstant{kvtRow}
+% \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.
 %
-% \NiceDescribeConstant{kvtTypeRow}
+% \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.
 %
-% \NiceDescribeConstant{kvtTotalRow}
+% \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
-% \textsf{keyvaltable} package.
+% \thispackage package.
 %
 % 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}[preset=\FakeRefs]
+% \begin{LTXexample}[morekeywords={kvtLabel}]
 % \NewKeyValTable{Labeled}{
 %   label: align=r, head=\textbf{\#},
 %          format=\kvtLabel{kvtRow};
@@ -433,31 +475,304 @@
 % (\meta{label}) is provided by the respective cell content.
 %
 % The |\kvtLabel| macro should work well with packages that change the
-% referencing, like \textsf{cleveref} or \textsf{varioref}. When using a
-% package that add an optional argument to the |\label| command (like
-% \textsf{cleveref} does), the \meta{labelopts} can be used to pass an
+% 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{Column Spanning}
+% \label{sec:colspan}
+%
+% Combining multiple consecutive cells in a row to a single cell (aka
+% column spanning) can serve several purposes.
+% The \thispackage package supports the following purposes:
+%
+% \begin{enumerate}[noitemsep]
+% \item grouping of columns through cells in the table's header that
+%   span all cells in the group and assign a joint title to the group;
+% \item individual combinations of cells in the table data.
+% \end{enumerate}
+%
+% The remainder of this section describes how each of the purposes can
+% be addressed in |KeyValTable| environments.
+%
+% \paragraph{Column groups in table headers}
+%
+% Column groups in table headers can be specified by the \meta{headers}
+% parameter of |\NewKeyValTable|.
+% The following two examples illustrate how this parameter can be used
+% for specifying column groups.
+% 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{ColGroup}{
+%   id:     align=r, default=\thekvtRow.;
+%   amount: align=r; ingredient: align=l;
+%   step:   align=X[l];
+% }[
+%   amount+ingredient: head=\textbf{ingredient};
+%   step: head=\textbf{step}, align=l;
+% ]
+% \begin{KeyValTable}{ColGroup}
+% \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.475\hsize]
+% \NewKeyValTable{ColGroup2}{
+%   date:   align=r, head=\textbf{date};
+%   min/Berlin: align=r, head=min;
+%   max/Berlin: align=r, head=max;
+%   min/Paris:  align=r, head=min;
+%   max/Paris:  align=r, head=max;
+% }[
+%   min/Berlin+max/Berlin+min/Paris+max/Paris:
+%     head=\textbf{temperature}\\
+%   min/Paris+max/Paris:   head=\textbf{Paris};
+%   min/Berlin+max/Berlin: head=\textbf{Berlin}\\
+%   ::
+% ]
+% \begin{KeyValTable}{ColGroup2}
+% \Row{date=01.01.1970,
+%      min/Berlin=0\degree C, max/Berlin=...}
+% \end{KeyValTable}
+% \end{LTXexample}
+%
+%
+% The syntax for \meta{headers} is as
+% follows:
+% \begin{itemize}[noitemsep]
+% \item \meta{headers} 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}.
+% \item The \meta{property}|=|\meta{value} pairs configure certain
+%   properties of the header cell. The \meta{property} can be one of the
+%   following:
+%   \begin{KeyValTable}{KeyDesc}
+%   \Row{key=align,
+%     desc={This property specifies the alignment of content in the
+%       column.  The \meta{value} can be set to any column alignment
+%       understood by the |tabu| environment of the \pkgname{tabu} package.
+%       This particularly includes |l|, |c|, |r|, |p|, and |X|.},
+%     default=c}
+%   \Row{key=head,
+%     desc={This property specifies the content of the column's header
+%       row. The default value for this property is the name of the
+%       column.}}
+%   \end{KeyValTable}
+% \end{itemize}
+%
+% \paragraph{Manual column spanning with \cmd{\multicolumn}}
+% 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{Alternative Table Environments}
+% \label{sec:AltTabEnv}
+%
+% Originally, the \thispackage package uses the \pkgname{tabu} package
+% and |tabu|, resp. |longtabu| environments for typesetting the actual
+% tables. Through the |shape| option of tables, the table environment
+% used by \thispackage tables can be changed. \Vref{tab:TabEnv} compares
+% the possible shapes/environments with regards to whether they support
+% tables that span multiple pages, whether they support |X|-type
+% (variable-width) columns, and whether their width can be specified
+% (through the |width| option). Finally, the table also displays the
+% package(s) that must be loaded manually when the respective shapes are
+% used.
+% Examples can be found in \vref{fig:TableTypes}.
+% \begin{table}[p]\centering
+% \NewKeyValTable[shape=tabular,headfmt=\bfseries]{ShapeProps}{
+%   shape: format=\texttt; env: format=\texttt, head=environment;
+%   multipage: align=c;
+%   Xcols: align=c, head=\texttt{X}-cols;
+%   width: align=c;
+%   packages: align=l;}
+% \begin{KeyValTable}{ShapeProps}
+% \Row{shape=onepage,   env=tabu,      multipage=no,  Xcols=yes, width=yes, packages={tabu}*}
+% \Row{shape=multipage, env=longtabu,  multipage=yes, Xcols=yes, width=yes, packages={tabu*, longtable*}}
+% \Row{shape=tabular,   env=tabular,   multipage=no,  Xcols=no,  width=no}
+% \Row{shape=tabularx,  env=tabularx,  multipage=no,  Xcols=yes, width=yes, packages={tabularx}}
+% \Row{shape=longtable, env=longtable, multipage=yes, Xcols=no,  width=no,  packages={longtable}}
+% \end{KeyValTable}
+% \smallskip\par\raggedright\footnotesize
+% Packages marked with "*" only need to be loaded if automatic loading
+% is not disabled via the |NoTabuPkg| option to the \thispackage
+% package.
+% \caption{Comparison of table shapes / environments}
+% \label{tab:TabEnv}
+% \end{table}
+%
+% \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;}[
+%   l+c+r: head=\textbf{\kvtTableOpt{shape} shape}\\ ::]
+% \begin{KeyValTable}[shape=tabular]{ShapeNoX}
+%   \Row{l=left,   c=center,     r=right}
+%   \Row{l=left-2, c=2-center-2, r=2-right}
+% \end{KeyValTable}\\
+% \begin{KeyValTable}[shape=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,onepage,multipage}]
+% \NewKeyValTable[showrules=false]{ShapeWithX}{
+%   id: align=l, default=\thekvtTypeRow;
+%   l: align=l; X: align=X; r: align=r;}[
+%   l+X+r: head=\textbf{\kvtTableOpt{shape} shape}\\ ::]
+% \begin{KeyValTable}[shape=tabularx]{ShapeWithX}
+%   \Row{l=left,   X=expandable,   r=right}
+%   \Row{l=left-2, X=expandable-2, r=2-right}
+% \end{KeyValTable}\medskip\\
+% \begin{KeyValTable}[shape=onepage]{ShapeWithX}
+%   \Row{l=left,   X=expandable,   r=right}
+%   \Row{l=left-2, X=expandable-2, r=2-right}
+% \end{KeyValTable}
+% \begin{KeyValTable}[shape=multipage]{ShapeWithX}
+%   \Row{l=left,   X=expandable,   r=right}
+%   \Row{l=left-2, X=expandable-2, r=2-right}
+% \end{KeyValTable}
+% \end{LTXexample}
+% \caption{Examples for the shape option}
+% \label{fig:TableTypes}
+% \end{figure}
+%
+%
+% \subsection{Special Row Formatting}\label{sec:RowOptions}
+%
+% Through the \meta{options} argument of the
+%   |\Row|\oarg{options}\marg{content}
+% and the
+%   |\KeyValRow|\marg{tname}\oarg{options}\marg{content}
+% macros, special options of the row 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 table lists the supported option keys and their meaning.
+%
+% \begin{KeyValTable}{KeyDesc}
+% \Row{key=hidden,
+%   desc={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|.},
+%   default=false}
+% \Row{key=bg,
+%   desc={This property specifies the background color for the
+%     particular row. If left empty, the default color as determined by
+%     the |rowbg| option of the table applies.},
+%   default={\normalfont\itshape(empty)}}
+% \Row{key=above,
+%   desc={This property specifies extra vertical space above the row.
+%     Note that this 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 \cmd{\vspace}.},
+%   default={\normalfont\itshape(empty)}}
+% \Row{key=below,
+%   desc={Analogously to |above|, this property specifies extra vertical
+%     space below the row.},
+%   default={\normalfont\itshape(empty)}}
+% \Row{key=around,
+%   desc={This property is a short-hand for setting both, |above| and
+%     |below|, to the same value.},
+%   default={\normalfont\itshape(empty)}}
+% \end{KeyValTable}
+%
+% The following example demonstrates the options.
+% \begin{LTXexample}[morepreset=\NewKeyValTable{Recipe}{amount:align=r;ingredient:align=l;step:align=X[l]},morekeywords={hidden,above,bg}]
+% \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=red!10!white]{
+%   step=serve with a smile}
+% \end{KeyValTable}
+% \end{LTXexample}
+%
+% \subsection{Rules Between Rows}
+%
+% Additional horizontal rules between rows can simply be added by
+% placing the respective rule command between |\Row| commands.
+% The following example demonstrates this possibility.
+% \begin{LTXexample}[morepreset=\NewKeyValTable{Recipe}{amount:align=r;ingredient:align=l;step:align=X[l]},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}
+%
+%
 % \section{Use with Other Packages}
 %
 % \subsection{Named References}\label{sec:package-cleveref}
 %
-% The |\kvtLabel| feature of the \textsf{keyvaltable} package can be
+% The |\kvtLabel| feature of the \thispackage package can be
 % used together with named references, as provided by the
-% \textsf{cleveref} package. A name to a row label can be given by using
+% \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}[preset=\FakeRefs]
+% \begin{LTXexample}
 % \usepackage{cleveref}
 % \crefname{row}{line}{lines}
-% \NewKeyValTable{NamedRef}{
-%   label: align=r, head=\textbf{Line},
+% \NewKeyValTable[headfmt=\bfseries]{NamedRef}{
+%   label: align=r, head=Line,
 %          format=\kvtLabel[row]{kvtRow};
-%   text:  align=l, head=\textbf{Text}}
+%   text:  align=l, head=Text}
 % \begin{KeyValTable}{NamedRef}
 % \Row{text=First row, label=one}
 % \Row{text=After \cref{one}}
@@ -468,7 +783,7 @@
 %
 % 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 \textsf{xint} package and defining a
+% 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}
@@ -484,8 +799,8 @@
 %
 % \subsection{Cell Formatting}
 %
-% The \textsf{keyvaltable} package can be used together with the
-% \textsf{makecell} package in at least two ways:
+% 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.
@@ -507,22 +822,22 @@
 %
 % 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 \textsf{keyvaltable} package.
+% loosely related functionalities to the \thispackage package.
 %
 % \begin{description}
-% \item[\textsf{ctable}:]
+% \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[\textsf{easytable}:]
+% \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 the
-%   \textsf{keyvaltable}. However, the package does not pursue
+%   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[\textsf{tabularkv}:]
+% \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
@@ -533,7 +848,10 @@
 % \section{Future Work}
 %
 % \begin{itemize}
-% \item configurable default heading format
+% \item support for further table environments, such as
+%   \pkgname{xltabular}: The existing code structure should make this
+%   not too complicated. Particularly for \pkgname{xltabular},
+%   a spurious "\verb!missing } inserted!" error occurs.
 % \item improved row coloring that makes sure that the alternation
 %   re-starts on continued pages of a table that spans several pages
 % \end{itemize}
@@ -546,22 +864,23 @@
 %\fi
 %
 % \section{Implementation}
+% \addtocontents{toc}{\protect\setcounter{tocdepth}{0}}
 %
-% We use \textsf{etoolbox} for some convenience macros that make the
-% code more easily maintainable and use \textsf{xkeyval} for options
-% in key--value form.
+% 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 \textsf{tabu} for creating the tables and \textsf{longtable}
-% for tables that can span multiple pages (via |longtabu|). We use
-% \textsf{booktabs} for nice horizontal lines and \textsf{xcolor}
-% for row coloring
+% We use \pkgname{booktabs} for nice horizontal lines and
+% \pkgname{xcolor} for row coloring.
 %    \begin{macrocode}
-\RequirePackage[table]{xcolor}
+\PassOptionsToPackage{table}{xcolor}
+\RequirePackage{xcolor}
 \RequirePackage{booktabs}
-\RequirePackage{longtable,tabu}
 %    \end{macrocode}
 %
 % \subsection{Setting Defaults}
@@ -581,7 +900,7 @@
 % The |\kvt@@lazypreset|\marg{family}\marg{head keys} macro collects a
 % request collects a request for pre-setting \meta{head keys} in family
 % key \meta{family}. Using this macro, one can avoid causing problems
-% with using \textsf{xkeyval}'s |\presetkeys| inside the \meta{function}
+% with using \pkgname{xkeyval}'s |\presetkeys| inside the \meta{function}
 % defined for a key (e.g., via |\define at key|). The collected requests
 % can be performed by expanding the |\kvt@@presetqueue| macro.
 %    \begin{macrocode}
@@ -590,14 +909,6 @@
 %    \end{macrocode}
 % \end{macro}
 %
-% \begin{macro}{\mkv at dossvlist}
-% The |\mkv at dossvlist|\marg{list} macro parses a semicolon-separated
-% list and runs |\do|\meta{item} for every element of the list.
-%    \begin{macrocode}
-\DeclareListParser{\mkv at dossvlist}{;}
-%    \end{macrocode}
-% \end{macro}
-%
 % \begin{macro}{\kvt at addtableprop}
 % The |\kvt at addtableprop|\marg{name}\marg{default} macro adds a new
 % table option, named \meta{name} and with default value \meta{default}.
@@ -669,17 +980,18 @@
 % \end{macro}
 %
 % \begin{macro}{\kvt at addchoicecolumnprop}
-% The |\kvt at addchoicecolumnprop|\marg{name}\marg{default}\marg{choice}
-% macro adds a new column option, named \meta{name} and with default
-% value \meta{default} and possible values from the comma-separated
-% list provided by \meta{choice}.
+% The |\kvt at addchoicecolumnprop|\marg{name}\marg{initial}\marg{default}\marg{choice}
+% macro adds a new column option, named \meta{name}, with initial value
+% \meta{initial}, with default argument value \meta{default}, and
+% possible values from the comma-separated list provided by
+% \meta{choice}.
 %    \begin{macrocode}
-\newcommand\kvt at addchoicecolumnprop[3]{%
+\newcommand\kvt at addchoicecolumnprop[4]{%
 %    \end{macrocode}
 % The following makes the \meta{name} available as an option for
 % |\kvtSet| for setting a global default value to this column option.
 %    \begin{macrocode}
-  \define at choicekey[kvt]{defaults}{#1}{#3}{%
+  \define at choicekey[kvt]{defaults}{#1}{#4}[#3]{%
     \kvt at lazypreset{Column}{#1=##1}}%
   \presetkeys[kvt]{defaults}{#1=#2}{}%
 %    \end{macrocode}
@@ -687,7 +999,7 @@
 % the \meta{colspecs} of |\NewKeyValTable| for setting a default value
 % to the particular column.
 %    \begin{macrocode}
-  \define at choicekey[kvt]{Column}{#1}{#3}%
+  \define at choicekey[kvt]{Column}{#1}{#4}[#3]%
     {\csdef{kvt at col@#1@\kvt@@column}{##1}}%
   \presetkeys[kvt]{Column}{#1=#2}{}%
 }
@@ -697,50 +1009,96 @@
 % The following are the known column properties and their defaults as
 % well as the known table properties and their defaults.
 % \changes{v0.2}{2016/05/21}{Added ``shape'' table option}
+% \changes{v1.0}{2018/12/30}{Enabled default ``true'' for ``hidden''}
 %    \begin{macrocode}
 \kvt at addtableprop{rowbg}{white..black!10}
 \kvt at addtableprop{headbg}{black!14}
 \kvt at addbooltableprop{showhead}{true}
-\kvt at addchoicetableprop{shape}{multipage}{multipage,onepage}
+\kvt at addbooltableprop{showrules}{true}
+\kvt at addtableprop{headfmt}{}
+\kvt at addtableprop{headalign}{}
+\kvt at addtableprop{width}{\linewidth}
+%    \end{macrocode}
+% When adding further |shape| options below, ensure to also add a
+% corresponding |\kvt at DefineStdTabEnv| counterpart further below in the
+% code.
+%    \begin{macrocode}
+\kvt at addchoicetableprop{shape}{multipage}{%
+  multipage,onepage,tabular,longtable,tabularx}
 \kvt at addcolumnprop{default}{}
-\kvt at addcolumnprop{format}{\kvt at struttedcell}
+\kvt at addcolumnprop{format}{\kvtStrutted}
 \kvt at addcolumnprop{align}{l}
 \kvt at addcolumnprop{head}{}
-\kvt at addchoicecolumnprop{hidden}{false}{false,true}
+\kvt at addchoicecolumnprop{hidden}{false}{true}{false,true}
 \kvtSet{}
 %    \end{macrocode}
 %
-% \begin{macro}{\kvt at struttedcell}
-% The |\kvt at struttedcell|\marg{arg} macro prefixes and suffixes
+% \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 at Table@#1\endcsname}
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\kvtStrutted}
+% The |\kvtStrutted|\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.
 % \changes{v0.3}{2016/06/06}{Fix for cells with vertical material}
 %    \begin{macrocode}
-\newcommand\kvt at struttedcell[1]{\strut #1\ifhmode\expandafter\strut\fi}
+\newcommand\kvtStrutted[1]{\strut #1\ifhmode\expandafter\strut\fi}
 %    \end{macrocode}
 % \end{macro}
 %
+%
 % \subsection{Declaring Key-Value Tables}
 %
 % \begin{macro}{\NewKeyValTable}
-% The |\NewKeyValTable|\oarg{options}\marg{tname}\marg{colspecs}
+% The
+% |\NewKeyValTable|\oarg{options}\marg{tname}\marg{colspecs}\oarg{headers}
 % 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}
 %    \begin{macrocode}
 \newcommand\NewKeyValTable[3][]{%
+  \@ifnextchar[%]
+    {\kvt at NewKeyValTable{#1}{#2}{#3}}%
+    {\kvt at NewKeyValTable{#1}{#2}{#3}[]}}
 %    \end{macrocode}
+% The
+% |\kvt at NewKeyValTable|\marg{options}\marg{tname}\marg{colspecs}\oarg{headers}
+% macro is an auxiliary macro used for parsing the fourth, optional
+% argument of |\NewKeyValTable|.
+%    \begin{macrocode}
+\def\kvt at NewKeyValTable#1#2#3[#4]{%
+%    \end{macrocode}
 % First initialize the ``variables''.
 %    \begin{macrocode}
   \csdef{kvt at options@#2}{#1}%
   \csdef{kvt at headings@#2}{}%
-  \csdef{kvt at alignments@#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}}
+% Fixme: Ideally, the whole extra column should be removed through
+% sufficient use of |\noalign| in headers and rows, such that even the
+% presence of |\multicolumn| does not produce errors.
+%    \begin{macrocode}
+  \csedef{kvt at alignments@#2}{p{0pt}\expandonce\kvt at HackIntercolSpace}%
   \csdef{kvt at colkeys@#2}{}%
-  \csdef{kvt at rowcount@#2}{1}%
+  \csdef{kvt at rowcount@#2}{0}%
   \csdef{kvt at rows@#2}{}%
+  \csdef{kvt at headings@#2}{\kvt at defaultheader}
   \listadd\kvt at alltables{#2}%
 %    \end{macrocode}
 % Now parse \meta{colspecs}, a semicolon-separated list of individual
@@ -749,7 +1107,20 @@
 %    \begin{macrocode}
   \def\do##1{%
     \kvt at parsecolspec{#2}##1::\@undefined}%
-  \mkv at dossvlist{#3}%
+  \kvt at dossvlist{#3}%
+%    \end{macrocode}
+% The following terminates the argument list of |\kvt at defaultheader|.
+%    \begin{macrocode}
+  \csappto{kvt at headings@#2}{{\@nil}}%
+%    \end{macrocode}
+% Finally, parse \meta{headers}, also a semicolon-separated list of
+% individual column groups, where |\\| marks a new row of column groups.
+% If \meta{headers} is omitted (or empty), then simply take the result
+% of |\kvt at parsecolspec| as the header row.
+%    \begin{macrocode}
+  \ifstrempty{#4}
+    {\csdef{kvt at headrowcount@#2}{1}}
+    {\kvt at parseheadrows{#2}{#4}}%
 }
 %    \end{macrocode}
 % The
@@ -766,10 +1137,16 @@
 %    \begin{macrocode}
   \ifcsstring{kvt at col@hidden@#1@#2}{true}{}{%
     \cseappto{kvt at alignments@#1}{\csexpandonce{kvt at col@align@#1@#2}}%
-    \ifcsvoid{kvt at headings@#1}{}{\csappto{kvt at headings@#1}{&}}%
-    \ifcsstring{kvt at col@head@#1@#2}{}%
-      {\cseappto{kvt at headings@#1}{#2}}%
-      {\cseappto{kvt at headings@#1}{\csexpandonce{kvt at col@head@#1@#2}}}%
+%    \end{macrocode}
+% Append the column heading to \cs{kvt at headings@\meta{tname}}, which
+% collects arguments to |\kvt at 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 head. Otherwise, the
+% |head| value is used.
+%    \begin{macrocode}
+    \ifcsvoid{kvt at col@head@#1@#2}%
+      {\csappto{kvt at headings@#1}{{#2}}}%
+      {\cseappto{kvt at headings@#1}{{\csexpandonce{kvt at col@head@#1@#2}}}}%
     \listcsadd{kvt at colkeys@#1}{#2}%
   }%
 %    \end{macrocode}
@@ -781,8 +1158,56 @@
 }
 %    \end{macrocode}
 % \end{macro}
+%
+%
+% \begin{macro}{\kvt at defaultheader}
+% The |\kvt at defaultheader|\marg{head1}\ldots\marg{headn}|\@nil| macro,
+% takes $n$ header cell titles, \meta{head1} to \meta{headn} and formats
+% them based on the |headfmt| and |headalign| options.
+% More precisely, when fully expanded, |\kvt at defaultheader| yields
+% "\meta{rowcolor}|& |\meta{fmthead1}| & |\ldots| & |\meta{fmtheadn}|\tabularnewline|".
+% In the above, \meta{rowcolor}=|\rowcolor{|\meta{headbg}|}|.
+%    \begin{macrocode}
+\newcommand\kvt at defaultheader{%
+  \noexpand\rowcolor{\cmdkvt at Table@headbg}%
+  \kvt at defaultheader@i}
+\newcommand\kvt at defaultheader@i[1]{%
+  \kvt at ifnil{#1}{\noexpand\tabularnewline}{%
+    \unexpanded{&}%
+    \ifdefvoid\cmdkvt at Table@headalign
+      {\expandonce\cmdkvt at Table@headfmt\unexpanded{#1}}
+      {\noexpand\multicolumn{1}{\expandonce\cmdkvt at Table@headalign}
+        {\expandonce\cmdkvt at Table@headfmt\unexpanded{#1}}}%
+    \kvt at defaultheader@i}}
+%    \end{macrocode}
+% \begin{macro}{\kvt at ifnil}
+% The |\kvt at 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 at ifnil[1]{%
+  \ifx\@nil#1\relax
+    \expandafter\@firstoftwo\else
+    \expandafter\@secondoftwo\fi}
+%    \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\kvt at HackIntercolSpace}
+% The |\kvt at HackIntercolSpace| macro captures the negative space that
+% cancels out the spacing otherwise caused by the extra column that the
+% package adds.
+%    \begin{macrocode}
+\newcommand\kvt at HackIntercolSpace{%
+  @{\hspace{-.5\arrayrulewidth}}}
+%    \end{macrocode}
+% \end{macro}
+%
 % \begin{macro}{\kvt at alltables}
-% The |\kvt at alltables| is an \textsf{etoolbox} list containing the names
+% The |\kvt at alltables| is an \pkgname{etoolbox} list containing the names
 % of all tables declared by |\NewKeyValTable|.
 %    \begin{macrocode}
 \newcommand\kvt at alltables{}
@@ -790,6 +1215,194 @@
 % \end{macro}
 %
 %
+% \subsection{Custom Column Headers}
+%
+% \begin{macro}{\kvt at parseheadrows}
+% The |\kvt at parseheadrows|\marg{tname}\marg{headers}
+% macro parses the \meta{headers} argument of |\NewKeyValTable|.
+%    \begin{macrocode}
+\newcommand\kvt at parseheadrows[2]{%
+  \csdef{kvt@@colgroups@#1}{}%
+  \csdef{kvt at headrowcount@#1}{0}%
+  \bgroup
+  \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 at 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{%
+    \def\kvt@@tmp{##1}\trim at post@space at in\kvt@@tmp%
+    \expandafter\ifstrequal\expandafter{\kvt@@tmp}{::}
+      {\appto\kvt@@parseheadrows{%
+         \cseappto{kvt@@colgroups@#1}{%
+           \csexpandonce{kvt at headings@#1}}}}
+      {\appto\kvt@@parseheadrows{\kvt at parseheadrow{#1}{##1}}}%
+%    \end{macrocode}
+% Increment the header row counter for each |\\|-separated item of
+% \meta{headers}.
+%    \begin{macrocode}
+    \appto\kvt@@parseheadrows{\csedef{kvt at headrowcount@#1}{%
+      \the\numexpr\csuse{kvt at headrowcount@#1}+1\relax}}%
+  }\kvt at dobrklist{#2}%
+%    \end{macrocode}
+% Finally, escape the inner group and overwrite the headings
+% with the result of the parsing.
+%    \begin{macrocode}
+  \expandafter\egroup\kvt@@parseheadrows
+  \csletcs{kvt at headings@#1}{kvt@@colgroups@#1}}
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\kvt at parseheadrow}
+% The |\kvt at parseheadrow|\marg{tname}\marg{colspec} macro parses a
+% single header row and appends the resulting table code to
+% \cs{kvt@@colgroups@\meta{tname}}.
+%    \begin{macrocode}
+\newcommand\kvt at parseheadrow[2]{%
+  \bgroup
+%    \end{macrocode}
+% First parse \meta{colspec}, populating the
+% \cs{kvt@@colgrpof@\meta{colname}} macros that associate each column
+% with the column group to which the column belongs.
+%    \begin{macrocode}
+  \def\do##1{\kvt at parsehdcolspec{#1}##1::\@undefined}%
+  \kvt at 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@@span| counter specifies how many
+% columns the current cell shall span.
+% Finally, |\kvt@@curgrp| and |\kvt@@lastgrp| hold the name of the group
+% in which the current column and, respectively, previous column are in.
+% Each of the two macros is undefined if there is no such column group.
+%    \begin{macrocode}
+  \let\kvt@@tmpgrphd\@empty
+  \kvt@@span\z@
+  \undef\kvt@@curgrp \undef\kvt@@lastgrp
+%    \end{macrocode}
+% Next, loop over all displayed (non-hidden) columns stored in
+% \cs{kvt at colkeys@\meta{tname}}. The following |\do|\marg{colname}
+% 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@@curgrp{kvt@@colgrpof@##1}%
+    \ifdefequal\kvt@@curgrp\kvt@@lastgrp
+%    \end{macrocode}
+% If the column group has not changed, simply increase the spanning
+% counter.
+%    \begin{macrocode}
+      {\advance\kvt@@span\@ne}%
+%    \end{macrocode}
+% Otherwise, i.e., if the column group has changed, then conclude the
+% previous column (if there was one) and reset the span to 1 (to count
+% for the column in |\kvt@@curgrp|) and set |\kvt@@lastgrp| to the
+% current one.
+%    \begin{macrocode}
+      {\ifnum\kvt@@span>\z@ \expandafter\kvt at concludecolumn\fi
+       \ifdefvoid\kvt@@curgrp{}{\ifcsdef{kvt@@colgrpdone@\kvt@@curgrp}{%
+         \kvt at error{Column group `\kvt@@curgrp' must consist of only
+            consecutive columns, but it is not}%
+           {Compare `|\kvt@@curgrp|' to the column ordering as specified
+            in `\string\NewKeyValTable{#1}'}}{}}%
+       \kvt@@span\@ne \let\kvt@@lastgrp\kvt@@curgrp}%
+  }\dolistcsloop{kvt at colkeys@#1}%
+  \kvt at concludecolumn
+%    \end{macrocode}
+% Finally, conclude the whole header row and append the row to the
+% overall list of rows, stored in \cs{kvt@@colgroups@\meta{tname}},
+% while ending the current \hologo{TeX} group.
+%    \begin{macrocode}
+  \appto\kvt@@tmpgrphd{\tabularnewline}%
+  \edef\do{\noexpand\csappto{kvt@@colgroups@#1}{%
+    \noexpand\noexpand\noexpand\rowcolor{\noexpand\cmdkvt at Table@headbg}%
+    \noexpand\unexpanded{\expandonce{\kvt@@tmpgrphd}}}}%
+  \expandafter\egroup\do}
+%    \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.
+%    \begin{macrocode}
+\newcount\kvt@@span
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\kvt at concludecolumn}
+% The |\kvt at concludecolumn| macro appends a cell, potentially spanning
+% multiple columns, to the row under construction (which is in
+% |\kvt@@tmpgrphd|).
+%    \begin{macrocode}
+\newcommand\kvt at concludecolumn{%
+%    \end{macrocode}
+% The following conditional checks whether this is the first column
+% group in the header row. If this is the case, then the
+% |\kvt@@extraalign| macro is set to |\kvt at HackIntercolSpace|, such that
+% the |\multicolumn| below does not throw away this spacing.
+%    \begin{macrocode}
+  \ifdefequal\kvt@@tmpgrphd\@empty
+    {\let\kvt@@extraalign\kvt at HackIntercolSpace}
+    {\let\kvt@@extraalign\@empty}%
+  \appto\kvt@@tmpgrphd{&}%
+  \ifdefvoid\kvt@@lastgrp{}{%
+    \eappto\kvt@@tmpgrphd{\noexpand\multicolumn
+      {\the\kvt@@span}
+      {\expandonce\kvt@@extraalign
+       \csexpandonce{kvt@@colgrp at align@\kvt@@lastgrp}}
+      {\csexpandonce{kvt@@colgrp at head@\kvt@@lastgrp}}}%
+%    \end{macrocode}
+% Mark the column group as already used and concluded, such that another
+% use of the same column group can be detected and raise an error.
+%    \begin{macrocode}
+    \cslet{kvt@@colgrpdone@\kvt@@lastgrp}{\@ne}}}
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\kvt at parsehdcolspec}
+% The |\kvt at parsehdcolspec|\marg{tname}\meta{cname}|:|\meta{config}|:|\meta{empty}|\@undefined|
+% macro parses a single header column (resp. column group), \meta{cname}.
+% For a column group, \meta{cname} can consist of multiple,
+% "+"-separated column names.
+%    \begin{macrocode}
+\def\kvt at parsehdcolspec#1#2:#3:#4\@undefined{%
+%    \end{macrocode}
+% First link the individual columns of a column group to the group.
+% In this, ensure that no column is contained in more than one column
+% group.
+%    \begin{macrocode}
+  \def\kvt@@colreg##1{%
+    \ifinlistcs{##1}{kvt at colkeys@#1}{}
+      {\kvt at error{Column `##1' referenced in column group `#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@@colgrpof@##1}
+      {\kvt at error{Column `##1' used in more than one column group}
+         {Check the fourth, optional argument of \string\NewKeyValTable
+         and eliminate multiple occurrences of column `##1'.}}
+      {\csdef{kvt@@colgrpof@##1}{#2}}%
+  }\kvt at forpsvlist{\kvt@@colreg}{#2}%
+%    \end{macrocode}
+% Now parse the \meta{config} of the column, resp. column group.
+%    \begin{macrocode}
+  \def\kvt@@colgrp{#2}%
+  \setkeys[kvt]{ColGroup}{#3}}
+%    \end{macrocode}
+% \end{macro}
+%
+% The following defines the options for header cells.
+%    \begin{macrocode}
+\define at key[kvt]{ColGroup}{head}{%
+  \csdef{kvt@@colgrp at head@\kvt@@colgrp}{#1}}
+\define at key[kvt]{ColGroup}{align}{%
+  \csdef{kvt@@colgrp at align@\kvt@@colgrp}{#1}}
+\presetkeys[kvt]{ColGroup}{align=c}{}%
+%    \end{macrocode}
+%
+%
 % \subsection{Row Numbering and Labeling}
 %
 % The following counters simplify row numbering in key-value tables.
@@ -820,7 +1433,7 @@
 % number, including all previous |KeyValTable| tables.
 %    \begin{macrocode}
 \newcounter{kvtTotalRow}
-\setcounter{kvtTotalRow}{1}
+\setcounter{kvtTotalRow}{0}
 %    \end{macrocode}
 % \end{macro}
 %
@@ -829,7 +1442,7 @@
 % 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., \textsf{cleveref}}
+% \changes{v0.3}{2016/06/09}{Robustified for use with, e.g., \pkgname{cleveref}}
 %    \begin{macrocode}
 \newcommand\kvtLabel[3][]{%
 %    \end{macrocode}
@@ -837,7 +1450,7 @@
 % current label, but it does not touch the \meta{counter} (in case
 % someone added some custom hooks to them).
 %    \begin{macrocode}
-  \setcounter{kvt at LabelCtr}{\csname the#2\endcsname}%
+  \setcounter{kvt at LabelCtr}{\value{#2}}%
   \addtocounter{kvt at LabelCtr}{-1}%
   \refstepcounter{kvt at LabelCtr}%
 %    \end{macrocode}
@@ -866,7 +1479,16 @@
 %    \begin{macrocode}
 \newenvironment{KeyValTable}[2][]{%
   \bgroup%
-  \def\Row##1{\kvt at AddKeyValRow{#2}{##1}\kvt@@row\\}%
+%    \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 at AddKeyValRow
+    {\noalign\bgroup}{\expandafter\egroup\kvt@@row}{#2}}%
+%    \end{macrocode}
+% \end{macro}
+%    \begin{macrocode}
   \kvt at SetOptions{#2}{#1}%
   \csuse{kvt at StartTable@\cmdkvt at Table@shape}{#2}%
 }{%
@@ -894,79 +1516,226 @@
 %    \end{macrocode}
 % \end{macro}
 %
-% \begin{macro}{\kvt at StartTable@onepage}
-% \begin{macro}{\kvt at StartTable@multipage}
-% \begin{macro}{\kvt at StartTabu}
-% The |\kvt at StartTable@onepage|\marg{tname} begins the table
-% environment for a |KeyValTable| of shape |onepage|, which includes
-% displaying the head row, and setting the row counters.
-% The |\kvt at StartTable@multipage|\marg{tname} does the same for a table
-% environment of shape |multipage|.
-% These macros internally use |\kvt at StartTabu|\marg{env}\marg{tname} for
-% beginning a table environment of the \textsf{tabu} package. The
-% \meta{env} specifies the concrete environment, either |tabu| or
-% |longtabu|.
+% \subsubsection{Table Environment Code}
+%
+% \begin{macro}{\kvt at StartTabularlike}
+% The
+% |\kvt at StartTabularlike|\marg{env}\marg{tname}\marg{bLong}\marg{bTabu}\marg{bWidth}
+% macro begins a table environment for the given table type \meta{tname}.
+% The \meta{env} parameter specifies the concrete environment name.
+% The parameters \meta{bLong}, \meta{bTabu}, and \meta{bWidth} are
+% Boolean parameters (expecting value |true| or value |false|).
+% They specify whether the table environment supports multi-page tables
+% (\meta{bLong}), whether the environment is a \pkgname{tabu}
+% environment (\meta{bTabu}), and whether the environment supports
+% specifying the width of the table (\meta{bWidth}).
 %    \begin{macrocode}
-\newcommand\kvt at StartTable@onepage[1]{%
-  \kvt at StartTabu{tabu}{#1}}
-\newcommand\kvt at StartTable@multipage[1]{%
-  \kvt at StartTabu{longtabu}{#1}}
-\newcommand\kvt at StartTabu[2]{%
+\newcommand\kvt at StartTabularlike[5]{%
 %    \end{macrocode}
 % The |\kvt@@recenttable| allows the |\AfterEndEnvironment| hook for
 % |KeyValTable| to access the most recent table type.
-% \changes{v0.3}{2016/06/05}{Added \texttt{showhead} option}
 %    \begin{macrocode}
   \gdef\kvt@@recenttable{#2}%
-  \bgroup\edef\kvt@@do{\egroup
-    \noexpand\begin{#1}{\csuse{kvt at alignments@#2}}%
-    \noexpand\toprule
-    \ifbool{kvt at Table@showhead}{%
-      \noexpand\rowcolor{\cmdkvt at Table@headbg}%
-      \unexpanded{\csuse{kvt at headings@#2}\\\midrule}}{}%
-    \noexpand\taburowcolors 2{\cmdkvt at Table@rowbg}%
-  }\kvt@@do%
-  \iftabu at long\expandafter\endhead\fi
-  \setcounter{kvtRow}{1}%
+%    \end{macrocode}
+% \changes{v1.0}{2019/02/18}{Implemented \texttt{showrules} option}
+%    \begin{macrocode}
+  \ifbool{kvt at Table@showrules}
+    {\def\kvt@@rule##1{\csuse{##1rule}}}
+    {\def\kvt@@rule##1{}}%
+  \csuse{kvt@@patchenvend@#1}%
+  \setcounter{kvtRow}{0}%
   \setcounter{kvtTypeRow}{\csuse{kvt at rowcount@#2}}%
-  \everyrow{%
-    \addtocounter{kvtRow}{1}%
-    \addtocounter{kvtTypeRow}{1}%
-    \addtocounter{kvtTotalRow}{1}%
-  }%
-}
 %    \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.
+%    \begin{macrocode}
+  \bgroup\edef\kvt@@do{\egroup
+    \ifbool{#4}{}{\noexpand\kvt at dottedrowcolors
+      {\ifbool{kvt at Table@showhead}
+        {\the\numexpr\csuse{kvt at headrowcount@#2}+1\relax}
+        {1}}%
+      {\expandonce\cmdkvt at Table@rowbg}}%
+%    \end{macrocode}
+% \changes{v1.0}{2019/03/09}{Added \texttt{width} option}
+%    \begin{macrocode}
+    \expandafter\noexpand\csname #1\endcsname
+      \ifbool{#5}
+        {\ifbool{#4}
+          {to \expandonce\cmdkvt at Table@width}
+          {{\expandonce\cmdkvt at Table@width}}}
+        {}%
+      {\csexpandonce{kvt at alignments@#2}}%
+    \noexpand\kvt@@rule{top}%
+%    \end{macrocode}
+% \changes{v0.3}{2016/06/05}{Added \texttt{showhead} option}
+%    \begin{macrocode}
+    \ifbool{kvt at Table@showhead}
+      {\csuse{kvt at headings@#2}\noexpand\kvt@@rule{mid}}
+      {}%
+    \ifbool{#4}
+      {\noexpand\taburowcolors 2{\expandonce\cmdkvt at Table@rowbg}}{}%
+    \ifbool{#3}{\noexpand\endhead}{}%
+  }\kvt@@do}
+%    \end{macrocode}
 % \end{macro}
+%
+% \begin{macro}{\kvt at stepcounters}
+% The |\kvt at stepcounters|\oarg{delta} macro increments all row counters
+% by \meta{delta}. If \meta{delta} is omitted, \meta{delta}=1.
+%    \begin{macrocode}
+\newcommand\kvt at stepcounters[1][1]{%
+  \addtocounter{kvtRow}{#1}%
+  \addtocounter{kvtTypeRow}{#1}%
+  \addtocounter{kvtTotalRow}{#1}}
+%    \end{macrocode}
 % \end{macro}
+%
+% \begin{macro}{\kvt at DefineStdTabEnv}
+% The
+% |\kvt at DefineStdTabEnv|\oarg{shape}\marg{env}\marg{bLong}\marg{bTabu}\marg{bWidth}\marg{endpatch}
+% 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.
+% The \meta{endpatch} parameter expects macro code that shall be run
+% at the beginning of the |KeyValTable| environment to (locally) patch
+% macros related to the end code of \meta{env} for ensuring
+% that the bottom rule, |\kvt@@rule{bottom}|, is displayed.
+% If \meta{endpatch} is empty, the rule is displayed via
+% \cs{kvt at EndTable@\meta{shape}}. Otherwise,
+% \cs{kvt at EndTable@\meta{shape}} equals \cs{end\meta{env}}.
+% Environments such as |tabularx| require the latter to parse for the
+% end of the environment.
+% The parameters \meta{bLong}, \meta{bTabu}, and \meta{bWidth}
+% are the same as for |\kvt at StartTabularlike|.
+%
+% Note: In the future, the macro could automatically add \meta{option}
+% to the list of possible values for the |shape| option.
+%    \begin{macrocode}
+\newcommand\kvt at DefineStdTabEnv{\@dblarg\kvt at DefineStdTabEnv@i}
+\newcommand\kvt at DefineStdTabEnv@i[6][]{%
+  \expandafter\newcommand\csname kvt at StartTable@#1\endcsname[1]{%
+    \kvt at StartTabularlike{#2}{##1}{#3}{#4}{#5}}%
+  \csedef{kvt at EndTable@#1}{%
+    \ifstrempty{#6}{\noexpand\kvt@@rule{bottom}}{}%
+    \expandafter\noexpand\csname end#2\endcsname}%
+  \ifstrempty{#6}{}{\csdef{kvt@@patchenvend@#2}{#6}}}
+%    \end{macrocode}
 % \end{macro}
 %
-% \begin{macro}{\kvt at EndTable@onepage}
-% \begin{macro}{\kvt at EndTable@multipage}
-% The |\kvt at EndTable@onepage| and |\kvt at EndTable@multipage| macros end a
-% table environment of the |onepage| or, respectively, |multipage|
-% shape.
+% The following lines define the macros for the various table shapes /
+% environments.
 %    \begin{macrocode}
-\newcommand\kvt at EndTable@onepage{%
-  \bottomrule%
-  \end{tabu}}
-\newcommand\kvt at EndTable@multipage{%
-  \bottomrule%
-  \end{longtabu}}
+\kvt at DefineStdTabEnv{tabular}{false}{false}{false}{}
+\kvt at DefineStdTabEnv{longtable}{true}{false}{false}{}
+\kvt at DefineStdTabEnv{tabularx}{false}{false}{true}{%
+  \preto\TX at endtabularx{\toks@\expandafter{\the\toks@
+      \kvt@@rule{bottom}}}}
+\kvt at DefineStdTabEnv{xltabular}{true}{false}{true}{%
+  \preto\XLT at ii@TX at endtabularx{\toks@\expandafter{\the\toks@
+      \kvt@@rule{bottom}}}}
+\kvt at DefineStdTabEnv[onepage]{tabu}{false}{true}{true}{}
+\kvt at DefineStdTabEnv[multipage]{longtabu}{true}{true}{true}{}
 %    \end{macrocode}
+%
+% \begin{macro}{\kvt at dottedrowcolors}
+% The |\kvt at dottedrowcolors|\marg{start-row}\marg{colors} sets up row
+% colors using the |\rowcolors| macro of \pkgname{xcolor}.
+% The \marg{colors} parameter expects arguments of the form
+% "\meta{color1}|..|\meta{color2}" (the syntax used for the |rowbg|
+% option. The row colors then alternate between \meta{color1} and
+% \meta{color2}, starting with \meta{color1} in \meta{start-row}.
+% This macro substitutes |\taburowcolors| for non-\pkgname{tabu}
+% environments.
+%    \begin{macrocode}
+\newcommand\kvt at dottedrowcolors[2]{%
+  \kvt at dottedrowcolors@i{#1}#2\@nil}
+\def\kvt at dottedrowcolors@i#1#2..#3\@nil{%
+%    \end{macrocode}
+% Since |\rowcolors| expects its color arguments to specify the odd and
+% even color, we swap arguments depending on the parity of
+% \meta{start-row} to ensure \meta{color1} is applied to
+% \meta{start-row}.
+%    \begin{macrocode}
+  \ifnumodd{#1}
+    {\rowcolors{#1}{#2}{#3}}
+    {\rowcolors{#1}{#3}{#2}}}
+%    \end{macrocode}
 % \end{macro}
-% \end{macro}
 %
+% \subsubsection{Environment-Independent Parts}
+%
+% The following block declares the known row options.
+%    \begin{macrocode}
+\define at cmdkey[kvt]{Row}{bg}{}%
+\define at boolkey[kvt]{Row}{hidden}[true]{}%
+\define at cmdkey[kvt]{Row}{below}{}
+\define at cmdkey[kvt]{Row}{above}{}
+\define at cmdkey[kvt]{Row}{around}{%
+  \def\cmdkvt at Row@above{#1}\def\cmdkvt at Row@below{#1}}
+%    \end{macrocode}
+%
 % \begin{macro}{\kvt at AddKeyValRow}
-% The |\kvt at AddKeyValRow|\marg{tname}\marg{content} adds a new row to
-% the current table of type \meta{tname}. The \meta{content} is a
+% The
+% |\kvt at 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 macro assumes that the current content of the table is
-% stored in |\kvt@@row| and modifies this macro by appending the
-% additional row.
+% 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 (|\bgroup| and |\egroup|) as well as
+% table placement via |\noalign|.
+% \changes{v1.0}{2019/03/17}{Added \oarg{options}}
 %    \begin{macrocode}
-\newcommand\kvt at AddKeyValRow[2]{%
-  \setkeys[KeyValTable]{#1}{#2}%
+\newcommand\kvt at AddKeyValRow[3]{%
+  #1%
 %    \end{macrocode}
+% It's essential that \meta{pre} above comes even before |\@ifnextchar|
+% and, therefore, cannot be moved into |\kvt at 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 at AddKeyValRow@i{#2}{#3}}
+    {\kvt at AddKeyValRow@i{#2}{#3}[]}}
+%    \end{macrocode}
+% \end{macro}
+% \begin{macro}{\kvt at AddKeyValRow@i}
+% The
+% |\kvt at AddKeyValRow@i|\marg{post}\marg{tname}\oarg{options}\marg{content}
+% macro parses \meta{options} and evaluates the |hidden| option.
+%    \begin{macrocode}
+\def\kvt at AddKeyValRow@i#1#2[#3]#4{%
+  \setkeys[kvt]{Row}{#3}%
+  \ifbool{kvt at Row@hidden}
+    {\let\kvt@@row\@empty #1}
+    {\kvt at AddKeyValRow@ii{#1}{#2}{#4}}}
+%    \end{macrocode}
+% \end{macro}
+% \begin{macro}{\kvt at AddKeyValRow@ii}
+% The
+% |\kvt at 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 at AddKeyValRow@i|.
+%    \begin{macrocode}
+\def\kvt at 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 at Row@above{}{%
+    \eappto\kvt@@row{\noexpand\noalign{\noexpand\vspace{%
+      \expandonce\cmdkvt at Row@above}}}}%
+  \ifdefvoid\cmdkvt at Row@bg{}{%
+    \eappto\kvt@@row{\noexpand\rowcolor{\expandonce\cmdkvt at Row@bg}}}%
+%    \end{macrocode}
+% Place the |everyrow| hook after |\noalign|.
+%    \begin{macrocode}
+  \expandafter\appto\expandafter\kvt@@row\expandafter{\kvt@@everyrow}
+%    \end{macrocode}
 % The following loop uses |\do|\marg{cname} to append the content of
 % all columns (in the given format and using the given default value),
 % where each column value is in
@@ -973,20 +1742,98 @@
 % \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
   \def\do##1{%
-    \ifdefvoid\kvt@@row{}{\appto\kvt@@row{&}}%
-    \eappto\kvt@@row{%
-      \csexpandonce{kvt at col@format@#1@##1}{%
-      \ifcsvoid{cmdKeyValTable@#1@##1}%
-        {\csexpandonce{kvt at col@default@#1@##1}}%
-        {\csexpandonce{cmdKeyValTable@#1@##1}}}%
-    }%
-  }\dolistcsloop{kvt at colkeys@#1}%
-}
 %    \end{macrocode}
+% First recover the cell content (either the specified value for the row
+% or, if no value is specified for the row, the cell's default value)
+% without formatting.
+%    \begin{macrocode}
+    \ifcsvoid{cmdKeyValTable@#2@##1}
+      {\letcs\kvt@@cell{kvt at col@default@#2@##1}}
+      {\letcs\kvt@@cell{cmdKeyValTable@#2@##1}}%
+%    \end{macrocode}
+% Separately also already create the formatted content.
+%    \begin{macrocode}
+    \edef\kvt@@fmtcell{\csexpandonce{kvt at col@format@#2@##1}{%
+      \expandonce\kvt@@cell}}%
+%    \end{macrocode}
+% Next, check whether a column-spanning cell is active
+% ($\cs{kvt@@span}>0$). If this is the case, ensure that if the raw cell
+% content in the current column is empty, then formatting does not make
+% the cell non-empty and, thereby, cause errors with the active
+% column-spanning cell.
+%    \begin{macrocode}
+    \ifnumgreater\kvt@@span{0}
+      {\advance\kvt@@span\m at ne
+       \ifstrempty\kvt@@cell{\def\kvt@@fmtcell{}}{}}
+      {\appto\kvt@@row{&}}%
+%    \end{macrocode}
+% Now check whether the cell itself spans multiple columns.
+%    \begin{macrocode}
+    \expandafter\kvt at CheckMulticolumn\kvt@@cell
+      \relax\relax\relax\relax\@undefined{#2}{##1}%
+    \expandafter\appto\expandafter\kvt@@row\expandafter{\kvt@@fmtcell}%
+  }\dolistcsloop{kvt at colkeys@#2}%
+%    \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 at Row@below{}{%
+    \eappto\kvt@@row{\noexpand\noalign{\noexpand\vspace{%
+      \expandonce\cmdkvt at 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 at everyrow}
+% The |\kvt at everyrow|\marg{code} registers \meta{code} to be included in
+% the first (invisible) cell of every row.
+%    \begin{macrocode}
+\newcommand\kvt at everyrow[1]{\def\kvt@@everyrow{#1}}
+\newcommand\kvt@@everyrow{}
+%    \end{macrocode}
+% \end{macro}
+% Initialize the hook for every row to increment the row counters.
+%    \begin{macrocode}
+\kvt at everyrow{\kvt at stepcounters}%
+%    \end{macrocode}
+%
+% \begin{macro}{\kvt at CheckMulticolumn}
+% The
+% |\kvt at CheckMulticolumn|\marg{arg1}\marg{arg2}\marg{arg3}\marg{arg4}|\@undefined|\linebreak[4]\marg{tname}\marg{colname}
+% macro checks whether a cell's initial content (captured by \meta{arg1}
+% to \meta{arg4}, starts a multi-column cell. If this is the case, the
+% macro records the arguments to |\multicolumn| for use by
+% |\kvt at AddKeyValRow|.
+% In this case, \meta{arg1}=|\multicolumn|, \meta{arg2}=\meta{n} (number
+% of columns to span), \meta{arg3}=\meta{format} (column alignment), and
+% \meta{arg4}=\meta{item} (the content of the cell).
+%    \begin{macrocode}
+\def\kvt at CheckMulticolumn#1#2#3#4\@undefined#5#6{%
+  \ifx#1\multicolumn
+%    \end{macrocode}
+% First, record \meta{n} in |\kvt@@span|. The subtraction of $-1$ is
+% already in preparation for the next column, in which one spanning has
+% already been reduced.
+%    \begin{macrocode}
+    \kvt@@span=#2\relax \advance\kvt@@span\m at ne
+%    \end{macrocode}
+% Second, move the defined cell format to inside of the \meta{item}
+% argument of |\multicolumn| rather than around the |\multicolumn|.
+%    \begin{macrocode}
+    \edef\kvt@@fmtcell{\unexpanded{\multicolumn{#2}{#3}}%
+      {\csexpandonce{kvt at col@format@#5@#6}{\expandonce{#4}}}}%
+  \fi}
+%    \end{macrocode}
+% \end{macro}
+%
 % \subsection{Collecting Key-Value Table Content}
 %
 % \begin{macro}{\ShowKeyValTable}
@@ -1004,17 +1851,19 @@
 % \end{macro}
 %
 % \begin{macro}{\AddKeyValRow}
-% The |\AddKeyValRow|\marg{tname}\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}, like with |\kvt at AddKeyValRow|, is supposed to be a
-% key-value list specifying the content of the cells in the row.
+% 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 at AddKeyValRow|.
+% The resulting row (|\kvt@@row|) is globally appended to
+% \cs{kvt at rows@\meta{tname}}.
 %    \begin{macrocode}
-\newcommand\AddKeyValRow[2]{%
-  \bgroup%
-  \kvt at AddKeyValRow{#1}{#2}%
-  \csxappto{kvt at rows@#1}{\expandonce{\kvt@@row}\noexpand\\}%
-  \egroup}
+\newcommand\AddKeyValRow[1]{%
+  \kvt at AddKeyValRow
+    {\bgroup}
+    {\csxappto{kvt at rows@#1}{\expandonce{\kvt@@row}}\egroup}
+    {#1}}
 %    \end{macrocode}
 % \end{macro}
 %
@@ -1030,6 +1879,66 @@
 %    \end{macrocode}
 % \end{environment}
 %
+%
+% \subsection{Package Options}
+%
+% The \pkgname{tabu} is used by default for typesetting the tables,
+% additionally with \pkgname{longtable} for tables that can span
+% multiple pages.
+% If the default packages are never used or the \pkgname{tabu} package
+% shall be loaded manually, the |noTabuPkg| option can be used.
+%    \begin{macrocode}
+\define at boolkey[kvt]{PackageOptions}[kvt@@]{noTabuPkg}[true]{}
+%    \end{macrocode}
+%
+% Next, set default package options and process them.
+%    \begin{macrocode}
+\ExecuteOptionsX[kvt]<PackageOptions>{%
+  noTabuPkg=false,
+}
+\ProcessOptionsX[kvt]<PackageOptions>\relax
+%    \end{macrocode}
+%
+% Finally, implement the outcome of the options parsing.
+%    \begin{macrocode}
+\ifbool{kvt@@noTabuPkg}{}{%
+  \RequirePackage{longtable,tabu}}
+%    \end{macrocode}
+%
+%
+% \subsection{Auxiliary Code}
+%
+% \begin{macro}{\kvt at dossvlist}
+% The |\kvt at dossvlist|\marg{list} macro parses a semicolon-separated
+% list and runs |\do|\meta{item} for every element of the list.
+%    \begin{macrocode}
+\DeclareListParser{\kvt at dossvlist}{;}
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\kvt at forpsvlist}
+% The |\kvt at forpsvlist|\marg{handler}\marg{list} parses a `+'-separated list.
+%    \begin{macrocode}
+\DeclareListParser*{\kvt at forpsvlist}{+}
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\kvt at dobrklist}
+% The |\kvt at dobrklist|\marg{list} parses a `|\\|'-separated list.
+%    \begin{macrocode}
+\DeclareListParser{\kvt at dobrklist}{\\}
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\kvt at error}
+% \begin{macro}{\kvt at warn}
+%    \begin{macrocode}
+\newcommand\kvt at error[2]{\PackageError{keyvaltable}{#1}{#2}}
+\newcommand\kvt at warn[1]{\PackageWarning{keyvaltable}{#1}}
+%    \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
 %\iffalse
 %</package>
 %\fi

Modified: trunk/Master/texmf-dist/tex/latex/keyvaltable/keyvaltable.sty
===================================================================
--- trunk/Master/texmf-dist/tex/latex/keyvaltable/keyvaltable.sty	2019-03-19 21:27:58 UTC (rev 50470)
+++ trunk/Master/texmf-dist/tex/latex/keyvaltable/keyvaltable.sty	2019-03-19 21:28:17 UTC (rev 50471)
@@ -20,12 +20,13 @@
 %% 
 \NeedsTeXFormat{LaTeX2e}[1999/12/01]
 \ProvidesPackage{keyvaltable}
-    [2018/11/01 v0.3b Package for filling tables using key-value lists]
+    [2019/03/17 v1.0 Package for filling tables using key-value lists]
 \RequirePackage{etoolbox}
 \RequirePackage{xkeyval}
-\RequirePackage[table]{xcolor}
+\RequirePackage{trimspaces}
+\PassOptionsToPackage{table}{xcolor}
+\RequirePackage{xcolor}
 \RequirePackage{booktabs}
-\RequirePackage{longtable,tabu}
 \newcommand\kvtSet[1]{\bgroup
   \def\kvt@@presetqueue{\egroup}
   \setkeys[kvt]{defaults}{#1}{}%
@@ -32,7 +33,6 @@
   \kvt@@presetqueue}
 \newcommand\kvt at lazypreset[2]{%
   \appto\kvt@@presetqueue{\presetkeys[kvt]{#1}{#2}{}}}
-\DeclareListParser{\mkv at dossvlist}{;}
 \newcommand\kvt at addtableprop[2]{%
   \define at key[kvt]{defaults}{#1}{%
     \kvt at lazypreset{Table}{#1=##1}}%
@@ -61,11 +61,11 @@
     \csdef{kvt at col@#1@\kvt@@column}{##1}}%
   \presetkeys[kvt]{Column}{#1=#2}{}%
 }
-\newcommand\kvt at addchoicecolumnprop[3]{%
-  \define at choicekey[kvt]{defaults}{#1}{#3}{%
+\newcommand\kvt at addchoicecolumnprop[4]{%
+  \define at choicekey[kvt]{defaults}{#1}{#4}[#3]{%
     \kvt at lazypreset{Column}{#1=##1}}%
   \presetkeys[kvt]{defaults}{#1=#2}{}%
-  \define at choicekey[kvt]{Column}{#1}{#3}%
+  \define at choicekey[kvt]{Column}{#1}{#4}[#3]%
     {\csdef{kvt at col@#1@\kvt@@column}{##1}}%
   \presetkeys[kvt]{Column}{#1=#2}{}%
 }
@@ -72,25 +72,40 @@
 \kvt at addtableprop{rowbg}{white..black!10}
 \kvt at addtableprop{headbg}{black!14}
 \kvt at addbooltableprop{showhead}{true}
-\kvt at addchoicetableprop{shape}{multipage}{multipage,onepage}
+\kvt at addbooltableprop{showrules}{true}
+\kvt at addtableprop{headfmt}{}
+\kvt at addtableprop{headalign}{}
+\kvt at addtableprop{width}{\linewidth}
+\kvt at addchoicetableprop{shape}{multipage}{%
+  multipage,onepage,tabular,longtable,tabularx}
 \kvt at addcolumnprop{default}{}
-\kvt at addcolumnprop{format}{\kvt at struttedcell}
+\kvt at addcolumnprop{format}{\kvtStrutted}
 \kvt at addcolumnprop{align}{l}
 \kvt at addcolumnprop{head}{}
-\kvt at addchoicecolumnprop{hidden}{false}{false,true}
+\kvt at addchoicecolumnprop{hidden}{false}{true}{false,true}
 \kvtSet{}
-\newcommand\kvt at struttedcell[1]{\strut #1\ifhmode\expandafter\strut\fi}
+\newcommand\kvtTableOpt[1]{\csname cmdkvt at Table@#1\endcsname}
+\newcommand\kvtStrutted[1]{\strut #1\ifhmode\expandafter\strut\fi}
 \newcommand\NewKeyValTable[3][]{%
+  \@ifnextchar[%]
+    {\kvt at NewKeyValTable{#1}{#2}{#3}}%
+    {\kvt at NewKeyValTable{#1}{#2}{#3}[]}}
+\def\kvt at NewKeyValTable#1#2#3[#4]{%
   \csdef{kvt at options@#2}{#1}%
   \csdef{kvt at headings@#2}{}%
-  \csdef{kvt at alignments@#2}{}%
+  \csedef{kvt at alignments@#2}{p{0pt}\expandonce\kvt at HackIntercolSpace}%
   \csdef{kvt at colkeys@#2}{}%
-  \csdef{kvt at rowcount@#2}{1}%
+  \csdef{kvt at rowcount@#2}{0}%
   \csdef{kvt at rows@#2}{}%
+  \csdef{kvt at headings@#2}{\kvt at defaultheader}
   \listadd\kvt at alltables{#2}%
   \def\do##1{%
     \kvt at parsecolspec{#2}##1::\@undefined}%
-  \mkv at dossvlist{#3}%
+  \kvt at dossvlist{#3}%
+  \csappto{kvt at headings@#2}{{\@nil}}%
+  \ifstrempty{#4}
+    {\csdef{kvt at headrowcount@#2}{1}}
+    {\kvt at parseheadrows{#2}{#4}}%
 }
 \def\kvt at parsecolspec#1#2:#3:#4\@undefined{%
   \def\kvt@@column{#1@#2}%
@@ -97,22 +112,111 @@
   \setkeys[kvt]{Column}{#3}%
   \ifcsstring{kvt at col@hidden@#1@#2}{true}{}{%
     \cseappto{kvt at alignments@#1}{\csexpandonce{kvt at col@align@#1@#2}}%
-    \ifcsvoid{kvt at headings@#1}{}{\csappto{kvt at headings@#1}{&}}%
-    \ifcsstring{kvt at col@head@#1@#2}{}%
-      {\cseappto{kvt at headings@#1}{#2}}%
-      {\cseappto{kvt at headings@#1}{\csexpandonce{kvt at col@head@#1@#2}}}%
+    \ifcsvoid{kvt at col@head@#1@#2}%
+      {\csappto{kvt at headings@#1}{{#2}}}%
+      {\cseappto{kvt at headings@#1}{{\csexpandonce{kvt at col@head@#1@#2}}}}%
     \listcsadd{kvt at colkeys@#1}{#2}%
   }%
   \define at cmdkey[KeyValTable]{#1}{#2}[]{}%
   \presetkeys[KeyValTable]{#1}{#2}{}%
 }
+\newcommand\kvt at defaultheader{%
+  \noexpand\rowcolor{\cmdkvt at Table@headbg}%
+  \kvt at defaultheader@i}
+\newcommand\kvt at defaultheader@i[1]{%
+  \kvt at ifnil{#1}{\noexpand\tabularnewline}{%
+    \unexpanded{&}%
+    \ifdefvoid\cmdkvt at Table@headalign
+      {\expandonce\cmdkvt at Table@headfmt\unexpanded{#1}}
+      {\noexpand\multicolumn{1}{\expandonce\cmdkvt at Table@headalign}
+        {\expandonce\cmdkvt at Table@headfmt\unexpanded{#1}}}%
+    \kvt at defaultheader@i}}
+\newcommand\kvt at ifnil[1]{%
+  \ifx\@nil#1\relax
+    \expandafter\@firstoftwo\else
+    \expandafter\@secondoftwo\fi}
+\newcommand\kvt at HackIntercolSpace{%
+  @{\hspace{-.5\arrayrulewidth}}}
 \newcommand\kvt at alltables{}
+\newcommand\kvt at parseheadrows[2]{%
+  \csdef{kvt@@colgroups@#1}{}%
+  \csdef{kvt at headrowcount@#1}{0}%
+  \bgroup
+  \def\kvt@@parseheadrows{}%
+  \def\do##1{%
+    \def\kvt@@tmp{##1}\trim at post@space at in\kvt@@tmp%
+    \expandafter\ifstrequal\expandafter{\kvt@@tmp}{::}
+      {\appto\kvt@@parseheadrows{%
+         \cseappto{kvt@@colgroups@#1}{%
+           \csexpandonce{kvt at headings@#1}}}}
+      {\appto\kvt@@parseheadrows{\kvt at parseheadrow{#1}{##1}}}%
+    \appto\kvt@@parseheadrows{\csedef{kvt at headrowcount@#1}{%
+      \the\numexpr\csuse{kvt at headrowcount@#1}+1\relax}}%
+  }\kvt at dobrklist{#2}%
+  \expandafter\egroup\kvt@@parseheadrows
+  \csletcs{kvt at headings@#1}{kvt@@colgroups@#1}}
+\newcommand\kvt at parseheadrow[2]{%
+  \bgroup
+  \def\do##1{\kvt at parsehdcolspec{#1}##1::\@undefined}%
+  \kvt at dossvlist{#2}%
+  \let\kvt@@tmpgrphd\@empty
+  \kvt@@span\z@
+  \undef\kvt@@curgrp \undef\kvt@@lastgrp
+  \def\do##1{\letcs\kvt@@curgrp{kvt@@colgrpof@##1}%
+    \ifdefequal\kvt@@curgrp\kvt@@lastgrp
+      {\advance\kvt@@span\@ne}%
+      {\ifnum\kvt@@span>\z@ \expandafter\kvt at concludecolumn\fi
+       \ifdefvoid\kvt@@curgrp{}{\ifcsdef{kvt@@colgrpdone@\kvt@@curgrp}{%
+         \kvt at error{Column group `\kvt@@curgrp' must consist of only
+            consecutive columns, but it is not}%
+           {Compare `|\kvt@@curgrp|' to the column ordering as specified
+            in `\string\NewKeyValTable{#1}'}}{}}%
+       \kvt@@span\@ne \let\kvt@@lastgrp\kvt@@curgrp}%
+  }\dolistcsloop{kvt at colkeys@#1}%
+  \kvt at concludecolumn
+  \appto\kvt@@tmpgrphd{\tabularnewline}%
+  \edef\do{\noexpand\csappto{kvt@@colgroups@#1}{%
+    \noexpand\noexpand\noexpand\rowcolor{\noexpand\cmdkvt at Table@headbg}%
+    \noexpand\unexpanded{\expandonce{\kvt@@tmpgrphd}}}}%
+  \expandafter\egroup\do}
+\newcount\kvt@@span
+\newcommand\kvt at concludecolumn{%
+  \ifdefequal\kvt@@tmpgrphd\@empty
+    {\let\kvt@@extraalign\kvt at HackIntercolSpace}
+    {\let\kvt@@extraalign\@empty}%
+  \appto\kvt@@tmpgrphd{&}%
+  \ifdefvoid\kvt@@lastgrp{}{%
+    \eappto\kvt@@tmpgrphd{\noexpand\multicolumn
+      {\the\kvt@@span}
+      {\expandonce\kvt@@extraalign
+       \csexpandonce{kvt@@colgrp at align@\kvt@@lastgrp}}
+      {\csexpandonce{kvt@@colgrp at head@\kvt@@lastgrp}}}%
+    \cslet{kvt@@colgrpdone@\kvt@@lastgrp}{\@ne}}}
+\def\kvt at parsehdcolspec#1#2:#3:#4\@undefined{%
+  \def\kvt@@colreg##1{%
+    \ifinlistcs{##1}{kvt at colkeys@#1}{}
+      {\kvt at error{Column `##1' referenced in column group `#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@@colgrpof@##1}
+      {\kvt at error{Column `##1' used in more than one column group}
+         {Check the fourth, optional argument of \string\NewKeyValTable
+         and eliminate multiple occurrences of column `##1'.}}
+      {\csdef{kvt@@colgrpof@##1}{#2}}%
+  }\kvt at forpsvlist{\kvt@@colreg}{#2}%
+  \def\kvt@@colgrp{#2}%
+  \setkeys[kvt]{ColGroup}{#3}}
+\define at key[kvt]{ColGroup}{head}{%
+  \csdef{kvt@@colgrp at head@\kvt@@colgrp}{#1}}
+\define at key[kvt]{ColGroup}{align}{%
+  \csdef{kvt@@colgrp at align@\kvt@@colgrp}{#1}}
+\presetkeys[kvt]{ColGroup}{align=c}{}%
 \newcounter{kvtRow}
 \newcounter{kvtTypeRow}
 \newcounter{kvtTotalRow}
-\setcounter{kvtTotalRow}{1}
+\setcounter{kvtTotalRow}{0}
 \newcommand\kvtLabel[3][]{%
-  \setcounter{kvt at LabelCtr}{\csname the#2\endcsname}%
+  \setcounter{kvt at LabelCtr}{\value{#2}}%
   \addtocounter{kvt at LabelCtr}{-1}%
   \refstepcounter{kvt at LabelCtr}%
   \ifstrempty{#3}{}{%
@@ -121,7 +225,8 @@
 \newcounter{kvt at LabelCtr}
 \newenvironment{KeyValTable}[2][]{%
   \bgroup%
-  \def\Row##1{\kvt at AddKeyValRow{#2}{##1}\kvt@@row\\}%
+  \def\Row{\kvt at AddKeyValRow
+    {\noalign\bgroup}{\expandafter\egroup\kvt@@row}{#2}}%
   \kvt at SetOptions{#2}{#1}%
   \csuse{kvt at StartTable@\cmdkvt at Table@shape}{#2}%
 }{%
@@ -134,59 +239,141 @@
     \setkeys[kvt]{Table}%
       {\csexpandonce{kvt at options@#1},\unexpanded{#2}}%
   }\kvt@@do}
-\newcommand\kvt at StartTable@onepage[1]{%
-  \kvt at StartTabu{tabu}{#1}}
-\newcommand\kvt at StartTable@multipage[1]{%
-  \kvt at StartTabu{longtabu}{#1}}
-\newcommand\kvt at StartTabu[2]{%
+\newcommand\kvt at StartTabularlike[5]{%
   \gdef\kvt@@recenttable{#2}%
+  \ifbool{kvt at Table@showrules}
+    {\def\kvt@@rule##1{\csuse{##1rule}}}
+    {\def\kvt@@rule##1{}}%
+  \csuse{kvt@@patchenvend@#1}%
+  \setcounter{kvtRow}{0}%
+  \setcounter{kvtTypeRow}{\csuse{kvt at rowcount@#2}}%
   \bgroup\edef\kvt@@do{\egroup
-    \noexpand\begin{#1}{\csuse{kvt at alignments@#2}}%
-    \noexpand\toprule
-    \ifbool{kvt at Table@showhead}{%
-      \noexpand\rowcolor{\cmdkvt at Table@headbg}%
-      \unexpanded{\csuse{kvt at headings@#2}\\\midrule}}{}%
-    \noexpand\taburowcolors 2{\cmdkvt at Table@rowbg}%
-  }\kvt@@do%
-  \iftabu at long\expandafter\endhead\fi
-  \setcounter{kvtRow}{1}%
-  \setcounter{kvtTypeRow}{\csuse{kvt at rowcount@#2}}%
-  \everyrow{%
-    \addtocounter{kvtRow}{1}%
-    \addtocounter{kvtTypeRow}{1}%
-    \addtocounter{kvtTotalRow}{1}%
-  }%
-}
-\newcommand\kvt at EndTable@onepage{%
-  \bottomrule%
-  \end{tabu}}
-\newcommand\kvt at EndTable@multipage{%
-  \bottomrule%
-  \end{longtabu}}
-\newcommand\kvt at AddKeyValRow[2]{%
-  \setkeys[KeyValTable]{#1}{#2}%
+    \ifbool{#4}{}{\noexpand\kvt at dottedrowcolors
+      {\ifbool{kvt at Table@showhead}
+        {\the\numexpr\csuse{kvt at headrowcount@#2}+1\relax}
+        {1}}%
+      {\expandonce\cmdkvt at Table@rowbg}}%
+    \expandafter\noexpand\csname #1\endcsname
+      \ifbool{#5}
+        {\ifbool{#4}
+          {to \expandonce\cmdkvt at Table@width}
+          {{\expandonce\cmdkvt at Table@width}}}
+        {}%
+      {\csexpandonce{kvt at alignments@#2}}%
+    \noexpand\kvt@@rule{top}%
+    \ifbool{kvt at Table@showhead}
+      {\csuse{kvt at headings@#2}\noexpand\kvt@@rule{mid}}
+      {}%
+    \ifbool{#4}
+      {\noexpand\taburowcolors 2{\expandonce\cmdkvt at Table@rowbg}}{}%
+    \ifbool{#3}{\noexpand\endhead}{}%
+  }\kvt@@do}
+\newcommand\kvt at stepcounters[1][1]{%
+  \addtocounter{kvtRow}{#1}%
+  \addtocounter{kvtTypeRow}{#1}%
+  \addtocounter{kvtTotalRow}{#1}}
+\newcommand\kvt at DefineStdTabEnv{\@dblarg\kvt at DefineStdTabEnv@i}
+\newcommand\kvt at DefineStdTabEnv@i[6][]{%
+  \expandafter\newcommand\csname kvt at StartTable@#1\endcsname[1]{%
+    \kvt at StartTabularlike{#2}{##1}{#3}{#4}{#5}}%
+  \csedef{kvt at EndTable@#1}{%
+    \ifstrempty{#6}{\noexpand\kvt@@rule{bottom}}{}%
+    \expandafter\noexpand\csname end#2\endcsname}%
+  \ifstrempty{#6}{}{\csdef{kvt@@patchenvend@#2}{#6}}}
+\kvt at DefineStdTabEnv{tabular}{false}{false}{false}{}
+\kvt at DefineStdTabEnv{longtable}{true}{false}{false}{}
+\kvt at DefineStdTabEnv{tabularx}{false}{false}{true}{%
+  \preto\TX at endtabularx{\toks@\expandafter{\the\toks@
+      \kvt@@rule{bottom}}}}
+\kvt at DefineStdTabEnv{xltabular}{true}{false}{true}{%
+  \preto\XLT at ii@TX at endtabularx{\toks@\expandafter{\the\toks@
+      \kvt@@rule{bottom}}}}
+\kvt at DefineStdTabEnv[onepage]{tabu}{false}{true}{true}{}
+\kvt at DefineStdTabEnv[multipage]{longtabu}{true}{true}{true}{}
+\newcommand\kvt at dottedrowcolors[2]{%
+  \kvt at dottedrowcolors@i{#1}#2\@nil}
+\def\kvt at dottedrowcolors@i#1#2..#3\@nil{%
+  \ifnumodd{#1}
+    {\rowcolors{#1}{#2}{#3}}
+    {\rowcolors{#1}{#3}{#2}}}
+\define at cmdkey[kvt]{Row}{bg}{}%
+\define at boolkey[kvt]{Row}{hidden}[true]{}%
+\define at cmdkey[kvt]{Row}{below}{}
+\define at cmdkey[kvt]{Row}{above}{}
+\define at cmdkey[kvt]{Row}{around}{%
+  \def\cmdkvt at Row@above{#1}\def\cmdkvt at Row@below{#1}}
+\newcommand\kvt at AddKeyValRow[3]{%
+  #1%
+  \@ifnextchar[%]
+    {\kvt at AddKeyValRow@i{#2}{#3}}
+    {\kvt at AddKeyValRow@i{#2}{#3}[]}}
+\def\kvt at AddKeyValRow@i#1#2[#3]#4{%
+  \setkeys[kvt]{Row}{#3}%
+  \ifbool{kvt at Row@hidden}
+    {\let\kvt@@row\@empty #1}
+    {\kvt at AddKeyValRow@ii{#1}{#2}{#4}}}
+\def\kvt at AddKeyValRow@ii#1#2#3{%
+  \setkeys[KeyValTable]{#2}{#3}%
+  \def\kvt@@row{}%
+  \ifdefvoid\cmdkvt at Row@above{}{%
+    \eappto\kvt@@row{\noexpand\noalign{\noexpand\vspace{%
+      \expandonce\cmdkvt at Row@above}}}}%
+  \ifdefvoid\cmdkvt at Row@bg{}{%
+    \eappto\kvt@@row{\noexpand\rowcolor{\expandonce\cmdkvt at Row@bg}}}%
+  \expandafter\appto\expandafter\kvt@@row\expandafter{\kvt@@everyrow}
+  \kvt@@span=0\relax
   \def\do##1{%
-    \ifdefvoid\kvt@@row{}{\appto\kvt@@row{&}}%
-    \eappto\kvt@@row{%
-      \csexpandonce{kvt at col@format@#1@##1}{%
-      \ifcsvoid{cmdKeyValTable@#1@##1}%
-        {\csexpandonce{kvt at col@default@#1@##1}}%
-        {\csexpandonce{cmdKeyValTable@#1@##1}}}%
-    }%
-  }\dolistcsloop{kvt at colkeys@#1}%
-}
+    \ifcsvoid{cmdKeyValTable@#2@##1}
+      {\letcs\kvt@@cell{kvt at col@default@#2@##1}}
+      {\letcs\kvt@@cell{cmdKeyValTable@#2@##1}}%
+    \edef\kvt@@fmtcell{\csexpandonce{kvt at col@format@#2@##1}{%
+      \expandonce\kvt@@cell}}%
+    \ifnumgreater\kvt@@span{0}
+      {\advance\kvt@@span\m at ne
+       \ifstrempty\kvt@@cell{\def\kvt@@fmtcell{}}{}}
+      {\appto\kvt@@row{&}}%
+    \expandafter\kvt at CheckMulticolumn\kvt@@cell
+      \relax\relax\relax\relax\@undefined{#2}{##1}%
+    \expandafter\appto\expandafter\kvt@@row\expandafter{\kvt@@fmtcell}%
+  }\dolistcsloop{kvt at colkeys@#2}%
+  \appto\kvt@@row{\tabularnewline}%
+  \ifdefvoid\cmdkvt at Row@below{}{%
+    \eappto\kvt@@row{\noexpand\noalign{\noexpand\vspace{%
+      \expandonce\cmdkvt at Row@below}}}}%
+  #1}
+\newcommand\kvt at everyrow[1]{\def\kvt@@everyrow{#1}}
+\newcommand\kvt@@everyrow{}
+\kvt at everyrow{\kvt at stepcounters}%
+\def\kvt at CheckMulticolumn#1#2#3#4\@undefined#5#6{%
+  \ifx#1\multicolumn
+    \kvt@@span=#2\relax \advance\kvt@@span\m at ne
+    \edef\kvt@@fmtcell{\unexpanded{\multicolumn{#2}{#3}}%
+      {\csexpandonce{kvt at col@format@#5@#6}{\expandonce{#4}}}}%
+  \fi}
 \newcommand\ShowKeyValTable[2][]{%
   \begin{KeyValTable}[#1]{#2}%
     \csuse{kvt at rows@#2}%
   \end{KeyValTable}%
   \csdef{kvt at rows@#2}{}}
-\newcommand\AddKeyValRow[2]{%
-  \bgroup%
-  \kvt at AddKeyValRow{#1}{#2}%
-  \csxappto{kvt at rows@#1}{\expandonce{\kvt@@row}\noexpand\\}%
-  \egroup}
+\newcommand\AddKeyValRow[1]{%
+  \kvt at AddKeyValRow
+    {\bgroup}
+    {\csxappto{kvt at rows@#1}{\expandonce{\kvt@@row}}\egroup}
+    {#1}}
 \newenvironment{KeyValTableContent}[1]{%
   \def\Row{\AddKeyValRow{#1}}}{}%
+\define at boolkey[kvt]{PackageOptions}[kvt@@]{noTabuPkg}[true]{}
+\ExecuteOptionsX[kvt]<PackageOptions>{%
+  noTabuPkg=false,
+}
+\ProcessOptionsX[kvt]<PackageOptions>\relax
+\ifbool{kvt@@noTabuPkg}{}{%
+  \RequirePackage{longtable,tabu}}
+\DeclareListParser{\kvt at dossvlist}{;}
+\DeclareListParser*{\kvt at forpsvlist}{+}
+\DeclareListParser{\kvt at dobrklist}{\\}
+\newcommand\kvt at error[2]{\PackageError{keyvaltable}{#1}{#2}}
+\newcommand\kvt at warn[1]{\PackageWarning{keyvaltable}{#1}}
 \endinput
 %%
 %% End of file `keyvaltable.sty'.



More information about the tex-live-commits mailing list