# How to define a macro which declares a fancyref prefix? How to prevent it from outputting text?

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?

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

-
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 – clemens Mar 3 '13 at 18:18
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

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.

-
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
@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