Assuming I understand your approach, here is a wrapper for \cref
which removes duplicate labels on the basis of the "type" (i.e., the counter to which they refer) and the "label" (i.e., the value of the counter for the label). If multiple labels in a list refer to the same "type" and "label" combination, only the first is retained.
The guts:
The comma separated list is parsed with \forcsvlist
from etoolbox
. The "type" and "label" for each entry are retrieved using the \cref@gettype
and \cref@getlabel
from cleveref
. A unique global command (comprised of the "type" and "label") is used to indicate if the combination has been used before. If the unique command is not defined or it is equal to \relax
, then the unique command is redefined to be equal to the label and the label is appended to \compressed@list
which contains the compressed list. If the unique command exists and it is not equal to \relax
, the label is skipped and a warning is raised (this may be commented out if you so desire).
The compressed list is then passed to the old version of \cref
. Finally, each of the unique commands are reinitialized to \relax
with \forcsvlist\@clear@list{\compressed@list}
in preparation for subsequent \cref
calls. \DeclareRobustCommand
was used to retain the native functionality of \cref
in headings.
Edit: As pointed out by the OP in the comments below, the original version of this answer did not pass undefined labels through to \cref
; this version has been corrected.
\documentclass{book}
\usepackage{cleveref}
%%pre-compress labels to remove duplicates
\usepackage{etoolbox}
\makeatletter
%Robust, allowing \cref to be used in headings (may or may not be desired)
\DeclareRobustCommand\@create@list[1]{%
\ifcsname r@#1@cref\endcsname%only process if the label is defined
\cref@gettype{#1}{\@temptype}%cleveref command, set \@temptype to type associated with label (i.e., the counter name)
\cref@getlabel{#1}{\@templbl}%cleveref command, set \@templbl to the label (i.e., number) associated with the label
\ifcsname Addval\@temptype\@templbl\endcsname%already defined
\expandafter\if\csname Addval\@temptype\@templbl\endcsname\relax%equal to relax
\expandafter\gdef\csname Addval\@temptype\@templbl\endcsname{#1}%save the label
\if\compressed@list\relax%
\gdef\compressed@list{#1}\else
\g@addto@macro\compressed@list{,#1}\fi
\else%already defined and not equal to \relax
\@latex@warning{Label #1 is a duplicate of \@temptype\space\@templbl}%
\fi
\else%not defined yet
\expandafter\gdef\csname Addval\@temptype\@templbl\endcsname{#1}%save the label
\if\compressed@list\relax%
\gdef\compressed@list{#1}\else
\g@addto@macro\compressed@list{,#1}\fi
\fi
\else%Added in edit: label not defined...add to the list anyway for "standard" handling
\if\compressed@list\relax%
\gdef\compressed@list{#1}\else
\g@addto@macro\compressed@list{,#1}\fi
\fi}
%Robust, allowing \cref to be used in headings (may or may not be desired)
\DeclareRobustCommand\@clear@list[1]{%command to set the addval\@temptype\@templbl commands to relax
\ifcsname r@#1@cref\endcsname%only process if the label is defined
\cref@gettype{#1}{\@temptype}%cleveref command, set \@temptype to type associated with label (i.e., the counter name)
\cref@getlabel{#1}{\@templbl}%cleveref command, set \@templbl to the label (i.e., number) associated with the label
\expandafter\gdef\csname Addval\@temptype\@templbl\endcsname{\relax}\fi}
\def\compressed@list{\relax}%initialize
\let\old@cref=\cref
\def\cref#1{%Now, cref will compress duplicate labels and provide a warning if found
\gdef\compressed@list{\relax}%ensure \relax
\expandafter\forcsvlist\expandafter\@create@list\expandafter{#1}%create compressed list
\if\relax\compressed@list\relax\else
\old@cref{\compressed@list}%pass compresed list to cref
\expandafter\forcsvlist\expandafter\@clear@list\expandafter{\compressed@list}%clear compressed list
\fi}
\makeatother
\begin{document}
\chapter{This chapter}
\section{A section}
Expressions\label{exp.int}
Definitions\label{def.int}
\section{Another section}
Expressions and definitions occur in
\cref{exp.int,def.int} on
\cpageref{exp.int,def.int}.
\end{document}
exp.int
anddef.int
are the same labels effectively? They both refer to same sectionexp.int
anddef.int
are in the same section, but he could change that without having to think about re-labelling and changes in thecref
commands.