tabl-tsp.mkxl /size: 19 Kb    last modification: 2025-02-21 11:03
1%D \module
2%D   [       file=tabl-tsp,
3%D        version=2000.10.20,
4%D          title=\CONTEXT\ Table Macros,
5%D       subtitle=Splitting,
6%D         author=Hans Hagen,
7%D           date=\currentdate,
8%D      copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
9%C
10%C This module is part of the \CONTEXT\ macro||package and is
11%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
12%C details.
13
14\writestatus{loading}{ConTeXt Table Macros / Splitting}
15
16%D The code in this file is moved here from other places and needs a mkiv cleanup.
17%D As it mostly targets at tables the code lives in the tabl and page namespaces.
18
19% work in progress
20
21\unprotect
22
23%D Although the name resembles floats, and therefore this should be a page module,
24%D we decided to make it core functionality because the table code depends on it.
25%D Othrwise there would be too much overloading afterwards involved. Actually, the
26%D float part is rather generic and not that related to floats.
27
28% \splitfloat [settings] {\placetable[optional args]{test}} {content}
29
30%D When \type {inbetween} is made empty instead of the default \type {\page}, we
31%D will get delayed flushing and text may continue below the graphic.
32%D
33%D \starttyping
34%D \dorecurse{2}{\input tufte }
35%D
36%D \splitfloat[lines=auto,inbetween=]
37%D   {\placetable{\dorecurse{5}{test\recurselevel\endgraf}}}
38%D   {\bTABLE[split=yes]
39%D    \bTR \bTD 11 \eTD \bTD \input tufte \eTD \eTR
40%D    \bTR \bTD 12 \eTD \bTD \input zapf \eTD \eTR
41%D    \bTR \bTD 13 \eTD \bTD \input bryson \eTD \eTR
42%D    \bTR \bTD 14 \eTD \bTD test  \eTD \eTR
43%D    \bTR \bTD 21 \eTD \bTD \input tufte \eTD \eTR
44%D    \bTR \bTD 22 \eTD \bTD \input zapf \eTD \eTR
45%D    \bTR \bTD 23 \eTD \bTD \input bryson \eTD \eTR
46%D    \bTR \bTD 24 \eTD \bTD test  \eTD \eTR
47%D    \bTR \bTD 31 \eTD \bTD \input tufte \eTD \eTR
48%D    \bTR \bTD 32 \eTD \bTD \input zapf \eTD \eTR
49%D    \bTR \bTD 33 \eTD \bTD \input bryson \eTD \eTR
50%D    \bTR \bTD 34 \eTD \bTD test  \eTD \eTR
51%D    \eTABLE}
52%D
53%D \dorecurse{10}{\input tufte }
54%D \stoptyping
55
56\installcorenamespace{floatsplitting}
57
58\installdirectcommandhandler \??floatsplitting {floatsplitting} % \??floatsplitting
59
60\setupfloatsplitting
61  [\c!conversion=\v!character, % \v!romannumerals
62   \c!lines=3,
63   \c!before=,
64   \c!inbetween=\page,
65   \c!after=]
66
67\newconditional\splitfloatfirstdone
68\newconditional\somenextsplitofffloat
69\newconditional\splitfloatdone
70\newconditional\onlyonesplitofffloat   \onlyonesplitofffloat\conditionaltrue
71
72\newif   \ifinsidesplitfloat   % will become conditional
73\newcount\noffloatssplits
74\newtoks \everysplitfloatsetup
75
76\mutable\let\extrasplitfloatlines \!!zerocount
77\mutable\let\splitfloatfinalizer  \relax
78
79\mutable\lettonothing\splitfloatcommand
80\mutable\lettonothing\floatcaptionsuffix
81
82\permanent\tolerant\protected\def\splitfloat[#S#1]#:#2% nog dubbele refs
83  {\bgroup
84   \global\splitfloatdone\conditionalfalse
85   \aftergroup\page_split_float_check
86   \insidefloattrue
87   \insidesplitfloattrue
88   \setupcurrentfloatsplitting[#1]%
89   \global\noffloatssplits\zerocount
90   \let\floatcaptionsuffix\page_split_float_suffix
91   \edef\extrasplitfloatlines{\floatsplittingparameter\c!lines}%
92   \expand\everysplitfloatsetup
93   \def\splitfloatcommand{#2}%
94   \global\onlyonesplitofffloat\conditionaltrue
95   \global\somenextsplitofffloat\conditionalfalse
96   \page_floats_push_saved
97   \floatsplittingparameter\c!before
98   \let\next} % \bgroup
99
100\protected\def\page_split_float_suffix
101  {\begingroup
102   \usefloatsplittingstyleandcolor\c!style\c!color % only the suffix
103   \convertnumber{\floatsplittingparameter\c!conversion}\noffloatssplits
104   \endgroup}
105
106\protected\def\page_split_float_check
107  {\ifconditional\splitfloatdone
108    %\splitfloatfinalizer % a weird place (could interfere with flushing)
109   \else
110     \blank
111     \begingroup
112     \tttf \dontleavehmode \getmessage\m!floatblocks{13}\empty
113     \endgroup
114     \blank
115     \showmessage\m!floatblocks{13}\empty
116   \fi
117   \splitfloatfinalizer} % a weird place (could interfere with flushing)
118
119\def\page_split_float_process % nextbox
120  {\ifinsidesplitfloat
121     \expandafter\page_split_float_process_yes
122   \else
123     \expandafter\page_split_float_process_nop
124   \fi}
125
126\def\page_split_float_process_yes
127  {\dowithnextboxcs\page_split_float_process_finish\vbox}
128
129\def\page_split_float_process_finish
130  {\forgetall
131   \dontcomplain
132   \global\splitfloatdone\conditionaltrue
133 % \nodelocationmode\zerocount % bypass auto-renumbering
134   \global\advanceby\noffloatssplits\plusone
135   \ifcase\noffloatssplits\relax \or
136     \ifconditional\onlyonesplitofffloat
137       \lettonothing\floatcaptionsuffix
138     \fi
139   \fi
140   \bgroup
141     \ifconditional\somenextsplitofffloat
142       \notesenabledfalse % best here, experimental, brrr; test with note in caption
143     \fi
144     \splitfloatcommand{\box\nextbox}%
145   \egroup
146   \ifconditional\somenextsplitofffloat
147     \edef\p_inbetween{\floatsplittingparameter\c!inbetween}%
148     \ifempty\p_inbetween
149       \ifconditional\splitfloatfirstdone\else\page\fi
150     \else
151       \p_inbetween
152     \fi
153   \else
154     \floatsplittingparameter\c!after
155     \page_floats_pop_saved
156     \page_floats_flush_saved
157   \fi
158   \global\splitfloatfirstdone\conditionaltrue}
159
160\def\page_split_float_process_nop
161  {\dowithnextboxcs\page_split_float_process_nop_finish\vbox}
162
163\def\page_split_float_process_nop_finish
164  {\forgetall
165   \dontcomplain
166   \box\nextbox % maybe an option to unvbox
167   \global\splitfloatfirstdone\conditionaltrue}
168
169\def\page_split_float_check_content#1% box
170  {\ifinsidesplitfloat
171   % \ifdim\ht#1=\zeropoint % funny: \ifcase does not check for overflow
172     \ifcase\ht#1\relax
173       \global\somenextsplitofffloat\conditionalfalse
174     \else
175       \global\somenextsplitofffloat\conditionaltrue
176       \global\onlyonesplitofffloat\conditionalfalse
177     \fi
178   \fi}
179
180\def\page_split_float_check_caption#1% depends on page-flt .. pretty messy
181  {\edef\extrasplitfloatlines{\extrasplitfloatlines}%
182   \ifx\extrasplitfloatlines\v!auto
183      \bgroup
184      \forcelocalfloats
185      \setuplocalfloats[\c!before=,\c!after=,\c!inbetween=]%
186      % This controls samepage resetting too but it also messes up the numbering
187      % so I need another fix.
188%       \settrialtypesetting
189      \splitfloatcommand{\hbox to #1{\strut}}% dummy line
190%       \resettrialtypesetting
191      \setbox\scratchbox\vbox{\flushlocalfloats}% \vpack ?
192      \getnoflines{\ht\scratchbox}%
193      \resetlocalfloats
194      \advanceby\noflines\minusone % compensate dummy line
195      \normalexpanded{\egroup\noexpand\edef\noexpand\extrasplitfloatlines{\the\noflines}}%
196      \global\usesamefloatnumber\conditionaltrue
197   \orelse\ifchknum\extrasplitfloatlines\else
198     \def\extrasplitfloatlines{1}
199   \fi}
200
201\permanent\protected\def\doifnotinsidesplitfloat
202  {\ifinsidesplitfloat
203     \expandafter\gobbleoneargument
204   \fi}
205
206%D Table splitter, on top of previous code:
207
208% todo: keep tail to rest, so we need a lookahead
209
210\newbox        \b_split_content
211\newbox        \b_split_result    % watch out, semi public, accessed in cs-*
212\newbox        \b_split_head
213\newbox        \b_split_next
214\newbox        \b_split_tail
215
216\newtoks       \t_split_before_result
217\newtoks       \t_split_after_result
218\newtoks       \t_split_before
219\newtoks       \t_split_inbetween
220\newtoks       \t_split_after
221\newtoks       \t_split_section
222\newtoks       \everyresettsplit
223
224\newinteger    \c_split_minimum_free_lines
225
226\newdimension  \d_split_minimum_free_space
227\newdimension  \d_split_available_height
228\newdimension  \d_split_inbetween_height
229
230\newconditional\c_tabl_split_done
231\newconditional\c_tabl_split_head
232\newconditional\c_tabl_split_full
233
234\newconditional\tabl_split_forced_page
235
236% \permanent\protected\def\lastsplithtdp{\htdp\b_split_result}
237
238\appendtoks
239   \c_split_minimum_free_lines\zerocount
240   \d_split_minimum_free_space\zeropoint
241   \setbox\b_split_content    \emptyvbox
242   \setbox\b_split_result     \emptyvbox
243   \setbox\b_split_head       \emptyvbox
244   \setbox\b_split_next       \emptyvbox
245   \setbox\b_split_tail       \emptyvbox
246   \t_split_before_result     \emptytoks
247   \t_split_after_result      \emptytoks
248   \t_split_inbetween         \emptytoks
249   \t_split_before            \emptytoks
250   \t_split_after             \emptytoks
251   \t_split_section           \emptytoks
252   \let\postprocesstsplit     \donothing
253\to \everyresettsplit
254
255\mutable\let\postprocesstsplit\donothing
256
257\permanent\protected\def\resettsplit
258  {\expand\everyresettsplit}
259
260\resettsplit
261
262\mutable\def\tsplitdirectwidth{\hsize}
263
264\permanent\protected\def\handletsplit
265  {\page_split_float_check_caption{\wd\b_split_content}%
266   \global\splitfloatfirstdone\conditionalfalse
267   \testpagesync % new, sync, but still tricky
268     [\the\c_split_minimum_free_lines]
269     [\dimexpr\d_split_minimum_free_space+\extrasplitfloatlines\lineheight\relax]%
270   \setbox\scratchbox\vbox{\expand\t_split_inbetween}%
271   \d_split_inbetween_height\htdp\scratchbox
272   \c_tabl_split_done\conditionalfalse
273   \localcontrolledrepeating
274     {\tabl_split_loop_body}%
275   \global\usesamefloatnumber\conditionalfalse % new, prevent next increment
276   \global\splitfloatfirstdone\conditionalfalse} % we can use this one for tests
277
278\newbox\b_split_result_saved
279
280\def\tabl_split_loop_body
281  {\ifinsidecolumns
282     % brrr, assumes empty columns
283     \global\splitfloatfirstdone\conditionalfalse
284     \d_split_available_height\textheight
285     \c_tabl_split_full\conditionaltrue
286   \else
287     \ifconditional\splitfloatfirstdone
288       \d_split_available_height\textheight
289       \c_tabl_split_full\conditionaltrue
290     \orelse\ifdim\pagegoal<\maxdimen
291       \d_split_available_height{\pagegoal-\pagetotal}%
292       \c_tabl_split_full\conditionalfalse
293     \else
294       \d_split_available_height\textheight
295       \c_tabl_split_full\conditionaltrue
296     \fi
297   \fi
298   \d_split_available_height {%
299      \d_split_available_height
300     -\d_split_inbetween_height
301     -\d_split_minimum_free_space
302     -\extrasplitfloatlines\lineheight
303   }%
304   \ifdim\htdp\b_split_tail>\zeropoint
305     \advanceby\d_split_available_height-\htdp\b_split_tail
306   \fi
307   \setbox\b_split_result\vbox
308     {\ifdim\ht\b_split_head>\zeropoint
309        \unvcopy\b_split_head
310        \expand\t_split_section
311        \expand\t_split_inbetween
312      \fi}%
313   \ifconditional\c_tabl_split_done \else
314     \ifdim\ht\b_split_next>\zeropoint
315       \setbox\b_split_head\box\b_split_next
316     \fi
317   \fi
318   \c_tabl_split_done\conditionaltrue
319   \ifdim\ht\b_split_result>\zeropoint
320     \c_tabl_split_head\conditionaltrue  % table head
321   \else
322     \c_tabl_split_head\conditionalfalse % no tablehead
323   \fi
324   \splittopskip\zeroskip
325   \ifvoid\b_split_result_saved\else
326     \setbox\b_split_result\box\b_split_result_saved
327     \c_tabl_split_head\conditionaltrue % no tablehead
328     \global\tabl_split_forced_page\conditionalfalse
329   \fi
330   % we get a lot of splittopskips here .. todo: ignore when zero
331   \localcontrolledrepeating
332     {\setbox\scratchbox\vsplit\b_split_content to \onepoint % \lineheight
333      \setbox\scratchbox\vbox % \vpack
334        {\unvbox\scratchbox
335         \setbox\scratchbox\vbox % \vpack
336           {\splitdiscards
337            \ifnum\lastpenalty>-\plustenthousand\else
338               % so that \bTR[before=\page] works
339               \global\tabl_split_forced_page\conditionaltrue
340            \fi}}%
341      \ifconditional\tabl_split_forced_page
342        \global\tabl_split_forced_page\conditionalfalse
343        \setbox\b_split_result\vbox
344          {\unvbox\b_split_result
345           \expand\t_split_inbetween
346           \unvbox\scratchbox}%
347        \quitloop
348      \orelse\ifdim{\d_split_available_height-\htdp\scratchbox-\htdp\b_split_result}>\zeropoint
349        \setbox\b_split_result\vbox
350          {\unvbox\b_split_result
351           \expand\t_split_inbetween
352           \unvbox\scratchbox}%
353        \ifvoid\b_split_content
354          \quitloop
355        \fi
356      \orelse\ifconditional\c_tabl_split_head
357        % we only have a tablehead so far
358        \global\setbox\b_split_result_saved\vbox{\unvbox\b_split_result\unvbox\scratchbox}% \vpack
359        \quitloop
360      \orelse\ifconditional\c_tabl_split_full
361        % we have text height available, but the (one) cell is too
362        % large to fit, so, in order to avoid loops/deadcycles we do:
363        \setbox\b_split_result\vbox
364          {\unvbox\b_split_result
365           \expand\t_split_inbetween
366           \unvbox\scratchbox}%
367        \quitloop
368      \else
369        \setbox\b_split_content\vbox
370          {\unvbox\scratchbox
371           \expand\t_split_inbetween
372           \ifvoid\b_split_content\else\unvbox\b_split_content\fi}%
373        \quitloop
374      \fi
375      \c_tabl_split_head\conditionalfalse
376      \c_tabl_split_full\conditionalfalse}%
377   \postprocesstsplit
378   \page_split_float_check_content\b_split_content
379   \ifvoid\b_split_content
380     \setbox\b_split_result\vbox
381       {\unvbox\b_split_result
382        \expand\t_split_inbetween
383        \unvcopy\b_split_tail}%
384     \page_split_float_process{\expand\t_split_before_result\box\b_split_result\expand\t_split_after_result}%
385     \doifnotinsidesplitfloat{\expand\t_split_after}%
386     \endgraf
387     \quitloop
388   \else
389     % hack
390     \ifdim\pagegoal<\maxdimen
391       \pagegoal{\pagegoal+\lineheight}% etex
392     \fi
393     % brrr
394     \ifdim\ht\b_split_result>\zeropoint
395       \setbox\b_split_result\vbox
396         {\unvbox\b_split_result
397          \expand\t_split_inbetween
398          \unvcopy\b_split_tail}%
399       \page_split_float_process{\expand\t_split_before_result\box\b_split_result\expand\t_split_after_result}%
400       \doifnotinsidesplitfloat{\expand\t_split_after}%
401       \endgraf
402       \global\usesamefloatnumber\conditionaltrue % new, prevent next increment
403     \fi
404     \ifinsidecolumns
405       \goodbreak % was \doifnotinsidesplitfloat\goodbreak
406     \else
407       \page      % was \doifnotinsidesplitfloat\page
408     \fi
409   \fi}
410
411%D The next one assumes that the split takes place elsewhere. This is used in
412%D xtables.
413
414\aliased\let\resetdirecttsplit\resettsplit
415
416\mutable\let\tsplitdirectsplitter\relax
417
418\permanent\protected\def\handledirecttsplit
419  {\page_split_float_check_caption{\tsplitdirectwidth}%
420   \global\splitfloatfirstdone\conditionalfalse
421   \testpagesync % new, sync, but still tricky
422     [\the\c_split_minimum_free_lines]
423     [\dimexpr\d_split_minimum_free_space+\extrasplitfloatlines\lineheight\relax]%
424   \localcontrolledrepeating
425     {\tabl_split_direct_loop_body}%
426   \global\usesamefloatnumber\conditionalfalse   % new, prevent next increment
427   \global\splitfloatfirstdone\conditionalfalse} % we can use this one for tests
428
429\newconditional\splitfloatfixedheight
430
431\def\splitfloatheight{\textheight}
432
433\def\tabl_split_direct_loop_body
434  {\ifconditional\splitfloatfixedheight
435     \d_split_available_height\splitfloatheight
436   \orelse\ifinsidecolumns
437     \global\splitfloatfirstdone\conditionalfalse
438     \d_split_available_height\textheight
439   \orelse\ifconditional\splitfloatfirstdone
440     \d_split_available_height\textheight
441   \orelse\ifdim\pagegoal<\maxdimen
442     \d_split_available_height{\pagegoal-\pagetotal}%
443   \else
444     \d_split_available_height\textheight
445   \fi
446   \d_split_available_height{%
447      \d_split_available_height
448     -\d_split_minimum_free_space
449     -\extrasplitfloatlines\lineheight
450   }%
451   \tsplitdirectsplitter\d_split_available_height % also sets state
452   \ifdim\ht\b_split_result>\zeropoint
453     \ifconditional\somenextsplitofffloat
454       \global\onlyonesplitofffloat\conditionalfalse
455     \fi
456     \ifconditional\splitfloatfixedheight
457       % not relevant
458     \orelse\ifdim\pagegoal<\maxdimen
459       \pagegoal{\pagegoal+\lineheight}%
460     \fi
461     \page_split_float_process{\expand\t_split_before_result\box\b_split_result\expand\t_split_after_result}%
462     \global\usesamefloatnumber\conditionaltrue % new, prevent next increment
463     \endgraf
464     \ifconditional\somenextsplitofffloat
465       \ifconditional\splitfloatfixedheight
466         \page
467       \orelse\ifinsidecolumns
468         \goodbreak
469       \else
470         \page
471       \fi
472     \fi
473     \global\splitfloatfirstdone\conditionaltrue
474   \orelse\ifconditional\somenextsplitofffloat
475     \ifconditional\splitfloatfixedheight
476       \page
477     \orelse\ifinsidecolumns
478       \goodbreak
479     \else
480       \page % no room
481     \fi
482   \else
483     \quitloop
484   \fi}
485
486%D Maybe handy:
487%D
488%D \starttyping
489%D \splitfloat
490%D   {\placefigure{some caption}}
491%D   {\startsplittext
492%D    \typefile[option=TEX,before=,after=]{oeps.tex}
493%D    \stopsplittext}
494%D \stoptyping
495
496\permanent\def\handlesplittext#1%
497  {\setbox\b_split_result\vbox
498     {\vsplit\b_split_content to {#1-\lineheight}}}
499
500\permanent\protected\def\startsplittext
501  {\begingroup
502   \resettsplit
503   \c_split_minimum_free_lines\zerocount
504   \d_split_minimum_free_space\zeropoint
505   \let\extrasplitfloatlines  \!!plusone
506   \let\tsplitdirectsplitter  \handlesplittext
507   \setbox\b_split_content\vbox\bgroup
508   \insidefloattrue}
509
510\permanent\protected\def\stopsplittext
511  {\egroup
512   \handledirecttsplit
513   \endgroup}
514
515\protect \endinput
516
517% test cases
518
519% \setupTABLE[split=repeat]
520%
521% \input tufte \endgraf
522% \splitfloat[lines=11]
523%   {\placetable{\dorecurse{10}{test\recurselevel\endgraf}}}
524%   {\bTABLE\dorecurse{100}{\bTR \bTD test \eTD \eTR}\eTABLE}
525% \input tufte \page
526%
527% \input tufte \endgraf
528% \splitfloat[lines=0]
529%   {}
530%   {\bTABLE\dorecurse{100}{\bTR \bTD test \eTD \eTR}\eTABLE}
531% \input tufte \endgraf \page
532%
533% \input tufte \endgraf
534% \bTABLE\dorecurse{100}{\bTR \bTD test \eTD \eTR}\eTABLE
535% \input tufte \page
536
537% \setuptabulate[split=yes]
538%
539% \input tufte \endgraf
540% \splitfloat[lines=11]
541%   {\placetable{\dorecurse{10}{test\recurselevel\endgraf}}}
542%   {\starttabulate\dorecurse{200}{\NC test \NC test \NC \NR}\stoptabulate}
543% \input tufte \page
544%
545% \input tufte \endgraf
546% \splitfloat[lines=0]
547%   {}
548%   {\starttabulate\dorecurse{200}{\NC test \NC test \NC \NR}\stoptabulate}
549% \input tufte \page
550%
551% \input tufte \endgraf
552% \starttabulate\dorecurse{200}{\NC test \NC test \NC \NR}\stoptabulate
553% \input tufte \page
554
555% \setuptables[split=yes]
556%
557% \newtoks\TestToks
558%
559% \TestToks\emptytoks
560% \appendtoks\starttablehead\to\TestToks
561% \dorecurse{3}{\appendtoks\VL head \VL head \VL \SR\to\TestToks}
562% \appendtoks\stoptablehead\to\TestToks
563% \appendtoks\starttabletail\to\TestToks
564% \dorecurse{3}{\appendtoks\VL tail \VL tail \VL \SR\to\TestToks}
565% \appendtoks\stoptabletail\to\TestToks
566% \appendtoks\starttables[|c|c|]\to\TestToks
567% \dorecurse{100}{\appendtoks\VL test \VL test \VL \SR\to\TestToks}
568% \appendtoks\stoptables\to\TestToks
569%
570% \input tufte \endgraf
571% \splitfloat[lines=auto] % [lines=11]
572%   {\placetable{\dorecurse{10}{test\recurselevel\endgraf}}}
573%   {\the\TestToks}
574% \input tufte \page
575%
576% \input tufte \endgraf
577% \splitfloat[lines=0]
578%   {}
579%   {\the\TestToks}
580% \input tufte \page
581%
582% \input tufte \endgraf
583% \the\TestToks
584% \input tufte \page
585%
586% multiple floats
587%
588% \starttext
589%   \dorecurse{3}{\input tufte } \endgraf
590%   \dorecurse{5}{\placefigure{}{\framed[height=.5\textheight]{}}}
591%   \splitfloat[lines=auto,inbetween=]
592%     {\placetable{\dorecurse{5}{test\recurselevel\endgraf}}}
593%     {\bTABLE[split=yes]
594%      \bTR \bTD 11 \eTD \bTD \input tufte \eTD \eTR
595%      \bTR \bTD 12 \eTD \bTD \input zapf \eTD \eTR
596%      \bTR \bTD 13 \eTD \bTD \input bryson \eTD \eTR
597%      \bTR \bTD 14 \eTD \bTD test  \eTD \eTR
598%      \bTR \bTD 21 \eTD \bTD \input tufte \eTD \eTR
599%      \bTR \bTD 22 \eTD \bTD \input zapf \eTD \eTR
600%      \bTR \bTD 23 \eTD \bTD \input bryson \eTD \eTR
601%      \bTR \bTD 24 \eTD \bTD test  \eTD \eTR
602%      \bTR \bTD 31 \eTD \bTD \input tufte \eTD \eTR
603%      \bTR \bTD 32 \eTD \bTD \input zapf \eTD \eTR
604%      \bTR \bTD 33 \eTD \bTD \input bryson \eTD \eTR
605%      \bTR \bTD 34 \eTD \bTD test  \eTD \eTR
606%      \eTABLE}
607%   \dorecurse{10}{\input tufte }
608% \stoptext
609