Pandoc Man 阅读器对 roff.IP宏的处理基于 #6858 的源码级解析与命令测试解读【免费下载链接】pandocUniversal markup converter项目地址: https://gitcode.com/gh_mirrors/pa/pandoc本篇技术指南聚焦 pandoc 的 Manroff/troff阅读器对 roff.IP宏的解析行为改进对应 issue/PR #6858以test/command/6858.md这一命令测试golden test文件为骨架结合src/Text/Pandoc/Readers/Man.hs源码与changelog.md中的版本记录深入讲解.IP宏如何被映射为定义列表、无序列表以及阅读器如何模拟 groff 跳过空行的行为。读完本文你将掌握 pandoc Man 阅读器列表解析的内部机制、命令测试文件的编写与运行方式以及如何复现与验证该修复。一、背景roff man 格式与.IP宏Manmanual页面使用 roff 排版语言编写通过.TH标题、.SH/.SS节标题、.IP缩进段落等宏控制文档结构。其中.IP宏Indented Paragraph的语义是带标签的缩进段落当.IP后跟一个参数时该参数作为标签tag后面跟随的文本是该标签的定义内容语义上等同于一个定义列表definition list当.IP后跟的标签是 bullet 字符如\[bu]、-、*、或序号时语义上分别对应无序列表bullet list或有序列表ordered list当.IP不带参数时则仅表示一个缩进段落。在 pandoc 中这一宏由 Man 阅读器Text.Pandoc.Readers.Man由 Yan Pashkovsky 与 John MacFarlane 维护解析。changelog.md第 11485-11487 行记录了 #6858 的修复内容Man reader: improve handling of.IP(#6858). We now better handle.IPwhen it is used with non-bullet, non-numbered lists, creating a definition list. We also skip blank lines like groff itself.即当.IP用于非 bullet、非编号的列表即标签为普通文本时现在能正确创建定义列表同时阅读器像 groff 一样跳过空行。二、命令测试文件结构golden test 的编写格式test/command/6858.md属于 pandoc 的命令测试command test套件由 test/Tests/Command.hs 驱动执行。理解其格式是读懂该文件的前提。根据Command.hs头部的注释一个命令测试是一个代码块遵循以下约定代码块第一行以%开头后面是要执行的命令随后是零行或多行文本作为命令的 stdin 输入stdin 以一行^D终止^D之后的行为期望的 stdout 输出如果期望出现 stderr 输出需要放在前面且每行以2前缀标记如果期望非零退出码最后一行应包含加退出码。Command.hs中的execTest第 60-70 行实际执行命令并将 stderr 行加上2前缀、将非零退出码以 N追加到输出末尾然后由runCommandTest第 101-129 行通过goldenTest将实际输出与期望输出逐行比对。值得注意的是第 72-78 行的pandocToEmulate会将命令中的pandoc替换为test-pandoc --emulate即测试实际调用的是构建产物中的测试二进制。三、测试用例一.IP定义列表标签为普通文本test/command/6858.md的第一个代码块完整演示了.IP在非 bullet、非编号场景下的解析结果% pandoc -t markdown -f man .TH FvwmAnimate 1 Date Fvwm Fvwm Modules .UC .SH NAME \fBFvwmAnimate\fP \- the fvwm animate module .SH SYNOPSIS Module FvwmAnimate [ModuleAlias] .IP *FvwmAnimate: Color \fBcolor\fP Tells \fBFvwmAnimate\fP what color to draw with. The color is XORed (exclusive ORed) onto the background. .IP *FvwmAnimate: Pixmap \fBpixmap\fP Tells \fBFvwmAnimate\fP to use \fBpixmap\fP to draw with. This can be useful if \fB*FvwmAnimate: Color\fP gives poor results. ^D # NAME **FvwmAnimate** - the fvwm animate module # SYNOPSIS Module FvwmAnimate \[ModuleAlias\] \*FvwmAnimate: Color color : Tells **FvwmAnimate** what color to draw with. The color is \XOR\ed\ (exclusive ORed) onto the background. \*FvwmAnimate: Pixmap pixmap : Tells **FvwmAnimate** to use **pixmap** to draw with. This can be useful if **\*FvwmAnimate: Color** gives poor results.输入是一份典型的 Fvwm 模块手册页输出揭示了几条关键解析行为.TH与.UC被消费.TH标题宏被 parseTitle 解析为元数据title/section/date/footer/header不产生块.UC属于未知宏被skipUnknownMacro第 555-562 行跳过并记录日志。.SH NAME映射为# NAME由parseHeader第 431-441 行处理.SH生成一级标题.SS生成二级标题。字体转义\fB...\fP映射为加粗\fBFvwmAnimate\fP输出为**FvwmAnimate**\fBcolor\fP输出为**color**。这一转换由linePartsToInlines第 262-308 行完成——词法器src/Text/Pandoc/Readers/Roff.hs 中的escFont将\fB记录为Font标记linePartsToInlines统计加粗/斜体/等宽区段后用strong、emph、code包装对应内联。带文本标签的.IP输出为定义列表*FvwmAnimate: Color color作为术语term跟随段落作为定义definition由 Pandoc markdown 的定义列表语法term: 定义呈现。这正是 #6858 的核心改进此前这类非 bullet、非编号的.IP无法被正确归类。Markdown 输出中转义规则原始 roff 中的*在 markdown 中被转义为\*[转义为\[转义为\以避免被 markdown 语法吞掉。四、测试用例二\[bu]标签映射为无序列表第二个代码块演示了.IP的 bullet 场景% pandoc -t markdown -f man .IP \[bu] hi .IP \[bu] there ^D - hi - there输入中连续两个.IP \[bu]每个后跟一个词和空行输出为标准的 markdown 无序列表- hi、- there。这说明roff 转义\[bu]被识别为 bullet 标记连续的同类.IP会被合并为同一个列表而不是两个孤立条目条目之间的空行被正确跳过见下文第五节。五、源码剖析.IP的类型判定与列表合并.IP的解析核心位于 listItem。其逻辑为先匹配一个带参数的.IP宏然后对第一个参数arg1做类型判定let cs linePartsToText arg1 let cs if not (T.any ( .) cs || T.any ( )) cs) then cs . else cs let lt case P.runParser anyOrderedListMarker defaultParserState list marker cs of Right (start, listtype, listdelim) | cs cs - Ordered (start, listtype, listdelim) | otherwise - Ordered (start, listtype, DefaultDelim) Left _ | cs \183 || cs - || cs * || cs - Bullet | otherwise - Definition cs判定规则可以归纳为.IP标签内容判定结果生成的 Pandoc 列表数字序号如1.、1)Ordered有序orderedListWith\183\[bu]、-、*、Bullet无序bulletList其他普通文本如*FvwmAnimate: Color colorDefinition定义definitionList其中cs的处理很有意思如果标签不含.或)会先补一个.再交给anyOrderedListMarker判定——这样IP 1这类省略点号的写法也能被识别为有序列表若补充后的写法判定失败而原始写法未变cs cs不成立则回退为DefaultDelim分隔符。类型判定之后parseList第 491-500 行负责列表的合并parseList try $ do x(lt, _) - listItem Nothing xs - many (listItem (Just lt)) ... return $ case lt of Bullet - bulletList $ map snd (x:xs) Ordered lattr - orderedListWith lattr $ map snd (x:xs) Definition _ - definitionList $ map toDefItem (x:xs)listTypeMatches第 459-465 行保证后续条目与首条目类型一致如都是Bullet从而将连续多个.IP归并为同一个列表——这正是用例二输出- hi与- there能成为一个无序列表的原因。定义列表条目则由toDefItem转为(term, [blocks])结构。此外还有两个配套机制bareIP第 377-380 行匹配无参数的.IPControlLine IP []用于parseIndentedParagraphs第 449-453 行缩进段落引用块以及列表续行continuation第 505 行bareIP * parsePara。continuation第 502-510 行在列表项后继续解析后续块并用notFollowedBy排除TP/IP/LP/P/PP/HP/RE/RS/SH/SS等会开启新块的宏保证续行不会越界吞掉下一个结构。六、行为对齐 groff跳过空行#6858 的第二个改进是skip blank lines like groff itself。对应实现是 parseNewParagraphparseNewParagraph do mmacro P | mmacro PP | mmacro LP | memptyLine return mempty它同时匹配.P、.PP、.LP宏与空行memptyLine对应EmptyLinetoken并返回空块。这意味着 roff 文档中常见的空行分隔不会产生多余的段落节点——在两个测试用例中.IP条目之间的空行都被静默跳过最终输出保持紧凑的列表结构。这保证了 pandoc 的 Man 阅读器与 groff 本身的排版行为一致转换结果不会出现幽灵空段落。七、在本地复现与验证如果你已构建 pandoc或使用仓库内stack.yaml/cabal.project配置的构建环境可以直接复现该测试。按 test/Tests/Command.hs 的机制最简单的方式是使用实际的pandoc命令执行同样的转换# 用例一定义列表 pandoc -t markdown -f man EOF .TH FvwmAnimate 1 Date Fvwm Fvwm Modules .UC .SH NAME \fBFvwmAnimate\fP \- the fvwm animate module .SH SYNOPSIS Module FvwmAnimate [ModuleAlias] .IP *FvwmAnimate: Color \fBcolor\fP Tells \fBFvwmAnimate\fP what color to draw with. EOF # 用例二无序列表 pandoc -t markdown -f man EOF .IP \[bu] hi .IP \[bu] there EOF预期输出与test/command/6858.md中^D之后的期望文本一致。若需运行整个命令测试套件可参考 Makefile 中测试目标的构建方式测试实际调用test-pandoc --emulate见pandocToEmulate第 72-78 行。此外真实的 man 页面样例可参考 man/pandoc.1 与测试目录 test/command/ 中的其他 man 相关用例便于横向对比.IP、.TPdefinitionListItem第 512-526 行等列表宏在不同输入下的表现。八、小结通过test/command/6858.md这个精悍的命令测试我们完整还原了 pandoc Man 阅读器对.IP宏的处理逻辑#6858 使.IP的三种语义定义列表、无序列表、有序列表得到准确归类并让阅读器像 groff 一样跳过空行。其背后是listItem的类型判定、parseList的同类归并、bareIP/continuation的边界控制以及linePartsToInlines的字体转义处理共同作用的结果。理解这一链路既有助于你在编写 roff/man 文档时预判 pandoc 的转换行为也为阅读其他阅读器如man与roff类输入的实现提供了可参考的分析路径。【免费下载链接】pandocUniversal markup converter项目地址: https://gitcode.com/gh_mirrors/pa/pandoc创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
企业数字化 ERP 产品动态
相关推荐
在 Apple Silicon Mac 上用 Colima 本地部署 OpenReplay:从环境搭建到问题排查的完整指南 可观测性开发工具前端后端 【免费下载链接】openreplay Session replay, cobrowsing and product analytics you can self-host. Best for reproducing issues and iterating on your product. 项目地址: https://gitcode.com/gh_mirrors/op/openreplay 点击查看 免… · 2026/9/23 2:22:57
Apache Pulsar 包管理(Packages)完全指南:函数与 IO 连接器的跨命名空间复用与版本化管理 消息队列后端流处理 【免费下载链接】pulsar Apache Pulsar - distributed pub-sub messaging system 项目地址: https://gitcode.com/gh_mirrors/pulsar28/pulsar 点击查看 免费下载 本指南以 Apache Pulsar 管理 API 中包管理(Package Management&… · 2026/9/23 2:22:50
计算机系统结构核心考点:指令系统、流水线与Cache地址变换实战解析 简介:计算机系统结构(张晨曦版)课后答案整理成一份doc文档,面向计算机相关专业本科生、考研学生以及自学系统结构的读者,帮助对照教材完成课后练习并梳理核心概念。文档共1个文件,压缩包约170KB,… · 2026/9/23 4:36:13
智慧实验室数字化转型:AI与大数据技术实践 1. 项目背景与行业痛点实验室数字化转型正在生命科学领域掀起一场静默革命。去年我在参与某基因测序中心智能化改造时,亲眼见证了一个典型场景:研究员每天要手动记录上百份样本的温湿度数据,而隔壁实验室的质谱仪却因为参数设置不当导致连续三… · 2026/9/23 4:36:13
数据科学必备:10个统计学核心概念与实战应用指南 做数据科学这几年,我最大的一个感受是:很多人并不是倒在模型调参上,而是倒在了统计基础不牢上。特征做了一大堆,一跑假设检验就懵;回归结果出来了,不知道怎么看显著性;A/B测试上线了,… · 2026/9/23 4:36:13
项目进度管理实战:从WBS拆解到关键路径,一套控制延期的方法 直接跟你说了吧:我见过太多项目延期,不是因为团队不努力,而是因为管进度的人把劲儿用错了地方。天天盯“百分比”没用,天天催“快一点”没用,真正让进度可控制的,是任务定义、依赖关系、风险预判和决策机制… · 2026/9/23 4:36:13
坭兴陶茶壶选购与养护全攻略 1. 坭兴陶茶壶选购指南:五款精品深度解析作为一名有着十年茶龄的老茶客,我深知一把好茶壶对品茶体验的重要性。今天要跟大家分享的是来自广西钦州的坭兴陶茶壶——这种采用特殊陶土烧制的茶具,因其独特的双气孔结构,能最大程度保留… · 2026/9/23 4:36:07
3招搞定手机怎么下载微信面试难题实战项目解析 3招搞定手机怎么下载微信面试难题实战项目解析 面试被问“手机怎么下载微信”背后的原理,90%的人答不上来。别笑,这看似弱智的问题,实则是考察你对移动应用分发机制、安全校验及网络协议理解的试金石。我带过不少校招新人,他们背了八股文,却连一个A… · 2026/9/23 0:00:03
你有新短消息请注意查收:3个新手避坑指南搞定消息系统选型 你有新短消息请注意查收:3个新手避坑指南搞定消息系统选型 面试被问“高并发下如何保证消息不丢失”,你张口就是“用Redis”,结果面试官追问“如果Redis宕机了怎么办”,你瞬间卡壳。这种场景太常见了,很多新手在背八股文时,只记住了技术名词… · 2026/9/23 0:00:29