![引用 Verbatim 环境中第三行的标签跳转到错误的位置](https://linux22.com/image/398783/%E5%BC%95%E7%94%A8%20Verbatim%20%E7%8E%AF%E5%A2%83%E4%B8%AD%E7%AC%AC%E4%B8%89%E8%A1%8C%E7%9A%84%E6%A0%87%E7%AD%BE%E8%B7%B3%E8%BD%AC%E5%88%B0%E9%94%99%E8%AF%AF%E7%9A%84%E4%BD%8D%E7%BD%AE.png)
我想要
- 参考软件包
Verbatim
提供的环境中的行fancyvrb
,并 - 使引用成为超链接,跳转到定义相应标签的正确位置,借助
hyperref
如果简单地使用fancyvrb
,hyperref
这些引用都会跳转到hyperref
的命名目标Doc-Start
(使用以下 MWE)。因此我修改\FV@refstepcounter
为直接使用\steprefcounter
。
此修改对 env 的第一行和第二行的标签有效Verbatim
。但是,从第三行开始,跳转到(使用以下 MWE)\ref{vrb:n}
的位置。\label{vrb:n-1}
\documentclass{article}
\usepackage{fancyvrb}
\usepackage{hyperref}
\makeatletter
\def\FV@refstepcounter#1{%
% \PackageError{FV}{pre step: \the\c@FancyVerbLine, \@currentHref}{}%
\refstepcounter{#1}%
% \PackageError{FV}{post step: \the\c@FancyVerbLine, \@currentHref}{}%
}
%% original def
%\def\FV@refstepcounter#1{%
% \stepcounter{#1}
% \protected@edef\@currentlabel{\csname p@#1\endcsname\arabic{FancyVerbLine}}%
%}
\makeatother
\begin{document}
\begin{verbatim}
1. For n = 1 or 2, \ref{vrb:n} jumps to destination \label{n}.
2. For n >= 3, \ref{vrb:n} jumps to destination \label{n - 1}.
\end{verbatim}
\begin{Verbatim}[commandchars=\\\{\},numbers=left]
first \label{vrb:1}
second \label{vrb:2}
third \label{vrb:3}
forth \label{vrb:4}
fifth \label{vrb:5}
sixth \label{vrb:6}
\end{Verbatim}
\ref{vrb:1}, \ref{vrb:2}, \ref{vrb:3}, \ref{vrb:4}, \ref{vrb:5}, and \ref{vrb:6}
\newpage\null
\end{document}
使用 texlive 2019 中包含的 pdflatex、lualatex 或 xelatex 均可重现此问题。我已安装最新fancyvrb
版本hyperref
。
我所调查的
.aux
表明每个标签都会创建不同的超级目标,例如\label{vrb:3}
创建\newlabel{vrb:3}{...}{1}{}{FancyVerbLine.3}{}
。- 输出PDF内容显示和的命名目标坐标
FancyVerbLine.2
相同FancyVerbLine.3
,导致跳转到错误位置的问题。 - 取消注释 行将
\PackageError
显示仅在 内部进行反向步进\FV@refstepcounter
。 - 此外,
listings
运行hyperref
正常。
\documentclass{article}
\usepackage{listings}
\usepackage{hyperref}
% use example in `texdoc listings`, sec. 8
\lstset{escapeinside={(*@}{@*)}}
\begin{document}
\begin{lstlisting}[numbers=left]
for i:=maxint to 0 do(*@\label{lst:1}@*)
begin (*@\label{lst:2}@*)
{ comment } (*@\label{lst:3}@*)
end;
\end{lstlisting}
\ref{lst:1}, \ref{lst:2} and \ref{lst:3}
\end{document}
答案1
这个问题仅与以下相关fancyvrb
。hyperref
使“内部信息”显而易见,但信息没有改变。所讨论的 mwe 提供的关键信息(我仍然对此感到困惑)是,
- “FancyVerbLine.2” 的 ypos 始终比“FancyVerbLine.1”低 10pt(无论在
Verbatim
env 之外设置了多少字体大小),并且 - “FancyVerbLine.3” 的 ypos 始终与“FancyVerbLine.2”相同
通过\FV@StepLineNo
从早期命令移至\FV@@PreProcessLine
非常晚期命令\FV@ListProcessLine
(逐行执行实际输出),这个问题似乎已解决。我不确定此补丁是否会导致任何新问题。
\documentclass{article}
\usepackage{etoolbox}
\usepackage{fancyvrb}
\usepackage{hyperref}
\makeatletter
\let\FV@refstepcounter\refstepcounter
\patchcmd\FV@@PreProcessLine
{\FV@StepLineNo}
{}
{}{\fail}
\patchcmd\FV@ListProcessLine
{\kern\leftmargin}
{\FV@StepLineNo\kern\leftmargin}
{}{\fail}
\makeatother
\begin{document}
\begin{Verbatim}[numbers=left]
first
second
third
forth
fifth
sixth
\end{Verbatim}
\def\xlink#1{\hyperlink{FancyVerbLine.#1}{#1}}
\xlink{1}, \xlink{2}, \xlink{3}, \xlink{4}, \xlink{5}, \xlink{6}
\newpage\null
\end{document}
一些解释,或者个人的理解:
hyperref
重新定义\refstepcounter
为- 更新
\@currentHref
(存储FancyVerbLine.<n>
在 mwe 中)和 - 将命名的目的地写入 PDF(更一般地说,驱动程序)。
- 更新
- 写入命名目标时,将使用间接坐标。对于 xetex + (x)dvipdfmx,将使用
@xpos
和@ypos
(而不是直接坐标数字),它们是从继承而来的dvipdfm
。 - 因此,问题在于,
\refstepcounter{FancyVerbLine}
在错误的位置调用。可以使用包的 savepos 模块检查这一点zref
,而无需加载hyperref
。(参见以下示例) fancyvrb
用作\FV@StepLineNo
的包装器\refstepcounter
,以支持以下选项numberblanklines
% !TeX program = pdflatex
\documentclass{article}
\usepackage{fancyvrb}
\usepackage[savepos]{zref}
\makeatletter
\let\FV@refstepcounter\refstepcounter
\newcounter{zRef}
\newcommand\showYPos[1][]{%
\stepcounter{zRef}%
\zsavepos{curr:\arabic{zRef}}%
\def\x{\the\expandafter\numexpr\zposy{curr:\arabic{zRef}}/65536\relax}
\PackageError{FV}{#1, line: \the\c@FancyVerbLine, ref \the\c@zRef, ypos \x}{}%
}
\def\FV@@PreProcessLine{%
\showYPos[before step]% ypos is wrong steped
\FV@StepLineNo
\FV@Gobble
\expandafter\FV@ProcessLine\expandafter{\FV@Line}}
\def\FV@ListProcessLine#1{%
\hbox to \hsize{% inside this hbox, ypos is ok
\FV@StepLineNo
% \showYPos[inside hbox]% ypos is ok
\kern\leftmargin
\hbox to \linewidth{%
\FV@LeftListNumber
\FV@LeftListFrame
\FancyVerbFormatLine{#1}\hss
\FV@RightListFrame
\FV@RightListNumber}%
\hss}%
% \showYPos[outside hbox]% ypos is wrong steped
}
\makeatother
\begin{document}
\fontsize{20}{50}\selectfont
\begin{Verbatim}
a
b
c
d
e
f
\end{Verbatim}
\end{document}