diff --git a/doc/custom-writers.md b/doc/custom-writers.md index fb08cd120..a1ce1ca56 100644 --- a/doc/custom-writers.md +++ b/doc/custom-writers.md @@ -15,8 +15,17 @@ install any additional software to do this. [Lua]: https://www.lua.org -A custom writer is a Lua file that defines functions for -rendering each element of a pandoc AST. +A custom writer is a Lua file that defines how to render the +document. Two styles of custom writers are supported: classic +custom writers must define rendering functions for each AST +element. New style writers, available since pandoc 2.17.2, must +define just a single function `Writer`, which gets passed the +document and writer options, and then does all rendering. + +# Classic style + +A writer using the classic style defines rendering functions for +all elements of pandoc's AST. For example, @@ -26,15 +35,15 @@ function Para(s) end ``` -The best way to go about creating a custom writer is to modify -the example that comes with pandoc. To get the example, you -can do +The best way to go about creating a classic custom writer is to +modify the example that comes with pandoc. To get the example, +you can do ``` pandoc --print-default-data-file sample.lua > sample.lua ``` -# A custom HTML writer +## A custom HTML writer `sample.lua` is a full-features HTML writer, with explanatory comments. To use it, just use the path to the custom writer as @@ -51,7 +60,7 @@ the functions in `sample.lua` according to your needs. ``` {.lua include="sample.lua"} ``` -# Template variables +## Template variables New template variables can be added, or existing ones modified, by returning a second value from function `Doc`. @@ -66,3 +75,43 @@ function Doc (body, meta, vars) return body, vars end ``` + +# New style + +Custom writers using the new style must contain a global function +named `Writer`. Pandoc calls this function with the document and +writer options as arguments, and expects the function to return a +string. + +``` lua +function Writer (doc, opts) + -- ... +end +``` + +## Example: modified Markdown writer + +Writers have access to all modules described in the [Lua filters +documentation][]. This includes `pandoc.write`, which can be used +to render a document in a format already supported by pandoc. The +document can be modified before this conversion, as demonstrated +in the following short example. It renders a document as GitHub +Flavored Markdown, but always uses fenced code blocks, never +indented code. + +``` lua +function Writer (doc, opts) + local filter = { + CodeBlock = function (cb) + -- only modify if code block has no attributes + if cb.attr == pandoc.Attr() then + local delimited = '```\n' .. cb.text .. '\n```' + return pandoc.RawBlock('markdown', delimited) + end + end + } + return pandoc.write(doc:walk(filter), 'gfm', opts) +end +``` + +[Lua filters documentation]: https://pandoc.org/lua-filters.html diff --git a/src/Text/Pandoc/Writers/Custom.hs b/src/Text/Pandoc/Writers/Custom.hs index e2b8bddf6..af3fd8306 100644 --- a/src/Text/Pandoc/Writers/Custom.hs +++ b/src/Text/Pandoc/Writers/Custom.hs @@ -33,4 +33,23 @@ writeCustom luaFile opts doc = either throw pure <=< runLua $ do dofileTrace luaFile >>= \case OK -> pure () _ -> throwErrorAsException - Classic.runCustom opts doc + -- Most classic writers contain code that throws an error if a global + -- is not present. This would break our check for the existence of a + -- "Writer" function. We resort to raw access for that reason, but + -- could also catch the error instead. + let rawgetglobal x = do + pushglobaltable + pushName x + rawget (nth 2) <* remove (nth 2) -- remove global table + + rawgetglobal "Writer" >>= \case + TypeNil -> do + pop 1 -- remove nil + Classic.runCustom opts doc + _ -> do + -- Writer on top of the stack. Call it with document and writer + -- options as arguments. + push doc + push opts + call 2 1 + forcePeek $ peekText top