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.

Why does using \uline within a pgfmath expression result in an error?

\documentclass{article}
\usepackage[normalem]{ulem}
\usepackage{tikz}

\begin{document}
\pgfmathparse{width("\uline{blabla}")}
\end{document}

The error:

! Undefined control sequence.
\ULset ->\UL@setULdepth \def \UL@leadtype 
                                          {\leaders \hrule \@height \UL@heig...
l.6 ...se{width("\let\uline\relax\uline{blabla}")}

! TeX capacity exceeded, sorry [input stack size=5000].
\UL@on #1->\leavevmode 
                       \UL@ender \let \UL@on \UL@onin \everymath {\UL@hrest ...
l.6 ...se{width("\let\uline\relax\uline{blabla}")}

!  ==> Fatal error occurred, no output PDF file produced!

My \uline is embedded in some other macro, so I can't simply not write it there. I had the idea to temporarily undefine \uline within the math expression (I don't need it to calculate the width, right!), but it only made matters more misterious: the error persists (it seems that \let is never executed).

\documentclass{article}
\usepackage[normalem]{ulem}
\usepackage{tikz}

\begin{document}
\pgfmathparse{width("\let\uline\relax\uline{blabla}")}
\end{document}
share|improve this question
4  
This will teach you not using underlining. ;-) –  egreg Feb 28 '13 at 22:55
    
;-) Don't worry, it wasn't for text. Just to signal that something is a predicate. –  Sašo Živanović Feb 28 '13 at 22:58
    
\pgfmathparse{width("...")} is bound to failure whenever there's something in the argument that doesn't survive \edef (\textbf, for instance). So I guess that the \sbox method is better in any case when you can't fully control the text. –  egreg Mar 1 '13 at 0:09
    
Although the \sbox and \wd way is certainly preferable and the most safe. With the package etoolbox, one can simply do \robustify\uline (which protects \uline from expansion by \edef) and \pgfmathprint{width("\uline{blabla}")} will give 26.66675 then. (Of course, this doesn’t work if you don’t know what to expect.) –  Qrrbrbirlbel Jul 18 '13 at 3:29
add comment

3 Answers

up vote 8 down vote accepted

It has all the signs of premature expansion, but the usual \protect methods don't seem to work here. You can make things safe by using a box register:

\documentclass{article}
\usepackage[normalem]{ulem}
\usepackage{tikz}

\begin{document}
\sbox{0}{\uline{blabla}}
\typeout{\the\wd0}
\pgfmathparse{width("\usebox{0}")}
\typeout{\pgfmathresult}
\end{document}

runs without error and \pgfmathresult gets the right value:

26.66675pt
26.66675
share|improve this answer
2  
Right, he could just use \pgfmathparse{+\wd0} then. :) –  Qrrbrbirlbel Feb 28 '13 at 23:37
    
@Qrrbrbirlbel well in this case you clearly don't need to parse at all since it's a fixed known width you could just use \wd0, but that's an artefact of a small example. You might need to make some macro-supplied text safe to use in a pgfmathparse expression and passing it through a box register is one way to do that. –  David Carlisle Feb 28 '13 at 23:44
add comment

There is one more inbetween check and as David Carlisle noticed it causes an early expansion. So more protection helps. This is also needed if the text is bold with \textbf etc.

\documentclass{article}
\usepackage[normalem]{ulem}
\usepackage{tikz}

\begin{document}
\pgfmathparse{width("\noexpand\noexpand\noexpand\uline{blabla}")}
\pgfmathresult
\end{document}
share|improve this answer
    
This won't work if the text to measure is passed as argument. –  egreg Mar 1 '13 at 0:10
    
@egreg You mean like \textbf{\mytext} –  percusse Mar 1 '13 at 0:12
    
I guess that nobody uses \pgfmathparse in the wild and probably it's inside some macro to which the text is passed as argument: \newcommand{\foo}[1]{\pgfmathparse{width("#1")}...} and in this case there's no possibility of adding \noexpand in unknown places. –  egreg Mar 1 '13 at 0:14
    
@egreg Oh I see now. But indeed it's not too smart to use that function in such cases. Instead boxing it inside \foo group directly and using \wd is much easier. The usage is for places where you can't escape and execute TeX commands easily. –  percusse Mar 1 '13 at 0:22
    
@egreg This was indeed the case. –  Sašo Živanović Mar 1 '13 at 2:32
show 3 more comments

Fix via \pgfmath@selectfont

This works good for the combination \uline and width.

Code

\documentclass{article}
\usepackage[normalem]{ulem}
\usepackage{tikz}

\makeatletter
\def\pgf@tempa{\let\uline\relax}
\expandafter\def\expandafter\pgfmath@selectfont\expandafter{\expandafter\pgf@tempa\pgfmath@selectfont}
\makeatother

\begin{document}
\uline{blabla}

\pgfmathparse{width("\uline{blabla}")}
\pgfmathresult

\uline{blabla}
\end{document}

Output

enter image description here

\let

You can temporarily eliminate \uline if you use \let\uline\relax outside of \pgfmathparse. Localize this and \uline works fine in the rest of the document.

To access the result outside of this group we need to define \pgfmathresult global (via \xdef).

Code

\documentclass{article}
\usepackage[normalem]{ulem}
\usepackage{tikz}

\begin{document}
\begingroup
  \let\uline\relax
  \pgfmathparse{width("\uline{blabla}")}%
  \xdef\pgfmathresult{\pgfmathresult}% make \pgfmathresult global
\endgroup
\pgfmathresult
\end{document}
share|improve this answer
    
This is of course a good idea, it just not feasible in the particular case. The computed value gets assigned locally and I have no control over that... –  Sašo Živanović Mar 1 '13 at 2:37
    
@SašoŽivanović I’m interested in your particular case. But it was rather an answer to your question’s last part. But maybe my updated answer can help you. Though, I would go with \sbox and \wd anyway. –  Qrrbrbirlbel Mar 1 '13 at 17:33
    
\sbox+\wd is what I used in the end indeed. My case has to do with my tree-drawing package forest: I had to do some manual adjustment (node-positioning algorithm doesn't take edge labels into account). Values given to dimen-type options of the nodes are automatically parsed by pgfmath (that's why using pgfmath's width was my first choice), but the result is assigned locally. Thus, if I enclosed the processing of the option into a group (which can be done using key TeX), the assignment would be forgotten (I guess I'd also get errors). –  Sašo Živanović Mar 3 '13 at 0:20
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.