Qual é o comando \span?

Qual é o comando \span?

Eu encontrei o \spanprimitivo algumas vezes. Tive a impressão de que está definido no programa TeX, nem mesmo no plain.tex. Isso está certo? E o quefazesse comando faz e para que serve?

Responder1

O primitivo \spantem dois significados muito diferentes se aparecer no preâmbulo \halignou no corpo.

Se estiver no preâmbulo, é antes do primeiro \crsignifica “expandir” o token seguinte; se aparecer no corpo encerra a célula atual, mas a mescla com a seguinte. Neste caso, geralmente é combinado com \omit.

O exemplo mais simples é

\halign{\hfil#\tabskip1em&#\hfil\cr
  a&b\cr
  c\span d\cr
}

onde a segunda linha terá apenas uma célula. A saída será

insira a descrição da imagem aqui

sem \tabskipespaçamento entre “c” e “d”, pois a segunda linha é apenas uma célula com \hfilantes e depois do conteúdo, mas o TeX levará isso \tabskipem consideração para determinar a largura da célula.

Geralmente, porém, acrescenta-se também \omitpara remover ovocêevpeças (vocêrefere-se ao que vem antes #,vpara o que se segue).

Quando o TeX está lendo um preâmbulo, \halignele não expande os tokens, a menos que encontre \tabskip(quando expande os tokens para encontrar a especificação de cola apropriada). A expansão de um token pode ser forçada precedendo-o com \span.

Um exemplo está emamsmath.sty

\def\align@#1#2{%
    \inalign@true \intertext@ \Let@ \chardef\dspbrk@context\z@
    \ifingather@\else\displ@y@\fi
    \let\math@cr@@@\math@cr@@@align
    \ifxxat@\else \let\tag\tag@in@align \fi
    \let\label\label@in@display
    #1% set st@r
    \ifst@rred\else \global\@eqnswtrue \fi
    \measure@{#2}%
    \global\row@\z@
    \tabskip\eqnshift@
    \halign\bgroup
        \span\align@preamble\crcr
        #2%
}

Esta é uma macro auxiliar usada para alignamigos; o preâmbulo é definido de uma vez por todas na macro\align@preamble

\def\align@preamble{%
   &\hfil
    \strut@
    \setboxz@h{\@lign$\m@th\displaystyle{##}$}%
    \ifmeasuring@\savefieldlength@\fi
    \set@field
    \tabskip\z@skip
   &\setboxz@h{\@lign$\m@th\displaystyle{{}##}$}%
    \ifmeasuring@\savefieldlength@\fi
    \set@field
    \hfil
    \tabskip\alignsep@
}

Isso simplifica muito a definição de \align@, colocando um grande pedaço de código em uma macro. Também permite alterar o comportamento alignmodificando \align@preamble(verÉ possível fazer com que colunas ímpares tenham implicitamente um prefixo {}?).

O kernel do LaTeX utiliza um método diferente para tabular, pois precisa construir o preâmbulo de acordo com suas regras, ou seja, uma combinação de lcrpcaracteres e assim por diante.

O segundo uso de \spané para mesclar colunas em um arquivo \halign. No Plain TeX encontramos\multispan

\def\multispan#1{\omit \mscount#1\relax
  \loop\ifnum\mscount>\@ne \sp@n\repeat}
\def\sp@n{\span\omit\advance\mscount\m@ne}

isso faz \omite adiciona tantos \span\omitpares quanto indicado no argumento (menos um); so \multispan{1}é equivalente a \omit, \multispan{2}a \omit\span\omite assim por diante. A \multicolumnmacro do LaTeX é construída sobre a mesma ideia

% latex.ltx, line 5053:
\long\def\multicolumn#1#2#3{\multispan{#1}\begingroup
  \@mkpream{#2}%
  \def\@sharp{#3}\set@typeset@protect
  \let\@startpbox\@@startpbox\let\@endpbox\@@endpbox
  \@arstrut \@preamble\hbox{}\endgroup\ignorespaces}

Ele primeiro o faz \multispan{#1}(definido exatamente como em Plain) e então prossegue para construir um preâmbulo de alinhamento “local” usando o mesmo \@mkpreamusado por tabulare arraypara avaliar seu argumento obrigatório.

Por que Knuth usou o mesmo primitivo para dois significados muito diferentes? Para economizar espaço; O TeX foi escrito quando o espaço de memória do computador era baixo e era importante economizar em uma definição. Como \spansó pode aparecer em \halign(ou \valign, é claro), não há problema.

Um uso tortuoso de \spanno primeiro significado aparece na solução do exercício 20.16 no TeXbook

O seguinte não deve ser levado muito a sério, mas funciona:

{\setbox0=\vbox{\halign{#{\c\span\d}\cr
       \let\next=0\edef\next#1{\gdef\next{\b#1}}\next\cr}}}
 \let\a=\next

O exercício trata de definir \acomo equivalente a \b(totalmente expandido) seguido por \c(não expandido) e por \d(expandido apenas uma vez) sem usar \noexpande \the. Por exemplo, se tivermos

\def\foo{xy\baz}
\def\baz{z}
\def\b{\foo\foo}
\def\c{--}
\def\d{\baz}

queremos definir \apara ter como texto substituto

xyzxyz\c\baz

A \setbox0=\vbox{parte é apenas para usar \halignsem qualquer saída. Agora o TeX avalia o \halignpreâmbulo como #{\c\baz}\cr, porque \spancausa uma expansão de um nível de \d. A única célula contém

\let\next=0\edef\next#1{\gdef\next{\b#1}}\next

que, de acordo com as regras, é usado no lugar #do preâmbulo, para que o fluxo de entrada se torne

\let\next=0\edef\next#1{\gdef\next{\b#1}}\next{\c\baz}\cr

O \crapenas termina a célula, então não é relevante. Por causa de \let\next=0, \nexttorna-se inexpansível, então \edeffaz com \nextque seja definido como se tivesse sido

\def\next#1{\gdef\next{<full expansion of \b>#1}}

e assim \next{\c\baz}executará obedientemente

\gdef\next{<full expansion of \b>\c\baz}

e o final \let\a=\nextacaba com tudo.

Isso explica bem o que \spanfaz apenasumpasso de expansão.


Uma solução diferente com o e-TeX (afinal, ele não usa \noexpande \the), seria

\edef\a{\b\unexpanded\expandafter{\expandafter\c\d}}

informação relacionada