Pandoc 实战:用--typst-input向 Typst 文档注入sys.inputs变量
【免费下载链接】pandocUniversal markup converter项目地址: https://gitcode.com/gh_mirrors/pa/pandoc
--typst-input是 Pandoc Typst 读取器提供的一个命令行参数,用于在把 Typst 源文件转换为其他格式时,把外部键值对注入到 Typst 的sys.inputs字典中。本文以仓库中的命令测试用例 test/command/11588.md 为起点,完整讲解该参数的语法、分隔符规则、空格处理方式、默认配置文件写法,并结合 Typst 读取器源码 说明其底层实现原理。读完本文,你将能熟练使用--typst-input实现"一次编写 Typst 文档、多次按参数渲染不同内容"的模板化转换流程。
一、测试用例:一行命令验证sys.inputs注入
仓库测试目录 test/command/11588.md 中的命令测试是理解该功能的最佳入口,其完整内容如下:
% pandoc --typst-input foo=FOO --typst-input bar="bar bim" -f typst -t plain #sys.inputs.at("foo"); #sys.inputs.at("bar"); ^D FOO bar bim这是一段标准的 Pandoc command 测试(与 test/Command.hs 中运行的test-pandoc.hs测试框架对应):第一行%之后是要执行的命令,紧接着是喂给标准输入(^D为输入结束标志)的 Typst 源文档,最后两段FOO与bar bim是期望的标准输出。它验证的核心行为是:
- 通过两个
--typst-input参数分别注入foo=FOO与bar="bar bim"; - 在 Typst 文档中用
#sys.inputs.at("foo")与#sys.inputs.at("bar")读取; - 转换到 plain 格式后,注入的变量值被原样输出:
FOO和bar bim。
也就是说,--typst-input让 Typst 文档中所有对sys.inputs的读取,在 Pandoc 转换阶段就完成了求值,结果直接进入转换后的文档,而不是停留在未被解析的 Typst 源码里。
1.1 测试用例覆盖的关键语法点
该用例虽短,却覆盖了三个必须注意的细节:
- 参数可重复:命令中出现了两个
--typst-input,说明该选项不是单值选项,而是可以多次指定、累积成一组键值对。 =作为键值分隔符:foo=FOO用=把键foo与值FOO分开。- 带空格的取值必须加引号:
bar="bar bim"中,值bar bim含有空格,因此整体用双引号包裹,shell 才不会把空格截断成多个参数。
二、官方文档中的参数规范
在仓库根目录的 MANUAL.txt 中,--typst-input的完整说明如下:
--typst-input=KEY[=VAL]Set a parameter value that will be made available to the typst parser in
sys.inputs, like--inputin thetypstCLI. Either:or=may be used to separateKEYfromVAL. Values containing spaces must be quoted.
从中可以提炼出四条规范:
| 规范 | 说明 |
|---|---|
| 用途 | 设置一个参数值,注入到 Typst 解析器的sys.inputs中 |
| 对标 | 等价于 Typst 官方 CLI 的--input参数 |
| 分隔符 | :与=均可用于分隔键和值(即--typst-input foo=bar与--typst-input foo:bar都合法) |
| 空格规则 | 值中含空格时必须加引号 |
注意:命令测试用例 11588 使用的是=分隔符,而 MANUAL 明确两者皆可,实测时可以按需选用。
三、默认文件(defaults file)中的等价写法
--typst-input除了作为命令行参数使用,还可以写进 Pandoc 的默认文件(defaults file,通常为 YAML)中。MANUAL 的"Options affecting specific writers/readers"与默认文件对应关系表中给出了明确示例(见 MANUAL.txt):
--typst-input foo=bar | typst-inputs: | foo: bar即命令行--typst-input foo=bar等价于在 YAML 默认文件中写:
typst-inputs: foo: bar这一键名typst-inputs与 Pandoc 默认文件解析代码中的字段完全对应——在 src/Text/Pandoc/App/Opt.hs 中,通过o .:? "typst-inputs" .!= optTypstInputs defaultOpts读取该字段;若默认文件中没有typst-inputs键,则回退到命令行选项optTypstInputs的默认值。也就是说,命令行参数与默认文件字段可以互补:默认文件提供基础参数集,命令行可追加或覆盖。
四、底层实现:从命令行到sys.inputs的完整调用链
理解--typst-input的实现,需要沿着三条代码路径串联起来。
4.1 命令行解析:KEY=VALUE拆分成键值对
在 src/Text/Pandoc/App/CommandLineOptions.hs 中,选项定义如下:
, option "" ["typst-input"] (ReqArg (\arg opt -> do let (key, val) = splitField arg return opt{ optTypstInputs = (T.pack key, T.pack val) : optTypstInputs opt }) "KEY=VALUE") Files (T.pack "Typst variable KEY=VALUE")关键点有三:
ReqArg:该选项必须携带一个参数(KEY=VALUE形式),不能单独出现;splitField:对传入的字符串按分隔符拆成(key, val)二元组(对应前面提到的:或=两种分隔符支持);- 累加语义:新解析出的键值对被
:前插到optTypstInputs列表头部,因此多次指定--typst-input会累积成一组键值对列表。
4.2 选项传递:optTypstInputs进入ReaderOptions
命令行解析得到的optTypstInputs需要传入读取器。在 src/Text/Pandoc/App.hs 中,它被写入ReaderOptions的readerTypstInputs字段:
, readerTypstInputs = optTypstInputs opts而ReaderOptions中该字段的定义位于 src/Text/Pandoc/Options.hs:
, readerTypstInputs :: [(Text, Text)] -- ^ parameters specified using --typst-input其默认值为空列表[](见 src/Text/Pandoc/Options.hs),即不指定参数时不会注入任何sys.inputs变量。
4.3 求值阶段:evaluateTypst消费键值对
最终消费这些键值对的是 Typst 读取器的核心入口 readTypst。整个流程为:
- 用
parseTypst把输入源解析为 Typst 语法树; - 构造
Operations记录(包含loadBytes、currentUTCTime、lookupEnvVar、checkExistence等 IO 操作); - 调用
evaluateTypst ops (readerTypstInputs opts) inputName parsed,把readerTypstInputs键值对传入求值器; - 求值结果(即经过变量替换后的内容)再交由
pPandoc解析器转换为 Pandoc AST,最终输出为目标格式。
从源码结构可以推断:evaluateTypst是"执行 Typst 求值"的通用求值器(模块头注释也写明本读取器的工作方式是 "Reads and evaluates a Typst document as a Pandoc AST",见 src/Text/Pandoc/Readers/Typst.hs),sys.inputs变量的解析正是发生在这一求值阶段,之后才轮到 Pandoc 自身的 AST 转换。
五、实战:模板化 Typst 文档的按参数渲染
结合上述语法与实现,--typst-input最常见的实战场景是:编写一份引用sys.inputs的 Typst 模板,转换时通过命令行传入不同取值,从而用同一份源文件产出不同内容的文档。
5.1 最小示例(对应测试用例)
沿用测试用例的写法,在终端执行:
pandoc --typst-input foo=FOO --typst-input bar="bar bim" -f typst -t plain <<'EOF' #sys.inputs.at("foo"); #sys.inputs.at("bar"); EOF输出为:
FOO bar bim要点:#sys.inputs.at("key")是 Typst 中读取sys.inputs字典的标准方式,其中at方法对字典按键取值。Pandoc 在转换时若发现该键已被--typst-input注入,就会用注入值替换;未被注入的键则保持 Typst 语义,由求值器按 Typst 自身规则处理。
5.2 带默认值的字段
sys.inputs是字典,因此 Typst 也支持带默认值的读取方式,例如:
#sys.inputs.at("author", default: "unknown")配合命令pandoc --typst-input author=Alice -f typst -t plain,输出Alice;而如果不注入author,则回退到默认值unknown。这为"可选参数"类模板提供了优雅的实现手段(at的第二个具名参数default是 Typst 字典方法的既有能力)。
5.3 与默认文件配合使用
把参数固化到默认文件typst-params.yaml中:
from: typst to: plain typst-inputs: title: "Pandoc 与 Typst 集成" author: Alice然后执行:
pandoc --defaults=typst-params.yaml input.typ再在命令行追加--typst-input author=Bob,即可在不修改默认文件的情况下临时覆盖作者信息(命令行与默认文件共同累积到optTypstInputs列表中)。
5.4 注意事项与限制
- 值含空格必须引号:
--typst-input bar="bar bim",否则 shell 会将其拆为多个参数导致解析错误; :与=都可作分隔符:若值本身包含=,建议改用:分隔,避免歧义;- 参数累积而非覆盖:多次指定
--typst-input会全部累积;从实现看,键值对以列表形式存储并传递给求值器,同一键多次注入时以后注入者生效与否取决于求值器对字典的处理,因此模板中应避免对同一键重复注入; - 仅作用于 Typst 读取器:该选项只在使用
-f typst(Typst 作为输入格式)时生效,输出格式无关——无论是 plain、markdown、html 还是其他格式,注入都发生在读取阶段。
六、总结
--typst-input打通了"外部参数"与"Typst 模板"之间的通道:语法上支持=/:两种分隔符、支持重复指定、要求带空格的值加引号;写法上既可用于命令行,也可写入默认文件的typst-inputs字段;实现上由 CommandLineOptions.hs 解析、经 App.hs 传入ReaderOptions,最终在 Typst 读取器 的evaluateTypst求值阶段注入sys.inputs。参考仓库测试 test/command/11588.md 与 MANUAL.txt 的规范,即可在项目实践中稳定复现"同一模板、按参数渲染"的工作流。
【免费下载链接】pandocUniversal markup converter项目地址: https://gitcode.com/gh_mirrors/pa/pandoc
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考