# 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
• @cgnieder: I also tried putting \csname fancyref#1labelprefix\endcsname but then it says Extra \endcsname. – Ralf Jung Mar 4 '13 at 9:32
• @Mico: Unfortunately, cleverref can not automatically print the page reference the way fancyref does: Using "on the next page", leave it away when it is on the same page, and the page number otherwise. (Also, sorry for adding three comments here and constantly editing them, somehow it wouldn't let me add a newline in a comment, and automatically post it as the browser looses focus, which I did not expect) – Ralf Jung Mar 4 '13 at 9:35

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