日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

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

發(fā)布時(shí)間:2025/3/8 编程问答 13 豆豆
生活随笔 收集整理的這篇文章主要介紹了 datatables 行分组信息展开与折叠的功能实现_[LaTeX 尝试] fancyvrb - 修复行引用的超链接跳转位置 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

本文已加入專欄文章目錄,歸入「進(jìn)階使用」文章系列。

本文可以看作對(duì)這個(gè)發(fā)生于 2019 年 7 月中旬的 TeX-SX 上自問(wèn)自答的展開(kāi)說(shuō)明。那個(gè)回答中避免了 python 的使用,而是利用 zref 宏包把位置信息以文本形式在 pdf 中呈現(xiàn),好處是不用引入 python,壞處是如果寫成文章,需要額外介紹 zref 的使用。

問(wèn)題的引入

fancyvrb 宏包提供了高度可配置的抄錄環(huán)境,功能大致上和 listings 相當(dāng)。

有些配置項(xiàng)提供了「跳出抄錄環(huán)境,回到一般 latex」的功能,例如 commandchars。它接受一串三個(gè)符號(hào)組成的值,分別代表命令開(kāi)始、左側(cè)分組、右側(cè)分組(實(shí)際可以歸結(jié)到 catcode,此處略過(guò))。

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

文檔截圖中的第二個(gè)例子展示了一種使用方式,利用 commandchars 為抄錄環(huán)境的某一行增加標(biāo)簽(label),然后在正文中引用(ref)它來(lái)獲得行號(hào)。特別地,hyperref 包還會(huì)自動(dòng)為行號(hào)添加超鏈接,點(diǎn)擊行號(hào)就能跳轉(zhuǎn)到抄錄環(huán)境中的對(duì)應(yīng)行。

上一段的最后一個(gè)分句,只是描述了我們期望的行為,實(shí)際的編譯和測(cè)試結(jié)果不是這樣的,點(diǎn)擊引用(ref)得到的行號(hào)后,無(wú)法跳轉(zhuǎn)到對(duì)應(yīng)行。

工具和示例準(zhǔn)備

除了靠手去點(diǎn)超鏈接,然后根據(jù)閱讀器跳轉(zhuǎn)的位置來(lái)判斷和分析,還可以借助工具直接讀取 PDF 文件里的超鏈接跳轉(zhuǎn)位置。例如,使用 Python 的 PyPDF2 庫(kù),

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

有關(guān) PDF 格式的補(bǔ)充說(shuō)明:

  • 「超鏈接跳轉(zhuǎn)位置」在 PDF 格式中稱為 named destination
  • 每個(gè) named destination 擁有一個(gè)全文檔唯一的名稱
  • 它的內(nèi)容,在本文中我們關(guān)心的是橫縱坐標(biāo)信息,有時(shí)也關(guān)心它的目標(biāo)頁(yè)面
  • 它的使用,是成為某個(gè) annotation(例如 hyperref 自動(dòng)添加的)的跳轉(zhuǎn)目標(biāo)

有關(guān)上述 python 腳本的說(shuō)明:

  • 第一組 print,輸出文檔內(nèi)所有 named destinations 的名稱和坐標(biāo)
  • 第二組 print,僅輸出與 fancyvrb(和 listings,用于對(duì)照) 有關(guān)的相鄰 named destinations 的縱坐標(biāo)差值

同時(shí),使用以下 latex 示例文檔

(注意,示例中的 newpagenull 是特意添加的,為的是保證 pdf 閱讀器有跳轉(zhuǎn),也就是把第一頁(yè)往上翻,的空間)

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,因?yàn)槟J(rèn)情況下 xdvipdfmx 會(huì)去掉未使用的 named destinations,并簡(jiǎn)化所有 named destinations 的名稱,所以需要通過(guò)選項(xiàng)讓 xdvipdfmx 不對(duì) named destinations 自動(dòng)優(yōu)化。

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

如果使用 pdflatex 或 lualatex,直接使用即可。

不同引擎生成的 pdf 中,named destination 的信息有微小差異。本文默認(rèn)使用 xelatex。

初步嘗試

編譯 latex 示例文檔生成 pdf,點(diǎn)擊那六個(gè)超鏈接,可以發(fā)現(xiàn)它們都跳轉(zhuǎn)到同一位置。

示例文檔生成的 pdf

執(zhí)行 python 腳本讀取這個(gè) pdf 里的信息,會(huì)獲得如下輸出

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

似乎六個(gè) label 根本沒(méi)有生成六個(gè)不同的跳轉(zhuǎn)目標(biāo),連一個(gè)也沒(méi)有生成。如果直接使用 xelatex xxx.tex,生成的 pdf 里就只有一條記錄

Coordinates of named destinations 0 [133.77, 667.2]

如果繼續(xù)使用 PyPDF2 的功能去看第一頁(yè)的所有 annotations 的跳轉(zhuǎn)目標(biāo)(此處略去代碼),就可以完全確定:六個(gè) label 完全沒(méi)有生成新跳轉(zhuǎn)目標(biāo),六個(gè) ref 都跳轉(zhuǎn)去了當(dāng)前頁(yè)的開(kāi)始處(具體位置是 page.1 跳轉(zhuǎn)目標(biāo)標(biāo)記的、頁(yè)面版心的左上角)。

以上是從 pdf 一側(cè)進(jìn)行的分析和探索。如果從 latex 一側(cè)進(jìn)行,從相關(guān)宏包的源碼入手,則能了解到以下事實(shí):

  • 在 fancyvrb 內(nèi)部負(fù)責(zé)遞增行號(hào)的宏 FV@refstepcounter 的定義中,重寫了一遍 latex2e 中 refstepcounter 的原始定義,刻意避免了直接使用 refstepcounter
  • hyperref 重定義后的 refstepcounter 會(huì)在展開(kāi)時(shí)插入新的跳轉(zhuǎn)目的地, 并把該目的地儲(chǔ)存在 @currentHref 中以供 label 在內(nèi)部引用(這則「事實(shí)」的展開(kāi)介紹,可能需要額外的一篇或多篇文章,此處略過(guò))

這樣,因?yàn)閒ancyvrb 在遞增行號(hào)時(shí)沒(méi)有使用 refstepcounter,所以對(duì)應(yīng)于新行號(hào)的跳轉(zhuǎn)位置無(wú)法生成,@currentHref 得不到更新,label 關(guān)聯(lián)的就變成了上一次更新過(guò)的 @currentHref 信息,也即 hyperref 在每一頁(yè)開(kāi)頭默認(rèn)插入的跳轉(zhuǎn)目標(biāo)。

第一步嘗試很簡(jiǎn)單,讓 FV@refstepcounter 成為 refstepcounter

letFV@refstepcounterrefstepcounter

繼續(xù)嘗試

修改保存、編譯 tex 文件、執(zhí)行 python,會(huì)發(fā)現(xiàn)問(wèn)題沒(méi)有完全解決。

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 腳本的輸出可以看出,雖然現(xiàn)在每個(gè) label 都對(duì)應(yīng)了不同的跳轉(zhuǎn)目標(biāo),但是目標(biāo)之間的縱坐標(biāo)差異并不一致。

  • 預(yù)期輸出是,每?jī)蓚€(gè)相鄰目標(biāo),在縱坐標(biāo)上都相差 12pt(對(duì)應(yīng) latex 中 baselineskip 儲(chǔ)存的值,也即行距)
  • 實(shí)際得到的是,
    • line 2 和 line 1 只差了 10pt(與字號(hào)有關(guān),與行距無(wú)關(guān),例如用 fontsize{10}{50}selectfont 修改行距后仍然是 10pt),
    • line 3 和 line 2 差 0pt,
    • 后面的正常。

推斷,FV@refstepcounter 展開(kāi)的位置有問(wèn)題。

根據(jù)對(duì)類似示例代碼的手動(dòng)展開(kāi)(見(jiàn)項(xiàng)目 muzimuzhi/latex-expansion 中以 fancyvrb 打頭的文件),判斷縱坐標(biāo)差異應(yīng)該源于 fancyvrb 對(duì)抄錄環(huán)境前三行的特殊處理(可能是為了控制在環(huán)境中間換頁(yè)的條件)具體涉及命令 FV@ListProcessLine@(i|ii|iii|iv)。這幾個(gè)宏的具體作用,限于時(shí)間和水平筆者還沒(méi)能了解清楚。

筆者采取了一個(gè)討巧(但可能帶來(lái)其他未知問(wèn)題)的解決方案:把 FV@refstepcounter(具體是調(diào)用它的 FV@StepLineNo 宏 )的展開(kāi)位置延遲到抄錄行文本剛要輸出之前,以保證通過(guò) refstepcounter 遞增行號(hào)并插入新跳轉(zhuǎn)目標(biāo)時(shí),所處高度和抄錄文本行一致。

這樣,要做的修改就很簡(jiǎn)單:把 FV@StepLineNo 從原來(lái)的位置刪掉,再在一個(gè)新的位置插入。

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

從 pdf 閱讀器里的點(diǎn)擊跳轉(zhuǎn)效果,和 python 腳本的輸出看,問(wèn)題似乎修好了。

其他

  • 包含修改代碼的 tex 文檔,見(jiàn)項(xiàng)目 muzimuzhi/latex-examples 中的文件 fancyvrb-improvements.tex。文件中還包含修改行號(hào)引用風(fēng)格的代碼,會(huì)在后續(xù)文章里介紹。
  • 最困難的部分可能是定位問(wèn)題和知道可以把 FV@StepLineNo 挪到哪,筆者主要是通過(guò)手動(dòng)展開(kāi)來(lái)探索的。
  • fancyvrb 被其他一些宏包依賴,依賴關(guān)系比較深的是 tcolorbox -> minted -> fvextra -> fancyvrb,文中介紹的嘗試,并未經(jīng)過(guò)充分測(cè)試。

總結(jié)

以上是生活随笔為你收集整理的datatables 行分组信息展开与折叠的功能实现_[LaTeX 尝试] fancyvrb - 修复行引用的超链接跳转位置的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。