Take the 2-minute tour ×
TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It's 100% free, no registration required.

Is it possible to take a box and retrieve the following information from it:

  • A list of all "top level" internal boxes;
  • All intervening space (kerns and glue: did I forget another type of space?)?

You might wonder why I want this. The reason is that I would like to be able to write, in a natural manner, a piece of text, but then to place each character inside a TikZ node without changing the spacing. The reason for that is so that I can refer to individual terms in a formula (say, for the purpose of putting arrows between them).

Currently I achieve this by doing the following:

\documentclass{article}
\usepackage{tikz}
\usetikzpackage{chains}
\begin{document}

\tikzstyle{node text}=
 [start chain,
  every node/.append style = {
   on chain, inner sep = 0pt, outer sep = 0pt,
   execute at begin node = \strut}, 
  node distance = 0pt]

\newcommand{\NodeTextCell}[2][]{
 \node [inner sep = 0pt, outer sep = 0pt, #1] (my node)
 \tikz[node text]{
  \foreach \letter [count = \n] in {#2}
   \node (my node*\n) {\letter};
 }
}

\begin{tikzpicture}
 \NodeTextCell{A, {}\otimes{}, B, {}\otimes{}, C}
 \draw (my node*1.north) to[bend left=30] (my node*3.north);
\end{tikzpicture}
\end{document}

That's a little clunky, but I can live with it if necessary. If you can think of a better way to do just this with TikZ, that would also serve as an answer. Thanks!

share|improve this question
    
download the lineno package that is unboxing a paragraph and adds lines as a good example to study. –  Yiannis Lazarides Nov 29 '10 at 21:44
    
@Yiannis Lazarides: That package is amazing (-ly complex) but from what I can gather from the commentary it uses the fact that it is breaking paragraphs quite explicitly. That is, it attaches the line numbering operation to the end of each line and to \par. I don't think its techniques would help to break up a single line into characters. –  Ryan Reich Nov 29 '10 at 22:47
    
If you only interested in capturing one line of characters and parse them individually it is easier. \def\test#1{} will read one character and you can recurse calling test again. If this is what you are looking for I can post a macro for you. –  Yiannis Lazarides Nov 29 '10 at 23:20
    
@Yiannis Lazarides: That's fine for parsing the input stream, but I want to manipulate already-typeset material. The main problem is that TeX inserts kerns and glue between characters in a way I don't know how to predict without just letting it do its thing. The goal is to wrap each top-level box or character in a node but otherwise not to disturb the line. –  Ryan Reich Nov 29 '10 at 23:42
    
Have you taken a look at ConTexT's visual debugging, among the answers on how to best debug in LaTeX? –  Bruno Le Floch Mar 14 '11 at 16:22
add comment

2 Answers

up vote 3 down vote accepted

Luatex has what looks to me like nice support for this, having primitives for traversing over the contents of boxes (which it represents internally using the more general concept of typed nodes).

If you have a smattering of Lua and read the first three chapters and section 4.10 of the Luatex manual, you will know as much as I do about how to use this. Hopefully one of our actual Luatex experts here will be able to say something more substantial. But it looks to me that in Luatex, the answers are:

  1. \hboxes are nodes of type hlist, which contain their top-level boxes as their list of contents, with the boxes being the nodes in the list with a box type. Luatex provides an iterator primitive, node.traverse, for this, which has to be a huge improvement over \lastbox;
  2. I'm not really clear on how glue is handled in Luatex, but I guess that the intervening space you want is the items of the same list with the glue or kern type (and I am also not sure whether other nodes might have space value). Then node.dimension gives the dimensions of the space.
share|improve this answer
    
My first reaction to this (having read none of the references) is that it is obviously the right way, if it indeed works. Actually, that's my reaction to LuaTeX in general. The caveat, of course, is to what degree LuaTeX indeed works. I shall have to find out, as I know nothing about it. –  Ryan Reich Nov 30 '10 at 10:12
    
I still don't know any luatex, but after a year and some, I think an answer of "no, but in a better programming environment, yes" is probably the correct one. –  Ryan Reich Feb 4 '12 at 21:37
add comment

There are \unhbox and \unvbox to unpack the contents of a box into the current list. Then you would have to go through the list with \lastskip and \lastbox. This is not for the faint of heart, but there are examples of this in Victor Eijkhout's TeX by Topic as well as in the TeXbook.

share|improve this answer
    
I like the idea, but I am worried about how \lastbox treats characters. A quick test suggests that a\setbox0\lastbox\showbox0 will indicate that \lastbox is void. How to I get it to pick up character boxes? –  Ryan Reich Nov 29 '10 at 23:12
1  
@Yossi: there are tons of online links to this document, but why not link to the CTAN node? ctan.org/pkg/texbytopic –  Will Robertson Nov 29 '10 at 23:25
    
@Ryan: I agree, I think; I can only get this to work with something like \leavevmode\setbox0=\hbox{a}\box0{\setbox0=\lastbox}b. I certainly could be wrong (often am) but I didn't know that you could unpick a box to this level of granularity. –  Will Robertson Nov 29 '10 at 23:29
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.