[f66f990] | 1 | \NeedsTeXFormat{LaTeX2e} |
---|
| 2 | \ProvidesPackage{sphinxmulticell}% |
---|
| 3 | [2017/02/23 v1.6 better span rows and columns of a table (Sphinx team)]% |
---|
| 4 | \DeclareOption*{\PackageWarning{sphinxmulticell}{Option `\CurrentOption' is unknown}}% |
---|
| 5 | \ProcessOptions\relax |
---|
| 6 | % |
---|
| 7 | % --- MULTICOLUMN --- |
---|
| 8 | % standard LaTeX's \multicolumn |
---|
| 9 | % 1. does not allow verbatim contents, |
---|
| 10 | % 2. interacts very poorly with tabulary. |
---|
| 11 | % |
---|
| 12 | % It is needed to write own macros for Sphinx: to allow code-blocks in merged |
---|
| 13 | % cells rendered by tabular/longtable, and to allow multi-column cells with |
---|
| 14 | % paragraphs to be taken into account sanely by tabulary algorithm for column |
---|
| 15 | % widths. |
---|
| 16 | % |
---|
| 17 | % This requires quite a bit of hacking. First, in Sphinx, the multi-column |
---|
| 18 | % contents will *always* be wrapped in a varwidth environment. The issue |
---|
| 19 | % becomes to pass it the correct target width. We must trick tabulary into |
---|
| 20 | % believing the multicolumn is simply separate columns, else tabulary does not |
---|
| 21 | % incorporate the contents in its algorithm. But then we must clear the |
---|
| 22 | % vertical rules... |
---|
| 23 | % |
---|
| 24 | % configuration of tabulary |
---|
| 25 | \setlength{\tymin}{3\fontcharwd\font`0 }% minimal width of "squeezed" columns |
---|
| 26 | \setlength{\tymax}{10000pt}% allow enough room for paragraphs to "compete" |
---|
| 27 | % we need access to tabulary's final computed width. \@tempdima is too volatile |
---|
| 28 | % to hope it has kept tabulary's value when \sphinxcolwidth needs it. |
---|
| 29 | \newdimen\sphinx@TY@tablewidth |
---|
| 30 | \def\tabulary{% |
---|
| 31 | \def\TY@final{\sphinx@TY@tablewidth\@tempdima\tabular}% |
---|
| 32 | \let\endTY@final\endtabular |
---|
| 33 | \TY@tabular}% |
---|
| 34 | % next hack is needed only if user has set latex_use_latex_multicolumn to True: |
---|
| 35 | % it fixes tabulary's bug with \multicolumn defined "short" in first pass. (if |
---|
| 36 | % upstream tabulary adds a \long, our extra one causes no harm) |
---|
| 37 | \def\sphinx@tempa #1\def\multicolumn#2#3#4#5#6#7#8#9\sphinx@tempa |
---|
| 38 | {\def\TY@tab{#1\long\def\multicolumn####1####2####3{\multispan####1\relax}#9}}% |
---|
| 39 | \expandafter\sphinx@tempa\TY@tab\sphinx@tempa |
---|
| 40 | % |
---|
| 41 | % TN. 1: as \omit is never executed, Sphinx multicolumn does not need to worry |
---|
| 42 | % like standard multicolumn about |l| vs l|. On the other hand it assumes |
---|
| 43 | % columns are separated by a | ... (if not it will add extraneous |
---|
| 44 | % \arrayrulewidth space for each column separation in its estimate of available |
---|
| 45 | % width). |
---|
| 46 | % |
---|
| 47 | % TN. 1b: as Sphinx multicolumn uses neither \omit nor \span, it can not |
---|
| 48 | % (easily) get rid of extra macros from >{...} or <{...} between columns. At |
---|
| 49 | % least, it has been made compatible with colortbl's \columncolor. |
---|
| 50 | % |
---|
| 51 | % TN. 2: tabulary's second pass is handled like tabular/longtable's single |
---|
| 52 | % pass, with the difference that we hacked \TY@final to set in |
---|
| 53 | % \sphinx@TY@tablewidth the final target width as computed by tabulary. This is |
---|
| 54 | % needed only to handle columns with a "horizontal" specifier: "p" type columns |
---|
| 55 | % (inclusive of tabulary's LJRC) holds the target column width in the |
---|
| 56 | % \linewidth dimension. |
---|
| 57 | % |
---|
| 58 | % TN. 3: use of \begin{sphinxmulticolumn}...\end{sphinxmulticolumn} mark-up |
---|
| 59 | % would need some hacking around the fact that groups can not span across table |
---|
| 60 | % cells (the code does inserts & tokens, see TN1b). It was decided to keep it |
---|
| 61 | % simple with \sphinxstartmulticolumn...\sphinxstopmulticolumn. |
---|
| 62 | % |
---|
| 63 | % MEMO about nesting: if sphinxmulticolumn is encountered in a nested tabular |
---|
| 64 | % inside a tabulary it will think to be at top level in the tabulary. But |
---|
| 65 | % Sphinx generates no nested tables, and if some LaTeX macro uses internally a |
---|
| 66 | % tabular this will not have a \sphinxstartmulticolumn within it! |
---|
| 67 | % |
---|
| 68 | \def\sphinxstartmulticolumn{% |
---|
| 69 | \ifx\equation$% $ tabulary's first pass |
---|
| 70 | \expandafter\sphinx@TYI@start@multicolumn |
---|
| 71 | \else % either not tabulary or tabulary's second pass |
---|
| 72 | \expandafter\sphinx@start@multicolumn |
---|
| 73 | \fi |
---|
| 74 | }% |
---|
| 75 | \def\sphinxstopmulticolumn{% |
---|
| 76 | \ifx\equation$% $ tabulary's first pass |
---|
| 77 | \expandafter\sphinx@TYI@stop@multicolumn |
---|
| 78 | \else % either not tabulary or tabulary's second pass |
---|
| 79 | \ignorespaces |
---|
| 80 | \fi |
---|
| 81 | }% |
---|
| 82 | \def\sphinx@TYI@start@multicolumn#1{% |
---|
| 83 | % use \gdef always to avoid stack space build up |
---|
| 84 | \gdef\sphinx@tempa{#1}\begingroup\setbox\z@\hbox\bgroup |
---|
| 85 | }% |
---|
| 86 | \def\sphinx@TYI@stop@multicolumn{\egroup % varwidth was used with \tymax |
---|
| 87 | \xdef\sphinx@tempb{\the\dimexpr\wd\z@/\sphinx@tempa}% per column width |
---|
| 88 | \endgroup |
---|
| 89 | \expandafter\sphinx@TYI@multispan\expandafter{\sphinx@tempa}% |
---|
| 90 | }% |
---|
| 91 | \def\sphinx@TYI@multispan #1{% |
---|
| 92 | \kern\sphinx@tempb\ignorespaces % the per column occupied width |
---|
| 93 | \ifnum#1>\@ne % repeat, taking into account subtleties of TeX's & ... |
---|
| 94 | \expandafter\sphinx@TYI@multispan@next\expandafter{\the\numexpr#1-\@ne\expandafter}% |
---|
| 95 | \fi |
---|
| 96 | }% |
---|
| 97 | \def\sphinx@TYI@multispan@next{&\relax\sphinx@TYI@multispan}% |
---|
| 98 | % |
---|
| 99 | % Now the branch handling either the second pass of tabulary or the single pass |
---|
| 100 | % of tabular/longtable. This is the delicate part where we gather the |
---|
| 101 | % dimensions from the p columns either set-up by tabulary or by user p column |
---|
| 102 | % or Sphinx \X, \Y columns. The difficulty is that to get the said width, the |
---|
| 103 | % template must be inserted (other hacks would be horribly complicated except |
---|
| 104 | % if we rewrote crucial parts of LaTeX's \@array !) and we can not do |
---|
| 105 | % \omit\span like standard \multicolumn's easy approach. Thus we must cancel |
---|
| 106 | % the \vrule separators. Also, perhaps the column specifier is of the l, c, r |
---|
| 107 | % type, then we attempt an ad hoc rescue to give varwidth a reasonable target |
---|
| 108 | % width. |
---|
| 109 | \def\sphinx@start@multicolumn#1{% |
---|
| 110 | \gdef\sphinx@multiwidth{0pt}\gdef\sphinx@tempa{#1}\sphinx@multispan{#1}% |
---|
| 111 | }% |
---|
| 112 | \def\sphinx@multispan #1{% |
---|
| 113 | \ifnum#1=\@ne\expandafter\sphinx@multispan@end |
---|
| 114 | \else\expandafter\sphinx@multispan@next |
---|
| 115 | \fi {#1}% |
---|
| 116 | }% |
---|
| 117 | \def\sphinx@multispan@next #1{% |
---|
| 118 | % trick to recognize L, C, R, J or p, m, b type columns |
---|
| 119 | \ifdim\baselineskip>\z@ |
---|
| 120 | \gdef\sphinx@tempb{\linewidth}% |
---|
| 121 | \else |
---|
| 122 | % if in an l, r, c type column, try and hope for the best |
---|
| 123 | \xdef\sphinx@tempb{\the\dimexpr(\ifx\TY@final\@undefined\linewidth\else |
---|
| 124 | \sphinx@TY@tablewidth\fi-\arrayrulewidth)/\sphinx@tempa |
---|
| 125 | -\tw@\tabcolsep-\arrayrulewidth\relax}% |
---|
| 126 | \fi |
---|
| 127 | \noindent\kern\sphinx@tempb\relax |
---|
| 128 | \xdef\sphinx@multiwidth |
---|
| 129 | {\the\dimexpr\sphinx@multiwidth+\sphinx@tempb+\tw@\tabcolsep+\arrayrulewidth}% |
---|
| 130 | % hack the \vline and the colortbl macros |
---|
| 131 | \sphinx@hack@vline\sphinx@hack@CT&\relax |
---|
| 132 | % repeat |
---|
| 133 | \expandafter\sphinx@multispan\expandafter{\the\numexpr#1-\@ne}% |
---|
| 134 | }% |
---|
| 135 | % packages like colortbl add group levels, we need to "climb back up" to be |
---|
| 136 | % able to hack the \vline and also the colortbl inserted tokens. This creates |
---|
| 137 | % empty space whether or not the columns were | separated: |
---|
| 138 | \def\sphinx@hack@vline{\ifnum\currentgrouptype=6\relax |
---|
| 139 | \kern\arrayrulewidth\arrayrulewidth\z@\else\aftergroup\sphinx@hack@vline\fi}% |
---|
| 140 | \def\sphinx@hack@CT{\ifnum\currentgrouptype=6\relax |
---|
| 141 | \let\CT@setup\sphinx@CT@setup\else\aftergroup\sphinx@hack@CT\fi}% |
---|
| 142 | % It turns out \CT@row@color is not expanded contrarily to \CT@column@color |
---|
| 143 | % during LaTeX+colortbl preamble preparation, hence it would be possible for |
---|
| 144 | % \sphinx@CT@setup to discard only the column color and choose to obey or not |
---|
| 145 | % row color and cell color. It would even be possible to propagate cell color |
---|
| 146 | % to row color for the duration of the Sphinx multicolumn... the (provisional?) |
---|
| 147 | % choice has been made to cancel the colortbl colours for the multicolumn |
---|
| 148 | % duration. |
---|
| 149 | \def\sphinx@CT@setup #1\endgroup{\endgroup}% hack to remove colour commands |
---|
| 150 | \def\sphinx@multispan@end#1{% |
---|
| 151 | % first, trace back our steps horizontally |
---|
| 152 | \noindent\kern-\dimexpr\sphinx@multiwidth\relax |
---|
| 153 | % and now we set the final computed width for the varwidth environment |
---|
| 154 | \ifdim\baselineskip>\z@ |
---|
| 155 | \xdef\sphinx@multiwidth{\the\dimexpr\sphinx@multiwidth+\linewidth}% |
---|
| 156 | \else |
---|
| 157 | \xdef\sphinx@multiwidth{\the\dimexpr\sphinx@multiwidth+ |
---|
| 158 | (\ifx\TY@final\@undefined\linewidth\else |
---|
| 159 | \sphinx@TY@tablewidth\fi-\arrayrulewidth)/\sphinx@tempa |
---|
| 160 | -\tw@\tabcolsep-\arrayrulewidth\relax}% |
---|
| 161 | \fi |
---|
| 162 | % we need to remove colour set-up also for last cell of the multi-column |
---|
| 163 | \aftergroup\sphinx@hack@CT |
---|
| 164 | }% |
---|
| 165 | \newcommand*\sphinxcolwidth[2]{% |
---|
| 166 | % this dimension will always be used for varwidth, and serves as maximum |
---|
| 167 | % width when cells are merged either via multirow or multicolumn or both, |
---|
| 168 | % as always their contents is wrapped in varwidth environment. |
---|
| 169 | \ifnum#1>\@ne % multi-column (and possibly also multi-row) |
---|
| 170 | % we wrote our own multicolumn code especially to handle that (and allow |
---|
| 171 | % verbatim contents) |
---|
| 172 | \ifx\equation$%$ |
---|
| 173 | \tymax % first pass of tabulary (cf MEMO above regarding nesting) |
---|
| 174 | \else % the \@gobble thing is for compatibility with standard \multicolumn |
---|
| 175 | \sphinx@multiwidth\@gobble{#1/#2}% |
---|
| 176 | \fi |
---|
| 177 | \else % single column multirow |
---|
| 178 | \ifx\TY@final\@undefined % not a tabulary. |
---|
| 179 | \ifdim\baselineskip>\z@ |
---|
| 180 | % in a p{..} type column, \linewidth is the target box width |
---|
| 181 | \linewidth |
---|
| 182 | \else |
---|
| 183 | % l, c, r columns. Do our best. |
---|
| 184 | \dimexpr(\linewidth-\arrayrulewidth)/#2- |
---|
| 185 | \tw@\tabcolsep-\arrayrulewidth\relax |
---|
| 186 | \fi |
---|
| 187 | \else % in tabulary |
---|
| 188 | \ifx\equation$%$% first pass |
---|
| 189 | \tymax % it is set to a big value so that paragraphs can express themselves |
---|
| 190 | \else |
---|
| 191 | % second pass. |
---|
| 192 | \ifdim\baselineskip>\z@ |
---|
| 193 | \linewidth % in a L, R, C, J column or a p, \X, \Y ... |
---|
| 194 | \else |
---|
| 195 | % we have hacked \TY@final to put in \sphinx@TY@tablewidth the table width |
---|
| 196 | \dimexpr(\sphinx@TY@tablewidth-\arrayrulewidth)/#2- |
---|
| 197 | \tw@\tabcolsep-\arrayrulewidth\relax |
---|
| 198 | \fi |
---|
| 199 | \fi |
---|
| 200 | \fi |
---|
| 201 | \fi |
---|
| 202 | }% |
---|
| 203 | % fallback default in case user has set latex_use_latex_multicolumn to True: |
---|
| 204 | % \sphinxcolwidth will use this only inside LaTeX's standard \multicolumn |
---|
| 205 | \def\sphinx@multiwidth #1#2{\dimexpr % #1 to gobble the \@gobble (!) |
---|
| 206 | (\ifx\TY@final\@undefined\linewidth\else\sphinx@TY@tablewidth\fi |
---|
| 207 | -\arrayrulewidth)*#2-\tw@\tabcolsep-\arrayrulewidth\relax}% |
---|
| 208 | % |
---|
| 209 | % --- MULTIROW --- |
---|
| 210 | % standard \multirow |
---|
| 211 | % 1. does not allow verbatim contents, |
---|
| 212 | % 2. does not allow blank lines in its argument, |
---|
| 213 | % 3. its * specifier means to typeset "horizontally" which is very |
---|
| 214 | % bad for paragraph content. 2016 version has = specifier but it |
---|
| 215 | % must be used with p type columns only, else results are bad, |
---|
| 216 | % 4. it requires manual intervention if the contents is too long to fit |
---|
| 217 | % in the asked-for number of rows. |
---|
| 218 | % 5. colour panels (either from \rowcolor or \columncolor) will hide |
---|
| 219 | % the bottom part of multirow text, hence manual tuning is needed |
---|
| 220 | % to put the multirow insertion at the _bottom_. |
---|
| 221 | % |
---|
| 222 | % The Sphinx solution consists in always having contents wrapped |
---|
| 223 | % in a varwidth environment so that it makes sense to estimate how many |
---|
| 224 | % lines it will occupy, and then ensure by insertion of suitable struts |
---|
| 225 | % that the table rows have the needed height. The needed mark-up is done |
---|
| 226 | % by LaTeX writer, which has its own id for the merged cells. |
---|
| 227 | % |
---|
| 228 | % The colour issue is solved by clearing colour panels in all cells, |
---|
| 229 | % whether or not the multirow is single-column or multi-column. |
---|
| 230 | % |
---|
| 231 | % In passing we obtain baseline alignements across rows (only if |
---|
| 232 | % \arraylinestretch is 1, as LaTeX's does not obey \arraylinestretch in "p" |
---|
| 233 | % multi-line contents, only first and last line...) |
---|
| 234 | % |
---|
| 235 | % TODO: examine the situation with \arraylinestretch > 1. The \extrarowheight |
---|
| 236 | % is hopeless for multirow anyhow, it makes baseline alignment strictly |
---|
| 237 | % impossible. |
---|
| 238 | \newcommand\sphinxmultirow[2]{\begingroup |
---|
| 239 | % #1 = nb of spanned rows, #2 = Sphinx id of "cell", #3 = contents |
---|
| 240 | % but let's fetch #3 in a way allowing verbatim contents ! |
---|
| 241 | \def\sphinx@nbofrows{#1}\def\sphinx@cellid{#2}% |
---|
| 242 | \afterassignment\sphinx@multirow\let\next= |
---|
| 243 | }% |
---|
| 244 | \def\sphinx@multirow {% |
---|
| 245 | \setbox\z@\hbox\bgroup\aftergroup\sphinx@@multirow\strut |
---|
| 246 | }% |
---|
| 247 | \def\sphinx@@multirow {% |
---|
| 248 | % The contents, which is a varwidth environment, has been captured in |
---|
| 249 | % \box0 (a \hbox). |
---|
| 250 | % We have with \sphinx@cellid an assigned unique id. The goal is to give |
---|
| 251 | % about the same height to all the involved rows. |
---|
| 252 | % For this Sphinx will insert a \sphinxtablestrut{cell_id} mark-up |
---|
| 253 | % in LaTeX file and the expansion of the latter will do the suitable thing. |
---|
| 254 | \dimen@\dp\z@ |
---|
| 255 | \dimen\tw@\ht\@arstrutbox |
---|
| 256 | \advance\dimen@\dimen\tw@ |
---|
| 257 | \advance\dimen\tw@\dp\@arstrutbox |
---|
| 258 | \count@=\dimen@ % type conversion dim -> int |
---|
| 259 | \count\tw@=\dimen\tw@ |
---|
| 260 | \divide\count@\count\tw@ % TeX division truncates |
---|
| 261 | \advance\dimen@-\count@\dimen\tw@ |
---|
| 262 | % 1300sp is about 0.02pt. For comparison a rule default width is 0.4pt. |
---|
| 263 | % (note that if \count@ holds 0, surely \dimen@>1300sp) |
---|
| 264 | \ifdim\dimen@>1300sp \advance\count@\@ne \fi |
---|
| 265 | % now \count@ holds the count L of needed "lines" |
---|
| 266 | % and \sphinx@nbofrows holds the number N of rows |
---|
| 267 | % we have L >= 1 and N >= 1 |
---|
| 268 | % if L is a multiple of N, ... clear what to do ! |
---|
| 269 | % else write L = qN + r, 1 <= r < N and we will |
---|
| 270 | % arrange for each row to have enough space for: |
---|
| 271 | % q+1 "lines" in each of the first r rows |
---|
| 272 | % q "lines" in each of the (N-r) bottom rows |
---|
| 273 | % for a total of (q+1) * r + q * (N-r) = q * N + r = L |
---|
| 274 | % It is possible that q == 0. |
---|
| 275 | \count\tw@\count@ |
---|
| 276 | % the TeX division truncates |
---|
| 277 | \divide\count\tw@\sphinx@nbofrows\relax |
---|
| 278 | \count4\count\tw@ % q |
---|
| 279 | \multiply\count\tw@\sphinx@nbofrows\relax |
---|
| 280 | \advance\count@-\count\tw@ % r |
---|
| 281 | \expandafter\xdef\csname sphinx@tablestrut_\sphinx@cellid\endcsname |
---|
| 282 | {\noexpand\sphinx@tablestrut{\the\count4}{\the\count@}{\sphinx@cellid}}% |
---|
| 283 | \dp\z@\z@ |
---|
| 284 | % this will use the real height if it is >\ht\@arstrutbox |
---|
| 285 | \sphinxtablestrut{\sphinx@cellid}\box\z@ |
---|
| 286 | \endgroup % group was opened in \sphinxmultirow |
---|
| 287 | }% |
---|
| 288 | \newcommand*\sphinxtablestrut[1]{% |
---|
| 289 | % #1 is a "cell_id", i.e. the id of a merged group of table cells |
---|
| 290 | \csname sphinx@tablestrut_#1\endcsname |
---|
| 291 | }% |
---|
| 292 | % LaTeX typesets the table row by row, hence each execution can do |
---|
| 293 | % an update for the next row. |
---|
| 294 | \newcommand*\sphinx@tablestrut[3]{\begingroup |
---|
| 295 | % #1 = q, #2 = (initially) r, #3 = cell_id, q+1 lines in first r rows |
---|
| 296 | % if #2 = 0, create space for max(q,1) table lines |
---|
| 297 | % if #2 > 0, create space for q+1 lines and decrement #2 |
---|
| 298 | \leavevmode |
---|
| 299 | \count@#1\relax |
---|
| 300 | \ifnum#2=\z@ |
---|
| 301 | \ifnum\count@=\z@\count@\@ne\fi |
---|
| 302 | \else |
---|
| 303 | % next row will be with a #2 decremented by one |
---|
| 304 | \expandafter\xdef\csname sphinx@tablestrut_#3\endcsname |
---|
| 305 | {\noexpand\sphinx@tablestrut{#1}{\the\numexpr#2-\@ne}{#3}}% |
---|
| 306 | \advance\count@\@ne |
---|
| 307 | \fi |
---|
| 308 | \vrule\@height\ht\@arstrutbox |
---|
| 309 | \@depth\dimexpr\count@\ht\@arstrutbox+\count@\dp\@arstrutbox-\ht\@arstrutbox\relax |
---|
| 310 | \@width\z@ |
---|
| 311 | \endgroup |
---|
| 312 | % we need this to avoid colour panels hiding bottom parts of multirow text |
---|
| 313 | \sphinx@hack@CT |
---|
| 314 | }% |
---|
| 315 | \endinput |
---|
| 316 | %% |
---|
| 317 | %% End of file `sphinxmulticell.sty'. |
---|