Pandoc 实战:用 `--typst-input` 向 Typst 文档注入 `sys.inputs` 变量
2026/9/19 11:00:42 网站建设 项目流程

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 源文档,最后两段FOObar bim是期望的标准输出。它验证的核心行为是:

  • 通过两个--typst-input参数分别注入foo=FOObar="bar bim"
  • 在 Typst 文档中用#sys.inputs.at("foo")#sys.inputs.at("bar")读取;
  • 转换到 plain 格式后,注入的变量值被原样输出:FOObar bim

也就是说,--typst-input让 Typst 文档中所有对sys.inputs的读取,在 Pandoc 转换阶段就完成了求值,结果直接进入转换后的文档,而不是停留在未被解析的 Typst 源码里。

1.1 测试用例覆盖的关键语法点

该用例虽短,却覆盖了三个必须注意的细节:

  1. 参数可重复:命令中出现了两个--typst-input,说明该选项不是单值选项,而是可以多次指定、累积成一组键值对。
  2. =作为键值分隔符foo=FOO=把键foo与值FOO分开。
  3. 带空格的取值必须加引号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 insys.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 中,它被写入ReaderOptionsreaderTypstInputs字段:

, 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。整个流程为:

  1. parseTypst把输入源解析为 Typst 语法树;
  2. 构造Operations记录(包含loadBytescurrentUTCTimelookupEnvVarcheckExistence等 IO 操作);
  3. 调用evaluateTypst ops (readerTypstInputs opts) inputName parsed,把readerTypstInputs键值对传入求值器;
  4. 求值结果(即经过变量替换后的内容)再交由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),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询