3

I encounter a small but annoying problem with the following MWE

\documentclass{article}

\usepackage{hyperref,cleveref}
\newtheorem{thm}{Theorem}

\begin{document}

\begin{thm}\label{good}
    Cleveref is good
\end{thm}

\section{Proof of \Cref{good}}
    It is trivial.

\end{document}

The compiler (pdflatex) complains

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

Also the PDF TOC shows Proof of good instead of Proof Theorem 1. Is their any solution other than saying \section{Proof of Theorem \ref{...}}? After all, the whole point of using cleveref is not to repeat the fact that good is a theorem.

PS1. I also want a solution for amsart or more general document classes. (That is, the order of \usepackages is more or less fixed)

PS2. Feel free to mark duplicate. Although other MWEs I saw on this site are far from minimal.

  • 2
    The issue is that cleveref's machinery is not expandable (\@ifnextchar, for example, isn't), so it can't be turned into a PDF string. The crossreftools package provides an expandable alternative. Possible duplicate? tex.stackexchange.com/q/381513/134574 – Phelype Oleinik Sep 14 at 19:35
  • @PhelypeOleinik I got an error complaining Use of \refstepcounter@optarg doesn't match its definition when I use \crtCref. – Symbol 1 Sep 14 at 19:53
  • Indeed, after leaving the comment I went to try my suggestion (I should probably try and then comment :-). This problem is because cleveref inserts some non-expandable \MakeUppercase in the reference to the theorem, and when crossreftools tries to use it in an expansion-only context, hell breaks loose. I'll investigate :-) – Phelype Oleinik Sep 14 at 19:56
4

As I said in the comment, the issue is that cleveref's machinery is not expandable (the \@ifnextchar that hyperref complains about, for example, isn't expandable), so it can't be turned into a PDF string.

The crossreftools package provides an expandable alternative for cross referencing commands. For cleverref you can replace \cref by \crtcref and \Cref by \crtCref.

However, as you noted in your comment, only using that breaks badly. The reason is that cleverref redefines some internals of the theorems and inserts some \MakeUppercase and \MakeLowercase (which aren't expandable). The issue boils down to the fact that these commands end up in the cross reference code, which is expected to contain only text. When hyperref tries to expand that, chaos ensues.

I tried to find a proper fix, but most of them led to a can of worms of code which would then be incompatible with everything. An easier way out, which preserves cleveref's functionality and leaves the cross reference text expandable, is to use expl3's case changing functions. I used etoolbox's \patchcmd to replace the two occurrences of \MakeUppercase and one of \MakeLowercase by \tl_upper_case:n and \tl_upper_case:n, respectively, from the commands \@othm, \@xnthm, and \@ynthm. After patching that, the expandability problem is no more :-)

The pdf:

enter image description here

and the pdf bookmark file:

\BOOKMARK [1][-]{section.1}{Proof of Theorem 1}{}% 1

Code:

\documentclass{article}

\usepackage{expl3,etoolbox}

\usepackage{hyperref,cleveref}
\usepackage{crossreftools}

% This patch must be after loading cleverref and before defining a new theorem
\ExplSyntaxOn
\makeatletter
\clist_map_inline:nn { \@othm, \@xnthm, \@ynthm }
  {
    \patchcmd #1 { \MakeUppercase } { \tl_upper_case:n } { } { \FAILED: }
    \patchcmd #1 { \MakeUppercase } { \tl_upper_case:n } { } { \FAILED: }
    \patchcmd #1 { \MakeLowercase } { \tl_lower_case:n } { } { \FAILED: }
  }
\makeatother
\ExplSyntaxOff

\newtheorem{thm}{Theorem}

\begin{document}

\begin{thm}\label{good}
    Cleveref is good. expl3 is awesome :D
\end{thm}

\section{Proof of \crtCref{good}}
    It is trivial.

\end{document}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.