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.pswp.cn/news/534207.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/534207.shtml
英文地址,請注明出處:http://en.pswp.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 與其他…

php源碼安裝配置,php源碼安裝時configure配置參數 | 學步園

在Linux下安裝PHP&#xff0c;源代碼方式安裝&#xff0c;總需要配置很多參數。這里列出常用配置參數&#xff0c;并詳細用中文解釋說明了。給大家一些參考./configure–prefix/usr/local/PHP php 安裝目錄–with-apxs2/usr/local/apache/bi…

python遞歸函數詳解-講解Python中的遞歸函數

在函數內部&#xff0c;可以調用其他函數。如果一個函數在內部調用自身本身&#xff0c;這個函數就是遞歸函數。 舉個例子&#xff0c;我們來計算階乘n! 1 x 2 x 3 x ... x n&#xff0c;用函數fact(n)表示&#xff0c;可以看出&#xff1a; ? 1 fact(n) n! 1 x2 x3 x ... x …

php 高效判斷是否登錄,php 判斷用戶是否登錄

判斷用戶登陸主要分幾個過程&#xff0c;第一步是用戶登陸成功后把數據保存到session中&#xff0c;然后當用戶訪問需要登陸過的用戶權限時就來判斷session是否為空&#xff0c;如果不是就登錄成功。下面來看個實例session_start();if(getconfig("chatroom_admin")$_…

php異步處理任務工具,php異步任務處理: gearman

Gearman是一個用來把工作委派給其他機器、分布式的調用更適合做某項工作的機器、并發的做某項工作在多個調用間做負載均衡準備軟件包gearmand-1.1.12.tar.gzgearman-1.1.1.tgz php擴展安裝支持組件yum -y install boost-devel* gperf* libevent-devel* libuuid-devel*./configu…

頁面錯誤!請稍后再試_微信內嵌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…

浪潮集團PHP,浪潮php實習第一天(初識php)

先推薦幾個比較好的php初學者資料php manual.chm(可在csdn下載頻道下載&#xff0c;可查到大部分函數)比較好的開發工具1 eclipse PDT(對eclipse比較熟悉的比較適應)2.zendStudio(公認的最好的php集成開發環境)php沒有想象中的那么難學&#xff0c;不僅僅是它的語法&#xff0c…

檢測到目標url存在內部ip地址泄露_Cendertron,動態爬蟲與敏感信息泄露檢測

Cendertron&#xff0c;動態爬蟲與敏感信息泄露檢測Cendertron Crawler RendertronCendertron https://url.wx-coder.cn/HinPM 是基于 Puppeteer 的 Web 2.0 動態爬蟲與敏感信息泄露檢測工具。其依托于 xe-crawler 的通用爬蟲、調度與緩存模型&#xff0c;新增了 Monkey Test…

wamp2 php配置,wamp安裝后自定義配置的方法

WampServer是目前應用非常廣泛的PHP集成開發環境&#xff0c;本文就來講述Wamp安裝后自定義配置的方法。供大家參考借鑒。具體如下&#xff1a;wamp2.5安裝完畢后&#xff0c;自己手動重新設置了apache的默認根目錄。但是發現本機可以訪問&#xff0c;別人不能訪問。提示信息為…

屏幕壞點檢測圖片_iPhone新機如何檢測質量 iPhone新機檢測質量步驟【詳解】

iPhone新機怎么檢測好壞_iPhone新機檢測質量方法 說實話&#xff0c;蘋果對于iPhone的品控把握確實一代不如一代&#xff0c;特別是去年發布的iPhone7系列&#xff0c;很多用戶都反映自己新買的手機存在劃痕、屏幕發黃、掉漆等問題。那么當我們購買一部全新的iPhone7時&#xf…

php 安全mysql,關于php:我從mysql注入安全嗎?

本問題已經有最佳答案&#xff0c;請猛點這里訪問。這是否足以避免SQL注入&#xff1f;這里只需要mysql_real_escape_string()方法。在將數據插入數據庫之前&#xff0c;不應該執行htmlentities()或urlencode()。這些方法通常是在呈現您提供給用戶的視圖期間編寫的代碼。避免SQ…

excel單元格斜線_怎么在excel中畫斜線?怎么在excel表格中畫斜線?

在excel表格中畫斜線的技巧教程&#xff1a;1.在Excel中打開一個空白工作簿。 2.您可以在任何大小的單元格中執行此操作&#xff0c;但是如果先將其增大則更容易理解。為此&#xff0c;我們只需單擊并按住第1行和第2行之間的線&#xff0c;然后將其拖動到所需的高度即可。然后對…

php報表數據打印機,通過打印機打印帶打印功能的php表

我有以下php表,我如何只在php表中添加打印功能&#xff1f;點擊一個按鈕,下面的表格通過打印機打印,我試過’CTRL P’,我只得到頁面的html部分示例頁眉,頁腳,導航欄,而不是結果php結果echo "FILEIDFirstnameLastnameIssue DateInterest RateTermsBalance OutstandingBalan…

xbox one s驅動_理想照進現實 理想ONE開始接受預定

2016年4月22日&#xff0c;車和家創始人&CEO李想在源碼資本第二屆碼會年會首談車和家&#xff0c;改造城市出行。車和家 創始人&CEO 李 想2016年碼會年會演講2019年4月10日&#xff0c;增程式智能電動車「理想ONE」正式公布售價并開始接受預訂&#xff0c;并將于2019年…

two+few+arguments+php,PHP5.5 ~ PHP7.2 新特性整理

PHP5.5 ~ PHP7.2 新特性整理一、從PHP 5.5.x 移植到 PHP 5.6.x使用表達式定義常量在之前的 PHP 版本中&#xff0c; 必須使用靜態值來定義常量&#xff0c;聲明屬性以及指定函數參數默認值。 現在你可以使用包括數值、字符串字面量以及其他常量在內的數值表達式來 定義常量、聲…

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語法大寫&…