资讯动态

Pandoc man 手册转 Typst 的括号转义修复:11210 测试用例与 escapeParens 实现解析

发布时间:2026/9/19 20:45:56 来源:尧图企业网站定制
文档开发工具CLI【免费下载链接】pandocUniversal markup converter项目地址https://gitcode.com/gh_mirrors/pa/pandoc点击查看免费下载本文以 pandoc 仓库中的回归测试用例 test/command/11210.md 为切入点完整剖析一个真实缺陷的成因与修复当 manroff格式的文档经 pandoc 转为 Typst 时紧跟在强调元素之后的左括号若不转义会在 Typst 编译器中被误判为函数调用而报错。读完本文你将理解 golden 测试的运作方式、Typst 的#emph...语法歧义、以及 pandoc Typst writer 中escapeParens的实现细节。一、测试用例全貌一段 man 输入一行关键输出test/command/11210.md 是 pandoc 测试体系中典型的「命令式 golden test」文件内以%开头的第一行声明要执行的 pandoc 命令行随后是标准输入以^D结束^D之后的内容则是期望的标准输出。用例原文如下% pandoc -t typst -f man .PP .IR login (1) .PP and a regular (paren) that should not be escaped. ^D #emph[login]\(1) and a regular (paren) that should not be escaped.该用例对应 GitHub issue #11210测试的是一条「man → Typst」的转换链路输入是 mantroff格式.PP表示段落分隔.IR login (1)是 man 的行内字体宏期望login以斜体渲染、(1)以正体渲染关键断言在期望输出的第一行#emph[login]\(1)——]之后的左括号前多了一个反斜杠转义而第二段普通文本and a regular (paren)中的括号则不应被转义。同一行输入、两种截然不同的处理正是这次修复的核心。二、本地复现让同一段 man 输入经过 pandoc在已构建好 pandoc 的环境中可以直接复现这一转换。把上文中的输入部分写入文件或直接通过管道喂给标准输入.PP .IR login (1) .PP and a regular (paren) that should not be escaped.然后执行pandoc -t typst -f man input.man在修复该缺陷的版本中第一行输出应为#emph[login]\(1)而第二段中的(paren)保持原样输出。如果你使用的是旧版本则会看到未转义的#emphlogin——这正是 Typst 编译器无法接受的形式。命令格式上-f man显式指定 man 读取器-t typst指定 Typst writer与用例命令行完全一致。三、为什么这是个 bugTypst 函数调用语法带来的歧义要理解修复动机需要先了解 Typst 标记语言的一个语法特征。在 Typst 中#emph[login]是对emph函数的调用方括号是其参数紧随其后的圆括号(1)会被 Typst 解析为对上一次调用结果的再次调用即#emphlogin等价于试图以参数1调用#emph[login]的返回值。这种写法在 Typst 中会引发类型错误导致整个文档编译失败。而 man 手册页中「程序名章节号」是极常见的写法——login (1)、ls (1)几乎出现在每一份手册的第一行因此这个问题对 man → Typst 转换是实际且高频的。pandoc 的变更记录 changelog.md 对此修复的说明是Typst writer: Escape open paren after non-space (#11210). This fixes an issue that occurs if an open paren comes right after e.g.#strong[test].注意其中的限定词after non-space——这正是用例第二段断言and a regular (paren)不转义的原因那里的左括号前面是空格不在修复范围内。四、修复源码Typst writer 中的 escapeParens修复实现位于 Typst writer 的 src/Text/Pandoc/Writers/Typst.hs核心是新增的escapeParens函数-- Add an escape before a parenthesis right after a non-space element. -- Otherwise we risk #emphtest which will error. See #11210. escapeParens :: [Inline] - [Inline] escapeParens [] [] escapeParens (s : x : xs) | isSpacey s s : x : escapeParens xs escapeParens (Str t : xs) | Just ((,_) - T.uncons t RawInline (Format typst) \\ : Str t : escapeParens xs escapeParens (x : xs) x : escapeParens xs该函数对 Pandoc 内联元素序列做逐个扫描逻辑分三层空列表直接返回作为递归终止条件前一个元素是空白isSpacey判断Space、SoftBreak、LineBreak见 同文件 L446-L450跳过检查保持原样递归处理后续——对应「普通文本中的括号不转义」当前元素是Str且以(开头在该文本元素之前插入一个RawInline (Format typst) \\即一个 Typst 格式的原生反斜杠然后再输出该文本。它被挂接在行内序列渲染的入口 inlinesToTypst 中所有内联元素在交给inlineToTypst逐项渲染之前先经过escapeParens预处理。从源码结构看这是渲染前的「语法消毒」层——pandoc 内部 AST 本身无需感知 Typst 语法只在最终输出 Typst 文本时做适配。五、man 读取器侧.IR 宏如何一步步产生触发 bug 的序列修复在 writer但触发条件由 reader 产生。追溯输入.IR login (1)在 man 读取器中的解析路径src/Text/Pandoc/Readers/Man.hs 的handleInlineMacro中行内宏分发表将IR映射为IR - parseAlternatingFonts [emph, id] args即交替字体宏第一个参数用emph斜体包装第二个参数保持id正体。因此.IR login (1)的两个参数login与(1)被解析为Emph [Str login]斜体 loginStr (1)正体 (1)而在 parseInlines 中相邻内联之间会以B.space连接于是最终 AST 序列为Emph [Str login]、Space、Str (1)。回到escapeParens的扫描逻辑第一个元素Emph [...]不是空白、也不是以(开头的Str落入兜底分支原样输出第二个元素Space满足isSpacey跳过第三个元素Str (1)以(开头于是插入RawInline \\。最终渲染结果正是#emph[login]后跟空格、再跟\(1)。整个过程可以从 Man.hs 的宏解析与 Typst.hs 的转义预处理中完整还原。六、边界情况与工程启示这个 13 行的测试用例背后是一个值得注意的边界设计转义只针对「紧贴非空格元素」的左括号。原因在于 Typst 的调用语法中#emphtest的歧义仅当圆括号与方括号直接相邻时才会出现一旦中间存在空格(3)就是独立的普通文本。isSpacey覆盖了Space、SoftBreak、LineBreak三种情况说明无论是普通空格、自动换行插入的断行还是显式换行都被视为「安全间隔」。从工程方法上看该用例体现了 pandoc 处理跨格式语法冲突的通用套路在 reader 侧忠实还原源格式语义man 的字体交替宏 → 统一的Emph内联不提前为目标格式做特判在 writer 侧输出前统一做目标格式的语法消毒escapeParens通过插入RawInline原生内容精确控制输出用 golden test 固定「该转义处转义、不该转义处不转义」的边界行为防止后续改动回归。类似的「writer 侧转义适配」思路在 Typst writer 中还有多处体现例如标签前插入零宽空格以避免标签误绑前序元素见 Typst.hs L427-L431 中对 #11568 的处理注释。如果你正在为 pandoc 贡献新的 writer 或修改 Typst 输出逻辑test/command/目录下的此类用例如 11210.md是最直接的回归保护网——修改后运行对应用例即可验证是否破坏既有边界行为。赞分享文档开发工具CLI【免费下载链接】pandocUniversal markup converter项目地址https://gitcode.com/gh_mirrors/pa/pandoc点击查看免费下载相关推荐Pandoc 与 Typst 引号转义从测试用例 11463 解析 、 与 \ 的读写往返Pandoc 与 Typst 引号转义从测试用例 11463 解析 、 与 \ 的读写往返 本篇技术指南以 pandoc 仓库中的回归测试用例 te文档开发工具CLIPandoc Typst 写入器转义机制深度解析从 link 括号输出到行首句点转义的修复实践Pandoc Typst 写入器转义机制深度解析从 link 括号输出到行首句点转义的修复实践 本文以 Pandoc 仓库中的命令测试用例 test/comm文档开发工具CLIpandoc 转换 Markdown 转义数字到 Typst1\. 与 --wrappreserve 的保真实现剖析pandoc 转换 Markdown 转义数字到 Typst 1\. 与 wrappreserve 的保真实现剖析 导读 本文以 pandoc 官方命令测试文档开发工具CLI创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价