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.

You would think that I would know better than to mess with an egreg solution, but in my defense I used a DavidCarlisle solution from \setbox vs. \sbox and \savebox - What are the differences I need to know about? to adapt egreg's solution to Proper way to detect empty/blank text. This has worked fine for me up until now, but when I attempt to use it within an enumerate environment it results in it gobbling up the item number:

enter image description here

Note that the item number is not gobbled for the case where there is no title to be used (Third Item).

If I replace the \sbox0{\begingroup\vbox{#1}\endgroup} as per the original solution:

\sbox0{#1}

this particular MWE work, but causes problems elsewhere (not shown here).

Question:

So, what is the minimal change I could make to the existing \sbox0 solution so that the item numbers is not gobbledr?

I am disabling some macros within the \begingroup so as to eliminate any side effects so do need the grouping.

Code:

\documentclass{article}
\usepackage{enumitem}

\makeatletter
\newcommand{\DoIfNonEmptyText}[1]{% Actually takes two parameters
    %\sbox0{#1}%
    \sbox0{\begingroup\vbox{#1}\endgroup}%
    \ifdim\wd0=\z@\relax% 
        \expandafter\@gobble%
    \else%
        \expandafter\@firstofone%
    \fi%
}%
\makeatother

\newcommand{\QuotableText}[3][]{%
    % [#1] = optional title
    % #2   = name for this (not relevant for this example)
    % #3   = the content
    \DoIfNonEmptyText{#1}{\textit{#1}:~}%
    #3%
}%


\begin{document}
\begin{enumerate}
    \item First Item
    \item \QuotableText[Sub title]{Text One}{Second Item}
    \item \QuotableText{Text Two}{Third Item}
    \item Fourth Item
\end{enumerate}
\end{document}

Update:

Based on Frank Mittelbach's answer, I attempted to use my own \savebox, but it still exhibits the same output as above:

\makeatletter
\newsavebox{\@DoIfNonEmptyTextBox}%
\newcommand{\DoIfNonEmptyText}[1]{% Actually takes two parameters
    \begingroup
    \savebox{\@DoIfNonEmptyTextBox}{\vbox{#1}}% -- This still gobbles the item number!
    %\savebox{\@DoIfNonEmptyTextBox}{#1}%        -- This works
    \ifdim\wd\@DoIfNonEmptyTextBox=\z@\relax% 
        \endgroup\expandafter\@gobble%
    \else%
        \endgroup\expandafter\@firstofone%
    \fi%
}%
\makeatother

but if I remove the \vbox{}, then this works just fine. So, how is the use of the \vbox (note: no use of \sbox0 here), causing the enumerate item to disappear?

share|improve this question
add comment

2 Answers

up vote 13 down vote accepted

The wrong answer (though by chance it solved the issue)

The answer is simply do not use box 0 or ensure that your use of it does no harm. This is a scratch box, but the \item command of LaTeX also uses that one to store its item for a tiny while (between encountering the \item command and typesetting the label once the paragraph started) and your \QuotableText is executed during this time.

Now your change to box0 is not local thus you overwrite the content.

Solution 1: use \newbox to get your private box register for your test

Solution 2: make your change to box0 local. You start a group and close it directly after making the measurement (which means close it in both branches):

\makeatletter
\newcommand{\DoIfNonEmptyText}[1]{% Actually takes two parameters
\begingroup
    \sbox0{#1}%
    \ifdim\wd0=\z@\relax% 
\endgroup
        \expandafter\@gobble%
    \else%
\endgroup
        \expandafter\@firstofone%
    \fi%
}%
\makeatother

You had

\sbox0{\begingroup\vbox{#1}\endgroup}%

but there the group is done at the wrong place. The setting of box 0 ist still outside the group. Inside your group there is only stuff that is being typeset and so the group has no effect whatsoever.

Update (why is the \vbox making the item label disappear)

This is a tricky one. One has to look carefully at how the list environment attaches the item label to the item paragraph.

Basically, what happens inside is that the label is constructed and stored in a box (and it is not as I claimed earlier box 0 but actually a private box (\@labels) so thanks for the vote of confidence, but my answer was simply wrong.

Now that box is attached to the by the use of \everypar, the actual definition used is

\everypar={\@minipagefalse \global \@newlistfalse \if@inlabel \global \@inlabel
false {\setbox \z@ \lastbox \ifvoid \z@ \kern -\itemindent \fi }\box \@labels 
\penalty \z@ \fi \if@nobreak \@nobreakfalse \clubpenalty \@M \else \clubpenalty 
\@clubpenalty \everypar {}\fi }

So the above gets executed when a switch from vertical mode to horizontal mode happens.

Now if we just test using \sbox then this is building an h-box and so \everyparis not executed. However, if we use a \vbox inside then any text in #1 will trigger that \everypar. And if you look carefully, the label will only be set if @inlabel is true and this switch is globally set to false in the true case.

So basically the label is put into this \vbox for testing and afterwards is not being typeset again.

So in summary the above initial argument was wrong (I didn't look carefully, the list environment does use box 0 but that is harmless) and my redefinition only worked because I took out the \vbox at the same time.

share|improve this answer
    
I'll change my referenced answer! Thanks. –  egreg May 25 '12 at 8:40
    
Thanks. Your explanation makes sense, but using my own save box still exhibits the problem (unless I remove the \vbox{}). See updated question. –  Peter Grill May 25 '12 at 19:55
    
@egreg: Ok, but even your original answer did not exhibit this problem. Something with \vbox{}? –  Peter Grill May 25 '12 at 19:56
    
@Peter yes my original answer was rubbish ... shame on me –  Frank Mittelbach May 25 '12 at 21:09
add comment

A good rule of thumb when an item label disappears is to add \leavevmode; but in this case (thanks to Frank for pointing it out) setting \everypar to empty should solve the issue.

\makeatletter
\newcommand{\DoIfNonEmptyText}[1]{% Actually takes two parameters
  \begingroup\sbox0{\vbox{\everypar{}#1}}%
  \ifdim\wd0=\z@\relax
    \endgroup
    \expandafter\@gobble
  \else
    \endgroup
    \expandafter\@firstofone
  \fi
}
\makeatother

The \everypar content will be restored at the end of the \vbox and this will keep enumerate happy.

share|improve this answer
    
yes the \leavevmode does the trick because it makes the item label being placed before it can vanish inside the vbox –  Frank Mittelbach May 25 '12 at 21:10
    
@FrankMittelbach Oh, yes! \everypar is redefined! –  egreg May 25 '12 at 21:14
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.