我同时使用了 varioref 和 cleveref。效果很好。不过我必须添加一个 hack,修改 varioref 使用的字符串(在德语中,对于章节、部分等,它应该读作“ab Seite X”(“从第 X 页开始”),而不是“auf Seite X”(“在第 X 页”)。
此修改的破解方法可在此处找到: http://texwelt.de/wissen/fragen/7013/vref-in-den-appendix
这也很好用。但我注意到,我无法将普通的旧版本\ref
与这个闪亮的新 cleveref+varioref+hack-setup 一起使用。当我使用
\vref{}
after 时\ref{}
,我会触发以下错误:
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.
这是一个简单的例子:
\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}
在 cleveref-Hack 中,我用 FIXME 突出显示了似乎与错误有关的行。我不明白这个错误……我\ref{}
还需要简单的内容,因为在某些情况下,我真的只需要章节/部分的编号,而不是任何花哨的内容,例如“第 X 章”(\cref{})或“第 X 章(第 ... 页)”(\vref{}
)。我使用的是 LuaLaTeX beta-0.76.0-2014042815(来自 TeX Live 2013/Arch Linux)。
提前感谢任何提示/指示。
答案1
问题是 LaTeX 中有两种»检查宏是否未定义«测试。
正如您所注意到的,错误带有未定义的标签和if\ref
在 之前使用\vref
。这给了我们一些线索:内部代码应该测试标签是否已定义,对吗?
\renewcommand*\cref@vref[2]{%
\ifcsdef{r@#2}% <<<<<<<< test if label is defined
{\cref@gettype{#2}{\curtlabtype}}%
{}%
\@old@cref@vref{#1}{#2}%
}
\ref
但显然,在使用a 之后它会失败。怎么会这样?嗯,\ref
还会测试标签是否存在。更准确地说,命令\@setref
(在某个时候被调用\ref
)也会这样做,它还会测试宏是否\r@<label>
已定义(或者更确切地说,是否未定义\relax
)。LaTeX 的定义\ref
是
\def\ref#1{\expandafter\@setref\csname r@#1\endcsname\@firstoftwo{#1}}
现在的问题是,如果尚不存在,则\csname r@#1\endcsname
定义一个等于的宏。但在定义看来,这是一个有效的定义,因此,如果在已使用之后使用,则无论标签是否存在,它(在本例中是错误的)都会使用真正的分支。\relax
\ifcsdef
\relax
\cref@vref
\ref
因此,我们需要一个测试来检查宏是否未定义或等于\relax
。由于您使用的是 KOMA-Script 类,因此这很容易:它带有
\scr@ifundefinedorrelax{<csname>}{<true>}{<false>}
\ifundefinedorrelax{<csname>}{<true>}{<false>}
由此,上述定义变为
\renewcommand*\cref@vref[2]{%
\scr@ifundefinedorrelax{r@#2}% <<<<<<<< test if label is defined
{}%
{\cref@gettype{#2}{\curtlabtype}}%
\@old@cref@vref{#1}{#2}%
}
错误就消失了。
也可以:做同一种测试确实如此\@setref
——这不需要 KOMA-Script 类或包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}%
}