尧图精选

Pandoc 回归测试实战:从命令测试 6821 看 LaTeX 写出器中行内代码与标题的转义处理

🕒 发布时间:2026/9/20 23:10:17 📁 来源:尧图网络
Pandoc 回归测试实战从命令测试 6821 看 LaTeX 写出器中行内代码与标题的转义处理【免费下载链接】pandocUniversal markup converter项目地址: https://gitcode.com/gh_mirrors/pa/pandoc导读本文以 pandoc 仓库中的命令行回归测试 test/command/6821.md 为线索完整拆解一次Native AST → LaTeX转换测试的输入、期望输出与底层实现。读者将掌握 pandoc 命令测试golden test文件的书写与执行机制理解行内代码Code在 LaTeX 写出器中的三种渲染路径以及为什么位于\caption中的高亮代码必须用\protect包裹issue #6821这一经典转义问题的来龙去脉。文中所涉结论均有仓库源码与测试用例支撑可直接对照 src/Text/Pandoc/Writers/LaTeX.hs 等文件深入验证。一、命令测试是什么pandoc 的 golden test 机制pandoc 的回归测试分为多个层级其中test/command/目录下存放的是命令行级 golden test黄金文件测试每个.md文件内含若干代码块每个代码块定义一次命令 标准输入 期望标准输出的完整用例。测试框架会对实际输出与期望输出逐字节比较任何差异都会被报告为失败。测试驱动逻辑位于 test/Tests/Command.hstests读取command/目录下所有.md文件第 83-84 行逐个解析其中的代码块extractCommandTest用 pandoc 自身将测试文件解析为文档过滤出代码块第 132-138 行runCommandTest通过goldenTest比较实际输出与期望输出第 101-129 行并支持--accept风格的自动更新updateGolden第 122-129 行。代码块内的格式约定见 test/Tests/Command.hs 的文件头注释第一行以%开头后跟要执行的命令随后若干行是传给命令的标准输入stdin输入以单独一行^D结束^D之后的行是期望的 stdout 输出若期望出现 stderr需放在最前并以2前缀标注若期望非零退出码末尾以 code标注。6821.md 正是这一格式的典型样例% pandoc -f native -t latex表示用 pandoc 读取 native 格式Pandoc 内部 AST 的文本表示并写出 LaTeX。二、6821.md 逐行拆解输入 AST 与期望输出对照测试文件 test/command/6821.md 的输入是一个由四个块组成的 Pandoc 文档块类型内容关注点Para行内代码Code (,[python],[]) x 5普通段落中的高亮行内代码Figure图片test.pngalt 文本含x 5caption 含普通文本与Code x 5图片的 alt 属性与 caption 中的代码Tablecaption 为Code (,[cpp],[]) caption空表头、含脚注行单元格 Alongtable 的 caption 中的代码Para行内代码Code (,[cpp],[]) caption对照组的普通行内代码对应的期望输出需要重点观察三处差异它们恰好对应本次测试要守卫的三类回归1. 普通段落中的行内代码——裸\VERB\VERB|\NormalTok{x }\OperatorTok{} \DecValTok{5}|2.\caption中的行内代码——加\protect\caption{This is a test \protect\VERB|\NormalTok{x }\OperatorTok{} \DecValTok{5}|}3. longtable 的\caption中的行内代码——同样加\protect\caption{\protect\VERB|\NormalTok{caption}|}\tabularnewline而段落末尾单独的Para [ Code ( , [cpp] , []) caption ]又输出为不带\protect的\VERB|\NormalTok{caption}|——说明\protect的出现与否完全由代码是否位于 caption 内决定与语言类别python/cpp无关。此外测试还同时锁定了 figure 与 longtable 的其他输出细节图片被渲染为\pandocbounded{\includegraphics[keepaspectratio,alt{This is a test x 5}]{test.png}}表格走longtable路径包含\endfirsthead、\endhead、\midrule\noalign{}、\bottomrule\noalign{}、\endlastfoot等分页控制结构。三、行内代码的三种渲染路径源码中的inlineToLaTeX (Code ...)Code内联元素在 LaTeX 写出器中的处理位于 src/Text/Pandoc/Writers/LaTeX.hs。函数首先读取写出状态中的四个布尔标志inHeading - gets stInHeading inItem - gets stInItem inSoul - gets stInSoulCommand inCaption - gets stInCaption随后根据writerHighlightMethod与classes决定走哪条路径第 1044-1052 行inHeading || inItem直接使用未高亮的\texttt原始路径rawCode避免在标题、列表项等脆弱环境里引入高亮宏注释引用 #5574IdiomaticHighlighting走listings宏包的\lstinline路径listingsCode第 985-1020 行所有可转义字符统一经\passthrough包裹#1629Skylighting/DefaultHighlighting且带有非空 classes走highlightCode第 1025-1032 行调用 src/Text/Pandoc/Highlighting.hs 导出的formatLaTeXInline对代码进行分词高亮同时把stHighlighting置为True以便模板按需引入高亮宏定义其余情况rawCode即\texttt{...}加空格转义escapeSpaces第 1021-1024 行。6821 测试中\VERB|\NormalTok{x }\OperatorTok{} \DecValTok{5}|的形态正是 skylighting 的 LaTeX 输出格式\VERB包裹、\NormalTok/\OperatorTok/\DecValTok等 token 类型命令分别着色。TokenType(NormalTok)等定义可见 src/Text/Pandoc/Highlighting.hs。四、核心修复#6821——caption 中的\VERB必须加\protect这是本次测试文件编号对应的核心问题。在 src/Text/Pandoc/Writers/LaTeX.hs 中源码以注释形式直接记录了修复动机-- for soul commands we need to protect VERB in an mbox or we get an error -- (see #1294). with regular texttt we dont get an error, but we get -- incorrect results if there is a space (see #5529). let inMbox x \\mbox braces x -- for captions we need to protect VERB with \protect (see #6821) let protect x \\protect x接着optionalProtect按当前上下文选择包装方式第 1041-1043 行let optionalProtect case () of _ | inSoul - inMbox | inCaption - protect | otherwise - id在soul 命令\hl、\ul、\st即 mark 高亮/下划线/删除线见第 918-920、956-962 行内部\VERB需要放进\mbox{...}否则 LaTeX 直接报错#1294带空格时输出也会出错#5529在caption 内部\VERB需要前缀\protect。原因是\caption参数属于移动参数moving argument会被写入辅助文件、用于生成图表目录List of Figures/Tables等处而\VERB这类 verbatim 命令在移动参数中不具鲁棒性\protect可防止其被展开求值——这正是 6821.md 期望输出中\protect\VERB|...|的来源。inCaption标志由独立的 caption 模块维护getCaption在渲染 caption 前后分别把stInCaption置为True/False见 src/Text/Pandoc/Writers/LaTeX/Caption.hs状态字段定义于 src/Text/Pandoc/Writers/LaTeX/Types.hs。该函数还会从 caption 中剔除脚注以生成短标题captForLofCaption.hs 第 39-47 行与\protect一起保证图表目录的安全输出。五、Figure 与 longtablecaption 被捕获的两个典型场景5.1 Figure 的渲染与 alt 文本Figure块的转换入口是blockToLaTeX (Figure ...)src/Text/Pandoc/Writers/LaTeX.hscaption 通过getCaption生成第 683 行因此图注中的代码会自动获得\protect图片本体输出为\includegraphics当未显式给出宽高时会包一层\pandocbounded{...}防止超宽溢出第 1224-1230 行alt 文本来自图片属性alt或标题的纯文本串接第 1183-1188 行生成alt{...}选项。6821 输入中图片描述文本包含行内代码x 5但 alt 输出为纯文本This is a test x 5经stringifyInlines串接而\caption内部则保留高亮代码并加\protect——两者被刻意区分保证无障碍阅读与目录安全两不误。5.2 longtable默认表格环境的 caption 结构表格写出逻辑位于独立的 src/Text/Pandoc/Writers/LaTeX/Table.hs。默认情况下表属性中不含floatclass使用longtable环境第 54-57、79-81 行以便跨页表格自动分页并重复表头。tableToLaTeXLongtable第 150-200 行将 caption 作为第一表头的一部分输出\caption{\protect\VERB|\NormalTok{caption}|}\tabularnewline \toprule\noalign{} \endfirsthead其中\endfirsthead之后的重复表头会通过walk removeNote剔除脚注第 162-171 行避免同一注释在续页表头重复出现。6821 的输入特意构造了空表头 表尾单元格A的组合期望输出因此呈现\bottomrule\noalign{}后直接进入\endlastfoot的形态完整覆盖了TableFoot的写出路径。顺带一提Figure内部若直接包含表格写出器会放弃figure环境包装因为把 longtable 放进 figure 或 center 环境没有意义LaTeX.hs这一防御逻辑与 6821 覆盖的 caption 转义问题共同体现了 LaTeX 写出器对脆弱环境的系统性处理。六、如何运行与扩展这类测试在已构建的 pandoc 源码树上运行命令测试cabal test pandoc --test-options-p Command # 或仅运行 6821 这一个用例 cabal test pandoc --test-options-p 6821test/command/6821.md的每个代码块会被分配一个形如#1、#2的编号test/Tests/Command.hs失败时 diff 会精确到行。若确认新行为是正确的可借助 tasty-golden 的--accept参数将实际输出回写为新的期望值updateGolden第 122-129 行从而让测试自我更新。新增用例的步骤同样简单在 test/command 目录下新建一个编号.md按第一节的格式书写命令、^D分隔的输入与期望输出即可框架会自动发现并纳入测试组第 83-87 行按文件后缀.md自动收集。这种以文档即测试的轻量模式正是 pandoc 长年积累下数千个回归用例、能够精细锁定诸如\protect\VERB这类边界行为的关键机制。结语通过 test/command/6821.md 这一个文件可以同时观察到 pandoc 测试方法论、LaTeX 写出器的上下文状态机stInCaption/stInSoulCommand/stInHeading等、skylighting 高亮输出的嵌入方式以及移动参数中 verbatim 命令的经典转义策略。当你在自己的文档中遇到caption 里代码高亮导致 LaTeX 编译失败的问题时\protect与\mbox的取舍逻辑LaTeX.hs就是可以直接借鉴的答案。【免费下载链接】pandocUniversal markup converter项目地址: https://gitcode.com/gh_mirrors/pa/pandoc创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
上一篇/下一篇内容由系统自动关联 返回资讯列表 →