4

cleveref's \cpageref seems to have an issue when it receives three or more labels spanning a range of pages. When this happens, \cpageref prints the first and the last labels (the arguments) instead of the pages it was supposed to print, and issues no warnings about it.

This problem has appeared here on the site, as far back as two years ago (see Incorrect \cpageref result with multiple (3+) references that span a page range and Multi-referencing with cleveref: is \cpageref compression bugged, or am I using it wrong?, there were no answers to either of them). Also, the problem has also been reported upstream, but so far hasn't been dealt with (the problem still affects "Version 0.21.5 (pre-release version)", available at https://www.dr-qubit.org/cleveref.html).

That given, I've also been affected by the issue, and took my own stab at it. And I think I understand the problem and have a fix for it. However, my TeX-fu is quite limited (to be kind), so I'm unsure about it. So, my question here is to ask for confirmation about this from more experienced users.

The issue itself can be reproduced by the following MWE:

\documentclass{article}

\usepackage{cleveref}

\begin{document}

See \cref{tab1,tab2,tab3,tab4} on \cpageref{tab1,tab2,tab3,tab4}.

\clearpage{}

\begin{table} \caption{Table 1} \label{tab1} \begin{tabular}{cc} 1 & 2 \ 3 & 4 \ \end{tabular} \end{table}

\begin{table} \caption{Table 2} \label{tab2} \begin{tabular}{cc} 1 & 2 \ 3 & 4 \ \end{tabular} \end{table}

\clearpage{}

\begin{table} \caption{Table 3} \label{tab3} \begin{tabular}{cc} 1 & 2 \ 3 & 4 \ \end{tabular} \end{table}

\begin{table} \caption{Table 4} \label{tab4} \begin{tabular}{cc} 1 & 2 \ 3 & 4 \ \end{tabular} \end{table}

\end{document}

Which compiles without errors or warnings, and produces:

enter image description here

Now, where I think the problem lies. In the definition of \@cref, at a certain point, cleveref does the following:

      \ifnum\count@consecutive=1\relax%
        \edef\@tempa{{\@beginref}{\@pos}}%
        \csname @set\cref@variant\expandafter\endcsname\@tempa%
      \else%
        \edef\@tempa{{\@beginref}{\@endref}{\@pos}}%
        \csname @set\cref@variant range\expandafter\endcsname\@tempa%
      \fi%

(I'm on a current TeXLive here, my cleveref.sty has date 2018/03/27 and version 0.21.4, and this occurs in lines 1021 to 1027).

At this point \@cref is looping over a subgroup consecutive labels. \cref@variant is the name of the user facing cleveref macro, which is received as the first argument of \@cref (e.g. cref, Cref, cpageref, etc). So, this is calling a set of macros with names either \@set<variant> or \@set<variant>range.

And we do find most of these explicitly defined in cleveref.sty: \@setcref, \@setCref and \@setlabelcref on lines 1044-1046; \@setcrefrange, \@setCrefrange and \@setlabelcrefrange on lines 1072-1074; \@setcpageref, \@setCpageref and \@setlabelcpageref on lines 1087-1089 (there are still others).

However, I cannot find \@setcpagerefrange, \@setCpagerefrange and \@setlabelcpagerefrange, and I think that's what's missing. Besides, though none of the linked questions mentioned \Cpageref and \labelcpageref, this observation would suggest they would fail in the same way as \cpageref does. And indeed, they do.

Providing them in the MWE above as:

\makeatletter
\newcommand*{\@setcpagerefrange}[3]{%
  \@@setcpagerefrange{#1}{#2}{cref}{#3}}
\newcommand*{\@setCpagerefrange}[3]{%
  \@@setcpagerefrange{#1}{#2}{Cref}{#3}}
\newcommand*{\@setlabelcpagerefrange}[3]{%
  \@@setcpagerefrange{#1}{#2}{labelcref}{#3}}
\makeatother

(Note that the order of the arguments in \@@setcpagerefrange is different from its siblings).

Will now give us expected results:

enter image description here

So, are this diagnostic and this fix correct?

gusbrs
  • 13,740
  • 2
    I don't have the time too look, but I asked someone whose documents fails too to test, and I also made another try with the maintainer with another address, but got the automated answer that he is to busy and will probably never see the mail ... – Ulrike Fischer Jul 03 '21 at 18:38
  • Hi @UlrikeFischer thank you for this. If you get any answer from that someone, I'd be glad to hear about it. I've also written again to the maintainer with this possible fix, I think the message went through, but if it is going to be actually received it is another matter (the email in the documentation simply returns and fails to deliver, I wrote then to the email on his site). This is a pity, since this is an almost "standard" package for this task, the failure is pretty bad (I think), and if I'm right, it is really easy to fix. – gusbrs Jul 03 '21 at 20:39
  • @UlrikeFischer If I may ask (and I do so considering the case). You said in the other question you are not much using cleveref, what do you use? Do you have any idea what people commonly use for this functionality area? – gusbrs Jul 03 '21 at 20:51
  • I don't write really long documents, and seldom need complicated references. So mostly I simply use \ref, or define a special command for one document if needed. – Ulrike Fischer Jul 03 '21 at 21:38
  • @UlrikeFischer Thank you. Yeah, I'm starting a larger project at the moment, and do welcome the automation cleveref provides for this. That's why I stumbled with the issue. I guess I'll just have to be watchful, I think. Hopefully, I got the fix right. :-) – gusbrs Jul 03 '21 at 21:51
  • well in the few cases where I had to code complicated references I made them with zref. It gives you more control. – Ulrike Fischer Jul 03 '21 at 21:57
  • @UlrikeFischer I'm glad I asked, I was unaware of zref, and I will take a look at it. Thank you once again. – gusbrs Jul 03 '21 at 22:00

1 Answers1

3

Well, not to leave this one unanswered, to the best of my knowledge, the problem is indeed the one diagnosed in the OP. An attempt of contact with the maintainer with the suggested fix has been made.

\documentclass{article}

\usepackage{cleveref}

\makeatletter \newcommand{@setcpagerefrange}[3]{% @@setcpagerefrange{#1}{#2}{cref}{#3}} \newcommand{@setCpagerefrange}[3]{% @@setcpagerefrange{#1}{#2}{Cref}{#3}} \newcommand*{@setlabelcpagerefrange}[3]{% @@setcpagerefrange{#1}{#2}{labelcref}{#3}} \makeatother

\begin{document}

See \cref{tab1,tab2,tab3,tab4} on \cpageref{tab1,tab2,tab3,tab4}.

\clearpage{}

\begin{table} \caption{Table 1} \label{tab1} \begin{tabular}{cc} 1 & 2 \ 3 & 4 \ \end{tabular} \end{table}

\begin{table} \caption{Table 2} \label{tab2} \begin{tabular}{cc} 1 & 2 \ 3 & 4 \ \end{tabular} \end{table}

\clearpage{}

\begin{table} \caption{Table 3} \label{tab3} \begin{tabular}{cc} 1 & 2 \ 3 & 4 \ \end{tabular} \end{table}

\begin{table} \caption{Table 4} \label{tab4} \begin{tabular}{cc} 1 & 2 \ 3 & 4 \ \end{tabular} \end{table}

\end{document}

enter image description here

gusbrs
  • 13,740