ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

Pandoc Man 阅读器对 roff `.IP` 宏的处理:基于 6858 的源码级解析与命令测试解读

Pandoc Man 阅读器对 roff `.IP` 宏的处理:基于 6858 的源码级解析与命令测试解读 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),仅供参考
返回列表