- 文档
- 开发工具
- CLI
【免费下载链接】pandoc
Universal markup converter
导读
本文以 pandoc 命令测试套件中的test/command/7521.md为切入点,系统讲解--strip-comments选项的官方语义、CLI 与配置文件的参数绑定方式、CommonMark/HTML 读取器中的源码级实现原理,以及该测试用例在命令回归测试框架中的组织方式。读完本文,你将掌握如何在 Markdown 转换时安全剔除 HTML 注释、理解其与markdown_in_html_blocks扩展的边界关系,并能读懂 pandoc 仓库中这类"命令测试"文件的结构与运行机制。
一、测试用例 7521:一条命令的最小验证
test/command/7521.md是 pandoc 命令回归测试(golden test)之一,全文是一个带格式说明的代码块:
% pandoc --strip-comments - one <!-- with comm --> - two ^D <ul> <li>one</li> <li>two</li> </ul>这段内容完整刻画了--strip-comments的核心行为:输入是一段无序列表 Markdown,其中第二项(- two的上一行)内嵌了一条 HTML 注释<!-- with comm -->;在未加任何参数时,注释会被作为原始 HTML 原样透传到输出,而加上--strip-comments后,注释被整体移除,最终输出的<ul>列表中只剩下<li>one</li>与<li>two</li>两项。
该测试属于 pandoc 的命令测试(Command Test)体系,其格式约定定义在 test/Tests/Command.hs 中:
- 代码块第一行以
%开头,后面是需要执行的命令行; - 随后若干行为通过 stdin 喂给命令的输入文本;
- 输入以单独一行
^D结束; ^D之后的各行是期望在 stdout 上得到的输出,测试框架逐字节比对实际输出与期望输出(compareValues',不一致时报告--- test/command/7521.md的差异信息)。
测试框架会扫描test/command/目录下所有.md文件(filter (".md"isSuffixOf) <$> getDirectoryContents "command"),把每个文件解析成一条测试用例并归入testGroup "Command:"。因此 7521 这类文件既是文档,也是可自动执行的断言:只要在本地构建 pandoc 后运行测试套件,pandoc --strip-comments对上述输入的行为一旦发生变化,测试就会失败并给出 diff。
二、选项的官方语义
MANUAL.txt 对--strip-comments[=true|false]给出了权威定义:
Strip out HTML comments in the Markdown or Textile source, rather than passing them on to Markdown, Textile or HTML output as raw HTML. This does not apply to HTML comments inside raw HTML blocks when the
markdown_in_html_blocksextension is not set.
关键信息有三点:
- 作用对象:剥离的是 Markdown / Textile 源文本中的 HTML 注释;
- 默认行为对照:不开启该选项时,注释会作为原始 HTML 被透传到输出(这正是 7521 测试想强调的差异);
- 边界条件:当
markdown_in_html_blocks扩展未启用时,位于原始 HTML 块内部的注释不受本选项影响——因为此时整个 HTML 块被视为不可解析的原始内容整体透传,读取器不会深入其中去剥离注释。
该选项同时支持布尔值变体--strip-comments=true|false(CLI 形式)与配置文件键strip-comments(见下文第三节),默认值为关闭(false)。
三、参数绑定:CLI、配置文件与内部选项结构
--strip-comments从命令行到读取器需要经过三层绑定,每一层在仓库源码中都有明确落点。
3.1 CLI 解析层
命令行选项定义在 src/Text/Pandoc/App/CommandLineOptions.hs:
option "" ["strip-comments"] (OptArg (\arg opt -> do boolValue <- readBoolFromOptArg "--strip-comments" arg return opt { optStripComments = boolValue }) "true|false") OptFlag (T.pack "Strip HTML comments")它采用OptArg+ 默认值解析器readBoolFromOptArg:单独写--strip-comments即视为true,也可显式写作--strip-comments=true或--strip-comments=false。解析结果写入命令选项记录Options的optStripComments字段。
3.2 配置文件层
同一选项在 YAML 默认文件中通过strip-comments: true|false键驱动。src/Text/Pandoc/App/Opt.hs 定义了 JSON/YAML 解析分支:
<*> o .:? "strip-comments" .!= optStripComments defaultOpts并在显式键处理分支(Opt.hs#L821-L822)中将读取到的布尔值写回optStripComments。MANUAL 的「默认文件」章节同样给出了等价映射表:CLI--strip-comments⇔ YAMLstrip-comments: true(见 MANUAL.txt)。
3.3 内部选项结构
optStripComments字段在 src/Text/Pandoc/App/Opt.hs 声明,默认值为False(Opt.hs#L906)。在启动转换时,src/Text/Pandoc/App.hs 将其灌入读取器选项:
readerStripComments = optStripComments opts读取器选项readerStripComments定义于 src/Text/Pandoc/Options.hs,其字段注释明确说明该功能"只在 commonmark 系列读取器中实现"(-- Strip HTML comments instead of parsing as raw HTML (only implemented in commonmark)),默认同样为False(Options.hs#L93)。
四、源码级实现原理
4.1 CommonMark 读取器:walk + 解析器组合
Markdown(含 GFM 等 commonmark 系)读取器在 src/Text/Pandoc/Readers/CommonMark.hs 中,于解析完成后对 AST 做一次后处理遍历:
readCommonMarkBody opts s toks = ... (if readerStripComments opts then walk stripBlockComments . walk stripInlineComments else id) <$> if isEnabled Ext_sourcepos opts ...当readerStripComments为真时,用walk分别对块级与行内级 AST 节点做变换(CommonMark.hs#L135-L143):
stripBlockComments :: Block -> Block stripBlockComments (RawBlock (B.Format "html") s) = RawBlock (B.Format "html") (removeComments s) stripBlockComments x = x stripInlineComments :: Inline -> Inline stripInlineComments (RawInline (B.Format "html") s) = RawInline (B.Format "html") (removeComments s) stripInlineComments x = x即:凡是内容格式为html的RawBlock/RawInline,都交给removeComments清洗;其余节点原样保留。removeComments(CommonMark.hs#L145-L157)用 attoparsec 解析器逐段扫描:
pRemoveComments = mconcat <$> A.many' ("" <$ (A.string "<!--" *> A.scan (0 :: Int) scanChar <* A.char '>') <|> (A.takeWhile1 (/= '<')) <|> (A.string "<")) scanChar st c = case c of '-' -> Just (st + 1) '>' | st >= 2 -> Nothing _ -> Just 0其状态机逻辑是:命中<!--后进入注释体,通过scan累计连续短横线个数;读到-计数加一,读到>且此前已有至少两个-即视为注释结束(对应-->),其余字符把计数清零;注释整体被替换为空串,非注释内容(<之前或之后的普通文本)原样保留。解析失败时回退为原字符串(either (const s) id),保证不会因异常输入而破坏文档。
4.2 HTML 读取器:解析期直接丢弃
HTML 读取器在标签解析阶段处理注释。src/Text/Pandoc/Readers/HTML.hs 的TagComment分支如下:
TagComment s | "<!--" `T.isPrefixOf` inp -> do string "<!--" count (T.length s) anyChar string "-->" stripComments <- getOption readerStripComments if stripComments then return (next, "") else return (next, "<!--" <> s <> "-->") | otherwise -> Prelude.fail "bogus comment mode, HTML5 parse error"实现非常直白:在读取 HTML 注释标签时动态读取readerStripComments选项;开启时返回空字符串(即注释被吞掉),关闭时把完整的<!-- ... -->原样返回作为原始 HTML。这与 7521 测试中"开/关行为对比"的语义完全吻合。
五、适用边界与注意事项
结合官方手册与源码注释,使用该选项时有三个边界需要牢记:
- 读取器范围:仓库源码中可确认的实现位于 CommonMark 读取器(CommonMark.hs)与 HTML 读取器(HTML.hs);
readerStripComments的字段注释明确指出该特性只在 commonmark 系列实现,其他读取器(如 LaTeX、docx 等格式本身的注释语法)不适用。 - 原始 HTML 块:当
markdown_in_html_blocks扩展未启用时,处于原始 HTML 块内部的注释不会被剥离(MANUAL.txt 的显式说明),因为整块被视为不透明的原始内容。 - 默认关闭:无论是 CLI 默认值(
optStripComments = False)还是读取器默认值(readerStripComments = False),该选项默认不生效,需要用户显式开启。
六、本地复现与扩展验证
在当前仓库中可直接复现 7521 测试:构建 pandoc 后执行
pandoc --strip-comments <<'EOF' - one <!-- with comm --> - two EOF得到的输出即测试期望的<ul><li>one</li><li>two</li></ul>。作为对照,去掉--strip-comments后输出会保留<!-- with comm -->原始注释,这正是 7521 用例反衬出的默认行为差异。
若想进一步验证实现细节,可关注test/command/目录下其他同类测试文件(它们同样采用% pandoc ...+ stdin +^D+ 期望输出的格式),或结合 test/Tests/Command.hs 理解回归测试的组织方式——任何对--strip-comments行为的改动都会在这些用例中被自动捕获。
总结
test/command/7521.md用 11 行代码块完整定义了 pandoc--strip-comments的验收标准。从官方手册(MANUAL.txt)到命令行/配置解析(CommandLineOptions.hs、Opt.hs),再到 CommonMark 与 HTML 读取器的两类实现策略(AST 后处理 walk 与解析期直弃),整个链路清晰可查。掌握这条从测试用例出发、逐层下钻到源码的阅读路径,不仅有助于理解注释剥离这一具体功能,也为阅读 pandoc 其他命令行选项(--strip-comments的同族选项如--no-highlight、--eol等)提供了可复用的方法论。
- 文档
- 开发工具
- CLI
【免费下载链接】pandoc
Universal markup converter
相关推荐
Pandoc 解析 RST `list-table` 指令:从命令行测试用例到源码实现全解析
Pandoc 解析 RST list table 指令:从命令行测试用例到源码实现全解析 Pandoc 的 RST 读取器(RST reader)完整支持 Do
文档开发工具CLIPandoc Org 读取器 `+INCLUDE` 与 `:lines` 行号过滤深度解析:从命令测试 6466 到源码实现
Pandoc Org 读取器 +INCLUDE 与 :lines 行号过滤深度解析:从命令测试 6466 到源码实现 本篇技术指南以 pandoc 仓库中的命令
文档开发工具CLIpandoc 通用 raw 属性(`raw_attribute` 扩展)深度解析:从测试用例到源码实现
pandoc 通用 raw 属性( raw_attribute 扩展)深度解析:从测试用例到源码实现 导读 raw_attribute 是 pandoc 中一种
文档开发工具CLI
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考