Folio Writer 的編譯流程涵蓋了 99% 的需求——引用、交叉引用、模板、格式。Lua 篩選器則是應付最後 1% 的逃生出口:期刊古怪的內部規定、你自己的簡寫、任何核取方塊都沒預料到的狀況。篩選器就是幾行在編譯過程中改寫文件的 Lua 程式碼,而 pandoc 原生就能執行它們——無須安裝任何東西。
pandoc 編譯你的手稿時,會先把 Markdown 解析成文件樹——段落、標題、span、引用。Lua 篩選器就是一組以這些元素命名的函式;每個函式都會以每個符合的元素為參數被呼叫,並可以回傳一個替代品。什麼都不回傳就是保持原樣,回傳 {} 就是刪除它,回傳新元素就是轉換它。整個模型就是這樣。
.lua 檔案——放在專案裡(例如 Research 中的 Filters 子資料夾),它就會隨手稿一起同步與移動。在任何地方輸入 @@today;編譯出的文件就會帶上編譯日期——在投稿信和草稿浮水印中很實用:
-- today.lua
function Str(el)
if el.text == "@@today" then
return pandoc.Str(os.date("%B %e, %Y"))
end
end
把寫給自己的筆記放在 fenced div 中,起草時看得見,輸出中則保證不會出現:
::: draft Ask Wei whether the 2019 calibration applies here. :::
-- strip-draft.lua
function Div(el)
if el.classes:includes("draft") then
return {} -- deleted from every compiled format
end
end
只把它掛在投稿用的設定檔上,這些筆記就仍會出現在給指導教授看的草稿設定檔中——每個設定檔各自的篩選器正是為此而設計。
讓 [key result]{.highlight} 在每種格式中都有實際意義——在 HTML 中是黃色標記,在 LaTeX PDF 中是螢光筆高亮:
-- highlight.lua
function Span(el)
if not el.classes:includes("highlight") then return nil end
if FORMAT:match("latex") then
local out = pandoc.Inlines(pandoc.RawInline("latex", "\\hl{"))
out:extend(el.content)
out:insert(pandoc.RawInline("latex", "}"))
return out
elseif FORMAT:match("html") then
local out = pandoc.Inlines(pandoc.RawInline("html", ""))
out:extend(el.content)
out:insert(pandoc.RawInline("html", ""))
return out
end
end
對於 LaTeX 分支,只需在格式中繼資料中加入一次高亮套件:header-includes: \usepackage{soul}。
兩個習慣能讓撰寫篩選器輕鬆無痛。想看清你要比對的文件樹,就在「終端機」中對一小段內容執行 pandoc -t native——它會精確印出你的函式將收到的元素。而當編譯出了問題時,編譯與預覽記錄會顯示完整的 pandoc 命令列及其輸出,包括篩選器錯誤。還有一點是 Folio Writer 特有的:如果篩選器的檔案被移動了,它會被略過,而不會讓編譯失敗——如果某個篩選器似乎默默失效了,請查看記錄。
pandoc Lua 篩選器文件列出了每一種元素與輔助函式,而社群的篩選器合集裡滿是現成的篩選器——縮寫處理、表格調整、圖表渲染。那裡的任何篩選器都能直接放進編譯面板。