Pandoc 命令测试 11046:修复 citeproc 脚注围绕破折号的移动行为
【免费下载链接】pandocUniversal markup converter项目地址: https://gitcode.com/gh_mirrors/pa/pandoc
导读
本篇文章围绕 Pandoc 仓库中编号为11046的命令测试文件(test/command/11046.md)展开,该测试对应一次真实缺陷修复:使用--citeproc处理引用时,生成的脚注不应围绕 em-dash(——)移动位置。读者将通过本文理解 Pandoc 命令测试的编写与执行机制、--citeproc结合 CSL note 风格的工作流程,以及mvPunct在 Text.Pandoc.Citeproc 中如何将"破折号"排除在标点移动逻辑之外。
测试文件是什么
命令测试的通用格式
Pandoc 仓库使用test/command/目录下的 Markdown 文件作为**命令测试(command test)**用例。每个文件可以包含一个或多个以% pandoc ...开头的代码块,格式由 test/Tests/Command.hs 定义:
- 第一行以
%开头,后面是要执行的完整命令行; - 接下来若干行作为命令的标准输入(stdin);
- 输入以单独一行
^D结束; ^D之后的若干行是期望的标准输出(stdout);- 若期望有标准错误输出,各行需以
2>前缀标记; - 若期望非零退出码,最后一行需以
=>开头并给出退出码。
执行时,Tests.Command 会读取command目录下所有.md文件,把每个代码块当作一个独立用例,通过test-pandoc --emulate运行并比对实际输出与期望输出(golden test)。11046.md正是这样一个符合上述格式的测试文件。
11046.md 的完整内容
test/command/11046.md 全文如下:
% pandoc --citeproc -t plain+smart --csl command/chicago-note-bibliography.csl --- references: - id: doe title: Title type: book date: 2006 author: John Doe ... blah blah [@doe]---blah blah. ^D blah blah[1]---blah blah. John Doe. Title, n.d. [1] John Doe, Title.它由两部分构成:命令 + stdin(% pandoc ...到^D)与期望输出(^D之后)。
命令解析:--citeproc 与 CSL note 风格
命令行各参数的作用
| 参数 | 含义 |
|---|---|
--citeproc | 启用 Pandoc 内建的引用处理引擎(citeproc),解析[@doe]形式的引用并将脚注/参考文献渲染进文档 |
-t plain+smart | 输出 plain 格式并开启smart扩展,使破折号、引号等得到智能排版 |
--csl command/chicago-note-bibliography.csl | 指定 CSL 样式文件,该文件位于 test/command/chicago-note-bibliography.csl,是 "Chicago Manual of Style (note)" 的 note 类样式 |
YAML 元数据中的参考文献
stdin 部分的 YAML 块定义了一个 id 为doe的文献条目:
title: Title— 书名;type: book— 文献类型为图书;date: 2006— 出版年份 2006;author: John Doe— 作者。
该条目通过references字段直接内嵌在文档元数据中,这也是--citeproc支持的标准文献数据来源之一(另一个常见来源是通过--bibliography指定外部.bib文件)。
note 类 CSL 的渲染特点
chicago-note-bibliography.csl的根元素声明了class="note"(第 2 行),属于脚注式引用样式:正文中的引用被渲染成上标序号脚注,文末另附完整参考文献列表。
从 citation 布局 可以看到:
- 首次引用渲染为"短注释 + 短标题"的格式;
- 相同文献再次出现时使用
ibid(同上)等缩略处理(position="ibid"分支); - 参考文献部分(bibliography)使用悬挂缩进(
hanging-indent="true"),并按contributors-sort、标题、体裁、出版年份排序(第 956-962 行)。
输入与期望输出逐行对照
输入行
正文只有一行:blah blah [@doe]---blah blah.
[@doe]是 citeproc 的引用语法,指向 id 为doe的文献;---在smart扩展开启时会排版为 em-dash(——);- 句末有英文句点。
期望输出
blah blah[1]---blah blah. John Doe. Title, n.d. [1] John Doe, Title.三段分别对应:
- 正文行:
blah blah[1]---blah blah.— 引用[@doe]被替换为上标脚注序号[1],且位置紧跟在blah之后、em-dash 之前; - 参考文献条目:
John Doe. Title, n.d.— 其中n.d.是"no date(无日期)"的缩写。注意 CSL 样式在 issued 宏 中,当文献缺少可用的issued日期字段时会输出<text term="no date" form="short"/>,即n.d.; - 脚注内容:
[1] John Doe, Title.— 脚注采用短格式(短注释 + 短标题),并保留句点结尾。
源码原理:为什么脚注不围绕 em-dash 移动
问题背景
该测试对应的缺陷记录在 changelog.md:
Text.Pandoc.Citeproc:Don't move footnotes around em-dashes (#11046).
即旧版 Pandoc 在移动标点(punctuation moving)时会错误地把脚注/引号挪到 em-dash 的另一侧,导致blah blah---[1]blah blah.这样不自然的结果。11046.md用 golden test 锁定了修复后的期望行为:脚注序号必须保持在 em-dash之前。
mvPunct 与 isPunct 的实现
修复位于 Text.Pandoc.Citeproc 的标点移动逻辑中。核心注释(第 459-462 行)写得很明确:
-- We don't treat an em-dash or en-dash as punctuation here, because we don't -- want notes and quotes to move around them. isPunct :: Char -> Bool isPunct c = isPunctuation c && c /= '\x2014' && c /= '\x2013'\x2014是 em-dash(——)的 Unicode 码点,\x2013是 en-dash(–);isPunct在判断"标点"时显式排除这两种破折号,尽管它们在 Unicode 分类中属于isPunctuation;- 这样,
mvPunct在执行脚注/引号移动时就不会把 em-dash / en-dash 当作可跨越的标点,从而保持脚注序号停留在破折号之前。
从源码结构可以推断,mvPunct负责在引用(Cite)与其相邻标点之间重排顺序(如将句点移动到脚注之后),而将破折号排除后,---两侧的内联元素顺序保持不变,正是11046.md期望输出所验证的行为。
测试如何运行与验证
运行命令测试
Pandoc 的命令测试由 test/test-pandoc.hs 驱动。构建完成后,在仓库根目录执行:
cabal test或单独运行命令测试子集:
cabal test pandoc-tests --test-options='-p "11046"'-p使用 tasty 的 pattern 匹配,"11046"会匹配名为Command:11046.md的测试组(每个文件在 Tests.Command 中生成一个同名 test group,文件内的多个代码块依次编号为#1、#2…)。
对比测试的实际执行
execTest(test/Tests/Command.hs#L56-L70)会把%后的命令改写为test-pandoc --emulate ...,将^D之前的内容作为 stdin 传入,并比较实际 stdout 与^D之后的期望输出。若两者不一致,会输出带+++/---标记的 diff。因此11046.md不仅是文档,更是一个可持续回归的自动化测试:任何将来重新引入"脚注围绕破折号移动"问题的改动都会立刻导致该用例失败。
延伸:同类 citeproc 测试用例
11046.md只是 Pandoc 庞大 citeproc 测试集的一例。test/command/下还有大量相关用例,例如:
- test/command/pandoc-citeproc-13.md — 同样使用
chicago-note-bibliography.csl,但以-t markdown-citations输出,展示脚注式引用在 Markdown 中的表示:正文为Foo.[^1],参考文献放入{#refs .references .csl-bib-body .hanging-indent}的 Div 容器中,脚注为[^1]: Author, "Title."; - 其余大量
--citeproc用例覆盖 BibTeX 导入、ibid缩略、多作者et al.规则、locator 定位符等场景。
这些用例与11046.md共同构成 citeproc 功能的回归防线,也从侧面说明:--csl指定的 CSL 样式对输出形态(note 式脚注 vs author-date 式括注)起着决定性作用,而mvPunct的标点移动规则则是保证最终排版符合出版习惯的最后一环。
小结
11046.md以最小复现的形式记录了一次精确的排版修复:
- 输入只需一行包含
[@doe]引用与---em-dash 的正文; - 期望输出严格约定脚注序号位于 em-dash 之前;
- 底层由 Text.Pandoc.Citeproc 中
isPunct对\x2014(em-dash)与\x2013(en-dash)的排除逻辑保证。
无论是想要理解 Pandoc 命令测试的编写范式,还是希望探究 citeproc 标点移动的边界行为,11046.md都是一个足够小而完整的切入点。
【免费下载链接】pandocUniversal markup converter项目地址: https://gitcode.com/gh_mirrors/pa/pandoc
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考