git.iko.soy/typeable/pandoc
on master help sign in
Added `Text.Pandoc.Writers.Custom`, `--print-custom-lua-writer`.

pandoc -t data/sample.lua will load the script sample.lua and use it as a custom writer. data/sample.lua is provided as an example. Added `--print-custom-lua-writer` option to print the sample script.

commit4fa2a947590f78160dac3197672e475f433f0e4f authorJohn MacFarlane <fiddlosopher@gmail.com> dateTue 2 Apr 2013, 21:08 (14 years ago) parentdede394
6 files changed+595−11
README+33−8 data/sample.lua+312 pandoc.cabal+5−1 pandoc.hs+8 src/Text/Pandoc.hs+7−2 src/Text/Pandoc/Writers/Custom.hs+230
README+33−8
@@ -174,14 +174,16 @@ General options
174174 (Slidy HTML and javascript slide show), `slideous` (Slideous HTML and
175175 javascript slide show), `dzslides` (DZSlides HTML5 + javascript slide
176176 show), `revealjs` (reveal.js HTML5 + javascript slide show), `s5`
177− (S5 HTML and javascript slide show). Note that `odt`, `epub`, and
178− `epub3` output will not be directed to *stdout*; an output
179− filename must be specified using the `-o/--output` option. If `+lhs` is
180− appended to `markdown`, `rst`, `latex`, `beamer`, `html`, or `html5`, the
181− output will be rendered as literate Haskell source: see [Literate Haskell
182− support](#literate-haskell-support), below. Markdown syntax extensions can
183− be individually enabled or disabled by appending `+EXTENSION` or
184− `-EXTENSION` to the format name, as described above under `-f`.
177+ (S5 HTML and javascript slide show), or the path of a custom
178+ lua writer (see [Custom writers](#custom-writers), below). Note that
179+ `odt`, `epub`, and `epub3` output will not be directed to *stdout*; an
180+ output filename must be specified using the `-o/--output` option. If
181+ `+lhs` is appended to `markdown`, `rst`, `latex`, `beamer`, `html`, or
182+ `html5`, the output will be rendered as literate Haskell source: see
183+ [Literate Haskell support](#literate-haskell-support), below. Markdown
184+ syntax extensions can be individually enabled or disabled by appending
185+ `+EXTENSION` or `-EXTENSION` to the format name, as described above
186+ under `-f`.
185187
186188`-o` *FILE*, `--output=`*FILE*
187189: Write output to *FILE* instead of *stdout*. If *FILE* is
@@ -301,6 +303,10 @@ General writer options
301303: Print the default template for an output *FORMAT*. (See `-t`
302304 for a list of possible *FORMAT*s.)
303305
306+`--print-sample-lua-writer`
307+: Print a sample lua custom writer (see [Custom writers](#custom-writers),
308+ below.
309+
304310`--no-wrap`
305311: Disable text wrapping in output. By default, text is wrapped
306312 appropriately for the output format.
@@ -2622,6 +2628,23 @@ ordinary HTML (without bird tracks).
26222628writes HTML with the Haskell code in bird tracks, so it can be copied
26232629and pasted as literate Haskell source.
26242630
2631+Custom writers
2632+==============
2633+
2634+Pandoc can be extended with custom writers written in [lua]. (Pandoc
2635+includes a lua interpreter, so lua need not be installed separately.)
2636+
2637+To use a custom writer, simply specify the path to the lua script
2638+in place of the output format. For example:
2639+
2640+ pandoc -t data/sample.lua
2641+
2642+Creating a custom writer requires writing a lua function for each
2643+possible element in a pandoc document. To get a documented example
2644+which you can modify according to your needs, do
2645+
2646+ pandoc --print-sample-lua-writer
2647+
26252648Authors
26262649=======
26272650
@@ -2668,3 +2691,5 @@ Sergey Astanin, Arlo O'Keeffe, Denis Laxalde, Brent Yorgey.
26682691[PDF]: http://www.adobe.com/pdf/
26692692[reveal.js]: http://lab.hakim.se/reveal-js/
26702693[FictionBook2]: http://www.fictionbook.org/index.php/Eng:XML_Schema_Fictionbook_2.1
2694+[lua]: TODO
2695+
data/sample.luanew file+312
@@ -0,0 +1,312 @@
1+-- This is a sample custom writer for pandoc. It produces output
2+-- that is very similar to that of pandoc's HTML writer.
3+-- There is one new feature: code blocks marked with class 'dot'
4+-- are piped through graphviz and images are included in the HTML
5+-- output using 'data:' URLs.
6+--
7+-- Invoke with: pandoc -t sample.lua
8+--
9+-- Note: you need not have lua installed on your system to use this
10+-- custom writer. However, if you do have lua installed, you can
11+-- use it to test changes to the script. 'lua sample.lua' will
12+-- produce informative error messages if your code contains
13+-- syntax errors.
14+
15+-- Character escaping
16+local function escape(s, in_attribute)
17+ return s:gsub("[<>&\"']",
18+ function(x)
19+ if x == '<' then
20+ return '&lt;'
21+ elseif x == '>' then
22+ return '&gt;'
23+ elseif x == '&' then
24+ return '&amp;'
25+ elseif x == '"' then
26+ return '&quot;'
27+ elseif x == "'" then
28+ return '&#39;'
29+ else
30+ return x
31+ end
32+ end)
33+end
34+
35+-- Helper function to convert an attributes table into
36+-- a string that can be put into HTML tags.
37+local function attributes(attr)
38+ local attr_table = {}
39+ for x,y in pairs(attr) do
40+ if y and y ~= "" then
41+ table.insert(attr_table, ' ' .. x .. '="' .. escape(y,true) .. '"')
42+ end
43+ end
44+ return table.concat(attr_table)
45+end
46+
47+-- Run cmd on a temporary file containing inp and return result.
48+local function pipe(cmd, inp)
49+ local tmp = os.tmpname()
50+ local tmph = io.open(tmp, "w")
51+ tmph:write(inp)
52+ tmph:close()
53+ local outh = io.popen(cmd .. " " .. tmp,"r")
54+ local result = outh:read("*all")
55+ outh:close()
56+ os.remove(tmp)
57+ return result
58+end
59+
60+-- Table to store footnotes, so they can be included at the end.
61+local notes = {}
62+
63+-- Blocksep is used to separate block elements.
64+function Blocksep()
65+ return "\n\n"
66+end
67+
68+-- This function is called once for the whole document. Parameters:
69+-- body, title, date are strings; authors is an array of strings;
70+-- variables is a table. One could use some kind of templating
71+-- system here; this just gives you a simple standalone HTML file.
72+function Doc(body, title, authors, date, variables)
73+ local buffer = {}
74+ local function add(s)
75+ table.insert(buffer, s)
76+ end
77+ add('<!DOCTYPE html>')
78+ add('<html>')
79+ add('<head>')
80+ add('<title>' .. title .. '</title>')
81+ add('</head>')
82+ add('<body>')
83+ if title ~= "" then
84+ add('<h1 class="title">' .. title .. '</h1>')
85+ end
86+ for _, author in pairs(authors) do
87+ add('<h2 class="author">' .. author .. '</h2>')
88+ end
89+ if date ~= "" then
90+ add('<h3 class="date">' .. date .. '</h3>')
91+ end
92+ add(body)
93+ if #notes > 0 then
94+ add('<ol class="footnotes">')
95+ for _,note in pairs(notes) do
96+ add(note)
97+ end
98+ add('</ol>')
99+ end
100+ add('</body>')
101+ add('</html>')
102+ return table.concat(buffer,'\n')
103+end
104+
105+-- The functions that follow render corresponding pandoc elements.
106+-- s is always a string, attr is always a table of attributes, and
107+-- items is always an array of strings (the items in a list).
108+-- Comments indicate the types of other variables.
109+
110+function Str(s)
111+ return escape(s)
112+end
113+
114+function Space()
115+ return " "
116+end
117+
118+function LineBreak()
119+ return "<br/>"
120+end
121+
122+function Emph(s)
123+ return "<em>" .. s .. "</em>"
124+end
125+
126+function Strong(s)
127+ return "<strong>" .. s .. "</strong>"
128+end
129+
130+function Subscript(s)
131+ return "<sub>" .. s .. "</sub>"
132+end
133+
134+function Superscript(s)
135+ return "<sup>" .. s .. "</sup>"
136+end
137+
138+function SmallCaps(s)
139+ return '<span style="font-variant: small-caps;">' .. s .. '</span>'
140+end
141+
142+function Strikeout(s)
143+ return '<del>' .. s .. '</del>'
144+end
145+
146+function Link(s, src, tit)
147+ return "<a href='" .. escape(src,true) .. "' title='" ..
148+ escape(tit,true) .. "'>" .. s .. "</a>"
149+end
150+
151+function Image(s, src, tit)
152+ return "<img src='" .. escape(src,true) .. "' title='" ..
153+ escape(tit,true) .. "'/>"
154+end
155+
156+function Code(s, attr)
157+ return "<code" .. attributes(attr) .. ">" .. escape(s) .. "</code>"
158+end
159+
160+function InlineMath(s)
161+ return "\\(" .. escape(s) .. "\\)"
162+end
163+
164+function DisplayMath(s)
165+ return "\\[" .. escape(s) .. "\\]"
166+end
167+
168+function Note(s)
169+ local num = #notes + 1
170+ -- insert the back reference right before the final closing tag.
171+ s = string.gsub(s,
172+ '(.*)</', '%1 <a href="#fnref' .. num .. '">&#8617;</a></')
173+ -- add a list item with the note to the note table.
174+ table.insert(notes, '<li id="fn' .. num .. '">' .. s .. '</li>')
175+ -- return the footnote reference, linked to the note.
176+ return '<a id="fnref' .. num .. '" href="#fn' .. num ..
177+ '"><sup>' .. num .. '</sup></a>'
178+end
179+
180+function Plain(s)
181+ return s
182+end
183+
184+function Para(s)
185+ return "<p>" .. s .. "</p>"
186+end
187+
188+-- lev is an integer, the header level.
189+function Header(lev, s, attr)
190+ return "<h" .. lev .. attributes(attr) .. ">" .. s .. "</h" .. lev .. ">"
191+end
192+
193+function BlockQuote(s)
194+ return "<blockquote>\n" .. s .. "\n</blockquote>"
195+end
196+
197+function HorizontalRule()
198+ return "<hr/>"
199+end
200+
201+function CodeBlock(s, attr)
202+ -- If code block has class 'dot', pipe the contents through dot
203+ -- and base64, and include the base64-encoded png as a data: URL.
204+ if attr.class and string.match(' ' .. attr.class .. ' ',' dot ') then
205+ local png = pipe("base64", pipe("dot -Tpng", s))
206+ return '<img src="data:image/png;base64,' .. png .. '"/>'
207+ -- otherwise treat as code (one could pipe through a highlighter)
208+ else
209+ return "<pre><code" .. attributes(attr) .. ">" .. escape(s) ..
210+ "</code></pre>"
211+ end
212+end
213+
214+function BulletList(items)
215+ local buffer = {}
216+ for _, item in pairs(items) do
217+ table.insert(buffer, "<li>" .. item .. "</li>")
218+ end
219+ return "<ul>\n" .. table.concat(buffer, "\n") .. "\n</ul>"
220+end
221+
222+function OrderedList(items)
223+ local buffer = {}
224+ for _, item in pairs(items) do
225+ table.insert(buffer, "<li>" .. item .. "</li>")
226+ end
227+ return "<ol>\n" .. table.concat(buffer, "\n") .. "\n</ol>"
228+end
229+
230+-- Revisit association list STackValue instance.
231+function DefinitionList(items)
232+ local buffer = {}
233+ for _,item in pairs(items) do
234+ for k, v in pairs(item) do
235+ table.insert(buffer,"<dt>" .. k .. "</dt>\n<dd>" ..
236+ table.concat(v,"</dd>\n<dd>") .. "</dd>")
237+ end
238+ end
239+ return "<dl>\n" .. table.concat(buffer, "\n") .. "\n</dl>"
240+end
241+
242+-- Convert pandoc alignment to something HTML can use.
243+-- align is AlignLeft, AlignRight, AlignCenter, or AlignDefault.
244+function html_align(align)
245+ if align == 'AlignLeft' then
246+ return 'left'
247+ elseif align == 'AlignRight' then
248+ return 'right'
249+ elseif align == 'AlignCenter' then
250+ return 'center'
251+ else
252+ return 'left'
253+ end
254+end
255+
256+-- Caption is a string, aligns is an array of strings,
257+-- widths is an array of floats, headers is an array of
258+-- strings, rows is an array of arrays of strings.
259+function Table(caption, aligns, widths, headers, rows)
260+ local buffer = {}
261+ local function add(s)
262+ table.insert(buffer, s)
263+ end
264+ add("<table>")
265+ if caption ~= "" then
266+ add("<caption>" .. caption .. "</caption>")
267+ end
268+ if widths and widths[1] ~= 0 then
269+ for _, w in pairs(widths) do
270+ add('<col width="' .. string.format("%d%%", w * 100) .. '" />')
271+ end
272+ end
273+ local header_row = {}
274+ local empty_header = true
275+ for i, h in pairs(headers) do
276+ local align = html_align(aligns[i])
277+ table.insert(header_row,'<th align="' .. align .. '">' .. h .. '</th>')
278+ empty_header = empty_header and h == ""
279+ end
280+ if empty_header then
281+ head = ""
282+ else
283+ add('<tr class="header">')
284+ for _,h in pairs(header_row) do
285+ add(h)
286+ end
287+ add('</tr>')
288+ end
289+ local class = "even"
290+ for _, row in pairs(rows) do
291+ class = (class == "even" and "odd") or "even"
292+ add('<tr class="' .. class .. '">')
293+ for i,c in pairs(row) do
294+ add('<td align="' .. html_align(aligns[i]) .. '">' .. c .. '</td>')
295+ end
296+ add('</tr>')
297+ end
298+ add('</table')
299+ return table.concat(buffer,'\n')
300+end
301+
302+-- The following code will produce runtime warnings when you haven't defined
303+-- all of the functions you need for the custom writer, so it's useful
304+-- to include when you're working on a writer.
305+local meta = {}
306+meta.__index =
307+ function(_, key)
308+ io.stderr:write(string.format("WARNING: Undefined function '%s'\n",key))
309+ return function() return "" end
310+ end
311+setmetatable(_G, meta)
312+
pandoc.cabal+5−1
@@ -101,6 +101,8 @@ Data-Files:
101101 data/dzslides/template.html,
102102 -- data for citeproc
103103 data/default.csl,
104+ -- sample lua custom writer
105+ data/sample.lua
104106 -- documentation
105107 README, INSTALL, COPYRIGHT, BUGS, changelog
106108Extra-Source-Files:
@@ -253,7 +255,8 @@ Library
253255 data-default >= 0.4 && < 0.6,
254256 temporary >= 1.1 && < 1.2,
255257 blaze-html >= 0.5 && < 0.7,
256− blaze-markup >= 0.5.1 && < 0.6
258+ blaze-markup >= 0.5.1 && < 0.6,
259+ hslua >= 0.3 && < 0.4
257260 if flag(embed_data_files)
258261 cpp-options: -DEMBED_DATA_FILES
259262 -- build-tools: hsb2hs
@@ -305,6 +308,7 @@ Library
305308 Text.Pandoc.Writers.RST,
306309 Text.Pandoc.Writers.Org,
307310 Text.Pandoc.Writers.AsciiDoc,
311+ Text.Pandoc.Writers.Custom,
308312 Text.Pandoc.Writers.Textile,
309313 Text.Pandoc.Writers.MediaWiki,
310314 Text.Pandoc.Writers.RTF,
pandoc.hs+8
@@ -327,6 +327,14 @@ options =
327327 "FORMAT")
328328 "" -- "Print default template for FORMAT"
329329
330+ , Option "" ["print-sample-lua-writer"]
331+ (NoArg
332+ (\_ -> do
333+ sample <- readDataFileUTF8 Nothing "sample.lua"
334+ UTF8.hPutStr stdout sample
335+ exitWith ExitSuccess))
336+ "" -- "Print sample lua custom writer"
337+
330338 , Option "" ["no-wrap"]
331339 (NoArg
332340 (\opt -> return opt { optWrapText = False }))
src/Text/Pandoc.hs+7−2
@@ -99,6 +99,7 @@ module Text.Pandoc
9999 , writeFB2
100100 , writeOrg
101101 , writeAsciiDoc
102+ , writeCustom
102103 -- * Rendering templates and default templates
103104 , module Text.Pandoc.Templates
104105 -- * Version
@@ -142,11 +143,12 @@ import Text.Pandoc.Writers.MediaWiki
142143import Text.Pandoc.Writers.Textile
143144import Text.Pandoc.Writers.Org
144145import Text.Pandoc.Writers.AsciiDoc
146+import Text.Pandoc.Writers.Custom
145147import Text.Pandoc.Templates
146148import Text.Pandoc.Options
147149import Text.Pandoc.Shared (safeRead, warn)
148150import Data.ByteString.Lazy (ByteString)
149−import Data.List (intercalate)
151+import Data.List (intercalate, isSuffixOf)
150152import Data.Version (showVersion)
151153import Text.JSON.Generic
152154import Data.Set (Set)
@@ -286,7 +288,10 @@ getWriter s =
286288 Left e -> Left $ intercalate "\n" $ [m | Message m <- errorMessages e]
287289 Right (writerName, setExts) ->
288290 case lookup writerName writers of
289− Nothing -> Left $ "Unknown writer: " ++ writerName
291+ Nothing
292+ | ".lua" `isSuffixOf` s ->
293+ Right $ IOStringWriter $ writeCustom s
294+ | otherwise -> Left $ "Unknown writer: " ++ writerName
290295 Just (PureStringWriter r) -> Right $ PureStringWriter $
291296 \o -> r o{ writerExtensions = setExts $
292297 getDefaultExtensions writerName }
src/Text/Pandoc/Writers/Custom.hsnew file+230
@@ -0,0 +1,230 @@
1+{-# LANGUAGE OverlappingInstances, FlexibleInstances, OverloadedStrings #-}
2+{-# OPTIONS_GHC -fno-warn-orphans #-}
3+{- Copyright (C) 2012 John MacFarlane <jgm@berkeley.edu>
4+
5+This program is free software; you can redistribute it and/or modify
6+it under the terms of the GNU General Public License as published by
7+the Free Software Foundation; either version 2 of the License, or
8+(at your option) any later version.
9+
10+This program is distributed in the hope that it will be useful,
11+but WITHOUT ANY WARRANTY; without even the implied warranty of
12+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+GNU General Public License for more details.
14+
15+You should have received a copy of the GNU General Public License
16+along with this program; if not, write to the Free Software
17+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18+-}
19+
20+{- |
21+ Module : Text.Pandoc.Writers.Custom
22+ Copyright : Copyright (C) 2012 John MacFarlane
23+ License : GNU GPL, version 2 or above
24+
25+ Maintainer : John MacFarlane <jgm@berkeley.edu>
26+ Stability : alpha
27+ Portability : portable
28+
29+Conversion of 'Pandoc' documents to custom markup using
30+a lua writer.
31+-}
32+module Text.Pandoc.Writers.Custom ( writeCustom ) where
33+import Text.Pandoc.Definition
34+import Text.Pandoc.Options
35+import Data.List ( intersperse )
36+import Scripting.Lua (LuaState, StackValue, callfunc)
37+import qualified Scripting.Lua as Lua
38+import Text.Pandoc.UTF8 (fromString, toString)
39+import Data.ByteString (ByteString)
40+import qualified Data.ByteString.Char8 as C8
41+import Data.Monoid
42+import qualified Data.Map as M
43+
44+attrToMap :: Attr -> M.Map ByteString ByteString
45+attrToMap (id',classes,keyvals) = M.fromList
46+ $ ("id", fromString id')
47+ : ("class", fromString $ unwords classes)
48+ : map (\(x,y) -> (fromString x, fromString y)) keyvals
49+
50+getList :: StackValue a => LuaState -> Int -> IO [a]
51+getList lua i' = do
52+ continue <- Lua.next lua i'
53+ if continue
54+ then do
55+ next <- Lua.peek lua (-1)
56+ Lua.pop lua 1
57+ x <- maybe (fail "peek returned Nothing") return next
58+ rest <- getList lua i'
59+ return (x : rest)
60+ else return []
61+
62+instance StackValue ByteString where
63+ push l x = Lua.push l $ C8.unpack x
64+ peek l n = (fmap . fmap) C8.pack (Lua.peek l n)
65+ valuetype _ = Lua.TSTRING
66+
67+instance StackValue a => StackValue [a] where
68+ push lua xs = do
69+ Lua.createtable lua (length xs + 1) 0
70+ let addValue (i, x) = Lua.push lua x >> Lua.rawseti lua (-2) i
71+ mapM_ addValue $ zip [1..] xs
72+ peek lua i = do
73+ top <- Lua.gettop lua
74+ let i' = if i < 0 then top + i + 1 else i
75+ Lua.pushnil lua
76+ lst <- getList lua i'
77+ Lua.pop lua 1
78+ return (Just lst)
79+ valuetype _ = Lua.TTABLE
80+
81+instance (StackValue a, StackValue b) => StackValue (M.Map a b) where
82+ push lua m = do
83+ let xs = M.toList m
84+ Lua.createtable lua (length xs + 1) 0
85+ let addValue (k, v) = Lua.push lua k >> Lua.push lua v >>
86+ Lua.rawset lua (-3)
87+ mapM_ addValue xs
88+ peek _ _ = undefined -- not needed for our purposes
89+ valuetype _ = Lua.TTABLE
90+
91+instance (StackValue a, StackValue b) => StackValue (a,b) where
92+ push lua (k,v) = do
93+ Lua.createtable lua 2 0
94+ Lua.push lua k
95+ Lua.push lua v
96+ Lua.rawset lua (-3)
97+ peek _ _ = undefined -- not needed for our purposes
98+ valuetype _ = Lua.TTABLE
99+
100+instance StackValue [Inline] where
101+ push l ils = Lua.push l . C8.unpack =<< inlineListToCustom l ils
102+ peek _ _ = undefined
103+ valuetype _ = Lua.TSTRING
104+
105+instance StackValue [Block] where
106+ push l ils = Lua.push l . C8.unpack =<< blockListToCustom l ils
107+ peek _ _ = undefined
108+ valuetype _ = Lua.TSTRING
109+
110+-- | Convert Pandoc to custom markup.
111+writeCustom :: FilePath -> WriterOptions -> Pandoc -> IO String
112+writeCustom luaFile opts doc = do
113+ luaScript <- readFile luaFile
114+ lua <- Lua.newstate
115+ Lua.openlibs lua
116+ Lua.loadstring lua luaScript "custom"
117+ Lua.call lua 0 0
118+ -- TODO - call hierarchicalize, so we have that info
119+ rendered <- docToCustom lua opts doc
120+ Lua.close lua
121+ return $ toString rendered
122+
123+docToCustom :: LuaState -> WriterOptions -> Pandoc -> IO ByteString
124+docToCustom lua opts (Pandoc (Meta title authors date) blocks) = do
125+ title' <- inlineListToCustom lua title
126+ authors' <- mapM (inlineListToCustom lua) authors
127+ date' <- inlineListToCustom lua date
128+ body <- blockListToCustom lua blocks
129+ callfunc lua "Doc" body title' authors' date' (writerVariables opts)
130+
131+-- | Convert Pandoc block element to Custom.
132+blockToCustom :: LuaState -- ^ Lua state
133+ -> Block -- ^ Block element
134+ -> IO ByteString
135+
136+blockToCustom _ Null = return ""
137+
138+blockToCustom lua (Plain inlines) = callfunc lua "Plain" inlines
139+
140+blockToCustom lua (Para [Image txt (src,tit)]) =
141+ callfunc lua "CaptionedImage" src tit txt
142+
143+blockToCustom lua (Para inlines) = callfunc lua "Para" inlines
144+
145+blockToCustom lua (RawBlock format str) =
146+ callfunc lua "RawBlock" format (fromString str)
147+
148+blockToCustom lua HorizontalRule = callfunc lua "HorizontalRule"
149+
150+blockToCustom lua (Header level attr inlines) =
151+ callfunc lua "Header" level inlines (attrToMap attr)
152+
153+blockToCustom lua (CodeBlock attr str) =
154+ callfunc lua "CodeBlock" (fromString str) (attrToMap attr)
155+
156+blockToCustom lua (BlockQuote blocks) = callfunc lua "BlockQuote" blocks
157+
158+blockToCustom lua (Table capt aligns widths headers rows') =
159+ callfunc lua "Table" capt (map show aligns) widths headers rows'
160+
161+blockToCustom lua (BulletList items) = callfunc lua "BulletList" items
162+
163+blockToCustom lua (OrderedList (num,sty,delim) items) =
164+ callfunc lua "OrderedList" items num (show sty) (show delim)
165+
166+blockToCustom lua (DefinitionList items) =
167+ callfunc lua "DefinitionList" items
168+
169+-- | Convert list of Pandoc block elements to Custom.
170+blockListToCustom :: LuaState -- ^ Options
171+ -> [Block] -- ^ List of block elements
172+ -> IO ByteString
173+blockListToCustom lua xs = do
174+ blocksep <- callfunc lua "Blocksep"
175+ bs <- mapM (blockToCustom lua) xs
176+ return $ mconcat $ intersperse blocksep bs
177+
178+-- | Convert list of Pandoc inline elements to Custom.
179+inlineListToCustom :: LuaState -> [Inline] -> IO ByteString
180+inlineListToCustom lua lst = do
181+ xs <- mapM (inlineToCustom lua) lst
182+ return $ C8.concat xs
183+
184+-- | Convert Pandoc inline element to Custom.
185+inlineToCustom :: LuaState -> Inline -> IO ByteString
186+
187+inlineToCustom lua (Str str) = callfunc lua "Str" $ fromString str
188+
189+inlineToCustom lua Space = callfunc lua "Space"
190+
191+inlineToCustom lua (Emph lst) = callfunc lua "Emph" lst
192+
193+inlineToCustom lua (Strong lst) = callfunc lua "Strong" lst
194+
195+inlineToCustom lua (Strikeout lst) = callfunc lua "Strikeout" lst
196+
197+inlineToCustom lua (Superscript lst) = callfunc lua "Superscript" lst
198+
199+inlineToCustom lua (Subscript lst) = callfunc lua "Subscript" lst
200+
201+inlineToCustom lua (SmallCaps lst) = callfunc lua "SmallCaps" lst
202+
203+inlineToCustom lua (Quoted SingleQuote lst) = callfunc lua "SingleQuoted" lst
204+
205+inlineToCustom lua (Quoted DoubleQuote lst) = callfunc lua "DoubleQuoted" lst
206+
207+inlineToCustom lua (Cite _ lst) = callfunc lua "Cite" lst
208+
209+inlineToCustom lua (Code attr str) =
210+ callfunc lua "Code" (fromString str) (attrToMap attr)
211+
212+inlineToCustom lua (Math DisplayMath str) =
213+ callfunc lua "DisplayMath" (fromString str)
214+
215+inlineToCustom lua (Math InlineMath str) =
216+ callfunc lua "InlineMath" (fromString str)
217+
218+inlineToCustom lua (RawInline format str) =
219+ callfunc lua "RawInline" format (fromString str)
220+
221+inlineToCustom lua (LineBreak) = callfunc lua "LineBreak"
222+
223+inlineToCustom lua (Link txt (src,tit)) =
224+ callfunc lua "Link" txt (fromString src) (fromString tit)
225+
226+inlineToCustom lua (Image alt (src,tit)) =
227+ callfunc lua "Image" alt (fromString src) (fromString tit)
228+
229+inlineToCustom lua (Note contents) = callfunc lua "Note" contents
230+