X-Git-Url: https://git.distorted.org.uk/~mdw/mdwtools/blobdiff_plain/86f6a31e4b41acb71ba37f3838a9ce75f7743330..9d809eaca2b424a34222f8912d58d476720ffa24:/mdwtab.dtx diff --git a/mdwtab.dtx b/mdwtab.dtx index 86afbdc..5f863b2 100644 --- a/mdwtab.dtx +++ b/mdwtab.dtx @@ -1,30 +1,11 @@ % \begin{meta-comment} % -% $Id: mdwtab.dtx,v 1.1 2002/02/03 20:49:03 mdw Exp $ +% $Id: mdwtab.dtx,v 1.3 2003/11/10 14:43:48 mdw Exp $ % % Another rewrite of the tabular environment, and maths alignments % % (c) 1996 Mark Wooding % -%----- Revision history ----------------------------------------------------- -% -% $Log: mdwtab.dtx,v $ -% Revision 1.1 2002/02/03 20:49:03 mdw -% Checkin for new build system. -% -% Revision 1.8 1996/12/09 23:20:42 mdw -% (\tab@setstrut): Fixed so that it uses \dimen@ii for the strut depth, -% as advertised. -% -% Revision 1.7 1996/11/29 21:59:16 mdw -% Fixed a little formatting mistake in a syntax diagram, and switched over -% to the new syntax diagram commands on the grounds that they're slightly -% less messy. Maybe. -% -% Revision 1.6 1996/11/19 20:54:33 mdw -% Entered into RCS -% -% % \end{meta-comment} % % \begin{meta-comment} @@ -51,13 +32,19 @@ % \begin{meta-comment} %<+mdwtab>\NeedsTeXFormat{LaTeX2e} %<+mdwtab>\ProvidesPackage{mdwtab} -%<+mdwtab> [1998/04/28 1.9 Table typesetting with style] +%<+mdwtab> [2003/08/24 1.10 Table typesetting with style] %<+mathenv>\NeedsTeXFormat{LaTeX2e} %<+mathenv>\ProvidesPackage{mathenv} -%<+mathenv> [1998/04/28 1.9 Various maths environments] +%<+mathenv> [2003/08/24 1.10 Various maths environments] +%<+colour>\NeedsTeXFormat{LaTeX2e} +%<+colour>\ProvidesPackage{mtcolour} +%<+colour> [2003/08/24 1.10 Colour support for mdwtab] +%<+color>\NeedsTeXFormat{LaTeX2e} +%<+color>\ProvidesPackage{mtcolor} +%<+color> [2003/08/24 1.10 Fix for people who can't spell] % \end{meta-comment} % -% \CheckSum{2876} +% \CheckSum{3402} %% \CharacterTable %% {Upper-case \A\B\C\D\E\F\G\H\I\J\K\L\M\N\O\P\Q\R\S\T\U\V\W\X\Y\Z %% Lower-case \a\b\c\d\e\f\g\h\i\j\k\l\m\n\o\p\q\r\s\t\u\v\w\x\y\z @@ -80,6 +67,7 @@ %<*driver> \input{mdwtools} \describespackage{mdwtab} +\describespackage{mtcolour} \describespackage{mathenv} \addcontents{lot}{\listoftables} \mdwdoc @@ -234,6 +222,10 @@ % action), and preambles like this will result in an error (and % probably a rather confusing one). % +% \item David Carlisle's \package{colortbl} package entirely fails to work +% with \package{mdwtab}. However, we now have colour support of our +% own which is at times similar in style. +% % \end{itemize} % % There are also several incompatibilities between \package{mdwtab} and @@ -278,7 +270,7 @@ % % \begin{grammar} % -% ::= \[[ +% ::= \[[ % "\\begin" % \begin{stack} % "{tabular}" \\ "{tabular*}" "{" "}" \\ @@ -292,23 +284,23 @@ % % ::= (see below) % -% ::= \[[ +% ::= \[[ % % \[ \< \> \] % \]] % % ::= \[[ \[ \] \]] % -% ::= \[[ +% ::= \[[ % \[ \] \[ \< \> \] % \[ \< \> \] \[ \] \[ \] % \]] % -% ::= \[[ "@" "{" "}" \]] +% ::= \[[ "@" "{" "}" \]] % -% ::= \[[ ">" "{" "}" \]] +% ::= \[[ \[ "?" \] ">" "{" "}" \]] % -% ::= \[[ +% ::= \[[ % \begin{stack} % \[ "T" \\ "M" \] \( "l" \\ "c" \\ "r" \) \\ % \( "p" \\ "m" \\ "b" \) "{" "}" \\ @@ -316,9 +308,9 @@ % \end{stack} % \]] % -% ::= \[[ "<" "{" "}" \]] +% ::= \[[ \[ "?" \] "<" "{" "}" \]] % -% ::= \[[ \( "|" \\ "!" "{" "}" \) \]] +% ::= \[[ \( "|" \\ "!" "{" "}" \) \]] % % \end{grammar} % @@ -335,49 +327,53 @@ % The actual column types are shown in table~\ref{tbl:columns}. % % \begin{table} -% \begin{tabular}[C]{| >{\synshorts} c | m{3in} |} \hlx{hv[1]} -% -% \multicolumn{2}{|c|}{\bf Column types} \\ \hlx{v[1]hv} -% \bf Name & \bf Meaning \\ \hlx{vhv.} -% "l" & Left aligned text (\env{tabular}) or -% equation (\env{array}). \\ \hlx{.} -% "c" & Centred text (\env{tabular}) or -% equation (\env{array}). \\ \hlx{.} -% "r" & Right aligned text (\env{tabular}) or -% equation (\env{array}). \\ \hlx{vhv.} +% \begin{tabular}[C]{| >{\synshorts} c | m{3in} |} \hlx{hv[1]} +% +% \multicolumn{2}{|c|}{\bf Column types} \\ \hlx{v[1]hv} +% \bf Name & \bf Meaning \\ \hlx{vhv.} +% "l" & Left aligned text (\env{tabular}) or +% equation (\env{array}). \\ \hlx{.} +% "c" & Centred text (\env{tabular}) or +% equation (\env{array}). \\ \hlx{.} +% "r" & Right aligned text (\env{tabular}) or +% equation (\env{array}). \\ \hlx{vhv.} % "Ml", "Mc" and "Mr" & Left, centre and right aligned -% equations.* \\ \hlx{.} +% equations.* \\ \hlx{.} % "Tl", "Tc" and "Tr" & Left, centre and right aligned -% text.* \\ \hlx{vhv.} +% text.* \\ \hlx{vhv.} % "p{""}" & Top aligned paragraph with the given -% width. \\ \hlx{.} +% width. \\ \hlx{.} % "m{""}" & Vertically centred paragraph with -% the given width. \\ \hlx{.} +% the given width. \\ \hlx{.} % "b{""}" & Bottom aligned paragraph with the -% given width. \\ \hlx{vhv.} +% given width. \\ \hlx{vhv.} % "#{"
"}{""}" & User defined column type:
-%		  \
 is inserted before the
-%		  cell entry, \ is inserted
-%		  afterwards.*				\\ \hlx{vhhv[1]}
-%
-% \multicolumn{2}{|c|}{\bf Other modifier characters}	\\ \hlx{v[1]hv}
-% \bf Name	& \bf Meaning				\\ \hlx{vhv.}
-% "|"		& Inserts a vertical rule between
-%		  columns.				\\ \hlx{.}
-% "$*[""]" & Inserts a vertical rule of given
+%                 \
 is inserted before the
+%                 cell entry, \ is inserted
+%                 afterwards.*                          \\ \hlx{vhhv[1]}
+%
+% \multicolumn{2}{|c|}{\bf Other modifier characters}   \\ \hlx{v[1]hv}
+% \bf Name      & \bf Meaning                           \\ \hlx{vhv.}
+% "|"           & Inserts a vertical rule between
+%                 columns.                              \\ \hlx{.}
+% "$*[""]" & Inserts a vertical rule of given
 %                 width between columns; "*" selects
-%                 "\arraythickrulewidth".               \\ \hlx{.}
-% "!{""}"	& Inserts \ between columns,
-%		  treating it as a vertical rule.	\\ \hlx{vhv.}
-% "@{""}"	& Inserts \ instead of the
-%		  usual intercolumn space.		\\ \hlx{vhv.}
-% ">{""}"	& Inserts \ just before the
-%		  actual column entry.			\\ \hlx{.}
-% "<{""}"	& Inserts \ just after the
-%		  actual column entry.			\\ \hlx{vhv.}
+%                 "\arraythickrulewidth".*              \\ \hlx{.}
+% "!{""}" & Inserts \ between columns,
+%                 treating it as a vertical rule.       \\ \hlx{vhv.}
+% "@{""}" & Inserts \ instead of the
+%                 usual intercolumn space.              \\ \hlx{vhv.}
+% ">{""}" & Inserts \ just before the
+%                 actual column entry.                  \\ \hlx{.}
+% "<{""}" & Inserts \ just after the
+%                 actual column entry.                  \\ \hlx{.}
+% "?<{""}" & Inserts \ before the column
+%                 entry \emph{and} the rules list.*     \\ \hlx{.}
+% "?>{""}" & Inserts \ after the column
+%                 entry \emph{and} the rules list.*     \\ \hlx{vhv.}
 % "*{""}{""}" & Inserts \
-%		  copies of the \ into the
-%		  preamble.				\\ \hlx{vhs}
+%                 copies of the \ into the
+%                 preamble.                             \\ \hlx{vhs}
 %
 % \multicolumn{2}{@{}l}{* This column type is a new feature}
 % \end{tabular}
@@ -408,13 +404,11 @@
 % concerned -- they'll work inside |\tabpause| without any problems.
 %
 % \DescribeMacro{\vline}
-% \DescribeMacro{\vline*}
 % The |\vline| command draws a vertical rule the height of the current table
 % cell (unless the current cell is being typeset in paragraph mode -- it
 % only works in the simple LR-mode table cells, or in \lit{@} or \lit{!}
-% modifiers).  It's now been given an optional argument which gives the
-% width of the rule to draw.  The |*|-version uses the |\arraythickrulewidth|
-% thickness rather than the default.
+% modifiers).  It's now been given an optional argument which describes
+% parameters for the line.  See section~\ref{sec:ruleparams}.
 %
 % { \let\tabstyle=\relax
 % \begin{demo}{An example of \cmd\vline}
@@ -438,7 +432,7 @@
 %   There's a nasty use of \env{smallmatrix} in the |testmath.tex| file which
 %   comes with the \package{amslatex} distribution.  It's actually there to
 %   simulate a `smallcases' environment, which the \package{mathenv} package
-%   includes, based around \env{smarray}.}
+%   includes, based around \env{smarray}.} ^^A
 % being implemented by totally unsuitable commands.  Someone may find it
 % handy.
 %
@@ -452,25 +446,21 @@
 % separated list of column numbers and ranges:
 %
 % \begin{grammar}
-% 	::= \[[
+%    ::= \[[
 %   "\\cline"
-%   \[ "*" \\ \tok{"[""]"} \]
+%   \[ "*" \] \\ \[ "["  "]" \]
 %   "{" \<  \[ "-"  \] \\ "," \> "}"
 % \]]
 % \end{grammar}
 %
-% The thickness of the rules may be modified.  The default is given by the
-% |\arrayrulewidth| length parameter.  The |\cline*| command uses the
-% |\arraythickrulewidth| parameter instead.  If neither of these does what
-% you want, then you can give a length yourself as an optional argument.
-% This feature is also available in the |\hline| and |\hlx| commands, and
-% (for vertical rules) in the |$| column type.\footnote{I couldn't use the
-% \texttt{\char`\|} type, because that would break old documents which
-% expect \texttt{\char`\| *\char`\{...\char`\}} to work properly.}
+% The rules printed by |\cline| and |\hline| can be modified by rule
+% parameters: see section~\ref{sec:ruleparams}.
 %
-% The positioning of the horizontal lines has also been improved a bit, so
-% that they meet up with the vertical lines properly.  Displays like the one
-% in the example below don't look good unless this has been done properly.
+% Note that |\cline| rules are rather bodgy.  Other rules now have
+% \emph{thickness}, but |\cline|s don't.  Instead, they backspace over
+% previous stuff.  If you don't like that, insert an appropriate gap, using
+% |\vgap|.  The \lit{z} rune in |\hlx| is perfect for this kind of thing --
+% precede your \lit{c} lines by \lit{z} lines for best results.
 %
 % {\let\tabstyle\relax
 % \begin{demo}[w]{A \cs{cline} example}
@@ -482,6 +472,15 @@
 % \end{demo}
 % }
 %
+% \subsection{Other stuff}
+%
+% \DescribeMacro\nextrow
+% The \env{tabular} and \env{array} environments maintain a counter
+% \textsf{tabrow}.  The counter is reset to zero at the start of each table.
+% It is stepped by one by default; you can provide an optional argument which
+% is the amount to add.
+%
+%
 % \subsection{Spacing control}
 %
 % One of the most irritating things about \LaTeX's tables is that there isn't
@@ -497,11 +496,11 @@
 %
 % \begin{grammar}
 %
-% 	::= \[[
+%     ::= \[[
 %   "\\vgap" \[ "["  "]" \] "{"  "}"
 % \]]
 %
-% 	::= \[[ \<  \[ "-"  \] \\ "," \> \]]
+%   ::= \[[ \<  \[ "-"  \] \\ "," \> \]]
 %
 % \end{grammar}
 %
@@ -528,18 +527,22 @@
 % The syntax is simple:
 % \begin{grammar}
 %
-% 	::= \[[
+%      ::= \[[
 %   "\\hlx"
-%   \[ "*" \\ \tok{"[""]"} \]
+%   \[ "*" \] \[ "["  "]" \]
 %   "{"
 %   \begin{rep}
 %     \begin{stack}
 %       "h" \\
 %       \tok{"v[""][""]"} \\
+%       \tok{"z[""][""]"} \\
 %       \tok{"s[""]"} \\
 %       \tok{"c{""}"} \\
 %       "b" \\
 %       \tok{"/[""]"} \\
+%       \tok{"!{""}"} \\
+%       \tok{"?{""}"} \\
+%       \tok{"+[""]"} \\
 %       "."
 %     \end{stack}
 %   \end{rep}
@@ -547,9 +550,10 @@
 % \]]
 %
 % \end{grammar}
-% The |*| or optional \ specify the width of horizontal rules to be
-% drawn, as for |\hline| and |\cline|.  (Note that you can't pass a |*| or
-% optional argument to the |h| or |c| subcommands.)
+% The |*| or optional \ give rule-drawing parameters for the |h|
+% and |c| subcommands.  (Note that you can't pass a |*| or an optional
+% parameters argument to the |h| or |c| subcommands directly.)  See
+% section~\ref{sec:ruleparams}.
 %
 % The argument works a bit like a table preamble, really.  Each letter is a
 % command.  The following are supported:
@@ -564,6 +568,11 @@
 %       \ is omitted, the value of |\doublerulesep| is used.
 %       This usually looks right.
 %
+% \item [\lit*{z[}\\lit*{][}\\lit*{]}]  Like \lit{v},
+%       except that the default gap is the current rule width (set by the
+%       \) rather than |\doublerulesep|.  This is a good thing
+%       to insert before a |\cline| row.
+%
 % \item [\lit*{s[}\\lit*{]}]  Leaves a vertical gap with the
 %       given size.  If you omit the \ then |\doublerulesep| is
 %       used.  This is usually right.
@@ -580,6 +589,15 @@
 %       except that the default is 0, which just permits a break without
 %       forcing it.
 %
+% \item [\lit*{!\char`\{}\\lit*{\char`\}}]  Change the rule
+%       parameters to be used for subsequent subcommands.
+%
+% \item [\lit*{?\char`\{}\\lit*{\char`\}}]  Do \, which can be
+%       any commands which \emph{don't} typeset anything.
+%
+% \item [\lit*{+[\]}]  Add \ (default is 1) to the value of the
+%       \textsf{tabrow} counter.
+%
 % \item [\lit*{.}]  (That's a dot)  Starts the next row of the table.  No
 %       more characters may follow the dot, and no |\hline|, |\hlx|, |\vgap|
 %       or |\multicolumn| commands may be used after it.  You don't have to
@@ -633,7 +651,7 @@
 % then you get an extra thick rule at the bottom of the page.  This is a bit
 % of a problem, because if the rule isn't there in the footer and you get
 % a break between two rows \emph{without} a rule between them, then the page
-% looks very odd.  
+% looks very odd.
 %
 % If you want to do ruled longtables, I'd recommend that you proceed as
 % follows:
@@ -685,54 +703,86 @@
 % it gets the positioning right all by itself.  You've never had it so good.
 %
 %
+% \subsection{Rule parameters}
+% \label{sec:ruleparams}
+%
+% The rule-drawing commands |\hline|, |\vline|, |\cline| and |\hlx|, and the
+% |$| column type (which is otherwise a synonym for "|") accept \emph{rule
+% parameters}.  If the command is followed by a |*|, then the rules are a bit
+% thicker than usual -- they use |\arraythickrulewidth| rather than
+% |\arrayrulewidth|.  However, there's an optional argument which can contain
+% one of:
+%
+% \begin{description}
+% \renewcommand\makelabel[1]{\kern\labelsep\ttfamily#1}
+% \item[thin] Use |\arrayrulewidth| as the line width.  This is the default.
+% \item[thick] Use |\arraythickrulewidth| as the line width.  This is the
+%   same as giving a |*| after the command.
+% \item[width=\] Make the rules exactly \ wide.
+% \item[\] The same as \texttt{width=\}, for compatibility.
+% \end{description}
+%
+% More of these keywords will be added later if past experience is anything
+% to go by.  Note that the individual |\hlx| subcommands \emph{don't} take
+% rule parameters, but see the |!| subcommand for updating the current
+% parameters.
+%
+% \DescribeMacro\tabsetruleparams
+% If you say \syntax{"\\tabsetruleparams{""}"} then the
+% \ will be prepended to any parameters provided to specific
+% rule-drawing commands (including the \lit{\char`\|} preamble command).  For
+% example, |\tabsetruleparams{thick}| makes all rules thick.  This is a local
+% declaration.
+%
+%
 % \subsection{User serviceable parts}
 %
 % There are a lot of parameters which you can modify in order to make arrays
 % and tables look nicer.  They are all listed in table~\ref{tbl:config}.
 %
 % \begin{table}
-% \begin{tabular}[C]{| l | m{3in} |}				   \hlx{hv}
-% \bf Parameter		& \bf Meaning				\\ \hlx{vhv}
-% |\tabstyle|		& A command executed at the beginning of
-%			  a \env{tabular} or \env{tabular$*$}
-%			  environment.  By default does nothing.
-%			  Change using |\renewcommand|.		\\ \hlx{vhv}
-% |\extrarowheight|	& A length added to the height of every
-%			  row, used to stop table rules
-%			  overprinting ascenders.  Default 0\,pt.
-%			  Usage is deprecated now: use |\hlx|
-%			  instead.				\\ \hlx{vhv}
-% |\tabextrasep|	& Extra space added between rows in a
-%			  \env{tabular} or \env{tabular$*$}
-%			  environment (added \emph{before} any
-%			  following |\hline|).  Default 0\,pt.	\\
-% |\arrayextrasep|	& Analogous to |\tabextrasep|, but for
-%			  \env{array} environments.  Default
-%			  1\,jot (3\,pt).			\\
-% |\smarrayextrasep|	& Analogous to |\tabextrasep|, but for
-%			  \env{smarray} environments.  Default
-%			  1\,pt.				\\ \hlx{vhv}
-% |\tabcolsep|		& Space added by default on each side of
-%			  a table cell (unless suppressed by an
-%			  \lit{@}-expression) in \env{tabular}
-%			  environments.  Default is defined by
-%			  your document class.			\\
-% |\arraycolsep|	& Analogous to |\tabcolsep|, but for
-%			  \env{array} environments.  Default is
-%			  defined by your document class.	\\
-% |\smarraycolsep|	& Analogous to |\tabcolsep|, but for
-%			  \env{smarray} environments.  Default
-%			  is 3\,pt.				\\ \hlx{vhv}
-% |\arrayrulewidth|	& The width of horizontal and vertical
-%			  rules in tables.			\\
-% |\arraythickrulewidth|& The width of starred rules in tables.	\\
-% |\doublerulesep|	& Space added between two adjacent
-%			  vertical or horizontal rules.  Also
-%			  used by |\hlx{v}|.			\\ \hlx{vhv}
-% |\arraystretch|	& Command containing a factor to
-%			  multiply the default row height.
-%			  Default is defined by your document
-%			  class (usually 1).			\\ \hlx{vh}
+% \begin{tabular}[C]{| l | m{3in} |}                               \hlx{hv}
+% \bf Parameter         & \bf Meaning                           \\ \hlx{vhv}
+% |\tabstyle|           & A command executed at the beginning of
+%                         a \env{tabular} or \env{tabular$*$}
+%                         environment.  By default does nothing.
+%                         Change using |\renewcommand|.         \\ \hlx{vhv}
+% |\extrarowheight|     & A length added to the height of every
+%                         row, used to stop table rules
+%                         overprinting ascenders.  Default 0\,pt.
+%                         Usage is deprecated now: use |\hlx|
+%                         instead.                              \\ \hlx{vhv}
+% |\tabextrasep|        & Extra space added between rows in a
+%                         \env{tabular} or \env{tabular$*$}
+%                         environment (added \emph{before} any
+%                         following |\hline|).  Default 0\,pt.  \\
+% |\arrayextrasep|      & Analogous to |\tabextrasep|, but for
+%                         \env{array} environments.  Default
+%                         1\,jot (3\,pt).                       \\
+% |\smarrayextrasep|    & Analogous to |\tabextrasep|, but for
+%                         \env{smarray} environments.  Default
+%                         1\,pt.                                \\ \hlx{vhv}
+% |\tabcolsep|          & Space added by default on each side of
+%                         a table cell (unless suppressed by an
+%                         \lit{@}-expression) in \env{tabular}
+%                         environments.  Default is defined by
+%                         your document class.                  \\
+% |\arraycolsep|        & Analogous to |\tabcolsep|, but for
+%                         \env{array} environments.  Default is
+%                         defined by your document class.       \\
+% |\smarraycolsep|      & Analogous to |\tabcolsep|, but for
+%                         \env{smarray} environments.  Default
+%                         is 3\,pt.                             \\ \hlx{vhv}
+% |\arrayrulewidth|     & The width of horizontal and vertical
+%                         rules in tables.                      \\
+% |\arraythickrulewidth|& The width of starred rules in tables. \\
+% |\doublerulesep|      & Space added between two adjacent
+%                         vertical or horizontal rules.  Also
+%                         used by |\hlx{v}|.                    \\ \hlx{vhv}
+% |\arraystretch|       & Command containing a factor to
+%                         multiply the default row height.
+%                         Default is defined by your document
+%                         class (usually 1).                    \\ \hlx{vh}
 % \end{tabular}
 %
 % \caption{Parameters for configuring table environments}
@@ -766,7 +816,7 @@
 % This implementation allows you to define lots of different sets of columns.
 % You can change the current set using the |\colset| declaration:
 % \begin{grammar}
-% 	::= \[[ "\\colset" "{"  "}" \]]
+%   ::= \[[ "\\colset" "{"  "}" \]]
 % \end{grammar}
 % This leaves a problem, though: at any particular moment, the current
 % column set could be anything, since other macros and packages can change
@@ -782,8 +832,8 @@
 % previous current column set.
 %
 % \begin{grammar}
-% 	::= \[[ "\\colpush" "{"  "}" \]]
-% 	::= \[[ "\\colpop" \]]
+%  ::= \[[ "\\colpush" "{"  "}" \]]
+%   ::= \[[ "\\colpop" \]]
 % \end{grammar}
 %
 % The macros which manipulate the column set stack work \emph{locally}.
@@ -819,7 +869,7 @@
 % something lower-level.
 %
 % \begin{grammar}
-% 	::= \[[
+%   ::= \[[
 %   "\\coldef"
 %     \[ "["  "]" \]
 %       "{"  "}"
@@ -840,7 +890,7 @@
 % Note that if you do gobble the |\tab@mkpream|, it's your responsibility to
 % insert another one at the very end of your macro's expansion (so that
 % further preamble characters can be read).
-% 
+%
 % The replacement text is inserted directly.  It's normal to insert preamble
 % elements here.  There are several to choose from:
 %
@@ -879,7 +929,7 @@
 %
 % \begin{grammar}
 %
-% 	::= \[[
+%   ::= \[[
 %   \[ "["  "]" \]  \[ "=" \] \[ "["  "]" \]
 %   
 % \]]
@@ -979,7 +1029,7 @@
 % using the |\tab@cr| command:
 %
 % \begin{grammar}
-% 	::= \[[
+%    ::= \[[
 %   "\\tab@cr"  "{"  "}" "{"  "}"
 % \]]
 % \end{grammar}
@@ -999,6 +1049,159 @@
 % to see how all this gets put into practice.
 %
 %
+% \subsection{Colour support}
+%
+% I've now added colour support to \package{mdwtab}.  That is, you can play
+% with the colours of table cell backgrounds, rules and text.  The support
+% isn't there by default: you have to either give the \textsf{colour} option
+% when you load \package{mdwtab}, or include the \package{mtcolour} package
+% yourself.  It's very new, and might break.  It's probably not as good as
+% \package{colortbl}.  I prefer English spellings for the commands and
+% declarations: to reduce confusion, I've provided synonyms with fewer `u's.
+% If only American package authors were so thoughtful.  The examples in this
+% part of the documentation may not display correctly in some DVI viewers:
+% for best results, run |dvips| and view the PostScript using (say)
+% GhostScript.
+%
+% \subsubsection{New commands and features}
+%
+% \DescribeMacro\cellcolour
+% The |\cellcolour| command changes the background colour for the current
+% cell.  You can use it directly in a table cell, or in the table preamble.
+% It doesn't matter whereabouts in the table cell it goes.  Note that
+% unlike the \package{colortbl}, the |\cellcolour| command works on the
+% \emph{entire} contents of the cell, including the |\tabcolsep| space and
+% the rules, if any.  That means that it's robust even if there are |@{...}|
+% preamble commands present.
+%
+% The actual syntax is like this:
+%
+% \begin{grammar}
+%  ::= \[[
+%   \( "\\cellcolour" \\ "\\cellcolor" \)
+%   \[ "*" \]
+%   \[ "["  "]" \]
+%   "{"  "}"
+%   \[ "["  "]"
+%      \[ "["  "]" \] \]
+% \]]
+% \end{grammar}
+%
+% The \lit{*} makes |\cellcolour| override an extant |\rowcolour| command
+% (see below).  The \ and \ are as for the |\color|
+% command.  The \ is how much the colour band should stick out
+% to the left of the cell; and similarly for the \.  If you
+% don't give a \ then the same value is used for both; if you
+% give neither then there's no overhang.  The reason you might want overhang
+% is to deal with |\extracolsep| glue.  I shouldn't worry about it if I were
+% you.
+%
+% It's very useful to use |\cellcolour| in a preamble, in particular, in the
+% |?>| preamble command (which was added specifically).  (If you use only |>|
+% then |\vgap| leaves very odd-looking gaps in the table.)
+%
+% { \let\tabstyle=\relax
+% \begin{demo}{A coloured table}
+%\newcolumntype{\c}[2]{%
+%  >{\color{#1}}%
+%  ?>{\cellcolour{#2}}%
+%}
+%\begin{tabular}
+%   {|\c{cyan}{red}c|
+%     \c{magenta}{green}c|
+%     \c{yellow}{blue}c|}
+%                       \hlx{hv}
+%  One  &Two  &Three \\ \hlx{vhv}
+%  Four &Five &Six   \\ \hlx{vhv}
+%  Seven&Eight&Nine  \\ \hlx{vh}
+%\end{tabular}
+% \end{demo}
+% }
+%
+% Obviously, judicious use of |\newcolumntype| would abbreviate the above
+% considerably.
+%
+% \DescribeMacro\rowcolour
+% \DescribeMacro\rowcolouroff
+% The |\rowcolour| command changes the background colour in the same way as
+% |\cellcolour|; however, its effect takes precedence over |\cellcolour| (but
+% not |\cellcolour*|) if both are active, and isn't automatically turned off
+% at the start of the next cell.  To actually turn it off again, say
+% |\rowcolouroff|.
+%
+% \begin{grammar}
+%  ::= \[[
+%   \( "\\rowcolour" \\ "\\rowcolor" \)
+%   \[ "["  "]" \]
+%   "{"  "}"
+% \]]
+% \end{grammar}
+%
+% Note that you don't get to specify overhang parameters here.  The ones from
+% the |\cellcolour| declaration are used, unless there isn't one in which
+% case there aren't any.
+%
+% \DescribeMacro\ifmod
+% A common thing to do is colour alternate rows of the table differently.
+% This is a bit tricker for \package{mdwtab} than it would be for, say,
+% \package{array}, since it's hard to spot where the `rows' actually change.
+% The solution is to use the \textsf{tabrow} counter, and |\ifmod|.  Saying
+% say \syntax{"\\ifmod{"$x$"}{"$m$"}{"$y$"}{""}{""}"} is the same as
+% saying \ if $x \bmod m = y$, and \ otherwise.  This is typically
+% used as follows.
+%
+% % { \let\tabstyle=\relax
+% \begin{demo}{Alternating row colours}
+%\begin{tabular}
+%  {|?>{\ifmod
+%    {\value{tabrow}}{2}{1}
+%    {\rowcolour{white}}
+%    {\rowcolour[gray]{0.9}}}
+%     c|c|}
+%  \hlx{h+v}
+%  One   & Two   \\ \hlx{vh+v}
+%  Three & Four  \\ \hlx{vh+v}
+%  Five  & Six   \\ \hlx{vh+v}
+%  Seven & Eight \\ \hlx{vh+v}
+%  Nine  & Ten   \\ \hlx{vh+}
+%\end{tabular}
+% \end{demo}
+% }
+%
+% There are new rule parameters for colours.  You get a colourful rule if you
+% say \syntax{"colour" "=" }.  You can also say \syntax{"colourmodel"
+% "=" } to choose unnamed colours.
+%
+% When I've thought of what other things need doing, I'll do some of them.
+% The kit I've provided \emph{can} do most interesting things, but it might
+% require a certain level of hacking.  Ask me if you want something and it's
+% not obvious how to do it.
+%
+% \subsubsection{Dirty tricks}
+%
+% The colour support interacts with |\vgap| very badly.  The preamble rune
+% |?>{\cellcolour{...}}| works well if you want to colour a column, and
+% |\rowcolour| works either in the preamble or as
+% |\hlx{?{\rowcolour{...}}}|.  But what if you want to just colour one table
+% cell?  You can, as suggested above, just say |\cellcolour{...}| in the
+% table text, but that leaves really nasty-looking gaps above and below if
+% there are adjacent |\vgap| rows.
+%
+% This is what |\hlx{?{...}}| was invented for.  Here's a demo.
+%
+% \begin{demo}[w]{Colouring just one cell}
+%\let\hack=\relax
+%\begin{tabular}[C]{|c|?>{\hack}c|}          \hlx{hv}
+%Uncoloured & cells here                  \\ \hlx{vhv}
+%And some & more                          \\
+%        \hlx{vh?{\gdef\hack{\cellcolour{red}}}v}
+%Yet more & This one's red!               \\
+%        \hlx{vh?{\global\let\hack=\relax}v}
+%And more & uncoloured cells              \\ \hlx{vh}
+%\end{tabular}
+% \end{demo}
+%
+%
 % \subsection{The \env{mathenv} package alignment environments}
 %
 % The \env{mathenv} package provides several environments for aligning
@@ -1034,7 +1237,7 @@
 %   \[ "[" \<  \> "]" \]
 % \]]
 %
-% 	::= \[[
+%   ::= \[[
 %   \[ "q" \\ ":" \]
 %   \[ \< ">" "{"  "}" \> \]
 %   \begin{stack}
@@ -1055,34 +1258,34 @@
 % table~\ref{tbl:eqnarray}.
 %
 % \begin{table}
-% \begin{tabular}[C]{| >{\synshorts} c | m{3in} |}	   \hlx{hv[1]}
-%
-% \multicolumn{2}{|c|}{\bf Column types}		\\ \hlx{v[1]hv}
-% \bf Name	& \bf Meaning				\\ \hlx{vhv.}
-% "l"		& Left aligned piece of equation.	\\ \hlx{.}
-% "c"		& Centred piece of equation.		\\ \hlx{.}
-% "x"		& Centred or flush-left whole equation
-%		  (depending on \textsf{fleqn} option).	\\ \hlx{.}
-% "r"		& Right aligned piece of equation.	\\ \hlx{vhv.}
-% "L"		& Left aligned piece of equation whose
-%		  width is considered to be 2\,em.	\\ \hlx{vhv.}
+% \begin{tabular}[C]{| >{\synshorts} c | m{3in} |}         \hlx{hv[1]}
+%
+% \multicolumn{2}{|c|}{\bf Column types}                \\ \hlx{v[1]hv}
+% \bf Name      & \bf Meaning                           \\ \hlx{vhv.}
+% "l"           & Left aligned piece of equation.       \\ \hlx{.}
+% "c"           & Centred piece of equation.            \\ \hlx{.}
+% "x"           & Centred or flush-left whole equation
+%                 (depending on \textsf{fleqn} option). \\ \hlx{.}
+% "r"           & Right aligned piece of equation.      \\ \hlx{vhv.}
+% "L"           & Left aligned piece of equation whose
+%                 width is considered to be 2\,em.      \\ \hlx{vhv.}
 % "Tl", "Tc" and "Tr" & Left, centre and right aligned
-%		  text.					\\ \hlx{vhhv[1]}
-%
-% \multicolumn{2}{|c|}{\bf Other modifier characters}	\\ \hlx{v[1]hv}
-% \bf Name	& \bf Meaning				\\ \hlx{vhv.}
-% ":"		& Leaves a big gap between equations.
-%		  By default, the `chunks' separated by
-%		  \lit{:}s are equally spaced on the
-%		  line.					\\ \hlx{.}
-% "q"		& Inserts 1\,em of space		\\ \hlx{vhv.}
-% ">{""}"	& Inserts \ just before the
-%		  actual column entry.			\\ \hlx{.}
-% "<{""}"	& Inserts \ just after the
-%		  actual column entry.			\\ \hlx{vhv.}
+%                 text.                                 \\ \hlx{vhhv[1]}
+%
+% \multicolumn{2}{|c|}{\bf Other modifier characters}   \\ \hlx{v[1]hv}
+% \bf Name      & \bf Meaning                           \\ \hlx{vhv.}
+% ":"           & Leaves a big gap between equations.
+%                 By default, the `chunks' separated by
+%                 \lit{:}s are equally spaced on the
+%                 line.                                 \\ \hlx{.}
+% "q"           & Inserts 1\,em of space                \\ \hlx{vhv.}
+% ">{""}" & Inserts \ just before the
+%                 actual column entry.                  \\ \hlx{.}
+% "<{""}" & Inserts \ just after the
+%                 actual column entry.                  \\ \hlx{vhv.}
 % "*{""}{""}" & Inserts \
-%		  copies of the \ into the
-%		  preamble.				\\ \hlx{vh}
+%                 copies of the \ into the
+%                 preamble.                             \\ \hlx{vh}
 % \end{tabular}
 %
 % \caption{\package{eqnarray} column types and modifiers}
@@ -1114,7 +1317,7 @@
 %
 % \begin{demo}[w]{Lots of equations}
 %\begin{eqnarray}[rl:rl:lq]
-% V_i &= v_i - q_i v_j,	& X_i &= x_i - q_i x_j,	&
+% V_i &= v_i - q_i v_j, & X_i &= x_i - q_i x_j, &
 %       U_i = u_i, \qquad \mbox{for $i \ne j$}  \\
 % V_j &= v_j,           & X_j &= x_j            &
 %       U_j u_j + \sum_{i \ne j} q_i u_i. \label{eq:A}
@@ -1138,7 +1341,7 @@
 % \begin{demo}{Splitting example}
 %\begin{eqnarray*}[Ll]
 %   w+x+y+z = \\
-%    & a+b+c+d+e+ \\
+%    & a+b+c+d+e+{} \\
 %    & f+g+h+i+j
 %\end{eqnarray*}
 % \end{demo}
@@ -1330,31 +1533,31 @@
 % you like them.  These are all shown in table~\ref{tbl:eqnparms}.
 %
 % \begin{table}
-% \begin{tabular}[C]{| l | p{3in} |}				   \hlx{hv}
-% \bf Parameter		& \bf Use				\\ \hlx{vhv}
-% |\eqaopenskip|	& Length put on the left of an
-%			  \env{eqnarray} environment.  By
-%			  default, this is |\@centering| (to
-%			  centre the alignment) or |\mathindent|
-%			  (to left align) depending on whether
-%			  you're using the \textsf{fleqn}
-%			  document class option.		\\
-% |\eqacloseskip|	& Length put on the right of an
-%			  \env{eqnarray} environment.  By
-%			  default, this is |\@centering|, to
-%			  align the environment correctly.	\\ \hlx{vhv}
-% |\eqacolskip|		& Space added by the \lit{:} column
-%			  modifier.  This should be a rubber
-%			  length, although it only stretches in
-%			  \env{eqnarray}, not in \env{eqnalign}.
-%			  The default value is 1\smallf1/2\,em
-%			  with 1000\,pt of stretch.		\\
-% |\eqainskip|		& Space added at each side of a normal
-%			  column.  By default this is 0\,pt.	\\ \hlx{vhv}
-% |\eqastyle|		& The maths style used in the alignment.
-%			  By default, this is |\textstyle|,
-%			  and you probably won't want to change
-%			  it.					\\ \hlx{vh}
+% \begin{tabular}[C]{| l | p{3in} |}                               \hlx{hv}
+% \bf Parameter         & \bf Use                               \\ \hlx{vhv}
+% |\eqaopenskip|        & Length put on the left of an
+%                         \env{eqnarray} environment.  By
+%                         default, this is |\@centering| (to
+%                         centre the alignment) or |\mathindent|
+%                         (to left align) depending on whether
+%                         you're using the \textsf{fleqn}
+%                         document class option.                \\
+% |\eqacloseskip|       & Length put on the right of an
+%                         \env{eqnarray} environment.  By
+%                         default, this is |\@centering|, to
+%                         align the environment correctly.      \\ \hlx{vhv}
+% |\eqacolskip|         & Space added by the \lit{:} column
+%                         modifier.  This should be a rubber
+%                         length, although it only stretches in
+%                         \env{eqnarray}, not in \env{eqnalign}.
+%                         The default value is 1\smallf1/2\,em
+%                         with 1000\,pt of stretch.             \\
+% |\eqainskip|          & Space added at each side of a normal
+%                         column.  By default this is 0\,pt.    \\ \hlx{vhv}
+% |\eqastyle|           & The maths style used in the alignment.
+%                         By default, this is |\textstyle|,
+%                         and you probably won't want to change
+%                         it.                                   \\ \hlx{vh}
 % \end{tabular}
 %
 % \caption{Parameters for the \env{eqnarray} and \env{eqnalign} environments}
@@ -1425,15 +1628,15 @@
 %
 % \begin{grammar}
 %
-% 	::= \[[    \]]
+%   ::= \[[    \]]
 %
 %  ::= \[[ "\\begin{matrix}" \[ "["  "]" \] \]]
 %
-% 	::= \[[
+%  ::= \[[
 %   \< \[ "[" \] \[ "T" \] \( "l" \\ "c" \\ "r" \) \>
 % \]]
 %
-% 	::= \[[ "\\end{stack}" \]]
+%   ::= \[[ "\\end{stack}" \]]
 %
 % \end{grammar}
 %
@@ -1609,11 +1812,14 @@
 %       variable.
 % \item [\cs{tab@columns}] contains the number of the current column.
 % \item [\cs{tab@hlstate}] contains the state required for hline management.
+% \item [\textsf{tabrow}] contains the row number in the table.  It's a
+%       proper \LaTeX\ counter.
 % \end{description}
 %
 %    \begin{macrocode}
 \newcount\tab@state
 \newcount\tab@columns
+\newcounter{tabrow}
 %    \end{macrocode}
 %
 % We need \emph{lots} of token registers.  Fortunately, most of them are only
@@ -1660,6 +1866,7 @@
 \newif\iftab@initrule
 \newif\iftab@rule
 \newif\iftab@vgap
+\newif\iftab@colour
 %    \end{macrocode}
 %
 % Now assign some default values to new dimen parameters.  These definitions
@@ -1682,6 +1889,17 @@
 %    \end{macrocode}
 %
 %
+% \subsection{Options processing}
+%
+% Notice options, load package.
+%
+%    \begin{macrocode}
+\DeclareOption{colour}{\tab@colourtrue}
+\DeclareOption{color}{\tab@colourtrue}
+\ProcessOptions
+\RequirePackage{mdwkey}
+%    \end{macrocode}
+%
 % \subsection{Some little details}
 %
 % \begin{macro}{\@maybe@unskip}
@@ -1728,14 +1946,14 @@
 %
 %
 % \subsection{Parser states}
-% 
+%
 % Now we start on the parser.  It's really simple, deep down.  We progress
 % from state to state, extracting tokens from the preamble and building
 % command names from them.  Each command calls one of the element-building
 % routines, which works out which state it should be in.  We go through each
 % of the states in between (see later) doing default things for the ones we
 % missed out.
-% 
+%
 % Anyway, here's some symbolic names for the states.  It makes my life
 % easier.
 %
@@ -1784,6 +2002,13 @@
   \fi%
 %    \end{macrocode}
 %
+% Now dump in the |\tab@lefttext| material.
+%
+%    \begin{macrocode}
+  \expandafter\tab@append\expandafter\tab@preamble%
+    \expandafter{\tab@lefttext}%
+%    \end{macrocode}
+%
 % Now we spill the token registers into the main list in a funny order (which
 % is why we're doing it in this strange way in the first place.
 %
@@ -1794,7 +2019,8 @@
     \the\expandafter\tab@pretext%
     \the\expandafter\tab@userpretext%
     \the\expandafter\toks@%
-    \the\tab@posttext%
+    \the\expandafter\tab@posttext%
+    \tab@righttext%
   }%
 %    \end{macrocode}
 %
@@ -1826,7 +2052,7 @@
 % {\bf while} $\it tab\_state \ne s$ {\bf do} \\
 % \qq $\mathit{tab\_state = tab\_state}+1$; \\
 % \qq {\bf if} $\it tab\_state = tab\_limitState$ {\bf then}
-%				$\it tab\_state=tab\_loopState$; \\
+%                               $\it tab\_state=tab\_loopState$; \\
 % \qq {\bf if} $\it tab\_state = tab\_preSpcState$ {\bf then} \\
 % \qq \qq {\bf if} $\it tab\_initRule$ {\bf then} \\
 % \qq \qq \qq $\it tab\_initRule = {\bf false}$; \\
@@ -1837,7 +2063,7 @@
 % \qq \qq {\bf end\,if}; \\
 % \qq {\bf end\,if}; \\
 % \qq {\bf if} $\it tab\_state \ne s$ {\bf then}
-%				$\it do\_default(tab\_state)$; \\
+%                               $\it do\_default(tab\_state)$; \\
 % {\bf end\,while};
 % \end{quote}
 %
@@ -1877,7 +2103,11 @@
     \else%
       \tab@looped%
       \tab@commit%
+      \expandafter\tab@append\expandafter\tab@shortline%
+        \expandafter{\tab@rightruletext}%
       \tab@append\tab@shortline{&\omit}%
+      \expandafter\tab@append\expandafter\tab@shortline%
+        \expandafter{\tab@leftruletext}%
     \fi%
   \fi%
 %    \end{macrocode}
@@ -2145,10 +2375,33 @@
 % \begin{macro}{\tab@initread}
 %
 % This macro sets up lots of variables to their normal states prior to
-% parsing a preamble.  Some things may need changing, but not many.
+% parsing a preamble.  Some things may need changing, but not many.  This
+% version just sets the major hooks, and then does a subread.  The midtext
+% macro contains what to put in the very middle of each template --
+% |\multicolumn| will insert its argument here.
 %
 %    \begin{macrocode}
 \def\tab@initread{%
+  \def\tab@lefttext{}%
+  \def\tab@leftruletext{}%
+  \def\tab@righttext{}%
+  \def\tab@rightruletext{}%
+  \def\tab@tabtext{&}%
+  \def\tab@midtext{\ignorespaces####\@maybe@unskip}%
+  \tab@initsubread%
+}
+%    \end{macrocode}
+%
+% \end{macro}
+%
+% \begin{macro}{\tab@initsubread}
+%
+% This is where most of the activity is.  We don't replace the left and right
+% texts, so that we effectively inherit them rfrom the enclosing
+% environment.
+%
+%    \begin{macrocode}
+\def\tab@initsubread{%
 %    \end{macrocode}
 %
 % First, reset the parser state to the start state.
@@ -2157,15 +2410,11 @@
   \global\tab@state\tab@startstate%
 %    \end{macrocode}
 %
-% We clear the token lists to sensible values, mostly.  The midtext macro
-% contains what to put in the very middle of each template -- |\multicolumn|
-% will insert its argument here.
+% We clear the token lists to sensible values, mostly.
 %
 %    \begin{macrocode}
   \tab@preamble{}%
   \tab@shortline{}%
-  \def\tab@tabtext{&}%
-  \def\tab@midtext{\ignorespaces####\@maybe@unskip}%
   \tab@pretext{}%
   \tab@userpretext{}%
   \tab@posttext{}%
@@ -2184,6 +2433,7 @@
   \tab@initruletrue%
   \tab@firstcoltrue%
 }
+
 %    \end{macrocode}
 %
 % \end{macro}
@@ -2196,9 +2446,13 @@
 %
 %    \begin{macrocode}
 \def\tab@readpreamble#1{%
+  \expandafter\tab@append\expandafter\tab@shortline%
+    \expandafter{\tab@leftruletext}%
   \tab@doreadpream{#1}%
   \iftab@initrule\global\tab@state\tab@prespcstate\fi%
   \tab@setstate\tab@rulestate%
+  \expandafter\tab@append\expandafter\tab@shortline%
+    \expandafter{\tab@rightruletext}%
   \tab@commit%
 }
 %    \end{macrocode}
@@ -2305,7 +2559,7 @@
 % to make everything work right, but it's simple really.
 %
 %    \begin{macrocode}
-\def\coldef{\@ifnextchar[\coldef@i{\coldef@i[\tab@colset]}}
+\def\coldef{\@testopt\coldef@i\tab@colset}
 \def\coldef@i[#1]#2#3#{\coldef@ii[#1]{#2}{#3}}
 \def\coldef@ii[#1]#2#3#4{%
   \expandafter\def\csname#1!col.\string#2\endcsname#3{%
@@ -2322,17 +2576,13 @@
 % to do it.
 %
 %    \begin{macrocode}
-\def\collet{\@ifnextchar[\collet@i{\collet@i[\tab@colset]}}
+\def\collet{\@testopt\collet@i\tab@colset}
 \def\collet@i[#1]#2{%
   \@ifnextchar=%
     {\collet@ii[#1]{#2}}%
     {\collet@ii[#1]{#2}=}%
 }
-\def\collet@ii[#1]#2={%
-  \@ifnextchar[%
-    {\collet@iii[#1]{#2}}%
-    {\collet@iii[#1]{#2}[\tab@colset]}%
-}
+\def\collet@ii[#1]#2={\@testopt{\collet@iii[#1]{#2}}\tab@colset}
 \def\collet@iii[#1]#2[#3]#4{%
   \expandafter\let\csname#1!col.\string#2\expandafter\endcsname%
                   \csname#3!col.\string#4\endcsname%
@@ -2352,7 +2602,7 @@
 % that \package{array} works.
 %
 %    \begin{macrocode}
-\def\newcolumntype#1{\@ifnextchar[{\nct@i{#1}}{\nct@i#1[0]}}
+\def\newcolumntype#1{\@testopt{\nct@i{#1}}0}
 \def\nct@i#1[#2]{\@ifnextchar[{\nct@ii{#1}[#2]}{\nct@iii{#1}{[#2]}}}
 \def\nct@ii#1[#2][#3]{\nct@iii{#1}{[#2][#3]}}
 \def\nct@iii#1#2#3{%
@@ -2388,6 +2638,14 @@
 % First, make sure we're setting up the right columns.  This also sets the
 % default for the user.  Other packages must not use the |\colset| command
 % for defining columns -- they should use the stack operations defined above.
+% For colour support, we ensure that the total stretch in a table cell is
+% 1\,fil.
+%
+%    \begin{macrocode}
+\def\tab@halfhfil{\hskip\z@\@plus.5fil\relax}
+%    \end{macrocode}
+%
+% And now on with the show.
 %
 %    \begin{macrocode}
 \colset{tabular}
@@ -2401,7 +2659,7 @@
 %
 %    \begin{macrocode}
 \coldef l{\tabcoltype{\kern\z@\tab@bgroup}{\tab@egroup\hfil}}
-\coldef c{\tabcoltype{\hfil\tab@bgroup}{\tab@egroup\hfil}}
+\coldef c{\tabcoltype{\tab@halfhfil\tab@bgroup}{\tab@egroup\tab@halfhfil}}
 \coldef r{\tabcoltype{\hfil\tab@bgroup}{\tab@egroup}}
 %    \end{macrocode}
 %
@@ -2415,7 +2673,7 @@
 \coldef M#1{\tab@aligncol{#1}{\tab@bmaths}{\tab@emaths}}
 \def\tab@aligncol#1#2#3{%
   \if#1l\tabcoltype{\kern\z@#2}{#3\hfil}\fi%
-  \if#1c\tabcoltype{\hfil#2}{#3\hfil}\fi%
+  \if#1c\tabcoltype{\tab@halfhfil#2}{#3\tab@halfhfil}\fi%
   \if#1r\tabcoltype{\hfil#2}{#3}\fi%
 }
 %    \end{macrocode}
@@ -2423,14 +2681,9 @@
 % Now for the default rules.
 %
 %    \begin{macrocode}
-\coldef ${\expandafter\tab@rulewd\expandafter\tab@vrule\@gobble}
-\def\tab@vrule{%
-  \expandafter\tabruletype\expandafter{%
-    \expandafter\vrule\expandafter\@width\the\tab@rulewidth%
-  }%
-  \tab@mkpreamble%
-}
-\coldef |{\tabruletype{\vrule\@width\arrayrulewidth}}
+\coldef ${\@firstoftwo{\tab@withrp\tab@vrule}}
+\coldef |{\@firstoftwo{\tab@withrp\tab@vrule[]}}
+\def\tab@vrule#1{\tabruletype{#1\vrule\@width\dimen@}\tab@mkpreamble}
 \coldef !#1{\tabruletype{#1}}
 %    \end{macrocode}
 %
@@ -2459,6 +2712,12 @@
 %    \begin{macrocode}
 \coldef >#1{\tabuserpretype{#1}}
 \coldef <#1{\tabuserposttype{#1}}
+\coldef ?#1#2{%
+  \ifx>#1\expandafter\tabuserpretype%
+  \else\expandafter\tabuserposttype\fi%
+  {#2}%
+  \tab@append\tab@shortline{#2}%
+}
 %    \end{macrocode}
 %
 % The strange column type.
@@ -2538,8 +2797,8 @@
 % appropriate depth.  Since this will lie on the previous baseline, it won't
 % alter the effective height of the box.  There's a snag here.  |\prevdepth|
 % may be wrong for example if the last thing inserted was a rule, or the
-% box is just empty.  Check for this specially.  (Thanks to Rowland for
-% spotting this.)
+% box is just empty.  Check for this specially.  (Thanks to Rowland McDonnell
+% for spotting this.)
 %
 %    \begin{macrocode}
   \ifdim\prevdepth>-\@m\p@\ifdim\prevdepth<\dp\@arstrutbox%
@@ -2596,7 +2855,11 @@
   \tab@initread%
   \def\tab@multicol{\@arstrut}%
   \tab@preamble{\tab@multicol}%
-  \def\tab@midtext{\ignorespaces\@sharp\@sharp\@maybe@unskip}%
+  \let\tab@lefttext\tab@lefttexthook%
+  \let\tab@righttext\tab@righttexthook%
+  \let\tab@leftruletext\tab@leftruletexthook%
+  \let\tab@rightruletext\tab@rightruletexthook%
+  \def\tab@midtext{\tab@setcr\ignorespaces\@sharp\@sharp\@maybe@unskip}%
   \tab@readpreamble{#1}%
   \gdef\@preamble{\the\tab@preamble}%
   \let\tab@bgroup\begingroup%
@@ -2605,7 +2868,6 @@
 }
 %    \end{macrocode}
 %
-%
 % \subsection{Debugging}
 %
 % This macro just parses a preamble and displays it on the terminal.  It
@@ -2664,9 +2926,9 @@
 %
 %    \begin{macrocode}
 \def\tab@btext{\begingroup}
-\def\tab@bmaths{$}
+\def\tab@bmaths{\color@begingroup$}
 \def\tab@etext{\endgroup}
-\def\tab@emaths{\m@th$}
+\def\tab@emaths{\m@th$\color@endgroup}
 %    \end{macrocode}
 %
 % \end{macro}
@@ -2691,7 +2953,11 @@
   \crcr%
   \egroup%
   \tab@right%
+  \endgroup%
   \tab@restorehlstate%
+  \global\c@tabrow\count@%
+  \def\@currentlabel{\p@tabrow\thetabrow}%
+  \tab@endhook%
 }
 %    \end{macrocode}
 %
@@ -2707,7 +2973,7 @@
   \extrarowheight\z@%
   \col@sep\smarraycolsep%
   \let\tab@extrasep\smarrayextrasep%
-  \def\tab@bmaths{$\scriptstyle}%
+  \def\tab@bmaths{\color@begingroup$\scriptstyle}%
   \def\tab@btext{\begingroup\scriptsize}%
   \setbox\z@\hbox{\scriptsize\strut}%
   \dimen@\ht\z@\dimen@ii\dp\z@\tab@setstrut%
@@ -2812,15 +3078,36 @@
 % The following bits are mainly for other packages to hook themselves onto.
 %
 %    \begin{macrocode}
-\let\@arrayleft\relax%
-\let\@arrayright\relax%
+\let\@arrayleft\relax
+\let\@arrayright\relax
+\let\tab@beginhook\@empty
+\let\tab@lefttexthook\@empty
+\let\tab@righttexthook\@empty
+\let\tab@leftruletexthook\@empty
+\let\tab@rightruletexthook\@empty
+\let\tab@endhook\@empty
 %    \end{macrocode}
 %
+% For setting these hooks, we provide some handy commands.
+%
+%    \begin{macrocode}
+\def\tab@addhookbefore#1#2{%
+  \toks@{#2}\toks@\expandafter{\the\expandafter\toks@#1}%
+  \edef#1{\the\toks@}%
+}
+\def\tab@addhookafter#1#2{%
+  \toks@\expandafter{#1#2}%
+  \edef#1{\the\toks@}%
+}
+%    \end{macrocode}
+%
+% And now we get on with the real thing.
+%
 %    \begin{macrocode}
 \def\@tabarray{%
   \let\@arrayleft\relax%
   \let\@arrayright\relax%
-  \@ifnextchar[\@array{\@array[c]}%
+  \@testopt\@array c%
 }
 %    \end{macrocode}
 %
@@ -2839,10 +3126,14 @@
 % control sequence to avoid wasting any more count registers.
 %
 %    \begin{macrocode}
+  \tab@beginhook%
+  \count@\c@tabrow%
+  \global\c@tabrow\z@%
   \edef\tab@restorehlstate{%
     \global\tab@endheight\the\tab@endheight%
     \gdef\noexpand\tab@hlstate{\tab@hlstate}%
   }%
+  \begingroup%
   \def\tab@hlstate{n}%
 %    \end{macrocode}
 %
@@ -2855,6 +3146,10 @@
 %    \begin{macrocode}
   \colset{tabular}%
   \tab@initread%
+  \let\tab@lefttext\tab@lefttexthook%
+  \let\tab@righttext\tab@righttexthook%
+  \let\tab@leftruletext\tab@leftruletexthook%
+  \let\tab@rightruletext\tab@rightruletexthook%
   \def\tab@midtext{\tab@setcr\ignorespaces####\@maybe@unskip}%
   \def\tab@multicol{\@arstrut\tab@startrow}%
   \tab@preamble{\tab@multicol\tabskip\z@skip}%
@@ -3191,6 +3486,7 @@
   \everypar{}%
   \lineskip\normallineskip%
   \let\\\@normalcr%
+  \color@begingroup%
   \tab@startpause%
   \vskip-\parskip%
   \parshape\@ne\@totalleftmargin\linewidth%
@@ -3200,6 +3496,7 @@
 \def\tabpause@i{%
   \nobreak%
   \tab@endpause%
+  \color@endgroup%
   \ifnum0=`{\fi}%
 }
 %    \end{macrocode}
@@ -3223,8 +3520,7 @@
   \multispan{#1}%
   \begingroup%
     \tab@multicol%
-    \tab@initread%
-    \tab@preamble{}%
+    \tab@initsubread%
     \long\def\tab@midtext{#3}%
     \let\tab@looped\tab@err@multi%
     \tab@readpreamble{#2}%
@@ -3385,25 +3681,69 @@
 % This is where all the gubbins for |\vgap| and friends is kept, lest it
 % contaminate fairly clean bits of code found elsewhere.
 %
-% \subsubsection{Common parsing for vertical rule width twiddling}
+% \subsubsection{Common parsing for rule parameters twiddling}
 %
-% \begin{macro}{\tab@rulewd}
+% \begin{macro}{\tab@ruleparams}
 %
-% Given a macro name, set |\tab@rulewidth| to be the chosen rule thickness
-% and call the macro.  We parse a `|*|' to mean |\arraythickrulewidth|, an
-% optional argument which should be something |\setlength| can understand, or
-% nothing, which gives the default |\arrayrulewidth|.
+% Given a macro name, make a (global) macro |\tab@ruledecls|, which sets
+% |\dimen0| to be the chosen rule thickness, and sets up colours and whatnot,
+% and then and calls the macro.  We parse a `|*|' to mean
+% |\arraythickrulewidth|, an optional argument which should be something
+% |\setlength| can understand, or nothing, which gives the default
+% |\arrayrulewidth|.
+%
+% To make this properly hookable, we need to make a list of properties and
+% gather them together.
 %
 %    \begin{macrocode}
-\def\tab@rulewd#1{%
-  {\ifnum0=`}\fi\@ifstar{\tab@rulewd@star{#1}}{\tab@rulewd@what{#1}}%
+\let\tab@rp@inithook\@empty
+\let\tab@rp@sethook\@empty
+\let\tab@rp@donehook\@empty
+\let\tab@rp@default\@empty
+\def\tab@ruleparams#1{%
+  {\ifnum0=`}\fi%
+  \tab@rp@inithook%
+  \def\tab@rp@next{\ifnum0=`{\fi}#1}%
+  \expandafter\tab@rp@keys\expandafter{\tab@rp@default}%
+  \@ifstar\tab@rp@star\tab@rp@what%
+}
+\def\tab@rp@star{\dimen@\arraythickrulewidth\tab@rp@what}
+\def\tab@rp@what{\@ifnextchar[\tab@rp@opt\tab@rp@done}
+\def\tab@rp@opt[#1]{\tab@rp@keys{#1}\tab@rp@done}
+\def\tab@rp@keys{\mkparse{mdwtab:rule}}
+\def\tab@rp@done{%
+  \protected@xdef\tab@rp@{\tab@rp@sethook}%
+  \tab@rp@donehook%
+  \tab@rp@next%
 }
-\def\tab@rulewd@what#1{%
-  \@ifnextchar[{\tab@rulewd@opt{#1}}{\tab@rulewd@done\arrayrulewidth#1}%
+\def\tab@withrp#1{\tab@ruleparams{\tab@withrp@i{#1}}}
+\def\tab@withrp@i#1{%
+  \toks@{#1}%
+  \toks@\expandafter{\the\expandafter\toks@\expandafter{\tab@rp@}}%
+  \the\toks@%
 }
-\def\tab@rulewd@star#1{\tab@rulewd@done\arraythickrulewidth#1}
-\def\tab@rulewd@opt#1[#2]{\setlength\dimen@{#2}\tab@rulewd@done\dimen@#1}
-\def\tab@rulewd@done#1{\global\tab@rulewidth#1\ifnum0=`{\fi}}
+%    \end{macrocode}
+%
+% And now to define the width parameters.
+%
+%    \begin{macrocode}
+\tab@addhookafter\tab@rp@inithook{\dimen@\arrayrulewidth}
+\tab@addhookafter\tab@rp@sethook{\dimen@\the\dimen@}
+\tab@addhookafter\tab@rp@donehook{\global\tab@rulewidth\dimen@}
+\mkdef{mdwtab:rule}{width}{\setlength\dimen@{#1}}
+\mkdef{mdwtab:rule}{thin}*{\dimen@\arrayrulewidth}
+\mkdef{mdwtab:rule}{thick}*{\dimen@\arraythickrulewidth}
+\mkdef*{mdwtab:rule}*{\setlength\dimen@{#1}}
+%    \end{macrocode}
+%
+% \end{macro}
+%
+% \begin{macro}{\tabsetruleparams}
+%
+% And the user default-parameter list.
+%
+%    \begin{macrocode}
+\def\tabsetruleparams{\def\tab@rp@default}
 %    \end{macrocode}
 %
 % \end{macro}
@@ -3418,7 +3758,7 @@
 % vertical space.
 %
 %    \begin{macrocode}
-\def\hline{\noalign\tab@rulewd\hline@prep}
+\def\hline{\noalign\tab@ruleparams\hline@prep}
 \def\hline@prep{%
   \tab@dohline%
   \noalign{\ifnum0=`}\fi%
@@ -3447,7 +3787,7 @@
 %
 % \begin{macro}{\tab@dohline}
 %
-% This is where hlines actually get drawn.  
+% This is where hlines actually get drawn.
 % Drawing lines is more awkward than it used to be, particularly in unboxed
 % tables.  It used to be a case simply of saying |\noalign{\hrule}|.
 % However, since unboxed tables are actually much wider than they look, this
@@ -3458,9 +3798,11 @@
 %
 %    \begin{macrocode}
 \def\tab@dohline{%
-  \multispan{\tab@columns}%
-  \leaders\hrule\@height\tab@rulewidth\hfil%
-  \tab@addruleheight\arrayrulewidth%  
+  \multispan\tab@columns%
+  \color@begingroup%
+  \tab@rp@\leaders\hrule\@height\dimen@\hfil%
+  \tab@addruleheight\dimen@%
+  \color@endgroup%
   \cr%
 }
 %    \end{macrocode}
@@ -3477,17 +3819,19 @@
 %
 % \begin{macro}{\vline}
 %
-% Now uses the general |\tab@rulewd| parser.
+% Now uses the general |\tab@ruleparams| parser.  We save and restore the
+% global |\tab@rulewidth| parameter here.
 %
 %    \begin{macrocode}
 \def\vline{%
   \begingroup%
-  \dimen@\tab@rulewidth%
-  \tab@rulewd{%
-    \vrule\@width\tab@rulewidth%
-    \global\tab@rulewidth\dimen@%
-    \endgroup%
-  }%
+  \@tempdima\tab@rulewidth\let\safe@\tab@rp@%
+  \tab@ruleparams\tab@vline%
+}
+\def\tab@vline{%
+  \tab@rp@\vrule\@width\dimen@%
+  \global\tab@rulewidth\@tempdima\global\let\tab@rp@\safe@%
+  \endgroup%
 }
 %    \end{macrocode}
 %
@@ -3503,7 +3847,12 @@
 % Not a single line of code written yet, and we already have a dilemma on
 % our hands.  Multiple consecutive |\cline| commands are meant to draw
 % on the same vertical bit of table.  But horizontal lines are meant to have
-% thickness now.  Oh, well [sigh], we'll skip back on it after all.
+% thickness now.  Worse, if the lines have real thickness then we leave gaps
+% in the vertical rules which aren't covered by our line.  But if we
+% backspace over the line, then we overwrite it with coloured blobs.
+%
+% We give up on doing the job properly -- that's just doomed.  Backspace over
+% the previous row, and provide a hack for doing the spacing right elsewhere.
 %
 % Now the problem remains how best to do the job.  The way I see it, there
 % are three possibilities:
@@ -3538,24 +3887,23 @@
 % |\tab@state|.
 %
 %    \begin{macrocode}
-\def\cline{\noalign\tab@rulewd\cline@prep}
-\def\cline@prep#1{%
-  \noalign{\kern-.5\tab@rulewidth\tab@penalty}%
-  \omit%
-  \global\tab@state\@ne%
-  \ranges\cline@i{#1}%
-  \cr%
-  \noalign{\kern-.5\tab@rulewidth\tab@penalty}%
-}
+\def\cline{\noalign\tab@ruleparams\cline@do}
 %    \end{macrocode}
 %
 % Now for the tricky bit.  When we're given a range, we look to see if the
 % first number is less than |\tab@state|.  If so, we quickly close the
 % current row, kern backwards and start again with an |\omit| and reset
-% |\tab@state| to 1, and try again.
+% |\tab@state| to 1, and try again.  This is hardly perfect, but gets the job
+% done in many cases.  Correct |\vgap| insertion fixes the remaining bugs.
 %
 %    \begin{macrocode}
-\def\cline@i#1#2{%
+\def\cline@do#1{%
+  \noalign{\kern-\tab@rulewidth}%
+  \omit%
+  \global\tab@state\@ne%
+  \ranges\cline@do@i{#1}\cr%
+}
+\def\cline@do@i#1#2{%
   \ifnum#1<\tab@state\relax%
     \tab@@cr%
     \noalign{\kern-\tab@rulewidth\tab@penalty}%
@@ -3565,7 +3913,7 @@
 %    \end{macrocode}
 %
 % We are now either at or in front of the column position required.  If
-% we're too far back, we must |\hfil&\omit| our way over to the correct%
+% we're too far back, we must |\hfil&\omit| our way over to the correct
 % column.
 %
 %    \begin{macrocode}
@@ -3602,7 +3950,10 @@
 % we start putting in |\hfil| glue when we step onto the next cell.
 %
 %    \begin{macrocode}
+  \color@begingroup%
+  \tab@rp@%
   \leaders\hrule\@height\tab@rulewidth\hfill%
+  \color@endgroup%
 }
 %    \end{macrocode}
 %
@@ -3642,18 +3993,18 @@
 %       Computer Programming} use the little `stub lines' to show where
 %       data items cross byte boundaries:
 %
-%	^^A This actually looks terrifyingly similar to the original.
-%	^^A The leading @{} is there to stop the table looking off-centre,
-%	^^A because there's no left hand rule telling you where the table
-%	^^A starts, like there is on the right, just the \tabcolsep glue.
+%       ^^A This actually looks terrifyingly similar to the original.
+%       ^^A The leading @{} is there to stop the table looking off-centre,
+%       ^^A because there's no left hand rule telling you where the table
+%       ^^A starts, like there is on the right, just the \tabcolsep glue.
 %
-%	\begingroup
-%	\newcommand{\wide}[2]{\multicolumn{#1}{c|}{\ttfamily #2}}
-%	\begin{tabular}[C]{@{} r @{\qquad} | Mc | *{5}{c|}} \hlx{c{2-7} v}
-%          empty & - & 1 & 0 & 0 & 0 & 0		\\ \hlx{v c{2-7} v}
-%	occupied & + & \wide{2}{LINK} & \wide{3}{KEY}	\\ \hlx{v c{2-7}}
-%	\end{tabular}
-%	\endgroup
+%       \begingroup
+%       \newcommand{\wide}[2]{\multicolumn{#1}{c|}{\ttfamily #2}}
+%       \begin{tabular}[C]{@{} r @{\qquad} | Mc | *{5}{c|}} \hlx{c{2-7} v}
+%          empty & - & 1 & 0 & 0 & 0 & 0                \\ \hlx{v c{2-7} v}
+%       occupied & + & \wide{2}{LINK} & \wide{3}{KEY}   \\ \hlx{v c{2-7}}
+%       \end{tabular}
+%       \endgroup
 %
 % \end{itemize}
 %
@@ -3772,7 +4123,7 @@
 % First, pass the string to another routine.
 %
 %    \begin{macrocode}
-\def\hlx{\noalign\tab@rulewd\hlx@prep}
+\def\hlx{\noalign\tab@ruleparams\hlx@prep}
 \def\hlx@prep#1{\hlx@loop#1\q@delim}
 %    \end{macrocode}
 %
@@ -3815,12 +4166,9 @@
 %    \begin{macrocode}
 \hlxdef h#1{%
   \noalign{%
-    \ifx#1h%
-      \def\@tempa{\hline@prep\hline@prep\hlx@loop}%
-    \else%
-      \def\@tempa{\hline@prep\hlx@loop#1}%
-    \fi%
-    \expandafter
+    \ifx#1h\def\@tempa{\hline@prep\hline@prep\hlx@loop}%
+    \else\def\@tempa{\hline@prep\hlx@loop#1}%
+    \fi\expandafter
   }%
   \@tempa%
 }
@@ -3844,43 +4192,39 @@
 % The `"/"' character allows a page break at the current position.
 %
 %    \begin{macrocode}
-\hlxdef /{%
-  \noalign{\ifnum0=`}\fi%
-  \@ifnextchar[\hlx@cmd@break@i{\hlx@cmd@break@i[0]}%
-}
-\def\hlx@cmd@break@i[#1]{\ifnum0=`{\fi}\pagebreak[0]\hlx@loop}
+\hlxdef /{\noalign{\ifnum0=`}\fi\@testopt\hlx@cmd@break@i0}
+\def\hlx@cmd@break@i[#1]{\ifnum0=`{\fi}\pagebreak[#1]\hlx@loop}
 %    \end{macrocode}
 %
 % \end{macro}
 %
 % \begin{macro}{\hlx v}
+% \begin{macro}{\hlx z}
 %
-% Handle a \lit{v} character.  This is rather like the |\vgap| code above,
-% although there are syntactic differences.
+% Handle a \lit{v} or \lit{z} character.  This is rather like the |\vgap|
+% code above, although there are syntactic differences.
 %
 %    \begin{macrocode}
-\hlxdef v{%
+\hlxdef v{\hlx@vgap\doublerulesep}
+\hlxdef z{\hlx@vgap\tab@rulewidth}
+\def\hlx@vgap#1{%
   \noalign{\nobreak}%
   \omit%
   \iffalse{\fi\ifnum0=`}\fi%
   \global\let\vgap@after\hlx@loop%
-  \@ifnextchar[\hlx@vgap@i{\hlx@vgap@ii\vgap@simple}%
+  \@ifnextchar[{\hlx@vgap@i{#1}}{\hlx@vgap@ii\vgap@simple{#1}}%
 }
-\def\hlx@vgap@i[#1]{%
-  \ifx!#1!%
-    \def\@tempa{\hlx@vgap@ii\vgap@simple}%
-  \else%
-    \def\@tempa{\hlx@vgap@ii{\vgap@spec{#1}}}%
-  \fi%
+\def\hlx@vgap@i#1[#2]{%
+  \ifx!#2!\def\@tempa{\hlx@vgap@ii\vgap@simple{#1}}%
+  \else\def\@tempa{\hlx@vgap@ii{\vgap@spec{#2}}{#1}}\fi%
   \@tempa%
 }
-\def\hlx@vgap@ii#1{%
-  \@ifnextchar[{\hlx@vgap@iii{#1}}{\hlx@vgap@iii{#1}[\doublerulesep]}%
-}
+\def\hlx@vgap@ii#1#2{\@testopt{\hlx@vgap@iii{#1}}{#2}}
 \def\hlx@vgap@iii#1[#2]{#1{#2}}
 %    \end{macrocode}
 %
 % \end{macro}
+% \end{macro}
 %
 % \begin{macro}{\hlx s}
 %
@@ -3890,7 +4234,7 @@
 \hlxdef s{%
   \noalign{\ifnum0=`}\fi%
   \nobreak%
-  \@ifnextchar[\hlx@space@i{\hlx@space@i[\doublerulesep]}%
+  \@testopt\hlx@space@i\doublerulesep%
 }
 \def\hlx@space@i[#1]{%
   \vskip#1%
@@ -3904,10 +4248,34 @@
 %
 % \begin{macro}{\hlx c}
 %
-% We might as well allow a \lit{c} command to do a |\cline|.
+% We might as well allow a \lit{c} command to do a |\cline|.  The fix to
+% |\cline| permeates here.
 %
 %    \begin{macrocode}
-\hlxdef c#1{\cline@prep{#1}\hlx@loop}
+\hlxdef c#1{\cline@do{#1}\hlx@loop}
+%    \end{macrocode}
+%
+% \end{macro}
+%
+% \begin{macro}{\hlx ?}
+%
+% Do some arbitrary stuff which won't typeset.  Put the stuff in a box which
+% is discarded, just in case.
+%
+%    \begin{macrocode}
+\hlxdef ?#1{%
+  \noalign{\setbox\z@\hbox{\color@begingroup#1\color@endgroup}}\hlx@loop%
+}
+%    \end{macrocode}
+%
+% \end{macro}
+%
+% \begin{macro}{\hlx !}
+%
+% Change parameters in mid-flow.
+%
+%    \begin{macrocode}
+\hlxdef !#1{\noalign\tab@ruleparams\hlx@loop[{#1}]}
 %    \end{macrocode}
 %
 % \end{macro}
@@ -3937,6 +4305,20 @@
 %
 % \end{macro}
 %
+% \begin{macro}{\hlx +}
+% \begin{macro}{\nextrow}
+%
+% The \lit{+} subcommand just steps the table-row counter.
+%
+%    \begin{macrocode}
+\hlxdef +{\nextrow\hlx@loop}
+\def\nextrow{\noalign{\ifnum0=`}\fi\@testopt\nextrow@i\@ne}
+\def\nextrow@i[#1]{\global\advance\c@tabrow#1\ifnum0=`{\fi}}
+%    \end{macrocode}
+%
+% \end{macro}
+% \end{macro}
+%
 %
 % \subsection{Starting new table rows}
 %
@@ -4042,13 +4424,8 @@
   \iffalse{\fi\ifnum0=`}\fi%
   \@ifstar{\tab@cr@i{#1}{#3}}{\tab@cr@i{#1}{#2}}%
 }
-\def\tab@cr@i#1#2{%
-  \@ifnextchar[{\tab@cr@ii{#1}{#2}}{\tab@cr@ii{#1}{#2}[\z@]}%
-}
-\def\tab@cr@ii#1#2[#3]{%
-  \ifnum0=`{}\fi%
-  #1{#3}{#2}%
-}
+\def\tab@cr@i#1#2{\@testopt{\tab@cr@ii{#1}{#2}}\z@}
+\def\tab@cr@ii#1#2[#3]{\ifnum0=`{}\fi#1{#3}{#2}}
 %    \end{macrocode}
 %
 % \end{macro}
@@ -4181,6 +4558,18 @@
 }
 %    \end{macrocode}
 %
+%
+% \subsection{Loading the colour package}
+%
+% If requested, we load the \package{mtcolour} package here.  This ensures
+% that it can patch this code if it needs to.
+%
+%    \begin{macrocode}
+\iftab@colour
+  \RequirePackage{mtcolour}
+\fi
+%    \end{macrocode}
+%
 % That's it.  No more.  Move along please.
 %
 %    \begin{macrocode}
@@ -4189,6 +4578,247 @@
 %
 %
 %^^A-------------------------------------------------------------------------
+% \section{Implementation of \package{mtcolour}}
+%
+%
+% This is in a separate package to avoid dragging in the \package{color}
+% package if it's unwanted.
+%
+% I prefer English spellings.  Here's a trivial redirection for Americans.
+%
+%    \begin{macrocode}
+%<*color>
+\DeclareOption*{\PassOptionsToPackage{\CurrentOption}{mtcolour}}
+\ProcessOptions
+\RequirePackage{mtcolour}
+%
+%    \end{macrocode}
+%
+% And now we can start the thing properly.
+%
+%    \begin{macrocode}
+%<*colour>
+\RequirePackage{color}
+%    \end{macrocode}
+%
+%
+% \subsection{Cell background colours}
+%
+% First, some simple preliminaries.  The |\iftab@colour| switch is set if the
+% current cell is meant to have a colour.
+%
+%    \begin{macrocode}
+\newif\iftab@colour
+\tab@colourfalse
+%    \end{macrocode}
+%
+% We shall store the cell colour information in |\tab@cellcolour|, and the
+% row colour information as |\tab@rowcolour|.  Because of the structure of
+% tables, we need to make global assignments; so we must copy the current
+% value away at the start of a table and put the value back at the end.  In
+% order to transfer the overhang information reliably, we use a separate
+% control sequence |\tab@colouroverhangs| for that -- otherwise |\color| can
+% corrupt it.
+%
+%    \begin{macrocode}
+\tab@addhookbefore\tab@beginhook{%
+  \let\tab@saverowcolour\tab@rowcolour%
+  \let\tab@savecolouroverhangs\tab@colouroverhangs%
+  \let\tab@savecellcolour\tab@cellcolour%
+}
+\tab@addhookafter\tab@endhook{%
+  \global\let\tab@rowcolour\tab@saverowcolour%
+  \global\let\tab@colouroverhangs\tab@savecolouroverhangs%
+  \global\let\tab@cellcolour\tab@savecellcolour%
+}
+%    \end{macrocode}
+%
+% Initially, there are no colours.
+%
+%    \begin{macrocode}
+\let\tab@rowcolour\@empty%
+\let\tab@cellcolour\@empty%
+\let\tab@colouroverhangs\@empty%
+%    \end{macrocode}
+%
+% \begin{macro}{\@snarfcolour}
+%
+% Reading a colour specification is something we'll need to do a few times,
+% so an abstraction is useful.  Its single argument is a continuation to
+% which we pass a colour-spec acceptable to the |\color| command.  (This is
+% the same code as found in the \package{sverb} package.  Remember to keep
+% them in step.)
+%
+%    \begin{macrocode}
+\def\@snarfcolour#1{%
+  \@ifnextchar[{\@snarfcolour@i{#1}}{\@snarfcolour@ii{#1}{}}%
+}
+\def\@snarfcolour@i#1[#2]{\@snarfcolour@ii{#1}{[#2]}}
+\def\@snarfcolour@ii#1#2#3{#1{#2{#3}}}
+%    \end{macrocode}
+%
+% \end{macro}
+%
+% \begin{macro}{\cellcolour}
+%
+% Setting a cell colour is a matter of stashing the right declarations in
+% |\tab@cellcolour| and |\tab@colouroverhangs|.  Note that the overhangs end
+% up in |\dimen0| and |\dimen2|.
+%
+%    \begin{macrocode}
+\def\cellcolour{%
+  \@ifstar{\tab@ccol@i{\let\tab@rowcolour\@empty}}{\tab@ccol@i{}}%
+}
+\def\tab@ccol@i#1{\@snarfcolour{\tab@ccol@ii{#1}}}
+\def\tab@ccol@ii#1#2{\@testopt{\tab@ccol@iii{#2#1}}\z@}
+\def\tab@ccol@iii#1[#2]{\@testopt{\tab@ccol@iv{#1}{#2}}{#2}}
+\def\tab@ccol@iv#1#2[#3]{%
+  \gdef\tab@cellcolour{\color#1\tab@colourtrue}%
+  \gdef\tab@colouroverhangs{%
+    \setlength\dimen@{#2}%
+    \setlength{\dimen\tw@}{#3}%
+  }%
+}
+%    \end{macrocode}
+%
+% \end{macro}
+%
+% \begin{macro}{\rowcolour}
+%
+% Setting the global row colour is simpler, because we don't mess with
+% overhangs.
+%
+%    \begin{macrocode}
+\def\rowcolour{\@snarfcolour\tab@setrowcolour}
+\let\rowcolor\rowcolour
+\def\tab@setrowcolour#1{%
+  \gdef\tab@rowcolour{\color#1\tab@colourtrue}%
+}
+%    \end{macrocode}
+%
+% \end{macro}
+%
+% \begin{macro}{\rowcolouroff}
+%
+% And turning the global colouring off is easy.
+%
+%    \begin{macrocode}
+\def\rowcolouroff{\global\let\tab@rowcolour\@empty}
+\let\rowcoloroff\rowcolouroff
+%    \end{macrocode}
+%
+% \end{macro}
+%
+% \begin{macro}{\tab@colourleft}
+%
+% Now we start on the table-cell hooks.  The left hook starts a box which
+% will capture the cell's text and natural width.  We add the hook to the
+% rule list as well, so that we can colour the bits in |\vgap|s correctly.
+%
+%    \begin{macrocode}
+\tab@addhookbefore\tab@lefttexthook\tab@colourleft
+\tab@addhookbefore\tab@leftruletexthook\tab@colourleft
+\def\tab@colourleft{%
+  \global\let\tab@cellcolour\@empty%
+  \global\let\tab@colouroverhangs\@empty%
+  \setbox\z@\hbox\bgroup\color@begingroup%
+}
+%    \end{macrocode}
+%
+% \end{macro}
+%
+% \begin{macro}{\tab@colourright}
+%
+% The right hook will insert an appropriate rule behind the cell and
+% retypeset the cell contents over the top.  Note that the stretch in a table
+% cell is exactly 1\,fil.  Because we add (leaders) and subtract (negative
+% |\hskip|) 1\,fil, we retain this stretch exactly.  Don't bother unless
+% there's actually some colouring.
+%
+%    \begin{macrocode}
+\tab@addhookafter\tab@righttexthook\tab@colourright
+\tab@addhookafter\tab@rightruletexthook\tab@colourright
+\def\tab@colourright{%
+  \color@endgroup\egroup%
+  \color@begingroup%
+  \global\tab@colourfalse%
+  \tab@cellcolour\tab@rowcolour%
+  \dimen@\z@\dimen\tw@\z@\tab@colouroverhangs%
+  \iftab@colour%
+    \skip@\wd\z@\advance\skip@\z@\@plus1fil%
+    \skip\tw@\skip@%
+    \kern-\dimen@%
+    \advance\skip\tw@\dimen@%
+    \advance\skip\tw@\dimen\tw@%
+    \leaders\vrule\hskip\skip\tw@%
+    \kern-\dimen\tw@%
+    \hskip-\skip@%
+  \fi%
+  \color@endgroup%
+  \unhbox\z@%
+}
+%    \end{macrocode}
+%
+% \end{macro}
+%
+%
+% \subsection{Coloured rules}
+%
+% We hook ourselves onto the rule-parameters edifice.  This is rather
+% straightforward.
+%
+%    \begin{macrocode}
+\tab@addhookafter\tab@rp@inithook{%
+  \let\tab@rulecolour\@empty%
+  \let\tab@rulecolourmodel\@empty%
+}
+\mkdef{mdwtab:rule}{colour}{\tab@setrulecolour{#1}}
+\mkdef{mdwtab:rule}{colourmodel}{\tab@setrulecolourmodel{#1}}
+\mkdef{mdwtab:rule}{color}{\tab@setrulecolour{#1}}
+\mkdef{mdwtab:rule}{colormodel}{\tab@setrulecolourmodel{#1}}
+\mkdef{mdwtab:rule}{nocolour}*{\let\tab@rulecolour\@empty}
+\mkdef{mdwtab:rule}{nocolor}*{\let\tab@rulecolour\@empty}
+\mkdef{mdwtab:rule}{nocolourmodel}*{\let\tab@rulecolourmodel\@empty}
+\mkdef{mdwtab:rule}{nocolormodel}*{\let\tab@rulecolourmodel\@empty}
+\def\tab@setrulecolour#1{%
+  \def\tab@rulecolour{\color\tab@rulecolourmodel{#1}}%
+}
+\def\tab@setrulecolourmodel#1{\def\tab@rulecolourmodel{[#1]}}
+\tab@addhookafter\tab@rp@sethook{\tab@rulecolour}
+%    \end{macrocode}
+%
+%
+% \subsection{Other stuff}
+%
+% \begin{macro}{\ifmod}
+%
+% \syntax{"\\ifmod{"$x$"}{"$m$"}{"y"}{""}{""}"} -- if $x \bmod m =
+% y$ then do \; otherwise do \.
+%
+%    \begin{macrocode}
+\def\ifmod#1#2#3{%
+  \begingroup%
+  \@tempcnta#1%
+  \@tempcntb#2%
+  \count@\@tempcnta%
+  \divide\count@\@tempcntb%
+  \multiply\count@\@tempcntb%
+  \advance\@tempcnta-\count@%
+  \count@#3\relax%
+  \ifnum\@tempcnta=\count@\endgroup\expandafter\@firstoftwo%
+  \else\endgroup\expandafter\@secondoftwo\fi%
+}
+%    \end{macrocode}
+%
+% \end{macro}
+%
+% Done.
+%
+%    \begin{macrocode}
+%
+%    \end{macrocode}
+%
+%^^A-------------------------------------------------------------------------
 % \section{Implementation of \package{mathenv}}
 %
 %
@@ -4255,7 +4885,7 @@
   \if@fleqn%
     \eqaopenskip\mathindent%
     \splitleft\mathindent\relax%
-    \splitright\mathindent\@minus\mathindent\relax%  
+    \splitright\mathindent\@minus\mathindent\relax%
   \else%
     \eqaopenskip\@centering%
     \splitleft2.5em\@minus2.5em%
@@ -4392,7 +5022,7 @@
   \eqnarray@i\eqa@eqcount%
 }
 \@namedef{eqnarray*}{\eqnarray@i{}}
-\def\eqnarray@i#1{\@ifnextchar[{\eqnarray@ii{#1}}{\eqnarray@ii{#1}[rcl]}}
+\def\eqnarray@i#1{\@testopt{\eqnarray@ii{#1}}{rcl}}
 %    \end{macrocode}
 %
 % Right.  Now for the real work.  The first argument is the default numbering
@@ -4517,7 +5147,7 @@
 % \end{environment}
 % \end{environment}
 %
-% Now we can define the column types. 
+% Now we can define the column types.
 %
 %    \begin{macrocode}
 \colpush{eqnarray}
@@ -4602,13 +5232,13 @@
 % The macro |\eqa@eqpos| will put its argument in the right place.
 %
 %    \begin{macrocode}
-\if@leqno
-  \def\eqa@eqpos#1{%
+\def\eqa@eqpos#1{%
+  \if@leqno%
     \hb@xt@.01\p@{}\rlap{\normalfont\normalcolor\hskip-\displaywidth#1}%
-  }
-\else
-  \def\eqa@eqpos#1{\normalfont\normalcolor#1}
-\fi
+  \else%
+    \normalfont\normalcolor#1%
+  \fi%
+}
 %    \end{macrocode}
 %
 % \end{macro}
@@ -4716,10 +5346,8 @@
 % First, sort out some simple things like optional arguments.
 %
 %    \begin{macrocode}
-\def\eqnalign{\@ifnextchar[\eqnalign@i{\eqnalign@i[rcl]}}
-\def\eqnalign@i[#1]{%
-  \@ifnextchar[{\eqnalign@ii{#1}}{\eqnalign@ii{#1}[c]}%
-}
+\def\eqnalign{\@testopt\eqnalign@i{rcl}}
+\def\eqnalign@i[#1]{\@testopt{\eqnalign@ii{#1}}c}
 %    \end{macrocode}
 %
 % Now we actually do the environment.  This is fairly easy, actually.
@@ -4862,6 +5490,7 @@
   \dsp@end%
   \global\let\eqa@number\eqa@oldnumber%
   \global\advance\c@equation\m@ne%
+  \global\@ignoretrue%
 }
 \expandafter\let\csname endspliteqn*\endcsname\endspliteqn
 %    \end{macrocode}
@@ -4952,9 +5581,13 @@
 % we need to remove them by hand at the extremities of the environment.
 %
 %    \begin{macrocode}
-\def\subsplit{%
+\def\subsplit{\@ifnextchar[\subsplit@i{\subsplit@i[c]}}
+\def\subsplit@i[#1]{%
+  \let\@tempa\vcenter%
+  \if#1t\let\@tempa\vtop\fi%
+  \if#1b\let\@tempa\vbox\fi%
   \let\\\seq@cr%
-  \vcenter\bgroup%
+  \@tempa\bgroup%
   \seq@dosplit{\hfil\qquad$##$\qquad\hfil}{\hfilneg\hskip-2em}%
 }
 %    \end{macrocode}
@@ -5167,7 +5800,7 @@
 % columns.
 %
 %    \begin{macrocode}
-  \@ifnextchar[\genmatrix@i{\genmatrix@i[[c]}%
+  \@testopt\genmatrix@i{[c}%
 }
 %    \end{macrocode}
 %
@@ -5331,7 +5964,7 @@
   \def\mat@right{\egroup}%
   \let\mat@font\scriptfont%
   \let\mat@textsize\scriptsize%
-  \@ifnextchar[\genmatrix@i{\genmatrix@i[c]}%
+  \@testopt\genmatrix@i c%
 }
 \let\endscript\endgenmatrix
 %    \end{macrocode}