Customizing varioref to only add “… on page XX”, and only when there is more than one page in between reference and figure

varioref is a nice package as it will, when referencing, add "... on the [facing/next/preceding/following] page" if the reference and figure (or whatever object is being reference) are located on different pages. If there is more than a page in between, varioref will add "... on page XX".

However, I've noticed that all these "... on the [facing/next/etc] page" becomes a bit excessive; what I only really need is the "... on page XX" when the reference is far away. In my document, I've solved this by redefining the appropriate TeX definitions of varioref:

\makeatletter
\def\reftextfaceafter{}
\def\reftextfacebefore{}
\def\reftextafter{}
\def\reftextbefore{}
\def\reftextcurrent{}
}
\makeatother


However, it doesn't feel very robust as this only works if english is selected as option. For american, I would have to copy-paste the same commands but replace extraenglish with extraamerican.

Is there some more efficient and "thorough" way of achieving the same thing, but for all language options? It is really not necessary in my case since I know I will be using english, but I'm interested out of curiosity. =)

-

As those commands are defined in any of the \extra... commands of babel (if babel is being used) one needs to either apply such changes for all languages in use or (the better alternative) one patches varioref itself. Fortunately the commands are used only in a single place namely \@@vpageref. So a general solution would be:

\documentclass{article}

\usepackage{varioref}
\usepackage{etoolbox}

\makeatletter
\patchcmd{\@@vpageref} {\reftextfacebefore}{\unskip}{\typeout{*** SUCCESS ***}}{\typeout{*** FAIL ***}}
\patchcmd{\@@vpageref} {\reftextfaceafter}{\unskip}{\typeout{*** SUCCESS ***}}{\typeout{*** FAIL ***}}

% for \reftextafter and \reftextbefore we have to patch twice

\patchcmd{\@@vpageref} {\reftextbefore}{\unskip}{\typeout{*** SUCCESS ***}}{\typeout{*** FAIL ***}}
\patchcmd{\@@vpageref} {\reftextbefore}{\unskip}{\typeout{*** SUCCESS ***}}{\typeout{*** FAIL ***}}

\patchcmd{\@@vpageref} {\reftextafter}{\unskip}{\typeout{*** SUCCESS ***}}{\typeout{*** FAIL ***}}
\patchcmd{\@@vpageref} {\reftextafter}{\unskip}{\typeout{*** SUCCESS ***}}{\typeout{*** FAIL ***}}

\show\@@vpageref  % have a look at the results
\makeatother


It is a bit crude as\@@vpageref now contains some absolutely useless code, ie a bunch of if-then-else statements without any code inside to execute. But who cares ;-)

The above also nicely works if you just want to disable the "face" ones but keep the ones where turning a page is required.

varioref + hyperref/nameref

If hyperref or nameref (a component of the hyperref bundle) is used in conjunction with varioref then the patching needs to be slightly different. In that case the macro that contains the calls is not \@@vpageref but \NR@vprageref. Furthermore it will get its definition only after \begin{document}, so the patch commands will look like this:

\makeatletter
\AtBeginDocument{%
\patchcmd{\NR@@vpageref} {\reftextfacebefore}{\unskip}{\typeout{*** SUCCESS ***}}{\typeout{*** FAIL ***}}%
\patchcmd{\NR@@vpageref} {\reftextfaceafter}{\unskip}{\typeout{*** SUCCESS ***}}{\typeout{*** FAIL ***}}%
\patchcmd{\NR@@vpageref} {\reftextbefore}{\unskip}{\typeout{*** SUCCESS ***}}{\typeout{*** FAIL ***}}%
\patchcmd{\NR@@vpageref} {\reftextbefore}{\unskip}{\typeout{*** SUCCESS ***}}{\typeout{*** FAIL ***}}%
\patchcmd{\NR@@vpageref} {\reftextafter}{\unskip}{\typeout{*** SUCCESS ***}}{\typeout{*** FAIL ***}}%
\patchcmd{\NR@@vpageref} {\reftextafter}{\unskip}{\typeout{*** SUCCESS ***}}{\typeout{*** FAIL ***}}}
\makeatother


Important: Even though this code is executed \AtBeginDocument it needs to be placed after hyperref was loaded, the reason being that hyperref also uses \AtBeginDocument to define \NR@@vpageref.

varioref + cleveref (+ hyperef)

If the cleveref package is used then some more/different patching is needed as this package unfortunately uses yet another "private" copy of parts of the varioref code, sigh. So in that case \cref@old@@vpageref needs to be patched, otherwise it is exactly the same approach:

\makeatletter

\patchcmd{\cref@old@@vpageref} {\reftextfacebefore}{\unskip}{\typeout{*** SUCCESS ***}}{\typeout{*** FAIL ***}}
\patchcmd{\cref@old@@vpageref} {\reftextfaceafter}{\unskip}{\typeout{*** SUCCESS ***}}{\typeout{*** FAIL ***}}

% for \reftextafter and \reftextbefore we have to patch twice

\patchcmd{\cref@old@@vpageref} {\reftextbefore}{\unskip}{\typeout{*** SUCCESS ***}}{\typeout{*** FAIL ***}}
\patchcmd{\cref@old@@vpageref} {\reftextbefore}{\unskip}{\typeout{*** SUCCESS ***}}{\typeout{*** FAIL ***}}

\patchcmd{\cref@old@@vpageref} {\reftextafter}{\unskip}{\typeout{*** SUCCESS ***}}{\typeout{*** FAIL ***}}
\patchcmd{\cref@old@@vpageref} {\reftextafter}{\unskip}{\typeout{*** SUCCESS ***}}{\typeout{*** FAIL ***}}
\makeatletter


Update/Correction

As Gabriel pointed out, has initial idea as well as my generalization of it, i.e., patching the commands \reftextafterand friends to simply do nothing has the side effect that you will end up with an extra space. The reason for this is that this space is generated automatically by \vref after the first number with the assumption that some text (such as "on the next page") will follow. So the correct way to deal with this is to patch the commands not by taking the mout but by replacing them with \unskip thereby removing that extra space again.

In the above code that is already corrected!

-
A nice thing about this approach compared to mine is that I don't have the problem of possible trailing whitespace. However, this solution doesn't appear to work when hyperref is included in the document (the patch has no effect, although it says "SUCCESS" for all patches). –  gablin Feb 11 '12 at 13:20
That is most certainly the case (that it doesn't work I mean). As hyperref changes the definitions of the vairoref internals you need to apply the same approach to the definitions in hyperef whatever they are), i.e., find the commands that execute \reftextafterand friends and patch them by taking the call out. Might add the corrsponding defs later .. have to run –  Frank Mittelbach Feb 11 '12 at 14:26
added the patch for the hyperref case - not tested though –  Frank Mittelbach Feb 11 '12 at 17:18
Ah, now it seems to work. Thanks! –  gablin Feb 11 '12 at 17:29
\AtBeginDocument{\def\reftextfaceafter{\unskip}%