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.

In a LaTeX document, I use the fancyref package for in-document references. However, I need a bunch of custom prefixes to reference lemmas, definitions and theorems, which fancyref dos not provide. Following the documentation, adding a prefix which supports both vario and plain for both fref and Fref takes a lot of text, and it's all the same all the time. I'd like to avoid this using a macro which does it all for me, and I got stuck with that.

Here's my current attempt:

\documentclass[a4paper]{article}
\usepackage{lmodern}
\usepackage[T1]{fontenc}
\usepackage[utf8]{inputenc}
\usepackage[english]{babel}
\usepackage[plain]{fancyref}

% command to define a fancyref prefix
\makeatletter
\def\mkfancyprefix#1#2{%
  \@namedef{fancyref#1labelprefix}{#1}%
  \frefformat{plain}{\@nameuse{fancyref#1labelprefix}}{%
    \MakeLowercase{#2}\fancyrefdefaultspacing##1%
  }%
  \Frefformat{plain}{\@nameuse{fancyref#1labelprefix}}{%
    #2\fancyrefdefaultspacing##1%
  }%
}
\makeatother

% environments and references for lemmas, ...
\newtheorem{lemma}{Lemma}
\mkfancyprefix{lem}{Lemma}

% content
\begin{document}
\begin{lemma}
\label{lem:lemma}
This is a Lemma
\end{lemma}
There's \fref{lem:lemma} around! \Fref{lem:lemma} is the same, but at the beginning of a sentence.
\end{document}

However, this fails to compile, complaining about a:

Missing \begin{document}

If I move the \mkfancyprefix{lem}{Lemma} after \begin{document}, I can see that it actually outputs fancyreflemlabelprefixfancyreflemlabelprefix. Other than that, everything works and looks as expected.

This confuses me a lot, why does the command print the expanded arguments of \@nameuse to the document? I did some experimenting and added \expandafter immediately before both occurrences of \@nameuse. That changes the output to lemlem, which does not reduce my confusion.

Why does it do that, and how can I prevent it?

Addendum:
Enrico provided a great answer to my question below. Expanding this a little yields the a command which declares a new fancyref prefix in the format variants vario and plain. If you use others (like main), you have to extend the macro accordingly.

\makeatletter
\def\mkfancyprefix#1#2{%
\expandafter\def\csname fancyref#1labelprefix\endcsname{#1}%
% plain lowercase
\begingroup\def\x{\endgroup\frefformat{plain}}%
    \expandafter\x\csname fancyref#1labelprefix\endcsname
    {\MakeLowercase{#2}\fancyrefdefaultspacing##1}%
% plain uppercase
\begingroup\def\x{\endgroup\Frefformat{plain}}%
    \expandafter\x\csname fancyref#1labelprefix\endcsname
    {#2\fancyrefdefaultspacing##1}%
% vario lowercase
\begingroup\def\x{\endgroup\frefformat{vario}}%
    \expandafter\x\csname fancyref#1labelprefix\endcsname
    {\MakeLowercase{#2}\fancyrefdefaultspacing##1##3}%
% vario uppercase
\begingroup\def\x{\endgroup\Frefformat{vario}}%
    \expandafter\x\csname fancyref#1labelprefix\endcsname
    {#2\fancyrefdefaultspacing##1##3}%
}
\makeatother
share|improve this question
    
Welcome to TeX.SX. Note that you don't have to sign with your name since it automatically appears in the lower right corner of your post. –  Claudio Fiandrino Mar 3 '13 at 18:17
    
The second argument of \frefformat needs to be a csname which \@nameuse only gives after two expansions. \@nameuse{foo} first expands to \csname foo\endcsname and then to \foo –  cgnieder Mar 3 '13 at 18:18
1  
Have you considered using the cleveref package instead of fancyref? The cleveref package should have predefined names for all of the objects you mention. –  Mico Mar 3 '13 at 18:20
    
@ClaudioFiandrino: Thanks. –  Ralf Jung Mar 4 '13 at 9:29
    
@cgnieder: I also tried putting \csname fancyref#1labelprefix\endcsname but then it says Extra \endcsname. –  Ralf Jung Mar 4 '13 at 9:32

1 Answer 1

up vote 6 down vote accepted

The problem is that \frefformat expects its second argument to be a control sequence, not the instructions to produce one; so you have to build the token before TeX sees \frefformat:

\makeatletter
\def\mkfancyprefix#1#2{%
  \@namedef{fancyref#1labelprefix}{#1}%
  \begingroup\def\x{\endgroup\frefformat{plain}}%
    \expandafter\x\csname fancyref#1labelprefix\endcsname
      {\MakeLowercase{#2}\fancyrefdefaultspacing##1}%
  \begingroup\def\x{\endgroup\Frefformat{plain}}%
    \expandafter\x\csname fancyref#1labelprefix\endcsname
      {#2\fancyrefdefaultspacing##1}%
}
\makeatother

The \x trick is just to be able to use \expandafter.

How does it work? When \mkfancyprefix{lem}{Lemma} is called, TeX does

\@namedef{fancyreflemlabelprefix}{lem}

which is equivalent to \def\fancyreflemlabelprefix{lem}. Then it finds

\begingroup\def\x{\endgroup\frefformat{plain}}%
  \expandafter\x\csname fancyreflemlabelprefix\endcsname
    {\MakeLowercase{Lemma}\fancyrefdefaultspacing#1}

(the ##1 in the definition of \mkfancyref now becomes #1 as it should). After doing the \def\x{...}, LaTeX still has a \begingroup pending and finds \expandafter\x, so it expands \csname fancyreflemlabelprefix\endcsname (once), which produces the token \fancyreflemlabelprefix. Next \x is expanded, so TeX is confronted with

\endgroup\frefformat{plain}\fancyreflemlabelprefix
  {\MakeLowercase{Lemma}\fancyrefdefaultspacing#1}

The \endgroup matches the still pending \begingroup and removes the definition of \x from memory; then the correct \frefformat instruction is ready for being processed.

share|improve this answer
    
Thank you very much, the second revision of this answer is working great, both in the MWE and in my actual document (the first one consumed the space after \fref{lem:lemma} for some reason). And the explanation is very helpful. :) –  Ralf Jung Mar 4 '13 at 10:17
    
@RalfJung I too was surprised because of the missing space. I really don't know why this happens, but the current version seems good. –  egreg Mar 4 '13 at 10:19
    
This is brilliant! I'll add a link to this answer in my answer to the question about cross-referencing commands. –  Mico Mar 4 '13 at 11:47
    
@Mico: I use this command to also declare the vario type formats (which are used by fancyref per default), but I omitted that from the question to keep it simpler. However, for your overview, the full command would IMHO be more helpful. Maybe even main should be added. How should that be handled? (I wanted add that as command over there, but somehow I can't) –  Ralf Jung Mar 4 '13 at 11:55
    
@RalfJung - Providing a full example that lets the user make use of both the fancyref and varioref packages would certainly be useful. You could provide an addendum to your question, in which you provide such a code snippet. I'll happily mention this code in my answer about cross-referencing packages. –  Mico Mar 4 '13 at 13:35

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.