解析与往返转换指南)
文档开发工具CLI【免费下载链接】pandocUniversal markup converter项目地址https://gitcode.com/gh_mirrors/pa/pandoc点击查看免费下载本指南以 pandoc 官方命令测试用例 test/command/9475.md 为骨架系统讲解 pandoc 如何解析 Emacs Org 模式中的#begin_note、#begin_warning、#begin_tip、#begin_caution、#begin_important五类特殊块admonition block以及从 Pandoc 原生 AST 写回 Org 格式的往返round-trip行为。读完本文你将掌握特殊块在 Pandoc AST 中的 Div 结构形态、#name:标识符如何传递到节点属性、写回时的类名判定规则以及如何用-f org -t native亲自验证输出。一、测试用例定位与背景9475.md是 pandoc 仓库中位于 test/command/ 目录下的一个命令测试文件。这类测试文件的格式由 test/Tests/Command.hs 定义代码块首行以%开头后面是要执行的命令后续若干行是作为 stdin 传给命令的输入输入以单独一行^D结束^D之后的若干行是命令应产生的标准输出期望结果。测试用例由% pandoc -f org -t native与% pandoc -f native -t org两个方向组成恰好覆盖了Org 文本 → Pandoc AST和Pandoc AST → Org 文本的完整往返链路测试运行入口见 test/test-pandoc.hs。因此该用例不仅是功能验证也是学习 Org 特殊块内部表示的最佳样例。二、Org 特殊块的源文本形态Org 模式的特殊块在源文档中写作#begin_类型与#end_类型包裹的形式如#begin_note Useful note. #end_note #begin_warning Be careful! #end_warning #begin_tip Try this... #end_tip #begin_caution Caution #end_caution #name: foo #begin_important Important #end_important注意最后一段的#name: foo它是附加在#begin_important之前的块属性行用于为块指定一个标识符identifier。下面将看到它如何进入 AST 节点。三、解析方向-f org -t native的 AST 形态将上述输入交给pandoc -f org -t native得到如下原生 AST[ Div ( , [ note ] , [] ) [ Div ( , [ title ] , [] ) [ Para [ Str Note ] ] , Para [ Str Useful , Space , Str note. ] ] , Div ( , [ warning ] , [] ) [ Div ( , [ title ] , [] ) [ Para [ Str Warning ] ] , Para [ Str Be , Space , Str careful! ] ] , Div ( , [ tip ] , [] ) [ Div ( , [ title ] , [] ) [ Para [ Str Tip ] ] , Para [ Str Try , Space , Str this\8230 ] ] , Div ( , [ caution ] , [] ) [ Div ( , [ title ] , [] ) [ Para [ Str Caution ] ] , Para [ Str Caution ] ] , Div ( foo , [ important ] , [] ) [ Div ( , [ title ] , [] ) [ Para [ Str Important ] ] , Para [ Str Important ] ] ]可以从这份 AST 中提炼出特殊块的通用映射规则每个特殊块都是一个Div节点其属性三元组(identifier, classes, key-value pairs)中classes列表只有一个元素即块类型本身note、warning、tip、caution、important。块内容的第一项是一个标题子节点Div (, [title], []) [Para [Str Note]]其中标题文字由块类型名首字母大写生成Note、Warning、Tip…其余内容原样保留为普通段落。#name: foo被解析为外层 Div 的 identifier对应行Div ( foo , [ important ] , [] )即 identifier 为foo类为important。内层正文中的普通标点与空格被展开为Str/Space内联元素Try this...中的省略号...被转换为 Unicode 省略号字符\8230即…这与 Org 读者对特殊字符串的处理有关详见下文省略号的转换一节。源码依据读者端的 admonitionBlock 实现上述行为可以在 Org 读者源码中找到确切实现。src/Text/Pandoc/Readers/Org/Blocks.hs 中的orgBlock解析器在读取块头类型后通过case分派当类型为note、warning、tip、caution、important之一时调用admonitionBlocknote - admonitionBlock note blockAttrs warning - admonitionBlock warning blockAttrs tip - admonitionBlock tip blockAttrs caution - admonitionBlock caution blockAttrs important - admonitionBlock important blockAttrsadmonitionBlock见 Blocks.hs的结构非常直白admonitionBlock blockType blockAttrs rawtext do bls - ignHeaders * parseBlockLines id rawtext let id fromMaybe mempty $ blockAttrName blockAttrs pure $ fmap (B.divWith (id, [blockType], []) . (B.divWith (, [title], []) (B.para (B.str (T.toTitle blockType))) )) bls即外层divWith (id, [blockType], [])携带块标识符与类型类名内部先注入一个title子 Div标题文本为T.toTitle blockType即首字母大写的类型名再接原块内容。而id来自blockAttrName blockAttrs正是#name:属性解析的结果。块属性含#name:由 Blocks.hs 的blockAttributes解析它收集若干形如#key: value的行只接受白名单内的键name、label、caption、attr_html、attr_latex、results其中name/label最终成为块的 identifier。此外非特殊类型的普通#begin_xxx块也走orgBlock的兜底分支见 Blocks.hs它们会被转换为以块类型作为 class 的通用 Div因此上述机制是可扩展的任何自定义的#begin_custom块都会得到一个custom类。四、写回方向-f native -t org的往返行为将上一步得到的 Pandoc AST 作为输入执行pandoc -f native -t org可以完整还原出与原文档几乎一致的 Org 文本#begin_note Useful note. #end_note #begin_warning Be careful! #end_warning #begin_tip Try this... #end_tip #begin_caution Caution #end_caution #name: foo #begin_important Important #end_important这说明 pandoc 的 Org 读者与写者在这五类特殊块上是互逆的解析时生成的Div (id, [type], []) 内部titleDiv 结构在写回时被识别并还原为#begin_type/#end_type块foo标识符也被重新输出为#name: foo。源码依据写者端的 Div 类型判定写回逻辑的核心在 src/Text/Pandoc/Writers/Org.hs 的divBlockType与isAdmonitiondivBlockType (ident, classes, kvs) | ([_], drawerName:classes) - partition ( drawer) classes Drawer drawerName (ident, classes, kvs) | (blockName:classes, classes) - partition isGreaterBlockClass classes GreaterBlock blockName (ident, classes classes, kvs) | otherwise UnwrappedWithAnchor ident where isGreaterBlockClass t case T.toLower t of center - True quote - True x - isAdmonition x isAdmonition warning True isAdmonition important True isAdmonition tip True isAdmonition note True isAdmonition caution True isAdmonition _ False可以看到note、warning、tip、caution、important与center、quote一样都被归类为GreaterBlockOrg 的大块类型。随后divToOrg见 Org.hs会先输出#name:来自 Div 的 identifier与#attr_html来自其余类与键值对这一格式化细节在attrHtml函数中实现见 Org.hs再输出#begin_类型、块内容、#end_类型对于 admonition 块内部的Div (,[title],[])标题子节点会被剥离不重复输出——因为标题文本由类型名自动还原这正是divToOrg中case bs of (Div (,[title],[]) _ : bs) | isAdmonition blockName - blockListToOrg bs分支的作用见 Org.hs。这一剥离逻辑保证了往返后不会出现标题被当成正文再输出一遍的冗余。五、一个容易忽略的细节省略号的智能转换对比输入与输出可以发现输入的Try this...在 AST 中变成Str this\8230而在写回 Org 时又恢复成Try this...。这背后是 Org 读者的两个开关exportSmartQuotes与exportSpecialStrings见 src/Text/Pandoc/Readers/Org/ParserState.hs它们分别由smart/smart_quotes与smart扩展驱动。特殊字符串的转换实现在 src/Text/Pandoc/Readers/Org/Inlines.hsspecialStrings do guard getExportSetting exportSpecialStrings choice [orgDash, orgEllipses, shyHyphen]其中orgEllipses把...解析为 Unicode 省略号…AST 中以\8230转义显示。因为 pandoc 内部统一用 Unicode 表示这类字符而 Org 写者又负责把它还原为可读的...所以往返输出看起来原样未变但中间 AST 实际上已经过一次规范化。六、实践验证方法如果你希望亲自复现上述结果无需额外安装依赖直接使用仓库内构建好的 pandoc 可执行文件# 方向一Org → 原生 AST pandoc -f org -t native # 方向二原生 AST → Org pandoc -f native -t org将本文第二节的源文本粘贴到终端以Ctrl-D结束输入即可得到第三节与第四节展示的输出。若同时希望核对命令测试的自动化运行方式可参考 test/test-pandoc.hs 中挂载Tests.Command测试组的入口以及 test/Tests/Command.hs 中遍历test/command/目录下所有.md文件的测试收集逻辑。七、小结通过分析命令测试用例 9475.md 及对应的读者/写者源码可以确认 pandoc 对 Org 特殊块的完整处理链路环节行为源码位置解析块头#begin_type按类型分派到admonitionBlockReaders/Org/Blocks.hsAST 表示Div (id, [type], [])内含Div (, [title], [])标题子节点Readers/Org/Blocks.hs标识符传递#name: foo→ identifierfooname/label白名单Readers/Org/Blocks.hs类型判定note/warning/tip/caution/important归为GreaterBlockWriters/Org.hs写回还原输出#name#begin_type…#end_type剥离 title 子节点Writers/Org.hs特殊字符串...与…在 AST 层面归一化Readers/Org/Inlines.hs掌握了这套文本 ↔ AST的映射规则你就能在编写 pandoc Lua 过滤器、自定义写者或调试 Org 文档转换时准确预判特殊块在 AST 中的形态并利用#name:为特殊块注入可编程的标识符。赞分享文档开发工具CLI【免费下载链接】pandocUniversal markup converter项目地址https://gitcode.com/gh_mirrors/pa/pandoc点击查看免费下载相关推荐Pandoc 代码块行号RST 与 Org 之间 number-lines / -n / n 的往返转换实战Pandoc 代码块行号RST 与 Org 之间 number lines / n / n 的往返转换实战 导读 本文以 test/command/5178文档开发工具CLI如何在10分钟内上手dazn-lambda-powertools从安装到部署的快速入门如何在10分钟内上手dazn lambda powertools从安装到部署的快速入门 你是否正在寻找一个能大幅简化 AWS Lambda 函数开发的完整工具文档开发工具CLIPandoc 中 Org 模式标签Tags的往返转换从源码读懂列对齐与属性抽屉的实现Pandoc 中 Org 模式标签Tags的往返转换从源码读懂列对齐与属性抽屉的实现 导读 本文以 Pandoc 仓库中的回归测试用例 test/comm文档开发工具CLI上一篇解决llama.cpp模型初始化异常从崩溃到稳定运行的实战指南下一篇终极指南使用Flame引擎构建实时多人对战游戏的网络同步方案创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考