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
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

View file

@ -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