7

I'm trying to do some voodoo with \peek_meaning. I want to have a command, \blubb, which is sensitive to repetitions of itself.

When I write \blubb{Lorem Ipsum}, I want the text coloured in red, but with \blubb\blubb{Lorem Ipsum} I would like the text to be coloured in blue. See this working example:

\documentclass{article}
\usepackage{xcolor}
\usepackage{expl3}
\usepackage{xparse}

%\usepackage{hyperref}

\ExplSyntaxOn

\DeclareRobustCommand\blubb{
    \peek_meaning:NTF \blubb { \colorTwo } { \colorOne }
}

\ExplSyntaxOff

\DeclareRobustCommand\colorOne[1]{\textcolor{red}{#1}}
\DeclareRobustCommand\colorTwo[2]{\textcolor{blue}{#2}}

\begin{document}

Lorem Ipsum \blubb{is red} Dolor Sit \blubb\blubb{is blue}

\section{Lorem Ipsum \blubb{is red} Dolor Sit \blubb\blubb{is blue}}
% ^ does not work with hyperref

\end{document}

screenshot

This works fine, until I enable the hyperref package. Then I get:

! TeX capacity exceeded, sorry [input stack size=5000].
\blubb  ->\peek_meaning:NTF \blubb 
                                   {\colorTwo }{\colorOne }
l.23 ...b{is red} Dolor Sit \blubb\blubb{is blue}}

Apparently, the \blubb after \peek_meaning gets expanded, which leads to a recursion. How do I prevent this?

2 Answers2

5
\documentclass{article}
\usepackage{xcolor}
\usepackage{expl3}
\usepackage{xparse}
\usepackage{hyperref}

\ExplSyntaxOn

\NewDocumentCommand \blubb { }
 {
  \peek_meaning_remove:NTF \blubb { \colorTwo } { \colorOne }
 }

\ExplSyntaxOff

\NewDocumentCommand \colorOne { m } {\textcolor{red}{#1}}
\NewDocumentCommand \colorTwo { m } {\textcolor{blue}{#1}}

\begin{document}

Lorem Ipsum \blubb{is red} Dolor Sit \blubb\blubb{is blue}

\section{Lorem Ipsum \blubb{is red} Dolor Sit \blubb\blubb{is blue}}
% ^ does not work with hyperref without warnings

\end{document}

output

But note the console output:

Package hyperref Warning: Token not allowed in a PDF string (PDFDocEncoding):
(hyperref)                removing `\blubb' on input line 139.

This is because hyperref makes a bookmark for the \section which cannot include the \blubb macro. See hyperref's documentation for details. We can use \texorpdfstring{}{} to avoid the problem.

\documentclass{article}
\usepackage{xcolor}
\usepackage{expl3}
\usepackage{xparse}
\usepackage{hyperref}

\ExplSyntaxOn

\NewDocumentCommand \blubb { }
 {
  \peek_meaning_remove:NTF \blubb { \colorTwo } { \colorOne }
 }

\ExplSyntaxOff

\NewDocumentCommand \colorOne { m } {\textcolor{red}{#1}}
\NewDocumentCommand \colorTwo { m } {\textcolor{blue}{#1}}

\begin{document}

Lorem Ipsum \blubb{is red} Dolor Sit \blubb\blubb{is blue}

\section{Lorem Ipsum \texorpdfstring{\blubb}{}{is red} Dolor Sit \texorpdfstring{\blubb\blubb}{}{is blue}}

\end{document}

A more convenient way to avoid the warning, however, maybe to use hyperref's hook to disable \blubb when necessary. For example (and also using the recommended bookmark package):

\documentclass{article}
\usepackage{xparse,xcolor}
\usepackage{hyperref}
\usepackage{bookmark}

\ExplSyntaxOn

\NewDocumentCommand \blubb { }
 {
  \peek_meaning_remove:NTF \blubb { \colorTwo } { \colorOne }
 }

\ExplSyntaxOff

\NewDocumentCommand \colorOne { m } {\textcolor{red}{#1}}
\NewDocumentCommand \colorTwo { m } {\textcolor{blue}{#1}}

\makeatletter
\pdfstringdefDisableCommands{%
  \let\blubb\@firstofone
}
\makeatother

\begin{document}

Lorem Ipsum \blubb{is red} Dolor Sit \blubb\blubb{is blue}

\section{Lorem Ipsum \blubb{is red} Dolor Sit \blubb\blubb{is blue}}

\end{document}
egreg
  • 1,121,712
cfr
  • 198,882
  • +1 for \peek_meaning_remove, this avoids the ugly, inconsistent definition of \colorXXX! – Peater de Xel Sep 13 '16 at 12:04
  • @raffix That wasn't me, I'm afraid. – cfr Sep 13 '16 at 20:25
  • @egreg I don't know if pinging this way works, but thank you! – cfr Sep 13 '16 at 20:25
  • @cfr Yes, it works. ;-) Adding a new answer just for fixing a couple of weaknesses was not a choice. – egreg Sep 13 '16 at 20:31
  • @egreg So it is better to have the function remove the next \blubb than have \ColorTwo throw its first argument away? Intuitively that seems better, but I could not explain why. – cfr Sep 13 '16 at 20:49
  • 2
    @cfr Indeed! You can define \colorOne and \colorTwo independently of their eventual position in the macro; with the _remove, the token is removed if found and the proper path is followed. This can be used to check for a third \blubb, for instance, without any need for defining differently \colorThree. – egreg Sep 13 '16 at 20:53
  • @egreg Thanks. That makes sense :-). – cfr Sep 13 '16 at 20:55
4

A different approach.

\documentclass{article}
\usepackage{xcolor}

\usepackage{hyperref}

\def\blubb#1{%
  \ifx\blubb#1\relax%
    \def\blubbcolor{blue}\expandafter\blubbhelp%
  \else
    \def\blubbcolor{red}\blubbhelp{#1}%
  \fi%
}
\def\blubbhelp#1{\textcolor{\blubbcolor}{#1}}

\begin{document}

Lorem Ipsum \blubb{is red} Dolor Sit \blubb\blubb{is blue}

Lorem Ipsum \blubb{is red}Dolor Sit \blubb\blubb{is blue}without trailing spaces.

\section{Lorem Ipsum \blubb{is red} Dolor Sit \blubb\blubb{is blue}}
% ^ does not work with hyperref

\end{document}

enter image description here

As cfr rightly notes, \blubb generates warnings when used in section titles using hyperref, for the purposes of creating bookmarks. It can be overcome with \texorpdfstring, us as follows: \section{Lorem Ipsum \texorpdfstring{\blubb{is red}}{is red} Dolor Sit \texorpdfstring{\blubb\blubb{is blue}}{is blue}}, for example.