Custom writer: support new-style Writer function.

This commit is contained in:
Albert Krewinkel 2022-02-05 00:36:45 +01:00 committed by John MacFarlane
parent f738c451d7
commit 0f0b042139
2 changed files with 76 additions and 8 deletions

View file

@ -15,8 +15,17 @@ install any additional software to do this.
[Lua]: https://www.lua.org [Lua]: https://www.lua.org
A custom writer is a Lua file that defines functions for A custom writer is a Lua file that defines how to render the
rendering each element of a pandoc AST. 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, For example,
@ -26,15 +35,15 @@ function Para(s)
end end
``` ```
The best way to go about creating a custom writer is to modify The best way to go about creating a classic custom writer is to
the example that comes with pandoc. To get the example, you modify the example that comes with pandoc. To get the example,
can do you can do
``` ```
pandoc --print-default-data-file sample.lua > sample.lua 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 `sample.lua` is a full-features HTML writer, with explanatory
comments. To use it, just use the path to the custom writer as 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"} ``` {.lua include="sample.lua"}
``` ```
# Template variables ## Template variables
New template variables can be added, or existing ones New template variables can be added, or existing ones
modified, by returning a second value from function `Doc`. modified, by returning a second value from function `Doc`.
@ -66,3 +75,43 @@ function Doc (body, meta, vars)
return body, vars return body, vars
end 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

View file

@ -33,4 +33,23 @@ writeCustom luaFile opts doc = either throw pure <=< runLua $ do
dofileTrace luaFile >>= \case dofileTrace luaFile >>= \case
OK -> pure () OK -> pure ()
_ -> throwErrorAsException _ -> throwErrorAsException
-- 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 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