Pandoc 输出 Typst:Markdown 高亮 `mark` 语义到 `highlight[...]` 的转换解析

Pandoc 输出 Typst:Markdown 高亮 `mark` 语义到 `highlight[...]` 的转换解析 Pandoc 输出 TypstMarkdown 高亮mark语义到#highlight[...]的转换解析【免费下载链接】pandocUniversal markup converter项目地址: https://gitcode.com/gh_mirrors/pa/pandoc导读本文以 pandoc 仓库中的命令测试用例 test/command/10747.md 为切入点剖析 Markdown 高亮语义mark在转换为 Typst 输出时如何被映射为#highlight[...]函数调用。读完本文你将理解 pandoc 内部 AST 中 Span 与 class 属性的作用、mark扩展与 bracket span 两种输入写法以及 Typst writer 源码中决定#highlight输出路径的具体实现并掌握如何在当前仓库中运行与验证这一转换。一、一条命令测试10747.md 说了什么test/command/10747.md 是 pandoc 命令测试command test体系中的一个小用例全文是一个代码块% pandoc -t typst [Mark]{.mark} ^D #highlight[Mark]按照 test/Tests/Command.hs 中定义的测试格式来解读第一行以%开头是实际要执行的命令这里是以 Typst 作为输出格式调用pandoc -t typst接下来[Mark]{.mark}是喂给 stdin 的输入文本单独一行的^D表示 stdin 结束类似终端 EOF^D之后的行是期望的 stdout 输出#highlight[Mark]。也就是说这条测试断言了一个稳定的行为契约Markdown 源文本[Mark]{.mark}经 pandoc 转换为 Typst 后应输出#highlight[Mark]。凡是改动破坏这一输出命令测试就会失败这为 Typst writer 的 mark 语义提供了回归保护。命令测试会作为项目测试套件的一部分执行例如在构建完成后运行cabal test或项目 Makefile 中的测试目标也可以借助 tools/diff-golden-tests.sh 这类脚本对 golden 输出做批量比对以排查行为变更。二、输入端[Mark]{.mark}如何进入 AST2.1 bracketed span把 class 挂在行内元素上[Mark]{.mark}是 pandoc Markdown 的bracketed span语法方括号内是文本内容花括号内是属性标识符、class 列表、键值对。在 Markdown reader 中这一语法由 bracketedSpan 解析最终在 AST 中生成一个Span行内节点其属性为Span (, [mark], []) [Str Mark]即标识符为空、class 为[mark]、键值对为空。这就是整个转换链路的中枢——pandoc 所有格式的 reader 都汇入同一个内部 ASTwriter 再从 AST 出发生成目标格式。2.2mark更简洁的等号语法除了 bracket spanpandoc 还提供了mark扩展Ext_mark允许用...标记高亮文本。该扩展定义于 src/Text/Pandoc/Extensions.hs并默认包含在allMarkdownExtensions中见 src/Text/Pandoc/Extensions.hs因此默认的markdown、commonmark_x等格式都会启用它。对应的解析器在 src/Text/Pandoc/Readers/Markdown.hsmark :: PandocMonad m MarkdownParser m (F Inlines) mark fmap (B.spanWith (,[mark],[])) $ (guardEnabled Ext_mark inlinesBetween markStart markEnd) where markStart string lookAhead nonspaceChar notFollowedBy (char ) markEnd try $ string 可以看到text与[text]{.mark}殊途同归解析器最终都调用B.spanWith (, [mark], [])构造出带markclass 的Span。官方手册对mark语法的说明位于 MANUAL.txt而关于高亮的一般性描述见 MANUAL.txt——其中同时给出了[Mark]{.mark}与span classmarkMark/span在启用native_spans时两种写法并指出它们在“所有支持高亮的输出格式中”都有效。2.3 另一种来源HTMLmark标签当输入是 HTML 时marktext/mark同样会进入该语义。仓库中的命令测试 test/command/11299.md 展示了mark与嵌套强调的解析行为可见 mark 语义并不局限于 Markdown 输入而是跨 reader 共享的统一 AST 表示。三、输出端Typst writer 如何生成#highlight[...]转换的关键代码位于 src/Text/Pandoc/Writers/Typst.hsSpan (ident,cls,kvs) inlines - do let lab case lookup typst-label kvs of Just l - toLabel FreestandingLabel l Nothing - toLabel FreestandingLabel ident let (_, typstTextAttrs) pickTypstAttrs kvs contents - inlinesToTypst inlines let addHl x #highlight brackets x return $ (if mark elem cls then addHl else id) (toTypstTextElement typstTextAttrs contents) lab这段代码的逻辑可以拆解为四步处理标签从typst-label键值对或 Span 的标识符中提取 Typst labellabel语法处理文本属性通过pickTypstAttrs从键值对中筛选出 Typst 支持的自定义属性如 fill、font 等用于构造#text(...)调用递归转换内容inlinesToTypst将 Span 内部的行内元素递归转换为 Typst 代码按 class 决定包装函数addHl #highlight brackets x将内容包装进#highlight[...]只有当 class 列表包含mark时才应用该包装否则保持原样或仅应用#text(...)属性包装。这正是 10747.md 测试断言所对应的代码路径Span (,[mark],[]) [Str Mark]中mark命中cls于是输出#highlight[Mark]此处无标签、无文本属性toTypstTextElement直接返回原内容。brackets辅助函数负责生成[...]参数括号这在 Typst 中意味着将内容作为内容型参数content argument传入函数。四、Typst 侧#highlight的语义在 Typst 排版语言中#highlight[Mark]调用的是 Typst 标准库内置的highlight函数其默认效果是给文本添加荧光笔背景色等价于 Markdown 语义中的“高亮/划重点”。由于它接收 content 参数内部可以继续嵌套任意排版内容例如#highlight[Mark *and* more]从 pandoc 的角度看#highlight是 Typst 中与markclass 语义最贴近的原生表达——这也是 writer 选择它而非#text(fill: ...)之类方案的原因。同文件中的其他行内样式映射可以佐证这一“语义对等”思路强调映射为#emph[...]、加粗映射为#strong[...]、删除线映射为#strike[...]见 src/Text/Pandoc/Writers/Typst.hs#highlight正是这个内置样式函数家族的一员。五、mark 语义的跨格式一致性“所有支持高亮的输出格式”并不是一句空话。在仓库源码中可以确认带markclass 的 Span 在多个 writer 中都有专门的映射输出格式生成代码源码位置Typst#highlight[...]src/Text/Pandoc/Writers/Typst.hsLaTeX\hl{...}依赖 soul 宏包src/Text/Pandoc/Writers/LaTeX.hsDjot{...}highlight 标记src/Text/Pandoc/Writers/Djot.hsMarkdown回写...启用Ext_mark时src/Text/Pandoc/Writers/Markdown/Inline.hsAsciiDoc文本标记#...包裹src/Text/Pandoc/Writers/AsciiDoc.hsDOCX / OpenDocument / RST对应高亮样式/指令src/Text/Pandoc/Writers/Docx/OpenXML.hs、src/Text/Pandoc/Writers/OpenDocument.hs、src/Text/Pandoc/Writers/RST.hs特别值得注意的是 Markdown writer 的往返round-trip能力当目标格式启用了Ext_mark时Span (,[mark],[])会被还原为...语法保证markdown - typst - markdown或markdown - 其他格式 - markdown的转换链不会丢失高亮信息。六、反向转换的现状Typst reader 的注意点从源码结构看src/Text/Pandoc/Readers/Typst.hs 的inlineHandlers表中已注册了emph、strong、strike等内置样式函数处理器但尚未看到针对highlight的处理器。这意味着当前版本的 Typst reader 在读取#highlight[...]时会将其视为未知内联元素并忽略参见 src/Text/Pandoc/Readers/Typst.hs 对未知元素的分支处理。因此可以推断pandoc -t typst输出的#highlight[...]目前主要用于 Typst 文档的直接排版消费反向Typst - Markdown读取时高亮信息可能无法恢复。如果你需要完整的双向保真建议关注 reader 后续版本对highlight的映射支持或在转换前评估这一不对称性对工作流的影响。七、验证与实战7.1 手动复现安装好 pandoc 后可以直接复现 10747.md 的行为printf [Mark]{.mark}\n | pandoc -t typst # 输出 #highlight[Mark]对比其他输入写法printf Mark\n | pandoc -t typst # 同样输出 #highlight[Mark] printf markMark/mark\n -f html | pandoc -t typstmark与mark两种写法在 AST 中都会收敛为带markclass 的 Span因此输出一致。7.2 回归测试修改 Typst writer 后test/command/10747.md 这条测试会作为回归保障自动校验输出是否仍为#highlight[Mark]。同目录下的其他 Typst 命令测试如 test/command/8966.md 对#strong[...]的断言一起构成了 Typst writer 的行为快照是排查输出变更的第一现场。7.3 排版效果生成的#highlight[Mark]可直接放入 Typst 文档正文如typst compile的源文件中渲染时即得到荧光笔高亮效果。若需调整颜色可在 Typst 侧通过#highlight(fill: ...)[...]覆盖默认样式而不影响 pandoc 输出的语义结构。八、小结从 test/command/10747.md 这 5 行测试出发本文梳理了 pandoc 中 mark 高亮语义的完整链路Markdown 侧由[Mark]{.mark}bracketed span、markExt_mark扩展或 HTMLmark统一收敛为带markclass 的Span节点Typst writer 侧则在Span处理分支中检测markclass 并输出#highlight[...]。这条路径不仅解释了测试断言背后的实现也展示了 pandoc“单一 AST、多格式映射”的核心设计——高亮作为一种语义在不同输出格式中被映射为各自最贴切的表达。【免费下载链接】pandocUniversal markup converter项目地址: https://gitcode.com/gh_mirrors/pa/pandoc创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考