ARTICLE DETAIL

资讯详情

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

pandoc 命令回归测试 4589 详解:Markdown 中的原始 LaTeX 宏与行内格式的正确解析

pandoc 命令回归测试 4589 详解:Markdown 中的原始 LaTeX 宏与行内格式的正确解析 pandoc 命令回归测试 4589 详解Markdown 中的原始 LaTeX 宏与行内格式的正确解析【免费下载链接】pandocUniversal markup converter项目地址: https://gitcode.com/gh_mirrors/pa/pandoc本指南以 test/command/4589.md 这一命令式回归测试用例为主体讲解 pandoc 在将 Markdown 转换为 LaTeX 时如何处理文档中嵌入的\newcommand宏定义与行内原始 TeX 命令以及为什么紧贴在一起的多个 LaTeX 命令会破坏后续 Markdown 强调格式这一缺陷需要专门修复。读完本文你将理解raw_tex扩展的行内解析入口、宏展开applyMacros的实现位置掌握命令测试command test文件的书写与运行方法并能复现验证该测试用例。1. 测试用例全貌从 Markdown 到 LaTeX 的往返4589.md是 pandoc 仓库中典型的**命令测试command test**文件。它没有讲解文字而是用一段输入 期望输出的黄金样例golden test锁定了某个具体行为的正确结果% pandoc -f markdown -t latex \newcommand{\one}[1]{#1} \newcommand{\two}[1]{#1} Formatting *is* working **here**. But sticking \one{two }\two{commands} together *breaks* formatting. ^D \newcommand{\one}[1]{#1} \newcommand{\two}[1]{#1} Formatting \emph{is} working \textbf{here}. But sticking two commands together \emph{breaks} formatting.这段内容包含三个层次的信息命令首行%之后是要执行的命令即pandoc -f markdown -t latex——从 Markdown 读取、以 LaTeX 格式输出标准输入^D之前是喂给 pandoc 的输入文档其中声明了两个 LaTeX 宏\one、\two并用它们与 Markdown 强调语法混合书写期望输出^D之后是本次转换应当产生的标准输出其中\one{two }与\two{commands}这两个原始命令被折叠展开为文本two commands而两侧的*is*、**here**、*breaks*均被正确转换为\emph{...}与\textbf{...}。注意一个关键细节输入中的\one{two }、\two{commands}在输出中消失了取而代之的是宏展开后的纯文本two commands。这正是本用例要守护的行为——详见下文第 3 节。1.1 命令测试文件的格式约定该文件的格式并非随意的而是由 pandoc 的测试框架 test/Tests/Command.hs 明确定义第一个代码块首行以%开头后面是要运行的命令随后若干行作为命令的 stdin 输入stdin 以单独一行^D结束^D之后的行是期望的 stdout 输出若还期望 stderr 输出须放在前面并以2前缀标记若期望非零退出码最后一行须形如 exit status。因此4589.md本身就是一个可独立运行的回归测试只要把文件内容中的输入喂给pandoc -f markdown -t latex再与期望输出逐行比对即可判定通过与否。2. 背景这条用例来自 pandoc 2.2 的原始 LaTeX 处理改进在 changelog.md 中pandoc 2.22018-04-27 发布见 changelog.md的 LaTeX 读取器一节明确记录了本次修复的来源Improve handling of raw LaTeX (for markdown etc.) (#4589, #4594). Previously there were some bugs in how macros were handled.也就是说4589.md是对 issue #4589以及相关 PR #4594所报告缺陷的回归守护修复之前Markdown 中对宏的处理存在 bug——具体表现为像\one{two }\two{commands}这样连续使用多个宏时会干扰紧随其后的 Markdown 强调解析导致*breaks*无法被识别为斜体。修复之后输出中的宏被正确展开强调格式也得以保全即本用例中\emph{breaks}的正确结果。3. 底层原理Markdown 读取器如何识别行内 LaTeX 命令要理解这个测试为何会失败又为何被修复需要追踪 Markdown 读取器对\开头的行内内容的解析分派。3.1\\的解析入口在 Markdown 读取器 src/Text/Pandoc/Readers/Markdown.hs 的行内元素分派表中遇到反斜杠时的解析顺序为\\ - math | escapedNewline | escapedChar | rawLaTeXInline即依次尝试数学公式、转义换行、转义字符、原始 LaTeX 行内元素。其中rawLaTeXInline的实现位于 src/Text/Pandoc/Readers/Markdown.hsrawLaTeXInline :: PandocMonad m MarkdownParser m (F Inlines) rawLaTeXInline do guardEnabled Ext_raw_tex notFollowedBy rawConTeXtEnvironment !s - rawLaTeXInline return $ return $ B.rawInline tex s -- tex because it might be context这段代码说明三件事该行为受raw_tex扩展控制guardEnabled Ext_raw_tex关闭该扩展后行内 TeX 命令不会被当作原始 LaTeX 解析若命中 ConTeXt 环境\start...\stop...则不按普通行内命令处理解析成功的文本会被包装为RawInline tex元素。3.2 宏展开发生在哪一层真正执行宏展开的是 LaTeX 读取器导出的rawLaTeXInline在 src/Text/Pandoc/Readers/LaTeX.hsrawLaTeXInline do lookAhead (try (char \\ letter)) toks - getInputTokens raw - snd $ ( rawLaTeXParser latexEnv toks (mempty $ (controlSeq input skipMany rawopt braced)) inlines | rawLaTeXParser latexEnv toks (void inline) inlines ) finalbraces - mconcat $ many (try (string {})) -- see #5439 return $ raw T.pack finalbraces它先把输入切成 TeX 记号流getInputTokens再用rawLaTeXParser在行内解析模式下解析命令过程中会把已注册的宏定义应用到命令文本上。而宏展开的核心函数applyMacros定义在 src/Text/Pandoc/Readers/LaTeX/Parsing.hs其行为是若关闭了latex_macros扩展则原样返回否则将输入重新分词tokenize、在收集到的宏表sMacros下重放解析runParserT retokenize最后untokenize回文本。把这条链路串起来4589.md输入中的\newcommand{\one}[1]{#1}会被 Markdown 读取器识别为块级原始 LaTeX 并注册进宏表随后行内的\one{two }、\two{commands}经rawLaTeXInline→rawLaTeXInline→applyMacros被逐一展开为two与commands最终在 LaTeX 输出中不再出现命令本身而只留下展开后的文本。修复前的 bug 就在于这一展开与后续*...*强调解析的衔接不完整导致紧跟命令序列的强调标记被吞掉或破坏。3.3 输出端\emph与\textbf从哪来期望输出中的\emph{is}、\textbf{here}、\emph{breaks}是 pandoc 内部Emph、Strong行内元素在 LaTeX 写入器中的标准渲染结果*...*对应Emph**...**对应Strong。本用例验证的正是原始 LaTeX 命令与 Markdown 强调标记交错出现时两者都能各归其位这一完整场景。4. 验证与复现把测试跑起来4589.md属于test/command/目录下的命令测试集它们由 test/Tests/Command.hs 驱动与仓库其他测试test-pandoc.hs、各读取器/写入器测试模块一起构成整体测试套件。若要手动验证本用例只需按%行给出的命令执行pandoc -f markdown -t latex然后粘贴如下输入并回车、再输入^D\newcommand{\one}[1]{#1} \newcommand{\two}[1]{#1} Formatting *is* working **here**. But sticking \one{two }\two{commands} together *breaks* formatting.预期输出应与测试文件^D之后的内容一致。你也可以把这段输入存为input.md后用pandoc -f markdown -t latex input.md验证。若你的环境是 2.2 之前的版本输出中\emph{breaks}可能残缺或命令序列后出现多余文本——这正是该回归测试存在的意义。5. 关联阅读raw_tex扩展与更灵活的raw_attribute4589.md守护的行为本质上属于raw_tex扩展的范畴。在 MANUAL.txt 中该扩展被描述为允许在文档中包含原始 LaTeX、TeX 与 ConTeXt行内 TeX 命令会被原样保留并透传给 LaTeX 与 ConTeXt 写入器但行内 LaTeX 在输出为 Markdown、LaTeX、Emacs Org mode、ConTeXt 之外的其他格式时会被忽略。例如This result was proved in \cite{jones.1967}.即可在 LaTeX 输出中保留 BibTeX 引用。若需要更显式、更可控地嵌入原始 TeX可改用raw_attribute扩展MANUAL.txt 中亦有说明例如text{...}{tex}形式的显式原始块/行内元素。6. 小结test/command/4589.md虽仅十余行却浓缩了 pandoc 中一条完整的解析链路命令测试框架test/Tests/Command.hs→ Markdown 行内分派Markdown.hs→ 行内原始 LaTeX 解析LaTeX.hs→ 宏展开LaTeX/Parsing.hs→ LaTeX 写入器。它用黄金样例锁定了 pandoc 2.2 对原始 LaTeX 宏处理缺陷#4589/#4594的修复结果确保此后任何对 Markdown 解析器、LaTeX 读取器或宏系统的改动都不会再次破坏Markdown 强调与内联 TeX 命令混排这一常见写作场景。理解这个用例也就理解了 pandoc 如何以注册宏表 记号流重放的方式在通用 Markdown 语法中安全地嵌入领域特定的 LaTeX 命令。【免费下载链接】pandocUniversal markup converter项目地址: https://gitcode.com/gh_mirrors/pa/pandoc创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表