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フィルタは以下のように記述します。簡略して書いているため、いくつか注意点があります。
- テンプレートファイルは
markdown
形式決め打ち - テンプレートファイルに相対パスを指定する場合は作業ディレクトリを基準
- 同じテンプレートを何度もコンパイルしている点など最適化の余地あり
--[[ 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!