summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/source/latex/keyvaltable
diff options
context:
space:
mode:
authorKarl Berry <karl@freefriends.org>2019-03-19 21:28:17 +0000
committerKarl Berry <karl@freefriends.org>2019-03-19 21:28:17 +0000
commitef1f2fe2f48a08a89cc523d65ea2f29e5b26f058 (patch)
treee14de39fb7274108e016acec92a16bccfd9c7625 /Master/texmf-dist/source/latex/keyvaltable
parent0c4b47b64e197d32e1d141f321e2f44725b0254a (diff)
keyvaltable (19mar19)
git-svn-id: svn://tug.org/texlive/trunk@50471 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master/texmf-dist/source/latex/keyvaltable')
-rw-r--r--Master/texmf-dist/source/latex/keyvaltable/keyvaltable.dtx1463
1 files changed, 1186 insertions, 277 deletions
diff --git a/Master/texmf-dist/source/latex/keyvaltable/keyvaltable.dtx b/Master/texmf-dist/source/latex/keyvaltable/keyvaltable.dtx
index f049c78e3cd..5a1006a2853 100644
--- a/Master/texmf-dist/source/latex/keyvaltable/keyvaltable.dtx
+++ b/Master/texmf-dist/source/latex/keyvaltable/keyvaltable.dtx
@@ -1,6 +1,6 @@
% \iffalse meta-comment
%
-% Copyright (C) 2016-2018 by Richard Grewe <r-g+tex@posteo.net>
+% Copyright (C) 2016-2019 by Richard Grewe <r-g+tex@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,39 +94,40 @@
%
% \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}
%
% 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@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@dossvlist}
-% The |\mkv@dossvlist|\marg{list} macro parses a semicolon-separated
-% list and runs |\do|\meta{item} for every element of the list.
-% \begin{macrocode}
-\DeclareListParser{\mkv@dossvlist}{;}
-% \end{macrocode}
-% \end{macro}
-%
% \begin{macro}{\kvt@addtableprop}
% The |\kvt@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@addchoicecolumnprop}
-% The |\kvt@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@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@addchoicecolumnprop[3]{%
+\newcommand\kvt@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@choicekey[kvt]{defaults}{#1}{#3}{%
+ \define@choicekey[kvt]{defaults}{#1}{#4}[#3]{%
\kvt@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@choicekey[kvt]{Column}{#1}{#3}%
+ \define@choicekey[kvt]{Column}{#1}{#4}[#3]%
{\csdef{kvt@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@addtableprop{rowbg}{white..black!10}
\kvt@addtableprop{headbg}{black!14}
\kvt@addbooltableprop{showhead}{true}
-\kvt@addchoicetableprop{shape}{multipage}{multipage,onepage}
+\kvt@addbooltableprop{showrules}{true}
+\kvt@addtableprop{headfmt}{}
+\kvt@addtableprop{headalign}{}
+\kvt@addtableprop{width}{\linewidth}
+% \end{macrocode}
+% When adding further |shape| options below, ensure to also add a
+% corresponding |\kvt@DefineStdTabEnv| counterpart further below in the
+% code.
+% \begin{macrocode}
+\kvt@addchoicetableprop{shape}{multipage}{%
+ multipage,onepage,tabular,longtable,tabularx}
\kvt@addcolumnprop{default}{}
-\kvt@addcolumnprop{format}{\kvt@struttedcell}
+\kvt@addcolumnprop{format}{\kvtStrutted}
\kvt@addcolumnprop{align}{l}
\kvt@addcolumnprop{head}{}
-\kvt@addchoicecolumnprop{hidden}{false}{false,true}
+\kvt@addchoicecolumnprop{hidden}{false}{true}{false,true}
\kvtSet{}
% \end{macrocode}
%
-% \begin{macro}{\kvt@struttedcell}
-% The |\kvt@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@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@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@NewKeyValTable{#1}{#2}{#3}}%
+ {\kvt@NewKeyValTable{#1}{#2}{#3}[]}}
+% \end{macrocode}
+% The
+% |\kvt@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@NewKeyValTable#1#2#3[#4]{%
% \end{macrocode}
% First initialize the ``variables''.
% \begin{macrocode}
\csdef{kvt@options@#2}{#1}%
\csdef{kvt@headings@#2}{}%
- \csdef{kvt@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@alignments@#2}{p{0pt}\expandonce\kvt@HackIntercolSpace}%
\csdef{kvt@colkeys@#2}{}%
- \csdef{kvt@rowcount@#2}{1}%
+ \csdef{kvt@rowcount@#2}{0}%
\csdef{kvt@rows@#2}{}%
+ \csdef{kvt@headings@#2}{\kvt@defaultheader}
\listadd\kvt@alltables{#2}%
% \end{macrocode}
% Now parse \meta{colspecs}, a semicolon-separated list of individual
@@ -749,7 +1107,20 @@
% \begin{macrocode}
\def\do##1{%
\kvt@parsecolspec{#2}##1::\@undefined}%
- \mkv@dossvlist{#3}%
+ \kvt@dossvlist{#3}%
+% \end{macrocode}
+% The following terminates the argument list of |\kvt@defaultheader|.
+% \begin{macrocode}
+ \csappto{kvt@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@parsecolspec| as the header row.
+% \begin{macrocode}
+ \ifstrempty{#4}
+ {\csdef{kvt@headrowcount@#2}{1}}
+ {\kvt@parseheadrows{#2}{#4}}%
}
% \end{macrocode}
% The
@@ -766,10 +1137,16 @@
% \begin{macrocode}
\ifcsstring{kvt@col@hidden@#1@#2}{true}{}{%
\cseappto{kvt@alignments@#1}{\csexpandonce{kvt@col@align@#1@#2}}%
- \ifcsvoid{kvt@headings@#1}{}{\csappto{kvt@headings@#1}{&}}%
- \ifcsstring{kvt@col@head@#1@#2}{}%
- {\cseappto{kvt@headings@#1}{#2}}%
- {\cseappto{kvt@headings@#1}{\csexpandonce{kvt@col@head@#1@#2}}}%
+% \end{macrocode}
+% Append the column heading to \cs{kvt@headings@\meta{tname}}, which
+% collects arguments to |\kvt@defaultheader|. Hence, the appended tokens
+% are enclosed in curly braces. If no |head| is specified for the
+% column, \meta{cname} is used for the column head. Otherwise, the
+% |head| value is used.
+% \begin{macrocode}
+ \ifcsvoid{kvt@col@head@#1@#2}%
+ {\csappto{kvt@headings@#1}{{#2}}}%
+ {\cseappto{kvt@headings@#1}{{\csexpandonce{kvt@col@head@#1@#2}}}}%
\listcsadd{kvt@colkeys@#1}{#2}%
}%
% \end{macrocode}
@@ -781,8 +1158,56 @@
}
% \end{macrocode}
% \end{macro}
+%
+%
+% \begin{macro}{\kvt@defaultheader}
+% The |\kvt@defaultheader|\marg{head1}\ldots\marg{headn}|\@nil| macro,
+% takes $n$ header cell titles, \meta{head1} to \meta{headn} and formats
+% them based on the |headfmt| and |headalign| options.
+% More precisely, when fully expanded, |\kvt@defaultheader| yields
+% "\meta{rowcolor}|& |\meta{fmthead1}| & |\ldots| & |\meta{fmtheadn}|\tabularnewline|".
+% In the above, \meta{rowcolor}=|\rowcolor{|\meta{headbg}|}|.
+% \begin{macrocode}
+\newcommand\kvt@defaultheader{%
+ \noexpand\rowcolor{\cmdkvt@Table@headbg}%
+ \kvt@defaultheader@i}
+\newcommand\kvt@defaultheader@i[1]{%
+ \kvt@ifnil{#1}{\noexpand\tabularnewline}{%
+ \unexpanded{&}%
+ \ifdefvoid\cmdkvt@Table@headalign
+ {\expandonce\cmdkvt@Table@headfmt\unexpanded{#1}}
+ {\noexpand\multicolumn{1}{\expandonce\cmdkvt@Table@headalign}
+ {\expandonce\cmdkvt@Table@headfmt\unexpanded{#1}}}%
+ \kvt@defaultheader@i}}
+% \end{macrocode}
+% \begin{macro}{\kvt@ifnil}
+% The |\kvt@ifnil|\marg{val}\marg{iftrue}\marg{iffalse} macro expands to
+% \meta{iftrue} if \meta{val} is |\@nil|, and expands to \meta{iffalse}
+% otherwise.
+% Fixme: The |\relax| in the following is not fully ideal as it is not
+% swallowed by the |\ifx| and therefore remains in the macro's
+% expansion.
+% \begin{macrocode}
+\newcommand\kvt@ifnil[1]{%
+ \ifx\@nil#1\relax
+ \expandafter\@firstoftwo\else
+ \expandafter\@secondoftwo\fi}
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\kvt@HackIntercolSpace}
+% The |\kvt@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@HackIntercolSpace{%
+ @{\hspace{-.5\arrayrulewidth}}}
+% \end{macrocode}
+% \end{macro}
+%
% \begin{macro}{\kvt@alltables}
-% The |\kvt@alltables| is an \textsf{etoolbox} list containing the names
+% The |\kvt@alltables| is an \pkgname{etoolbox} list containing the names
% of all tables declared by |\NewKeyValTable|.
% \begin{macrocode}
\newcommand\kvt@alltables{}
@@ -790,6 +1215,194 @@
% \end{macro}
%
%
+% \subsection{Custom Column Headers}
+%
+% \begin{macro}{\kvt@parseheadrows}
+% The |\kvt@parseheadrows|\marg{tname}\marg{headers}
+% macro parses the \meta{headers} argument of |\NewKeyValTable|.
+% \begin{macrocode}
+\newcommand\kvt@parseheadrows[2]{%
+ \csdef{kvt@@colgroups@#1}{}%
+ \csdef{kvt@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@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@post@space@in\kvt@@tmp%
+ \expandafter\ifstrequal\expandafter{\kvt@@tmp}{::}
+ {\appto\kvt@@parseheadrows{%
+ \cseappto{kvt@@colgroups@#1}{%
+ \csexpandonce{kvt@headings@#1}}}}
+ {\appto\kvt@@parseheadrows{\kvt@parseheadrow{#1}{##1}}}%
+% \end{macrocode}
+% Increment the header row counter for each |\\|-separated item of
+% \meta{headers}.
+% \begin{macrocode}
+ \appto\kvt@@parseheadrows{\csedef{kvt@headrowcount@#1}{%
+ \the\numexpr\csuse{kvt@headrowcount@#1}+1\relax}}%
+ }\kvt@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@headings@#1}{kvt@@colgroups@#1}}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\kvt@parseheadrow}
+% The |\kvt@parseheadrow|\marg{tname}\marg{colspec} macro parses a
+% single header row and appends the resulting table code to
+% \cs{kvt@@colgroups@\meta{tname}}.
+% \begin{macrocode}
+\newcommand\kvt@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@parsehdcolspec{#1}##1::\@undefined}%
+ \kvt@dossvlist{#2}%
+% \end{macrocode}
+% Initialize variables for the subsequent loop.
+% The |\kvt@@tmpgrphd| macro collects the code for the cells of the
+% current header row. The |\kvt@@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@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@concludecolumn\fi
+ \ifdefvoid\kvt@@curgrp{}{\ifcsdef{kvt@@colgrpdone@\kvt@@curgrp}{%
+ \kvt@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@colkeys@#1}%
+ \kvt@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@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@concludecolumn}
+% The |\kvt@concludecolumn| macro appends a cell, potentially spanning
+% multiple columns, to the row under construction (which is in
+% |\kvt@@tmpgrphd|).
+% \begin{macrocode}
+\newcommand\kvt@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@HackIntercolSpace|, such that
+% the |\multicolumn| below does not throw away this spacing.
+% \begin{macrocode}
+ \ifdefequal\kvt@@tmpgrphd\@empty
+ {\let\kvt@@extraalign\kvt@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@align@\kvt@@lastgrp}}
+ {\csexpandonce{kvt@@colgrp@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@parsehdcolspec}
+% The |\kvt@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@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@colkeys@#1}{}
+ {\kvt@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@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@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@key[kvt]{ColGroup}{head}{%
+ \csdef{kvt@@colgrp@head@\kvt@@colgrp}{#1}}
+\define@key[kvt]{ColGroup}{align}{%
+ \csdef{kvt@@colgrp@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@LabelCtr}{\csname the#2\endcsname}%
+ \setcounter{kvt@LabelCtr}{\value{#2}}%
\addtocounter{kvt@LabelCtr}{-1}%
\refstepcounter{kvt@LabelCtr}%
% \end{macrocode}
@@ -866,7 +1479,16 @@
% \begin{macrocode}
\newenvironment{KeyValTable}[2][]{%
\bgroup%
- \def\Row##1{\kvt@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@AddKeyValRow
+ {\noalign\bgroup}{\expandafter\egroup\kvt@@row}{#2}}%
+% \end{macrocode}
+% \end{macro}
+% \begin{macrocode}
\kvt@SetOptions{#2}{#1}%
\csuse{kvt@StartTable@\cmdkvt@Table@shape}{#2}%
}{%
@@ -894,78 +1516,225 @@
% \end{macrocode}
% \end{macro}
%
-% \begin{macro}{\kvt@StartTable@onepage}
-% \begin{macro}{\kvt@StartTable@multipage}
-% \begin{macro}{\kvt@StartTabu}
-% The |\kvt@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@StartTable@multipage|\marg{tname} does the same for a table
-% environment of shape |multipage|.
-% These macros internally use |\kvt@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|.
-% \begin{macrocode}
-\newcommand\kvt@StartTable@onepage[1]{%
- \kvt@StartTabu{tabu}{#1}}
-\newcommand\kvt@StartTable@multipage[1]{%
- \kvt@StartTabu{longtabu}{#1}}
-\newcommand\kvt@StartTabu[2]{%
+% \subsubsection{Table Environment Code}
+%
+% \begin{macro}{\kvt@StartTabularlike}
+% The
+% |\kvt@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@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@alignments@#2}}%
- \noexpand\toprule
- \ifbool{kvt@Table@showhead}{%
- \noexpand\rowcolor{\cmdkvt@Table@headbg}%
- \unexpanded{\csuse{kvt@headings@#2}\\\midrule}}{}%
- \noexpand\taburowcolors 2{\cmdkvt@Table@rowbg}%
- }\kvt@@do%
- \iftabu@long\expandafter\endhead\fi
- \setcounter{kvtRow}{1}%
+% \end{macrocode}
+% \changes{v1.0}{2019/02/18}{Implemented \texttt{showrules} option}
+% \begin{macrocode}
+ \ifbool{kvt@Table@showrules}
+ {\def\kvt@@rule##1{\csuse{##1rule}}}
+ {\def\kvt@@rule##1{}}%
+ \csuse{kvt@@patchenvend@#1}%
+ \setcounter{kvtRow}{0}%
\setcounter{kvtTypeRow}{\csuse{kvt@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@dottedrowcolors
+ {\ifbool{kvt@Table@showhead}
+ {\the\numexpr\csuse{kvt@headrowcount@#2}+1\relax}
+ {1}}%
+ {\expandonce\cmdkvt@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@Table@width}
+ {{\expandonce\cmdkvt@Table@width}}}
+ {}%
+ {\csexpandonce{kvt@alignments@#2}}%
+ \noexpand\kvt@@rule{top}%
+% \end{macrocode}
+% \changes{v0.3}{2016/06/05}{Added \texttt{showhead} option}
+% \begin{macrocode}
+ \ifbool{kvt@Table@showhead}
+ {\csuse{kvt@headings@#2}\noexpand\kvt@@rule{mid}}
+ {}%
+ \ifbool{#4}
+ {\noexpand\taburowcolors 2{\expandonce\cmdkvt@Table@rowbg}}{}%
+ \ifbool{#3}{\noexpand\endhead}{}%
+ }\kvt@@do}
% \end{macrocode}
% \end{macro}
-% \end{macro}
+%
+% \begin{macro}{\kvt@stepcounters}
+% The |\kvt@stepcounters|\oarg{delta} macro increments all row counters
+% by \meta{delta}. If \meta{delta} is omitted, \meta{delta}=1.
+% \begin{macrocode}
+\newcommand\kvt@stepcounters[1][1]{%
+ \addtocounter{kvtRow}{#1}%
+ \addtocounter{kvtTypeRow}{#1}%
+ \addtocounter{kvtTotalRow}{#1}}
+% \end{macrocode}
% \end{macro}
%
-% \begin{macro}{\kvt@EndTable@onepage}
-% \begin{macro}{\kvt@EndTable@multipage}
-% The |\kvt@EndTable@onepage| and |\kvt@EndTable@multipage| macros end a
-% table environment of the |onepage| or, respectively, |multipage|
-% shape.
+% \begin{macro}{\kvt@DefineStdTabEnv}
+% The
+% |\kvt@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@EndTable@\meta{shape}}. Otherwise,
+% \cs{kvt@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@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@EndTable@onepage{%
- \bottomrule%
- \end{tabu}}
-\newcommand\kvt@EndTable@multipage{%
- \bottomrule%
- \end{longtabu}}
+\newcommand\kvt@DefineStdTabEnv{\@dblarg\kvt@DefineStdTabEnv@i}
+\newcommand\kvt@DefineStdTabEnv@i[6][]{%
+ \expandafter\newcommand\csname kvt@StartTable@#1\endcsname[1]{%
+ \kvt@StartTabularlike{#2}{##1}{#3}{#4}{#5}}%
+ \csedef{kvt@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}
+%
+% The following lines define the macros for the various table shapes /
+% environments.
+% \begin{macrocode}
+\kvt@DefineStdTabEnv{tabular}{false}{false}{false}{}
+\kvt@DefineStdTabEnv{longtable}{true}{false}{false}{}
+\kvt@DefineStdTabEnv{tabularx}{false}{false}{true}{%
+ \preto\TX@endtabularx{\toks@\expandafter{\the\toks@
+ \kvt@@rule{bottom}}}}
+\kvt@DefineStdTabEnv{xltabular}{true}{false}{true}{%
+ \preto\XLT@ii@TX@endtabularx{\toks@\expandafter{\the\toks@
+ \kvt@@rule{bottom}}}}
+\kvt@DefineStdTabEnv[onepage]{tabu}{false}{true}{true}{}
+\kvt@DefineStdTabEnv[multipage]{longtabu}{true}{true}{true}{}
+% \end{macrocode}
+%
+% \begin{macro}{\kvt@dottedrowcolors}
+% The |\kvt@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@dottedrowcolors[2]{%
+ \kvt@dottedrowcolors@i{#1}#2\@nil}
+\def\kvt@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}
%
+% \subsubsection{Environment-Independent Parts}
+%
+% The following block declares the known row options.
+% \begin{macrocode}
+\define@cmdkey[kvt]{Row}{bg}{}%
+\define@boolkey[kvt]{Row}{hidden}[true]{}%
+\define@cmdkey[kvt]{Row}{below}{}
+\define@cmdkey[kvt]{Row}{above}{}
+\define@cmdkey[kvt]{Row}{around}{%
+ \def\cmdkvt@Row@above{#1}\def\cmdkvt@Row@below{#1}}
+% \end{macrocode}
+%
% \begin{macro}{\kvt@AddKeyValRow}
-% The |\kvt@AddKeyValRow|\marg{tname}\marg{content} adds a new row to
-% the current table of type \meta{tname}. The \meta{content} is a
+% The
+% |\kvt@AddKeyValRow|\marg{pre}\marg{post}\marg{tname}\oarg{options}\marg{content}
+% macro composes a row for the table of type \meta{tname} from the given
+% \meta{content} and \meta{options}. The \meta{content} is a
% key-value list that specifies the content of the individual cells in
-% the row. The 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@AddKeyValRow[3]{%
+ #1%
+% \end{macrocode}
+% It's essential that \meta{pre} above comes even before |\@ifnextchar|
+% and, therefore, cannot be moved into |\kvt@AddKeyValRow@i|:
+% The |\@ifnextchar| is not fully expandable and therefore any
+% |\noalign| (in \meta{pre}) following |\@ifnextchar| would lead to
+% "misplaced |\noalign|" errors.
+% \begin{macrocode}
+ \@ifnextchar[%]
+ {\kvt@AddKeyValRow@i{#2}{#3}}
+ {\kvt@AddKeyValRow@i{#2}{#3}[]}}
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{\kvt@AddKeyValRow@i}
+% The
+% |\kvt@AddKeyValRow@i|\marg{post}\marg{tname}\oarg{options}\marg{content}
+% macro parses \meta{options} and evaluates the |hidden| option.
% \begin{macrocode}
-\newcommand\kvt@AddKeyValRow[2]{%
- \setkeys[KeyValTable]{#1}{#2}%
+\def\kvt@AddKeyValRow@i#1#2[#3]#4{%
+ \setkeys[kvt]{Row}{#3}%
+ \ifbool{kvt@Row@hidden}
+ {\let\kvt@@row\@empty #1}
+ {\kvt@AddKeyValRow@ii{#1}{#2}{#4}}}
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{\kvt@AddKeyValRow@ii}
+% The
+% |\kvt@AddKeyValRow@ii|\marg{post}\marg{tname}\marg{content}
+% macro mainly processes \meta{content} as well as \meta{options}
+% that have already been parsed by |\kvt@AddKeyValRow@i|.
+% \begin{macrocode}
+\def\kvt@AddKeyValRow@ii#1#2#3{%
+ \setkeys[KeyValTable]{#2}{#3}%
+% \end{macrocode}
+% Initialize and first add the |\noalign| material to the row.
+% \begin{macrocode}
+ \def\kvt@@row{}%
+ \ifdefvoid\cmdkvt@Row@above{}{%
+ \eappto\kvt@@row{\noexpand\noalign{\noexpand\vspace{%
+ \expandonce\cmdkvt@Row@above}}}}%
+ \ifdefvoid\cmdkvt@Row@bg{}{%
+ \eappto\kvt@@row{\noexpand\rowcolor{\expandonce\cmdkvt@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),
@@ -973,17 +1742,95 @@
% \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@col@format@#1@##1}{%
- \ifcsvoid{cmdKeyValTable@#1@##1}%
- {\csexpandonce{kvt@col@default@#1@##1}}%
- {\csexpandonce{cmdKeyValTable@#1@##1}}}%
- }%
- }\dolistcsloop{kvt@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@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@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@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@CheckMulticolumn\kvt@@cell
+ \relax\relax\relax\relax\@undefined{#2}{##1}%
+ \expandafter\appto\expandafter\kvt@@row\expandafter{\kvt@@fmtcell}%
+ }\dolistcsloop{kvt@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@Row@below{}{%
+ \eappto\kvt@@row{\noexpand\noalign{\noexpand\vspace{%
+ \expandonce\cmdkvt@Row@below}}}}%
+% \end{macrocode}
+% At the very end of the expansion text, put \meta{post}.
+% \begin{macrocode}
+ #1}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\kvt@everyrow}
+% The |\kvt@everyrow|\marg{code} registers \meta{code} to be included in
+% the first (invisible) cell of every row.
+% \begin{macrocode}
+\newcommand\kvt@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@everyrow{\kvt@stepcounters}%
+% \end{macrocode}
+%
+% \begin{macro}{\kvt@CheckMulticolumn}
+% The
+% |\kvt@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@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@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@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@col@format@#5@#6}{\expandonce{#4}}}}%
+ \fi}
% \end{macrocode}
% \end{macro}
%
@@ -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@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@AddKeyValRow|.
+% The resulting row (|\kvt@@row|) is globally appended to
+% \cs{kvt@rows@\meta{tname}}.
% \begin{macrocode}
-\newcommand\AddKeyValRow[2]{%
- \bgroup%
- \kvt@AddKeyValRow{#1}{#2}%
- \csxappto{kvt@rows@#1}{\expandonce{\kvt@@row}\noexpand\\}%
- \egroup}
+\newcommand\AddKeyValRow[1]{%
+ \kvt@AddKeyValRow
+ {\bgroup}
+ {\csxappto{kvt@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@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@dossvlist}
+% The |\kvt@dossvlist|\marg{list} macro parses a semicolon-separated
+% list and runs |\do|\meta{item} for every element of the list.
+% \begin{macrocode}
+\DeclareListParser{\kvt@dossvlist}{;}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\kvt@forpsvlist}
+% The |\kvt@forpsvlist|\marg{handler}\marg{list} parses a `+'-separated list.
+% \begin{macrocode}
+\DeclareListParser*{\kvt@forpsvlist}{+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\kvt@dobrklist}
+% The |\kvt@dobrklist|\marg{list} parses a `|\\|'-separated list.
+% \begin{macrocode}
+\DeclareListParser{\kvt@dobrklist}{\\}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\kvt@error}
+% \begin{macro}{\kvt@warn}
+% \begin{macrocode}
+\newcommand\kvt@error[2]{\PackageError{keyvaltable}{#1}{#2}}
+\newcommand\kvt@warn[1]{\PackageWarning{keyvaltable}{#1}}
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
%\iffalse
%</package>
%\fi