Pandoc Lua 过滤器结构

Lua 过滤器是表格结构,元素名称作为键,值则是对这些元素进行操作的函数。

过滤器应放在单独的文件中,并通过 --lua-filter 命令行参数传递。例如,如果一个过滤器定义在名为 current-date.lua 的文件中,则应用该过滤器的方式如下:

pandoc --lua-filter=current-date.lua -f markdown MANUAL.txt

--lua-filter 选项可以多次提供。Pandoc 会按照命令行中出现的顺序应用所有过滤器(包括通过 --filter 指定的 JSON 过滤器和通过 --lua-filter 指定的 Lua 过滤器)。

Pandoc 期望每个 Lua 文件返回一系列过滤器列表。该列表中的过滤器按顺序被调用,每个过滤器处理前一个过滤器的结果。如果没有值由过滤脚本返回,那么 Pandoc 将尝试生成一个单一的过滤器,通过收集所有顶层函数来实现,这些函数的名称与 Pandoc 元素( 如 StrParaMetaPandoc )的名称相对应。(这就是为什么上面两个例子等价的原因。)

对于每个过滤器,文档会被遍历,每个元素都会被过滤器处理。对于过滤器包含条目的元素(即具有同名函数的元素),它们会被传递给 Lua 元素过滤器函数。换句话说,对于文档中的每个相应元素,过滤器条目都会被调用,并将相应的元素作为输入。

过滤器函数的返回值必须是以下之一:

  • nil:这意味着对象应该保持不变。
  • 一个 Pandoc 对象:这必须与输入类型相同,并且将替换原始对象。
  • Pandoc 对象的列表:这些将替换原始对象;列表将与原始对象的邻居合并(插入到原始对象所属的列表中);返回空列表将删除对象。

过滤器函数的输出必须产生与输入相同类型的元素。这意味着作用于内联元素的过滤器函数必须返回 nil 、一个内联元素或内联元素列表,而过滤块元素的函数必须返回 nil 、一个块元素或块元素列表。如果违反此条件,Pandoc 将抛出错误。

如果没有匹配元素节点类型的函数,则过滤系统将查找更通用的回退函数。支持两种回退函数,InlineBlock 。每个都匹配相应类型的元素。

没有匹配函数的元素保持不变。

请参阅 模块文档 以获取 Pandoc 元素列表。

元素序列的过滤器

对于某些过滤任务,需要知道元素在文档中出现的顺序。仅检查单个元素是不够的。

有两种特殊函数名可用于定义内联列表或块列表上的过滤器。

  • Inlines (inlines):如果出现在过滤器中,此函数将被调用在所有内联元素列表上,例如 Para(段落)块的内容或 Image 的描述。传递给函数的 inlines 参数将是每次调用的 内联元素 列表
  • Blocks (blocks):如果出现在过滤器中,此函数将被调用在所有块元素列表上,例如 MetaBlocks 元元素块的内容、列表中的每一项以及 Pandoc 文档的主要内容。传递给函数的 blocks 参数将是每次调用的 块元素 列表

这些过滤器函数是特殊的,因为结果必须是 nil,在这种情况下列表保持不变,或者必须是正确类型的列表,即与输入参数相同的类型。不允许单个元素作为返回值,因为在这种上下文中通常意味着有 bug。

请参阅 “删除正常引用前的空格” 以获取示例。

此功能已在 Pandoc 2.9.2 中添加。

遍历顺序

可以通过设置键 traverse'topdown''typewise' 来选择过滤器的遍历顺序;默认值为 'typewise'

示例:

local filter = {
  traverse = 'topdown',
  -- ... 过滤器函数 ...
}
return {filter}

此支持在 Pandoc 2.17 中添加;先前版本忽略 traverse 设置 。

按类型遍历

过滤器集内的元素过滤器函数以固定顺序被调用,跳过任何不存在的函数:

  1. 对于 Inline元素 的函数,
  2. Inlines 过滤器函数,
  3. 对于 Block元素 的函数,
  4. Blocks 过滤器函数,
  5. Meta 过滤器函数,最后
  6. Pandoc 过滤器函数。

仍然可以通过显式返回多个过滤器集来强制不同的顺序。例如,如果希望Meta的过滤器在Str之前运行,可以编写:

-- ... 过滤器定义 ...
return {
  { Meta = Meta },  -- (1)
  { Str = Str }     -- (2)
}

过滤器集按返回的顺序应用。因此,(1) 中的所有函数都在 (2) 之前运行,导致Meta的过滤器函数在开始过滤Str元素之前运行。

从上至下的遍历

有时,从根到叶的深度优先遍历文档树,并且在单次运行中完成会更加自然。

例如,一个块列表 [Plain [Str "a"], Para [Str "b"]] 将尝试按以下顺序应用过滤器函数:BlocksPlainInlinesStrParaInlinesStr

顶向下的遍历可以通过在过滤器函数中返回 false 作为第二个值来提前终止。在这种情况下,返回元素的任何子元素都不会被处理。

例如,要排除脚注的内容不被处理,可以编写如下内容:

traverse = 'topdown'
function Note(n)
  return n, false
end

全局变量

Pandoc 通过设置全局变量向 Lua 过滤器传递额外的数据。

  • FORMAT

    全局变量 FORMAT 设置为使用的 Pandoc 写入器格式(如 html5latex 等),因此过滤器的行为可以根据最终输出格式进行条件判断。

  • PANDOC_READER_OPTIONS

    提供给解析器的选项表。( 类型为 ReaderOptions

  • PANDOC_WRITER_OPTIONS

    将传递给写入器的选项表。虽然对象可以修改,但这些更改不会被 Pandoc 捕获。( 类型为 WriterOptions

    自定义写入器 中访问此变量已 废弃。从 Pandoc 3.0 开始,在自定义写入器中它被设置为占位符值(默认选项)。实际写入器选项是通过 WriterByteStringWriter 函数提供的,这些函数将选项作为第二个函数参数传递。

    自 Pandoc 2.17 版本起

  • PANDOC_VERSION

    包含 Pandoc 的版本号作为一个 Version 对象,该对象像数值索引表一样工作,最显著的数字排在前面。例如,对于 Pandoc 2.7.3,变量的值等同于表 {2, 7, 3}。使用 tostring(PANDOC_VERSION) 来生成版本字符串。此变量也在自定义写入器中设置。

  • PANDOC_API_VERSION

    包含 Pandoc 编译时所针对的 pandoc-types API 的版本。它是一个数值索引表,最显著的数字排在前面。例如,如果 Pandoc 是基于 pandoc-types 1.17.3 编译的,则变量的值将等同于表 {1, 17, 3}。使用 tostring(PANDOC_API_VERSION) 来生成版本字符串。此变量也在自定义写入器中设置。

  • PANDOC_SCRIPT_FILE

    调用过滤器所用的文件名。此值可用于相对于脚本文件查找其他文件。此变量也在自定义写入器中设置。

  • PANDOC_STATE

    所有读取器和写入器共享的状态。Pandoc 使用它来收集和传递信息。此变量的值类型为 CommonState 并且只读。

  • pandoc

    通过全局变量 pandoc 可获得 pandoc 模块,该模块在下一节中描述。本文档中描述的其他模块则作为各自名称下的子字段加载。

  • lpeg

    此变量持有 lpeg 模块,这是一个基于解析表达式文法 (PEG) 的包。它提供了优秀的解析工具,并在官方 LPeg 主页 上进行了文档说明。Pandoc 使用内置的库版本,除非包维护者配置了依赖系统范围内的安装。

    注意 require 'lpeg' 的结果不一定等于这个值;require 机制更倾向于使用系统的 lpeg 库而不是内置版本。

  • re

    包含基于 LPeg 的 LPeg.re 模块,提供了一个 正则表达式引擎 的实现。Pandoc 使用内置的库版本,除非包维护者配置了依赖系统范围内的安装。

    注意 require 're' 的结果不一定等于这个值;require 机制更倾向于使用系统的 lpeg 库而不是内置版本。

在本文档中