混合 cleveref、vref 和 ref:\@firstoftwo 的参数有一个额外的 }

混合 cleveref、vref 和 ref:\@firstoftwo 的参数有一个额外的 }

我同时使用了 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}%
}

相关内容