Take the 2-minute tour ×
TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It's 100% free, no registration required.

I am using varioref and cleveref together. This works pretty well. I had to add a hack though, which modifies the strings used by varioref (in german it should read "ab Seite X" ("starting on page X") instead of "auf Seite X" ("on page X") for chapters, sections, etc.).

The hack for this modification can be found here: http://texwelt.de/wissen/fragen/7013/vref-in-den-appendix

This also works pretty well. But I noticed that I cannot use the plain old \ref alongside of this shiny new cleveref+varioref+hack-setup. When I use \vref{} after \ref{}, I trigger the following error:

LaTeX Warning: Reference `Foo' on page 1 undefined on input line 38.

! Argument of \@firstoftwo has an extra }.
<inserted text> 
\par 
l.39 Second Ref: \vref{Foo}
                         .
? 
! Emergency stop.

Here is a minimal example:

\documentclass[a4paper,11pt]{scrreprt}
\usepackage{fontspec}
\usepackage{etoolbox}

\usepackage[ngerman]{varioref}
\usepackage{cleveref}

% This changes the string "auf Seite..." to "ab Seite..." for
% chapter/section/etc.-labels, which are 'far away'.
%
% Thanks for this hack to http://texwelt.de/wissen/fragen/7013/vref-in-den-appendix
% and http://www.schlosser.info/latex-cleveref-varioref-ab-seite/

\makeatletter
\newcommand*\curtlabtype{}
\let\@old@cref@vref\cref@vref
\renewcommand*\cref@vref[2]{%
  \ifcsdef{r@#2}% teste, ob Label `#2' definiert ist
    {\cref@gettype{#2}{\curtlabtype}}% %% FIXME, this line seems to break it! %
    {}%
  \@old@cref@vref{#1}{#2}%
}
\vref@addto\extrasngerman{%
  \renewcommand*\reftextfaraway[1]{%
    (%
    \ifboolexpr
      {
        test {\ifdefstring{\curtlabtype}{chapter}}
      }
      {ab Seite}
      {auf Seite}%
    ~\pageref{#1})}%
}
\makeatother

\begin{document}

First Ref: \ref{Foo}. Without this, it works.
Second Ref: \vref{Foo}.

\chapter{Foo}
\label{Foo}

\end{document}

In the cleveref-Hack, I highlighted the line which seems to have something to do with error with a FIXME. I don't understand this error... I need the plain \ref{} also, because in some context I really only need the number of the chapter/section, not anything fancy, like "Chapter X" (\cref{}) or "Chapter X (on page ...)" (\vref{}). I am using LuaLaTeX beta-0.76.0-2014042815 (from TeX Live 2013/Arch Linux).

Thanks in advance for any hints/pointers.

share|improve this question
1  
The LaTeX warning message you're getting should tip you off as to what's going on: Since you don't provide a \label{Foo} statement anywhere in the MWE, LaTeX cannot resolve the \ref{Foo} statement and hence issues a warning message. Provide the directive \label{Foo} after \chapter{Foo} and your MWE compiles flawlessly. (By the way, the answer to your posting in TeXWelt already informed you that you must provide \label statements so that cross-references can be resolved.) –  Mico Jul 29 at 1:29
    
@Mico: I'm sorry for my mistake -- in the example I uplodaded I forgot the \label{Foo} -- it's fixed now (above). Still, the example fails with the very same error message. Did you maybe have some old *aux files around? When the labels are already in the *aux files, then it does compile, but when I do a clean compile, it fails. Maybe I understood the posting in TeXWelt wrong (btw, it was not my posting), then the code (\ifcsdef) makes the sure that it also compiles when the labels are not already there. This works for all the vref and cref-commands, but not for plain old ref. –  mfuglos Jul 29 at 9:16
    
@mfuglos Out of curiosity: is there a reason you asked the follow-up question here and not on TeXwelt? –  cgnieder Jul 29 at 9:43
    
cgnieder: Well, just to clarify: I haven't posted anything to TeXwelt (I only found this cleveref-Hack there). Regarding TeXwelt vs. tex.stackexchange: I think TeXwelt is only german (right?) and I do have a tex.stackexchange account (which I found to be very helpful for me). –  mfuglos Jul 29 at 9:58
    
@mfuglos ok sorry. I thought you were the one who posted on TeXwelt, too. –  cgnieder Jul 29 at 10:05

1 Answer 1

up vote 4 down vote accepted

The problem is that there are two kinds of »check if macro is undefined« tests in LaTeX.

As you've noticed the error appears with an undefined label and if \ref is used before \vref. This gives us some clues: the internal code should test if a label is defined or not, right?

\renewcommand*\cref@vref[2]{%
  \ifcsdef{r@#2}% <<<<<<<< test if label is defined
    {\cref@gettype{#2}{\curtlabtype}}%
    {}%
  \@old@cref@vref{#1}{#2}%
}

But obviously it fails after a \ref has been used. How can that be? Well, \ref also tests if a label exists. More precisely the command \@setref (which is called by \ref at some point) does it, also by testing if the macro \r@<label> is defined (or rather if it is not \relax). LaTeX's definition of \ref is

\def\ref#1{\expandafter\@setref\csname r@#1\endcsname\@firstoftwo{#1}}

The problem now is that \csname r@#1\endcsname defines a macro equal to \relax if it does not exist yet. But in the eyes of \ifcsdef a definition \relax is a valid one so it (mistakenly in this case) uses the true branch if \cref@vref is used after \ref has been used regardless if the label exists or not.

So we need a test that checks if a macro is undefined or equal to \relax. Since you're using a KOMA-Script class this is easy: it comes with

\scr@ifundefinedorrelax{<csname>}{<true>}{<false>}
\ifundefinedorrelax{<csname>}{<true>}{<false>}

With this the definition of above becomes

\renewcommand*\cref@vref[2]{%
  \scr@ifundefinedorrelax{r@#2}% <<<<<<<< test if label is defined
    {}%
    {\cref@gettype{#2}{\curtlabtype}}%
  \@old@cref@vref{#1}{#2}%
}

and the error is gone.

Also possible: doing the same kind of test that \@setref does – this does not require a KOMA-Script class or the package scrbase:

\renewcommand*\cref@vref[2]{%
  \expandafter\ifx\csname r@#2\endcsname\relax % <<<<<<<< test if label is defined
  \else
    \cref@gettype{#2}{\curtlabtype}%
  \fi
  \@old@cref@vref{#1}{#2}%
}
share|improve this answer
    
I also updated the corresponding Post on TeXwelt –  cgnieder Jul 29 at 12:15

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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