# PDF plain text for a macro with a starred version

I'm typesetting a document with PDFLaTeX. In some section titles, I use a macro which has a starred version. In the PDF index (the table of contents that PDF viewers typically show in a side pane), I get the macro's arguments, showing that the macro has been erased somewhere. As it happens, I want to have just the second argument of the macro as the degraded plain text (whether the macro call has a star or not).

That is, I write

\section{\foo{one}{two}}


and I want it to be sort of like

\section[two]{\foo{one}{two}}


except that the table of contents should still have \foo{one}{two} and I want this to be automatic, I don't want to have to do something different in every section title where I use the macro.

This looks to me like a case for \texorpdfstring. But how do I eat up the star? LaTeX complains about \@ifnextchar ending up in a PDF string, which makes sense, because that's where the expandability stops. How can I eat up the star in an expandable way, or whatever it takes to get this right?

Toy example illustrating the problem:

\documentclass{article}
\usepackage[english]{babel}
\usepackage{xr-hyper}
\usepackage[destlabel=true]{hyperref}
\makeatletter
\def\foo@star#1#2{\textsf{#1}-{#2}}
\def\foo@plain#1#2{\textit{#1}-{#2}}
\DeclareRobustCommand{\foo}{\@ifstar\foo@star\foo@plain}
\def\foo@pdf#1#2{#2}
\DeclareRobustCommand{\goo}{\texorpdfstring{\@ifstar\foo@star\foo@plain}{\@ifstar\foo@pdf\foo@pdf}}
\DeclareRobustCommand{\hoo}{\texorpdfstring{\@ifstar\foo@star\foo@plain}{\foo@pdf}}
\makeatother
\begin{document}
\section{\foo{plain}{direct}}
\section{\foo*{starred}{direct}}
\section{\goo{plain}{texorpdfstring+ifstar}}
\section{\goo*{starred}{texorpdfstring+ifstar}}
\section{\hoo{plain}{texorpdfstring}}
\section{\hoo*{starred}{texorpdfstring}}
\end{document}


\foo is the base version, without consideration for PDF strings. \goo is what I wish would work, but doesn't because \@ifstar isn't fully expandable. \hoo works for the unstarred version but doesn't eat the star when it's present.

Warnings from LaTeX:

Package hyperref Warning: Token not allowed in a PDF string (PDFDocEncoding):
(hyperref)                removing \@ifnextchar' on input line 14.

Package hyperref Warning: Token not allowed in a PDF string (PDFDocEncoding):
(hyperref)                removing \@ifnextchar' on input line 15.

Package hyperref Warning: Token not allowed in a PDF string (PDFDocEncoding):
(hyperref)                removing \@ifnextchar' on input line 16.

Package hyperref Warning: Token not allowed in a PDF string (PDFDocEncoding):
(hyperref)                removing \@ifnextchar' on input line 17.


PDF index:

plaindirect
*starreddirect
plaintexorpdfstring+ifstar
*starredtexorpdfstring+ifstar
texorpdfstring
starredtexorpdfstring


What I want to have there is just the second argument, no first argument, no star.

• It makes no sense having \@ifstar in the “pdf part” of \texorpdfstring – egreg May 20 '16 at 12:51
• @egreg I know. It makes no sense to have \@ifstar in the TeX part either since it then gets interpreted as part of the PDF string. – Gilles May 20 '16 at 13:11
• Even stranger, \edef\temp{\foo{plain}{direct}} also crashes - Argument of KV@def has an extra }. – John Kormylo May 20 '16 at 13:38

I think this is what you want:

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

\DeclareExpandableDocumentCommand{\foo}{smm}{%
\texorpdfstring
{\IfBooleanTF{#1}{\textsf}{\textit}{#2}--#3}
{#2-#3}%
}

\begin{document}

\section{This is \foo{A}{B}}

\section{This is \foo*{A}{B}}

\end{document}


All you needed was \string.

\documentclass{article}
\usepackage[english]{babel}
\usepackage{xr-hyper}
\usepackage[destlabel=true]{hyperref}
\makeatletter
\newcommand{\foo@star}[2]{\textsf{#1}-{#2}}
\newcommand{\foo@plain}[2]{\textit{#1}-{#2}}
\DeclareRobustCommand{\foo}{\@ifstar\foo@star\foo@plain}
\makeatother

\newcommand{\mysection}[1]{\section[\string #1]{#1}}

\begin{document}
\tableofcontents

\mysection{\foo{plain}{direct}}
\mysection{\foo*{starred}{direct}}

\end{document}


• How would this solution generalize to a non-toy example where the problematic macro isn't the first thing in the title? – Gilles May 20 '16 at 14:38
• @Gilles - Further experiments showed no problems using additional text or macros. One can use \protect instead of \string, but I have never found a case where it works any better. – John Kormylo May 20 '16 at 14:58