diff options
author | Karl Berry <karl@freefriends.org> | 2019-03-19 21:28:17 +0000 |
---|---|---|
committer | Karl Berry <karl@freefriends.org> | 2019-03-19 21:28:17 +0000 |
commit | ef1f2fe2f48a08a89cc523d65ea2f29e5b26f058 (patch) | |
tree | e14de39fb7274108e016acec92a16bccfd9c7625 /Master/texmf-dist/source | |
parent | 0c4b47b64e197d32e1d141f321e2f44725b0254a (diff) |
keyvaltable (19mar19)
git-svn-id: svn://tug.org/texlive/trunk@50471 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master/texmf-dist/source')
-rw-r--r-- | Master/texmf-dist/source/latex/keyvaltable/keyvaltable.dtx | 1463 |
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 |