PandocのLuaフィルタからPandoc templateを呼べるpandoc.templateモジュールがとても便利

by
カテゴリ:
タグ:

Pandoc 3.0以降ではLuaフィルタで使えるモジュールにpandoc.templateが追加されました。これを使うとLuaフィルタ内でPandoc Templateを展開できます。

うまく使うと定型句を任意のタイミングで、少しずつ文言を変えながら展開する、といったことが可能です。

たとえば、後述するLuaフィルタとテンプレートファイルを書いておいてあげれば、以下の<div>からテンプレートを展開して、Pandocはいいぞと出力されます。

<div template=assets/template.md x="Pandoc"></div>

属性xの値を"Pandoc"から"Luaフィルタ"に書き換えれば出力はLuaフィルタはいいぞになります。

<div template=assets/template.md x="Luaフィルタ"></div>

この程度のシンプルな例であれば、Luaフィルタ上で直接文字列操作をしてやれば済むでしょうが、定型句が長くなる、条件分岐するなど複雑さを増すごとに威力を発揮するでしょう。

<div>を使って好きなタイミングで読んでいるだけなので、入力がHTMLやMarkdownであれば、定型句(<div>)の前後に任意の文章を挿入できる柔軟性も魅力です。

肝心のLuaフィルタは以下のように記述します。簡略して書いているため、いくつか注意点があります。

--[[ assets/filter.lua ]]

---テキストファイルを読む
---@param filepath string テンプレートのファイルパス。相対パスの基準はPandoc実行時の作業ディレクトリ。
---@return string テンプレートの中身
local function read_lines(filepath)
  local lines = {}
  for i in io.lines(filepath) do
    table.insert(lines, i)
  end
  return table.concat(lines, "\n")
end

---テンプレートファイルを指定したコンテキスト化で展開し、Markdownとして処理する
---@param filepath string テンプレートのファイルパス。相対パスの基準はPandoc実行時の作業ディレクトリ。
---@param context table<any, any>
---@return any blocks PandocのBlock要素のリスト
local function apply_template(filepath, context)
  local content = read_lines(filepath)
  local compiled = pandoc.template.compile(content)
  local rendered = pandoc.template.apply(compiled, context):render()
  return pandoc.read(rendered, "markdown", PANDOC_READER_OPTIONS).blocks
end

---divのtemplate属性にファイルが指定されていれば、divの属性をコンテキストとしてテンプレートを展開するフィルタ
function Div(el)
  if el.attributes.template then
    local ctx = {}
    for k, v in pairs(el.attributes) do
      ctx[k] = v
    end
    return apply_template(el.attributes.template, ctx)
  end
  return el
end

assets/template.mdの中身は以下の通りです。

<!-- assets/template.md -->
${x}はいいぞ

では、このフィルタとテンプレートを利用するMarkdownファイルを用意しましょう。

<!-- assets/example.md -->

# 好きなもの紹介するぞ

<div template=assets/template.md x="Pandoc"></div>
<div template=assets/template.md x="Luaフィルタ"></div>
<div template=assets/template.md x="R"></div>

あとはMarkdownファイルをPandocで良い感じに処理すれば、無事にテンプレートが展開されます。 <div>x属性に指定していた値が、テンプレートの${x}に展開されていることがわかりますね。

> cat assets/example.md | pandoc -t markdown -L assets/filter.lua --strip-comments
# 好きなもの紹介するぞ

Pandocはいいぞ

Luaフィルタはいいぞ

Rはいいぞ

ENJOY!