ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Pandoc RST 读取器如何处理未知指令:以 Sphinx toctree 透传为范例(含源码解析与复现验证)

Pandoc RST 读取器如何处理未知指令:以 Sphinx toctree 透传为范例(含源码解析与复现验证) Pandoc RST 读取器如何处理未知指令以 Sphinx toctree 透传为范例含源码解析与复现验证【免费下载链接】pandocUniversal markup converter项目地址: https://gitcode.com/gh_mirrors/pa/pandoc导读本文围绕 Pandoc 仓库中的一条命令级测试用例 test/command/4715.md深入讲解 Pandoc 的 reStructuredTextRST读取器如何处理 Sphinx 特有的toctree指令它会被当作未知指令解析为带属性的Div块指令名成为 CSS 类、:name:与:class:字段成为标识与类名、其余字段原样透传为键值属性。读完本文你将掌握pandoc -f rst -t native下未知指令的完整转换规则、源码实现位置与验证方法并能在自己的 RST 文档中预判toctree等 Sphinx 指令的转换结果。一、测试用例全景从命令行到 Native 输出test/command/4715.md是 Pandoc 的命令测试command test文件其格式约定为第一段代码块内的首行是完整的 pandoc 命令行随后是标准输入以^D结束之后为该命令的期望输出。该用例完整内容如下% pandoc -f rst -t native .. toctree:: :name: tree1 :class: foo bar :caption: Indice dei contenuti :numbered: :maxdepth: 3 premessa.rst acquisizione-software.rst riuso-software.rst ^D [ Div ( tree1 , [ toctree , foo , bar ] , [ ( caption , Indice dei contenuti ) , ( numbered , ) , ( maxdepth , 3 ) ] ) [ Para [ Str premessa.rst , SoftBreak , Str acquisizione-software.rst , SoftBreak , Str riuso-software.rst ] ] ]1.1 复现步骤在仓库根目录或任意包含 pandoc 可执行文件的目录执行pandoc -f rst -t native然后粘贴上方的 RST 输入并按CtrlD^D结束输入即可得到与测试一致的 Native 输出。这里的两个关键参数含义为-f rst指定输入格式为 reStructuredText实际对应读取器模块 src/Text/Pandoc/Readers/RST.hs-t native指定输出为 Pandoc 内部 AST 的文本表示Pandoc类型的 show 形式是排查解析行为最直观的手段。1.2 逐段解读输出结构输出是一个包含单个元素的列表即文档 Body 的顶层块序列Div块代表 Sphinx 的toctree指令被整体包裹为一个容器Div三部分属性依次为标识符tree1来自:name: tree1字段类名列表[toctree, foo, bar]首元素toctree是指令名本身foo与bar来自:class: foo bar字段按空白切分键值属性列表(caption, Indice dei contenuti)、(numbered, )、(maxdepth, 3)分别对应:caption:、:numbered:、:maxdepth:字段其中无值的:numbered:被解析为空字符串值。Para块指令的正文三个 RST 文件名被当作普通段落解析行与行之间以SoftBreak连接文件名文本由Str承载。可见Pandoc 并不理解toctree的语义它属于 Sphinx 文档构建体系的指令而是采取未知指令通用透传策略保留下全部属性信息让下游过滤器或自定义模板自行消费。二、源码级原理未知指令的通用透传路径2.1 指令的识别与字段解析RST 读取器中所有指令统一由directive解析器入口处理src/Text/Pandoc/Readers/RST.hs#L793-L797directive :: PandocMonad m RSTParser m Blocks directive try $ do string .. directivedirective完成三件事src/Text/Pandoc/Readers/RST.hs#L798-L824解析指令名directiveLabel允许字母与连字符后跟::读取指令首行剩余部分top与后续的字段列表fields从字段中提取三类信息let name trim $ fromMaybe (lookup name fields) classes T.words $ maybe trim (lookup class fields) keyvals [(k, trim v) | (k, v) - fields, k / name, k / class]即:name:字段成为Div的标识符:class:字段按空白切分后并入类名列表其余所有字段如:caption:、:numbered:、:maxdepth:作为键值对keyvals保留。2.2 已知指令的分发与未知指令的兜底随后directive通过case label of对指令名做模式匹配分发src/Text/Pandoc/Readers/RST.hs#L848-L957已支持的指令包括include、table、list-table、csv-table、line-block、raw、role、container、replace、date、unicode、compound、pull-quote、epigraph、highlights、rubric、各 admonition 类指令、sidebar、topic、default-role、highlight、code/code-block/sourcecode、aafig、math、figure、image、bibliography、class等。当指令名不匹配任何已知分支时落入兜底分支othersrc/Text/Pandoc/Readers/RST.hs#L953-L957other - do pos - getPosition logMessage $ SkippedContent (.. other) pos bod - parseFromString parseBlocks $ top \n\n body return $ B.divWith (name, other:classes, keyvals) bod这一分支正是toctree测试用例的实现依据指令名other被(:)前置到类名列表首位故输出中第一个类为toctree:name:/:class:之外的字段keyvals被原样挂到Div属性上:numbered:这类无值字段解析后值为空字符串指令正文与首行top拼接后交给parseBlocks递归解析因此三个文件名被解析成带SoftBreak的段落同时通过logMessage $ SkippedContent ...记录一条跳过内容日志——在命令行加--verbose可看到类似[WARNING] SkippedContent .. toctree的提示表明该指令语义未被 Pandoc 消费仅做结构保留。2.3 版本依据该行为在 Pandoc 变更日志中有明确记录changelog.md#L15659-L15660RST reader: Pass through fields in unknown directives as div attributes (#4715). Supportclassandnameattributes for all directives.即未知指令的字段透传为Div属性并对所有指令支持class与name属性这正是 issue #4715也是本测试文件名 4715 的由来所要求的特性。测试文件 test/command/4715.md 本身即为该回归特性提供了命令级验证。三、实战把透传结果用起来3.1 在 Native / JSON 中间产物中消费属性toctree被解析为Div后属性中的类名与键值对可供下游使用。例如转换为 JSON 格式查看pandoc -f rst -t json input.rst输出中对应块为{t:Div,c:[[tree1,[toctree,foo,bar],[[caption,Indice dei contenuti],[numbered,],[maxdepth,3]]],[...]]}3.2 借助 Lua 过滤器还原 Sphinx 目录语义由于 Pandoc 只负责保真透传真正的toctree语义目录层级、编号、展开深度应由过滤器实现。一个典型的 Lua 过滤器toctree.lua可写成function Div(el) local cls el.classes or {} if cls[1] toctree then local caption el.attributes[caption] local numbered el.attributes[numbered] ~ nil local maxdepth tonumber(el.attributes[maxdepth] or 1) -- 基于 el.content 中的段落与文件名生成自定义目录结构 return pandoc.Div(el.content, pandoc.Attr(, {toc}, { caption caption, numbered tostring(numbered), maxdepth tostring(maxdepth) })) end end配合--lua-filter使用pandoc -f rst -t html --lua-filtertoctree.lua input.rst3.3 修改:name:与:class:的实践要点:name:只能出现一次用于锚点定位映射到Div的id:class:支持空格分隔的多个类名会追加在指令名类之后指令名类永远在首位其余字段全部进入keyvals因此自定义字段如:titlesonly:、:glob:等 Sphinx 扩展选项也会被无差别透传供过滤器读取需要特别注意的是Pandoc 不校验字段名任何拼写错误的字段都会被静默透传建议在过滤器中做白名单校验。四、扩展认知未知指令与已知指令的边界4.1 指令名的大小写与解析规则directiveLabel在 src/Text/Pandoc/Readers/RST.hs#L789-L791 中通过T.toLower将指令名统一转为小写因此.. TOCTREE::与.. toctree::等价指令名仅允许字母与连字符后跟::。4.2 与已知指令的差异与toctree不同像.. container::、.. admonition::、.. code-block::等已知指令会被 Pandoc 专门处理例如container生成Div但类名语义不同admonition生成带title子块的Divcode-block直接生成CodeBlock。因此只有对 Pandoc 未知的指令才会走other兜底分支并保留字段透传。这一点可以从同一源码文件的case label of分发逻辑中验证。4.3 与测试套件的关系该用例隶属于 Pandoc 的命令测试体系test/Command.hs运行整套测试时会自动执行test/command/*.md中的每个命令行示例并比对输出。若你对 Pandoc 的 RST 行为做了修改可通过运行命令测试来验证该用例是否仍然通过确保toctree等未知指令的透传行为不回归。结语通过 test/command/4715.md 这条精炼的测试用例我们完整还原了 Pandoc RST 读取器对未知指令的通用处理模型指令名进入类名首位:name:与:class:字段特殊化处理其余字段键值透传正文按 RST 递归解析。这一设计让 Pandoc 无需理解 Sphinx 的toctree语义即可无损地把结构信息交给下游过滤器与模板是解析与语义解耦思想的典型体现。掌握该规律后你在处理任何包含 Sphinx 扩展指令的 RST 文档时都能准确预测并利用其转换结果。【免费下载链接】pandocUniversal markup converter项目地址: https://gitcode.com/gh_mirrors/pa/pandoc创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表