4

In order to prevent conflicts with labels when gathering exercices from a database, I need to redefine the commands \label, \ref and \pageref to add a local prefix to labels. Unfortunately, the package varioref does not work anymore.

Here is a MWE.

\documentclass{article}
\usepackage{varioref}

\newcommand*{\globallabel}[1]{global:#1}

\AtBeginDocument{%
  \let\origref\ref
  \renewcommand*{\ref}[1]{%
    \origref{\globallabel{#1}}%
  }
  \let\origpageref\pageref
  \renewcommand*{\pageref}[1]{%
    \origpageref{\globallabel{#1}}%
  }
  \let\origlabel\label%
  \renewcommand*{\label}[1]{%
    \origlabel{\globallabel{#1}}
  }
}
\makeatother

\begin{document}

Example 1: figure~\vref{fig:example1}.

Example 2: figure~\vpageref{fig:example2}.

\begin{figure}
  \caption{Example 1}
  \label{fig:example1}
\end{figure}

\clearpage

\begin{figure}
  \caption{Example 2}
  \label{fig:example2}
\end{figure}

\end{document}

I get

Example 1: figure 1 on page 1.
Example 2: figure on page 2.

instead of

Example 1: figure 1.
Example 2: figure on the next page.

In the log file, I found

LaTeX Warning: Reference `fig:example1' on page 1 undefined on input line 31.
LaTeX Warning: Reference `fig:example2' on page 1 undefined on input line 33.

I've tried to redefine the commands \vref and \pagreref in the same way ; without success.

2 Answers2

10

Also some internals of package varioref need to be redefined, e.g.:

\documentclass{article}
\usepackage{varioref}

\newcommand*{\globallabel}[1]{global:#1}

\makeatletter
\AtBeginDocument{%  
  \let\origref\ref
  \renewcommand*{\ref}[1]{%
    \origref{\globallabel{#1}}%
  }%
  \let\origpageref\pageref
  \renewcommand*{\pageref}[1]{%
    \origpageref{\globallabel{#1}}%
  }%
  \let\origlabel\label%
  \renewcommand*{\label}[1]{%
    \origlabel{\globallabel{#1}}%
  }%
  \let\orig@@vpageref\@@vpageref
  \def\@@vpageref#1[#2]#3{%
    \begingroup
      \let\pageref\origpageref
      \orig@@vpageref{#1}[{#2}]{\globallabel{#3}}%
    \endgroup
  }%
  \let\origvr@f\vr@f
  \renewcommand*{\vr@f}[1]{%
    \begingroup
      \let\ref\origref
      \let\@@vpageref\orig@@vpageref
      \origvr@f{\globallabel{#1}}%
    \endgroup
  }%
}
\makeatother  

\begin{document}

Example 1: figure~\vref{fig:example1}.

Example 2: figure~\vpageref{fig:example2}.

\begin{figure}
  \caption{Example 1}
  \label{fig:example1}
\end{figure}
\clearpage

\begin{figure}
  \caption{Example 2}
  \label{fig:example2}
\end{figure}   

\end{document}

Result:

Example 1: figure 1.
Example 2: figure on the next page.

Remarks:

  • Using the internals rather than \vref or \vpageref makes it easier to support the various syntax forms (star, optional arguments) of \vref and \vpageref.
  • In the redefinition of \vref/\vpageref, some original referencing commands are enabled to avoid double prefixes.

Patch for hyperref

  • A nested \globallabel is avoided in \vref by disabling it locally.

Example:

\documentclass{article}
\usepackage{nameref}
\usepackage{varioref}
\usepackage{hyperref}
\usepackage{letltxmacro}

\newcommand*{\globallabel}[1]{global:#1}

\makeatletter
\AtBeginDocument{%
  \LetLtxMacro\origref\ref
  \renewcommand*{\ref}[1]{%
    \origref{\globallabel{#1}}%
  }%
  \LetLtxMacro\origpageref\pageref
  \renewcommand*{\pageref}[1]{%
    \origpageref{\globallabel{#1}}%
  }%
  \LetLtxMacro\origlabel\label%
  \renewcommand*{\label}[1]{%
    \origlabel{\globallabel{#1}}%
  }%
  \let\orig@@vpageref\@@vpageref
  \def\@@vpageref#1[#2]#3{%
    \begingroup
      \let\pageref\origpageref
      \orig@@vpageref{#1}[{#2}]{\globallabel{#3}}%
    \endgroup
  }%
  \let\origvr@f\vr@f
  \renewcommand*{\vr@f}[1]{%
    \begingroup
      \let\ref\origref
      \let\@@vpageref\orig@@vpageref
      \expandafter\let\expandafter\globallabel\expandafter\@firstofone
      \expandafter\origvr@f\expandafter{\globallabel{#1}}%
    \endgroup
  }%
}
\makeatother

\begin{document}

Example 1: figure~\vref{fig:example1}.

Example 2: figure~\vpageref{fig:example2}.
\documentclass{article}
\usepackage{varioref}

\newcommand*{\globallabel}[1]{global:#1}

\makeatletter
\AtBeginDocument{%  
  \let\origref\ref
  \renewcommand*{\ref}[1]{%
    \origref{\globallabel{#1}}%
  }%
  \let\origpageref\pageref
  \renewcommand*{\pageref}[1]{%
    \origpageref{\globallabel{#1}}%
  }%
  \let\origlabel\label%
  \renewcommand*{\label}[1]{%
    \origlabel{\globallabel{#1}}%
  }%
  \let\orig@@vpageref\@@vpageref
  \def\@@vpageref#1[#2]#3{%
    \begingroup
      \let\pageref\origpageref
      \orig@@vpageref{#1}[{#2}]{\globallabel{#3}}%
    \endgroup
  }%
  \let\origvr@f\vr@f
  \renewcommand*{\vr@f}[1]{%
    \begingroup
      \let\ref\origref
      \let\@@vpageref\orig@@vpageref
      \origvr@f{\globallabel{#1}}%
    \endgroup
  }%
}
\makeatother  

\begin{document}

Example 1: figure~\vref{fig:example1}.

Example 2: figure~\vpageref{fig:example2}.

\begin{figure}
  \caption{Example 1}
  \label{fig:example1}
\end{figure}
\clearpage

\begin{figure}
  \caption{Example 2}
  \label{fig:example2}
\end{figure}   

\end{document}
Heiko Oberdiek
  • 271,626
  • +1 I thought it a bit late at night for changing vref internals:-) – David Carlisle Jun 14 '13 at 23:47
  • Thanks, but :-) the MWE does not compile with hyperref package. I replaced \let by \LetLtxMacro as you said here. But at compile time, I get: TeX Warning: Reference 'global:global:fig:example1' on page 1 undefined on in put line 44. – Éric Guirbal Jun 15 '13 at 19:00
  • There is problem too with babel for french language. Replacing the active character ':' in labels with '-', or \usepackage[babel,kerning=true]{microtype} solve the problem. – Éric Guirbal Jun 15 '13 at 19:09
  • @EricGuirbal: I can't reproduce the problem, if I add \usepackage[french]{babel} to both examples. – Heiko Oberdiek Jun 15 '13 at 19:21
  • @Heiko Oberdiek: I get Missing \endcsname inserted. <to be read again> :. According to egreg: "The problem is that varioref and cref don't like babel shorthands in the labels." Putting \shorthandoff{:} in \AtBeginDocument is another solution. – Éric Guirbal Jun 15 '13 at 20:35
  • @EricGuirbal: Perhaps you have an older version of varioref. There are fixes for french/babel in versions 2010/11/12 v1.4y and 2011/10/02 v1.4z of package varioref for LaTeX bug reports latex/4093 and tools/4159. – Heiko Oberdiek Jun 15 '13 at 20:49
  • @HeikoOberdiek: Ok, now I am working with TeXLive 2012. The MWE with your patch compile. \vref works perfectly but \vpageref{fig} has the same output as page~\pageref{fig}. Loading package varioref in block \AtBeginDocument make \vpageref works properly. But when I add babel for french language, Bada Boum ! Missing \endcsname inserted. <to be read again> \penalty l.47 Example 1: figure~\vref{fig:example1} ?! Extra \endcsname. \@ifundefined ...dafter \ifx \csname #1\endcsname \relax \expandafter \@firs... – Éric Guirbal Jun 16 '13 at 12:26
  • @EricGuirbal: Package babel activates its shorthands in \begin{document}. That disturbs packages that are loaded afterwards via \AtBeginDocument. – Heiko Oberdiek Jun 16 '13 at 12:55
4

enter image description here

It's a bit harder to redefine the names as you need to redefine both \vref and \ref to catch top level use but \vref uses \ref internally and things get double-prefixed. It would be possible to open up the sources just to add the prefixes in the right place but easier is to use new top level names to add the prefix, then things work as expected as the prefix is just added once and the internal use of \ref uses the already prefixed key without prefixing it again.

\documentclass{article}
\usepackage{varioref}

\newcommand*{\globallabel}[1]{global:#1}

  \newcommand*{\myref}[1]{%
    \ref{\globallabel{#1}}%
  }
  \newcommand*{\myvref}[1]{%
    \vref{\globallabel{#1}}%
  }
  \newcommand*{\myvpageref}[1]{%
    \vpageref{\globallabel{#1}}%
  }
  \newcommand*{\mypageref}[1]{%
    \pageref{\globallabel{#1}}%
  }
  \newcommand*{\mylabel}[1]{%
    \label{\globallabel{#1}}%
  }



\begin{document}

Example 1: figure~\myvref{fig:example1}.

Example 2: figure~\myvpageref{fig:example2}.

\begin{figure}
  \caption{Example 1}
  \mylabel{fig:example1}
\end{figure}

\clearpage

\begin{figure}
  \caption{Example 2}
  \mylabel{fig:example2}
\end{figure}

\end{document}
David Carlisle
  • 757,742