setting \tabskip in a repeating \halign preamble

Is it somehow possible to set the \tabskip glue to zero for the first and last column in a repeated \halign?

Eg.

% tabskip=0pt
\halign{&#\hfil\tabskip1em plus1em minus.5em\cr
Foo&Bar&Baz\cr
\noalign{\smallskip\hrule}
}
\bye


There you can see that for the last column, there is a tabskip after it.

I would like to have a preamble which has zero tabskip for the first and last column. Is this somehow possible?

You can achieve what you wish by doubling the number of columns.

\halign{&#\tabskip0pt&#\hfil\tabskip1em plus1em minus.5em\cr
Foo&&Bar&&Baz\cr
\noalign{\smallskip\hrule}
}


If the alignment is large, and you don't want to type & each time, it is possible to hide the extra & in the preamble and place it just after every & with \aftergroup. However, it needs to be removed after each \cr, hence the setting of \everycr. This, in turn, requires us to add a weird extra \amp after the first \cr.

\def\amp{&}
\begingroup
\def\gobbleamp\amp{} \everycr{\gobbleamp}
\halign{&#\tabskip0pt\aftergroup\amp&#\hfil\tabskip1em plus1em minus.5em\cr\amp
Foo&Bar&Baz\cr
\noalign{\smallskip\hrule}
}
\endgroup


Ha! I got some "eviler" method, with a nicer input.

\def\amp{&}
\halign{&#\tabskip0pt&\amp#\hfil\tabskip1emplus1emminus.5em\cr
Foo&Bar&Baz\cr
\noalign{\smallskip\hrule}
}


The \amp is adding a & just after each & actually typed by the user.

TeX calls the part of a cell's preamble before # the "u-part", and the part after # the "v-part". Here, the \amp is in the u-part of the preamble for even cells. When such a cell starts, TeX expands the tokens to check for the presence of \omit. Once it sees (in our case) that there is no \omit, TeX inserts the u-part, hence an \amp. It then proceeeds with typesetting. \amp is expanded to &, which ends the cell. At this point, the v-part is inserted (\hfil). Then TeX starts the following odd cell after the & that the preamble had inserted.

Earlier, I was trying to put \amp in the v-part of the preamble for odd cells, naively equivalent: trying to insert & before each user-provided & instead of after. I don't fully understand why it doesn't work.

• This is incredible wizardry. – Ryan Reich Oct 22 '11 at 15:59
• @RyanReich: Thanks. You might prefer the new method I found (third code snippet) :D. – Bruno Le Floch Oct 22 '11 at 17:59

I suspect not. From TeX by Topic

The value of \tabskip that holds outside the alignment is used before the first column, and after all subsequent columns, unless the preamble contains assignments to \tabskip. Any assignment to \tabskip is executed while TeX is scanning the preamble; the value that holds when a tab character is reached will be used at that place in each row, and after all subsequent columns, unless further assignments occur. The value of \tabskip that holds when \cr is reached is used after the last column.

• I was hoping there would've been some \unvbox-based magical solution for this, but oh well. Thanks! – morbusg Jan 1 '11 at 18:57

Just for the record, another solution with a frame and multispan columns.

We need the following preamble:

% \tabskip = 0 pt
\vrule #\strut \tabskip = 0 pt plus 1 fil
& \hfil #\hfil
& #\vrule \tabskip = 0 pt \cr


To get an infinite preamble (second part after & &):

  % \tabskip = 0 pt
\vrule #\strut \tabskip = 0 pt plus 1 fil
& \hfil #\hfil
& #\vrule \tabskip = 0 pt
& & #\tabskip = 0 pt plus 1 fil  % same as first element without \strut and \vrule
& \hfil #\hfil
& #\vrule \tabskip = 0 pt \cr % ends with a \vrule and a 0 pt \tabskip


After reducing the preamble, we've got:

\tabskip = 0 pt
\everycr = {} % code executed after each \cr
\halign to \hsize { % preamble (here we are in vertical mode)
\vrule #\strut \tabskip = 0 pt plus 1 fil
& & \hfil #\hfil
& #\vrule \tabskip = 0 pt % the table always ends with this column
& #\tabskip = 0 pt plus 1 fil \cr % same as first element without \strut and \vrule
% body (here we are in vertical mode)
\noalign { \hrule } % here we are in vertical mode
& \multispan 7\hidewidth Just a table\hidewidth &\cr % 9 columns − first − last = 7 multispan
\noalign { \hrule } % No space after the argument of multispan!
& 2& & & 5& & & 8& \cr
\noalign { \hrule }
& \multispan 4\hidewidth multispan = 4\hidewidth & & & 8& \cr
\noalign { \hrule } }


I use \hidewidth …\hidewidth instead of \hfil …\hfil to center, because the text to center (“Just a table”, “multispan = 4”) is “wide” (wider than expected by TeX so the table would be messy!)

Note: I don't usually use a framed table. (And I don't usually use a table at all! :))