datatables 行分组信息展开与折叠的功能实现_[LaTeX 尝试] fancyvrb - 修复行引用的超链接跳转位置

本文已加入专栏文章目录,归入「进阶使用」文章系列。

本文可以看作对这个发生于 2019 年 7 月中旬的 TeX-SX 上自问自答的展开说明。那个回答中避免了 python 的使用,而是利用 zref 宏包把位置信息以文本形式在 pdf 中呈现,好处是不用引入 python,坏处是如果写成文章,需要额外介绍 zref 的使用。

问题的引入

fancyvrb 宏包提供了高度可配置的抄录环境,功能大致上和 listings 相当。

有些配置项提供了「跳出抄录环境,回到一般 latex」的功能,例如 commandchars。它接受一串三个符号组成的值,分别代表命令开始、左侧分组、右侧分组(实际可以归结到 catcode,此处略过)。

直接看 fancyvrb 文档 Sec. 4.1.12 的例子

8ec2a5ce409c6b5b0179927ef118418a.png

文档截图中的第二个例子展示了一种使用方式,利用 commandchars 为抄录环境的某一行增加标签(label),然后在正文中引用(ref)它来获得行号。特别地,hyperref 包还会自动为行号添加超链接,点击行号就能跳转到抄录环境中的对应行。

上一段的最后一个分句,只是描述了我们期望的行为,实际的编译和测试结果不是这样的,点击引用(ref)得到的行号后,无法跳转到对应行。

工具和示例准备

除了靠手去点超链接,然后根据阅读器跳转的位置来判断和分析,还可以借助工具直接读取 PDF 文件里的超链接跳转位置。例如,使用 Python 的 PyPDF2 库,

from PyPDF2 import PdfFileReaderfname = 'xxx.pdf'
pdf = PdfFileReader(fname)
named_dests = pdf.namedDestinations.items()print('Coordinates of named destinations')
for k, v in named_dests:print(k, [v['/Left'], v['/Top']])top = None
print('nVertical distances between labels of line numbers')
for k, v in named_dests:if 'FancyVerbLine' in k or 'lstnumber' in k:curr = v['/Top']if top is not None:print(k, float(top - curr) / 72 * 72.27, 'pt')top = curr

有关 PDF 格式的补充说明:

  • 「超链接跳转位置」在 PDF 格式中称为 named destination
  • 每个 named destination 拥有一个全文档唯一的名称
  • 它的内容,在本文中我们关心的是横纵坐标信息,有时也关心它的目标页面
  • 它的使用,是成为某个 annotation(例如 hyperref 自动添加的)的跳转目标

有关上述 python 脚本的说明:

  • 第一组 print,输出文档内所有 named destinations 的名称和坐标
  • 第二组 print,仅输出与 fancyvrb(和 listings,用于对照) 有关的相邻 named destinations 的纵坐标差值

同时,使用以下 latex 示例文档

(注意,示例中的 newpagenull 是特意添加的,为的是保证 pdf 阅读器有跳转,也就是把第一页往上翻,的空间)

documentclass{article}
usepackage{fancyvrb}
usepackage{hyperref}% <possible config appears here>begin{document}
begin{Verbatim}[numbers=left, commandchars={}]
firstlabel{vrb:1}
secondlabel{vrb:2}
thirdlabel{vrb:3}
forthlabel{vrb:4}
fifthlabel{vrb:5}
sixthlabel{vrb:6}
aend{Verbatim}ref{vrb:1}, ref{vrb:2}, ref{vrb:3}, ref{vrb:4}, ref{vrb:5}, and ref{vrb:6}
newpagenull
end{document}

最后,需要留意示例文档的编译方式

如果使用 xelatex,因为默认情况下 xdvipdfmx 会去掉未使用的 named destinations,并简化所有 named destinations 的名称,所以需要通过选项让 xdvipdfmx 不对 named destinations 自动优化。

xelatex -no-pdf xxx
xelatex -no-pdf xxx
xdvipdfmx -C 0x0010 xxx

如果使用 pdflatexlualatex,直接使用即可。

不同引擎生成的 pdf 中,named destination 的信息有微小差异。本文默认使用 xelatex

初步尝试

编译 latex 示例文档生成 pdf,点击那六个超链接,可以发现它们都跳转到同一位置。

147b429339315b78eae16e501fda8e9e.png
示例文档生成的 pdf

执行 python 脚本读取这个 pdf 里的信息,会获得如下输出

Coordinates of named destinations
Doc-Start [133.77, 667.2]
page.1 [132.77, 705.06]
page.2 [132.77, 705.06]Vertical distances between labels of line numbers

似乎六个 label 根本没有生成六个不同的跳转目标,连一个也没有生成。如果直接使用 xelatex xxx.tex,生成的 pdf 里就只有一条记录

Coordinates of named destinations
0 [133.77, 667.2]

如果继续使用 PyPDF2 的功能去看第一页的所有 annotations 的跳转目标(此处略去代码),就可以完全确定:六个 label 完全没有生成新跳转目标,六个 ref 都跳转去了当前页的开始处(具体位置是 page.1 跳转目标标记的、页面版心的左上角)。

以上是从 pdf 一侧进行的分析和探索。如果从 latex 一侧进行,从相关宏包的源码入手,则能了解到以下事实:

  • fancyvrb 内部负责递增行号的宏 FV@refstepcounter 的定义中,重写了一遍 latex2e 中 refstepcounter 的原始定义,刻意避免了直接使用 refstepcounter
  • hyperref 重定义后的 refstepcounter 会在展开时插入新的跳转目的地, 并把该目的地储存在 @currentHref 中以供 label 在内部引用(这则「事实」的展开介绍,可能需要额外的一篇或多篇文章,此处略过)

这样,因为fancyvrb 在递增行号时没有使用 refstepcounter,所以对应于新行号的跳转位置无法生成,@currentHref 得不到更新,label 关联的就变成了上一次更新过的 @currentHref 信息,也即 hyperref 在每一页开头默认插入的跳转目标。

第一步尝试很简单,让 FV@refstepcounter 成为 refstepcounter

letFV@refstepcounterrefstepcounter

继续尝试

修改保存、编译 tex 文件、执行 python,会发现问题没有完全解决。

Coordinates of named destinations
Doc-Start [133.77, 667.2]
FancyVerbLine.1 [133.77, 667.2]
FancyVerbLine.2 [133.77, 657.18]
FancyVerbLine.3 [133.77, 657.18]
FancyVerbLine.4 [133.77, 645.22]
FancyVerbLine.5 [133.77, 633.22]
FancyVerbLine.6 [133.77, 621.31]
page.1 [132.77, 705.06]
page.2 [132.77, 705.06]Vertical distances between labels of line numbers
FancyVerbLine.2 10.057574999999998 pt
FancyVerbLine.3 0.0 pt
FancyVerbLine.4 12.004850000000001 pt
FancyVerbLine.5 12.044999999999998 pt
FancyVerbLine.6 11.954662499999998 pt

从 python 脚本的输出可以看出,虽然现在每个 label 都对应了不同的跳转目标,但是目标之间的纵坐标差异并不一致。

  • 预期输出是,每两个相邻目标,在纵坐标上都相差 12pt(对应 latex 中 baselineskip 储存的值,也即行距)
  • 实际得到的是,
    • line 2 和 line 1 只差了 10pt(与字号有关,与行距无关,例如用 fontsize{10}{50}selectfont 修改行距后仍然是 10pt),
    • line 3 和 line 2 差 0pt,
    • 后面的正常。

推断,FV@refstepcounter 展开的位置有问题。

根据对类似示例代码的手动展开(见项目 muzimuzhi/latex-expansion 中以 fancyvrb 打头的文件),判断纵坐标差异应该源于 fancyvrb 对抄录环境前三行的特殊处理(可能是为了控制在环境中间换页的条件)具体涉及命令 FV@ListProcessLine@(i|ii|iii|iv)。这几个宏的具体作用,限于时间和水平笔者还没能了解清楚。

笔者采取了一个讨巧(但可能带来其他未知问题)的解决方案:把 FV@refstepcounter(具体是调用它的 FV@StepLineNo 宏 )的展开位置延迟到抄录行文本刚要输出之前,以保证通过 refstepcounter 递增行号并插入新跳转目标时,所处高度和抄录文本行一致。

这样,要做的修改就很简单:把 FV@StepLineNo 从原来的位置删掉,再在一个新的位置插入。

usepackage{etoolbox}% move FV@StepLineNo into FV@ListProcessLine
patchcmdFV@@PreProcessLine{FV@StepLineNo}{}{}{fail}patchcmdFV@ListProcessLine{kernleftmargin}{FV@StepLineNokernleftmargin}{}{fail}

从 pdf 阅读器里的点击跳转效果,和 python 脚本的输出看,问题似乎修好了。

其他

  • 包含修改代码的 tex 文档,见项目 muzimuzhi/latex-examples 中的文件 fancyvrb-improvements.tex。文件中还包含修改行号引用风格的代码,会在后续文章里介绍。
  • 最困难的部分可能是定位问题和知道可以把 FV@StepLineNo 挪到哪,笔者主要是通过手动展开来探索的。
  • fancyvrb 被其他一些宏包依赖,依赖关系比较深的是 tcolorbox -> minted -> fvextra -> fancyvrb,文中介绍的尝试,并未经过充分测试。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/534207.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

qtcreator摄像头显示时间_三星Galaxy S11 +渲染器展现出巨大的相机凹凸和四边形曲面显示...

我们正接近一年中三星宣布其Galaxy S系列最新设备的时间。Galaxy S10系列被认为是三星发布的最好的版本之一&#xff0c;因此在这方面他们有很多重要的事情。我们已经看到了Galaxy S11和Galaxy S11e的渲染&#xff0c;但是现在我们首先来看看Galaxy S11 。三星Galaxy S11 与其他…

页面错误!请稍后再试_微信内嵌H5页面授权和分享

近期新上线项目&#xff0c;用到了微信授权获取用户信息和分享&#xff0c;掉坑无数次&#xff0c;遂写此篇&#xff0c;为后人指路项目情况技术选型项目语言&#xff1a;HTML、CSS、JavaScript项目框架&#xff1a;Vue.js项目搭建脚手架&#xff1a;vue-cli工程化工具&#xf…

电脑打字手指正确姿势_正确的弹琴手型,应该是怎样的?

手型是基础&#xff0c;手型规范才有助于练习出正确的指法&#xff0c;指法正确就可以提高练习质量。刚入门的时候&#xff0c;不能刻意的要求手型&#xff0c;但是我们要有一个基本的要求&#xff0c;就是手要保持放松。弹琴的时候&#xff0c;没有多余的身体的力量参与到触键…

php 开源 采集,迅睿CMS 火车头内容采集

采集工具&#xff1a;火车采集器 v7.6采集模块&#xff1a;新闻 News一、编写采集入库脚本接口新建&#xff1a;./api/caiji.php/*** 数据采集*/define(IS_API, basename(__FILE__, .php)); // 项目标识define(SELF, pathinfo(__FILE__, PATHINFO_BASENAME)); // 该文件的名称r…

英文数据集txt_YOLOv5在建筑工地中安全帽佩戴检测的应用(已开源+数据集)

点击上方“计算机视觉cv”即可“进入公众号”重磅干货第一时间送达前言随着人工智能的发展&#xff0c;现在越来越多的场景需要人工智能。在工厂的厂区中以安全为首&#xff0c;但工人普遍缺乏佩戴安全帽意识&#xff1b;工厂环境复杂&#xff0c;有各种各样的禁止进入的区域&a…

检测到目标url存在内部ip地址泄露_Cendertron,动态爬虫与敏感信息泄露检测

Cendertron&#xff0c;动态爬虫与敏感信息泄露检测Cendertron Crawler RendertronCendertron https://url.wx-coder.cn/HinPM 是基于 Puppeteer 的 Web 2.0 动态爬虫与敏感信息泄露检测工具。其依托于 xe-crawler 的通用爬虫、调度与缓存模型&#xff0c;新增了 Monkey Test…

屏幕坏点检测图片_iPhone新机如何检测质量 iPhone新机检测质量步骤【详解】

iPhone新机怎么检测好坏_iPhone新机检测质量方法 说实话&#xff0c;苹果对于iPhone的品控把握确实一代不如一代&#xff0c;特别是去年发布的iPhone7系列&#xff0c;很多用户都反映自己新买的手机存在划痕、屏幕发黄、掉漆等问题。那么当我们购买一部全新的iPhone7时&#xf…

excel单元格斜线_怎么在excel中画斜线?怎么在excel表格中画斜线?

在excel表格中画斜线的技巧教程&#xff1a;1.在Excel中打开一个空白工作簿。 2.您可以在任何大小的单元格中执行此操作&#xff0c;但是如果先将其增大则更容易理解。为此&#xff0c;我们只需单击并按住第1行和第2行之间的线&#xff0c;然后将其拖动到所需的高度即可。然后对…

xbox one s驱动_理想照进现实 理想ONE开始接受预定

2016年4月22日&#xff0c;车和家创始人&CEO李想在源码资本第二届码会年会首谈车和家&#xff0c;改造城市出行。车和家 创始人&CEO 李 想2016年码会年会演讲2019年4月10日&#xff0c;增程式智能电动车「理想ONE」正式公布售价并开始接受预订&#xff0c;并将于2019年…

date设置时间_解决 IDEA 无法找到 java.util.Date 的问题

原文首发于 https://studyidea.cn/问题最近在项目中频繁使用到 java.util.Date&#xff0c;但是使用 IDEA 提示查找 Date 类&#xff0c;却无法找到 java.util.Date。可以看到&#xff0c;智能提示的结果没有 java.util.Date。没办法&#xff0c;只能暂时手动导入该包。最近闲下…

mysql插入语句例句,一句简单的MySql插入语句怎么写 ?

守候你守候我insert into 表名 values(default,"名字","2011-04-15 12:22:25"); //default可以换成null------------------------------insert into 表名 (name,datetime) values("名字","2011-04-15 12:22:25");使用SQL语法大写&…

路由器下一跳地址怎么判断_网络基本功三:细说路由器

介绍以太网交换机工作在第二层即数据链路层&#xff0c;用于在同一网络内部转发以太网帧。但是&#xff0c;当源和目的IP地址位于不同网络时&#xff0c;以太网帧必须发送给路由器。路由器负责在不同网络间传输报文&#xff0c;通过路由表来决定最佳转发路径。当主机将报文发送…

python函数的作用域_python学习第五篇 函数 变量作用域

原博文 2019-07-18 23:40 − 函数 函数是组合好的&#xff0c;可以重复使用的&#xff0c;用来实现单一或相关联功能的代码片段作用 能提高应用的模块性和代码的重复利用率函数的创建 第一函数的规则 1.函数代码块一def关键字开头&#xff0c;后接函数标识符名称和圆括号‘&…

python pip使用_Python——pip的安装与使用

pip 是 Python 包管理工具&#xff0c;该工具提供了对Python 包的查找、下载、安装、卸载的功能。目前如果你在 python.org 下载最新版本的安装包&#xff0c;则是已经自带了该工具。Python 2.7.9 或 Python 3.4 以上版本都自带 pip 工具。pip 官网&#xff1a;https://pypi.o…

php文章列表样式,PHPCMS V9 文章列表循环样式自定义方法

在此&#xff0c;再次分享Whidy的文章"phpcms文章列表循环不同样式制作方法"&#xff0c;下面CMSYOU来与大家具体分享&#xff0c;原地址为http://whidy.net/phpcms-list-with-different-style.html&#xff0c;在这里感谢。大家在用PHPCMS系统做网站的时候,有时候在…

查看ie保存的表单_解决浏览器保存密码自动填充问题

解决浏览器保存密码自动填充问题问题描述话说有一天&#xff0c;我如往常一样打开我的开发网站进行登录操作。浏览器很平常的在我们进行登录操作之后询问我是否需要记住密码&#xff0c;懒惰如我点击了记住密码。一切都很正常的进行着&#xff0c;没有什么异常发生。然而&#…

python mysql 正则表达式,MySQL之正则表达式(REGEXP)

MySQL中正则表达式通常被用来检索或替换符合某个模式的文本内容&#xff0c;根据指定的匹配模式匹配文中符合要求的特殊字符串。例如&#xff0c;从一个文件中提取电话号码&#xff0c;查找一篇文章中重复的单词或替换用户输入的敏感语汇等&#xff0c;这些地方都可以使用正则表…

pyecharts anaconda_Pyecharts安装使用和绘图案例

一次偶然的机会&#xff0c;接触了pyecharts&#xff0c;发现做图交互效果非常棒&#xff0c;便深究、摸索、入坑。这篇文章主要讲述自己在安装和使用中遇到的问题&#xff0c;解决方法&#xff0c;最后还会有pyecharts中自己比较喜欢的绘图功能。pyecharts是一款将python与ech…

如何把密度函数化为标准正态二维分布_概率微课:第三章(22) 二维随机变量及分布函数定义...

主要内容二维随机变量及分布函数定义更多系列视频概率微课&#xff1a;第二章(1) 随机变量的定义概率微课&#xff1a;第二章(2) 离散型随机变量概率微课&#xff1a;第二章(3) 两点分布及伯努利试验概率微课&#xff1a;第二章(4) 二项分布1概率微课&#xff1a;第二章(5) 二…

php中的缓,php中的缓存机制解释

php缓存的理解&#xff0c;先列出ob系列函数的作用&#xff1a;ob_start(func) 开启php缓存&#xff0c;回调函数是对缓存内数据的处理函数ob_gzhandler 作为 ob_start 的回调函数&#xff0c;对数据进行gz压缩ob_implicit_flush(true/false) 打开或关闭apache缓存&#xff0c…