# Toggling Phantom In Macros (plain TeX)

I am using plain TeX / pdfTeX.

Is there a way to build a set of macros, say \showOn / \showOff, such that

1. I can nest them

2. for a given piece of text, it "looks up the parse tree", find the first \showOn/\showOff parent, and gets displayed if and only if it's on?

For example:

Cat \showOff { dog \showOn {red \showOff {blue} green } superman} wonderwoman


Would result in:

Cat [spacing for dog] red [spacing for blue] green [spacing for superman] wonderwoman


So, I know that I can do the spacing without display part through using phantom - however, is there any way to turn phantom on/off in a nested manner?

Right now, I have:

\def\showOn#1{{#1}}
\def\showOff#2{\phantom{#2}}
\showOff {\showOn {foo}}
\bye


However, this clearly fails the nesting since \showOff {\showOn {foo}} will NOT output foo.

## Edit:

My fault for not including this earlier. Color changing does not work. The document changes colors all over the place (in pdfTeX).

• Welcome to TeX.SE. It is always best to compose a MWE that illustrates the problem including the \documentclass and the appropriate packages so that those trying to help don't have to recreate it. – Peter Grill Nov 18 '11 at 22:13
• What do you want in a minimum working example? I have no idea how to create this in the first place. What part of my description is not clear? – TeXinical Novice Nov 18 '11 at 22:15
• @PeterGrill A MWE here would be in plain :-) – Joseph Wright Nov 18 '11 at 22:17
• Is there anything else I can do to make the question easier to answer? – TeXinical Novice Nov 18 '11 at 22:22
• @JosephWright: Could add the \def\showOff{} \def\showOn{} and \bye. Not everyone uses plain TeX so it takes time to get to this point (well at least for me). – Peter Grill Nov 18 '11 at 22:23

An answer which does not rely on colors and allows verbatim text.

\catcode 64 11
\newif\if@inSO@
\def\ShowOff{\afterassignment\ShowOff@\setbox\z@\hbox}
\def\ShowOff@{\@inSO@true\aftergroup\ShowOff@@}
\def\ShowOff@@{\hskip\wd\z@}
\def\ShowOn{\if@inSO@\expandafter\ShowOn@\fi}
\def\ShowOn@#{\egroup\bgroup\aftergroup\ShowOn@@\let\next= }
\def\ShowOn@@{\ShowOff\bgroup}
\catcode 64 12

abcdefghijklmnop
coffin

abc\ShowOff{defg\ShowOn{hi\ShowOff{jk}lm}n}op
\ShowOn{co\ShowOff{f\ShowOn{f}i}n}

\end


How does \phantom work? It stores the text in a box, then creates an empty box with the same width, height and depth. In a similar way, I'll collect the text that should be hidden in box 0, and produce a horizontal space of the same width as that box. All text that is to be displayed is typeset directly.

Let us analyse for example \ShowOff{abc} First, it becomes

\afterassignment\ShowOff@ \setbox\z@\hbox{abc}


TeX remembers \ShowOff@ for use after the next assignment, namely \setbox. The placement of the "after assignment" token in the case of \setbox is a little bit tricky; in our case it ends up after the opening brace following \hbox. Ignore \@inSO@true for the moment. \aftergroup\ShowOff@@ will place \ShowOff@@ as soon as the box that is being build ends. This macro, in turn, inserts a horizontal skip of the size of the box.

Now, \ShowOn cancels this hiding by ending the box of \ShowOff early, namely with the \egroup in \ShowOn@. The horizontal skip is then inserted there. We can then typeset the argument of \ShowOn, and resume hiding afterwards. I could have defined \def\ShowOn@#1{\egroup#1\ShowOff\bgroup}, but this grabs the argument early, forbidding verbatim. Instead, I used \aftergroup again: the argument of \ShowOn comes as a group, {...}. Somehow, we want to insert \aftergroup\ShowOn@@ after the opening brace. Open a brace (\bgroup), and remove the one that the user put (\let\next=).

I still have to explain the @inSO@ switch. If \ShowOn appears outside any \ShowOff command, it should just do nothing to its argument. Otherwise, it acts as described in the previous paragraph.

EDIT: I tried to add support for math mode below (didn't incorporate it above because the macros become ugly).

\catcode@=11
\def\ShowOff
{%
\v@true\h@true
\ifmmode
\expandafter\mathpalette\expandafter\ShowOff@math
\else
\afterassignment\ShowOff@\setbox\z@\hbox
\fi
}
\def\ShowOff@{\let\ShowOn\ShowOn@\aftergroup\finph@nt}
\long\def\ShowOff@math#1{%
\setbox\z@\hbox\bgroup$\m@th #1% \bgroup \aftergroup\ShowOff@math@ \long\def\ShowOn##1{\egroup##1\ShowOff@math#1\bgroup}% \let\next= } \def\ShowOff@math@{$\egroup\finph@nt}
\let\ShowOn\relax
\def\ShowOn@#{\egroup\bgroup\aftergroup\ShowOn@@\let\next= }
\def\ShowOn@@{\ShowOff\bgroup}
\catcode@=12

% Tests.
$abcdefg^h_{ijkl}mnop$ $co^{ffi}n$

$abc\ShowOff{defg\ShowOn{^h_{i\ShowOff{jk}l}m}n}op$
$\ShowOn{co^{\ShowOff{f\ShowOn{f}i}}n}$

abcdefghijklmnop coffin

abc\ShowOff{defg\ShowOn{hi\ShowOff{jk}lm}n}op
\ShowOn{co\ShowOff{f\ShowOn{f}i}n}

\bye

• Wow. Nice job using #{, too. – Ryan Reich Nov 19 '11 at 4:37
• Great solution! – Boris Nov 19 '11 at 4:43
• It's 1:22am here. I was about to go to sleep. But this looks too cool to not read and understand. – TeXinical Novice Nov 19 '11 at 9:23
• So I'm reading page 279 of Knuth's TexBook. Your \afterassignment\ShowOff@ \setbox\z@\hbox{abc} becomes: \setbox\z@\hbox{\ShowOff@ abc} <-- is this correct? – TeXinical Novice Nov 19 '11 at 9:38
• Two more requests: (1) how can I change the \hskip\wd\z@ so it does both width, height & depth. (2) Right now, if I use \showOff within math mode, it breaks, i.e. $\ShowOff{\sum_{i=1}^n}$ results in compile error for me. How do I fix this? -- Thanks! – TeXinical Novice Nov 19 '11 at 9:49
\input color
\def\showOn#1{\textcolor{black}{#1}}
\def\showOff#1{\textcolor{white}{#1}}
Cat \showOff { dog \showOn {red \showOff {blue} green } superman} wonderwoman
\bye


Update

Here is the solution that does not assume the text is black. It assumes, however, that the background is white. Also, any explicit color change inside \showOff makes the text visible.

\input color
\catcode\@=11
\newif\ifinside@showoff
\def\showOff#1{\textcolor{white}{\inside@showofftrue#1}}
\def\showOn#1{\ifinside@showoff
\bgroup\inside@showofffalse\reset@color#1\egroup\color{white}%
\else#1\fi}
\color{green} Cat \showOff { dog \showOn {\textcolor{red}{red}
\showOff {blue} green } superman} wonderwoman
\bye

• The OP is using plain TeX, not LaTeX. – Torbjørn T. Nov 18 '11 at 22:20
• My fault for not mentioning the document uses pdf's color changing abilities; so toggling to black/white won't work. – TeXinical Novice Nov 18 '11 at 22:20
• (Sorry for not mentioning the fact I was using pdftex's color changing abilities earlier.) – TeXinical Novice Nov 18 '11 at 22:20
• Clever, but this also produces the green and wonderwoman` in white. – Peter Grill Nov 18 '11 at 22:37
• @TorbjørnT. Thanks - I've changed my answer – Boris Nov 18 '11 at 22:39