3

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.

3
  • It makes no sense having \@ifstar in the “pdf part” of \texorpdfstring
    – egreg
    Commented May 20, 2016 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. Commented May 20, 2016 at 13:11
  • Even stranger, \edef\temp{\foo{plain}{direct}} also crashes - Argument of KV@def has an extra }. Commented May 20, 2016 at 13:38

2 Answers 2

2

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}

enter image description here

0

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}

demo

2
  • How would this solution generalize to a non-toy example where the problematic macro isn't the first thing in the title? Commented May 20, 2016 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. Commented May 20, 2016 at 14:58

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .