Pandoc内置了Lua解释器,可以直接处理语法树。

初体验

  1. 运行pandoc -v找到User data directory,在该目录中创建filters文件夹,在其中编写filters。使用以下命令快速获取目录:

    1
    2
    
    pandoc -v | sed -n 's/^User data directory: //p' # win
    pandoc -v | sed -n 's/.*: \([^ ]*\) or.*/\1/p' # linux
    

    WindowsTerminal_YUBfqqGRv3

  2. 将filter放在上述的文件夹中的优势是不用再指定filter的绝对路径,比如原来调用命令:

    1
    
    pandoc --lua-filter C:\test\smallcaps.lua
    

    变为

    1
    
    pandoc --lua-filter smallcaps.lua # 自动在data directory中的filters文件夹搜寻
    
  3. 使用vscode打开此目录,安装Lua插件,下载pandoc定义文件到此目录。创建header.lua,编写如下代码:

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    
    ---@module "pandoc-types-annotations"
    local pandoc = pandoc ---@type pandoc
    
    ---comment
    ---@param elem Header
    ---@return Inline | List<Inline> | nil
    function Header(elem)
        elem = elem:walk {
            Str = function(el)
                el.text = pandoc.text.upper(el.text)
                return el
            end
        }
    
        if elem.level == 1 then
            elem.level = 3
            return elem
        end
        return elem
    end
    
  4. 创建test.md

    1
    2
    3
    
    # heading1
    ## heading2
    ### heading3
    
  5. 运行pandoc --lua-filter=header.lua test.md -o output.md,结果如下

    1
    2
    3
    4
    5
    
    ### HEADING1
    
    ## HEADING2
    
    ### HEADING3
    
  6. 可以看到所有的标题都变成了大写,标题1变成了标题3。我们定义了一个Header函数,pandoc会将Ast树中的所有Header元素依次调用这个函数,接收的elem参数即为当前的Header元素。

    1. 我们可以使用elem.level去调整标题等级,修改完成后,一定要返回一个元素(可以是修改后的元素)。Pandoc期待返回一个同类型的元素(Inline类型或者Block类型),或者同类型的列表,或者是nil,nil表示不改动该元素

    2. 在本例中Header属于Block类型,我们可以使用以下命令查看文档包含哪些元素

      1
      
      pandoc -s -t native test.md  # -s get meta -t convert to what format
      
    3. 类似于Header函数,我们可以定义StrParaPara等函数,Pandoc会一次将对应的元素传入对应的函数中。如果我们不定义全局函数的话,我们也可以返回一个table

      1
      2
      3
      4
      5
      
      return {
      	Str: function,
      	Header: function,
      	Pandoc: function
      }
      

      Pandoc会将对应的元素传入的这些函数中。

    4. 在上述代码的第8行,我们调用了walk方法,几乎所有的元素都有此方法。此方法会遍历该元素的子元素,根据元素类型调用对应的函数。这些函数都需要返回同类型的元素或者数组或者nil。

    5. walk方法返回一个深拷贝后的元素,修改完后,要返回该元素(line 19)