summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlbert Krewinkel <albert@zeitkraut.de>2022-02-05 00:36:45 +0100
committerJohn MacFarlane <jgm@berkeley.edu>2022-02-06 16:37:39 -0800
commit0f0b042139e3a82673590f14b70e5fcb5e57ea61 (patch)
treecb4cd4f3e5609da619ed965e74275b30c7fb9f14
parentf738c451d7092e5fa5562d68bf3dcc4b1274e156 (diff)
Custom writer: support new-style Writer function.
-rw-r--r--doc/custom-writers.md63
-rw-r--r--src/Text/Pandoc/Writers/Custom.hs21
2 files changed, 76 insertions, 8 deletions
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