summaryrefslogtreecommitdiff
path: root/data
diff options
context:
space:
mode:
authorJohn MacFarlane <fiddlosopher@gmail.com>2013-04-02 21:08:38 -0700
committerJohn MacFarlane <jgm@berkeley.edu>2013-04-14 00:31:39 -0500
commit4fa2a947590f78160dac3197672e475f433f0e4f (patch)
tree658c4e6ec08ce1cf3dc4217d61dd1fb6c75cb656 /data
parentdede39452f9488002daa1b402eed8d25aa88994f (diff)
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.
Diffstat (limited to 'data')
-rw-r--r--data/sample.lua312
1 files changed, 312 insertions, 0 deletions
diff --git a/data/sample.lua b/data/sample.lua
new file mode 100644
index 000000000..fe425b749
--- /dev/null
+++ b/data/sample.lua
@@ -0,0 +1,312 @@
+-- This is a sample custom writer for pandoc. It produces output
+-- that is very similar to that of pandoc's HTML writer.
+-- There is one new feature: code blocks marked with class 'dot'
+-- are piped through graphviz and images are included in the HTML
+-- output using 'data:' URLs.
+--
+-- Invoke with: pandoc -t sample.lua
+--
+-- Note: you need not have lua installed on your system to use this
+-- custom writer. However, if you do have lua installed, you can
+-- use it to test changes to the script. 'lua sample.lua' will
+-- produce informative error messages if your code contains
+-- syntax errors.
+
+-- Character escaping
+local function escape(s, in_attribute)
+ return s:gsub("[<>&\"']",
+ function(x)
+ if x == '<' then
+ return '&lt;'
+ elseif x == '>' then
+ return '&gt;'
+ elseif x == '&' then
+ return '&amp;'
+ elseif x == '"' then
+ return '&quot;'
+ elseif x == "'" then
+ return '&#39;'
+ else
+ return x
+ end
+ end)
+end
+
+-- Helper function to convert an attributes table into
+-- a string that can be put into HTML tags.
+local function attributes(attr)
+ local attr_table = {}
+ for x,y in pairs(attr) do
+ if y and y ~= "" then
+ table.insert(attr_table, ' ' .. x .. '="' .. escape(y,true) .. '"')
+ end
+ end
+ return table.concat(attr_table)
+end
+
+-- Run cmd on a temporary file containing inp and return result.
+local function pipe(cmd, inp)
+ local tmp = os.tmpname()
+ local tmph = io.open(tmp, "w")
+ tmph:write(inp)
+ tmph:close()
+ local outh = io.popen(cmd .. " " .. tmp,"r")
+ local result = outh:read("*all")
+ outh:close()
+ os.remove(tmp)
+ return result
+end
+
+-- Table to store footnotes, so they can be included at the end.
+local notes = {}
+
+-- Blocksep is used to separate block elements.
+function Blocksep()
+ return "\n\n"
+end
+
+-- This function is called once for the whole document. Parameters:
+-- body, title, date are strings; authors is an array of strings;
+-- variables is a table. One could use some kind of templating
+-- system here; this just gives you a simple standalone HTML file.
+function Doc(body, title, authors, date, variables)
+ local buffer = {}
+ local function add(s)
+ table.insert(buffer, s)
+ end
+ add('<!DOCTYPE html>')
+ add('<html>')
+ add('<head>')
+ add('<title>' .. title .. '</title>')
+ add('</head>')
+ add('<body>')
+ if title ~= "" then
+ add('<h1 class="title">' .. title .. '</h1>')
+ end
+ for _, author in pairs(authors) do
+ add('<h2 class="author">' .. author .. '</h2>')
+ end
+ if date ~= "" then
+ add('<h3 class="date">' .. date .. '</h3>')
+ end
+ add(body)
+ if #notes > 0 then
+ add('<ol class="footnotes">')
+ for _,note in pairs(notes) do
+ add(note)
+ end
+ add('</ol>')
+ end
+ add('</body>')
+ add('</html>')
+ return table.concat(buffer,'\n')
+end
+
+-- The functions that follow render corresponding pandoc elements.
+-- s is always a string, attr is always a table of attributes, and
+-- items is always an array of strings (the items in a list).
+-- Comments indicate the types of other variables.
+
+function Str(s)
+ return escape(s)
+end
+
+function Space()
+ return " "
+end
+
+function LineBreak()
+ return "<br/>"
+end
+
+function Emph(s)
+ return "<em>" .. s .. "</em>"
+end
+
+function Strong(s)
+ return "<strong>" .. s .. "</strong>"
+end
+
+function Subscript(s)
+ return "<sub>" .. s .. "</sub>"
+end
+
+function Superscript(s)
+ return "<sup>" .. s .. "</sup>"
+end
+
+function SmallCaps(s)
+ return '<span style="font-variant: small-caps;">' .. s .. '</span>'
+end
+
+function Strikeout(s)
+ return '<del>' .. s .. '</del>'
+end
+
+function Link(s, src, tit)
+ return "<a href='" .. escape(src,true) .. "' title='" ..
+ escape(tit,true) .. "'>" .. s .. "</a>"
+end
+
+function Image(s, src, tit)
+ return "<img src='" .. escape(src,true) .. "' title='" ..
+ escape(tit,true) .. "'/>"
+end
+
+function Code(s, attr)
+ return "<code" .. attributes(attr) .. ">" .. escape(s) .. "</code>"
+end
+
+function InlineMath(s)
+ return "\\(" .. escape(s) .. "\\)"
+end
+
+function DisplayMath(s)
+ return "\\[" .. escape(s) .. "\\]"
+end
+
+function Note(s)
+ local num = #notes + 1
+ -- insert the back reference right before the final closing tag.
+ s = string.gsub(s,
+ '(.*)</', '%1 <a href="#fnref' .. num .. '">&#8617;</a></')
+ -- add a list item with the note to the note table.
+ table.insert(notes, '<li id="fn' .. num .. '">' .. s .. '</li>')
+ -- return the footnote reference, linked to the note.
+ return '<a id="fnref' .. num .. '" href="#fn' .. num ..
+ '"><sup>' .. num .. '</sup></a>'
+end
+
+function Plain(s)
+ return s
+end
+
+function Para(s)
+ return "<p>" .. s .. "</p>"
+end
+
+-- lev is an integer, the header level.
+function Header(lev, s, attr)
+ return "<h" .. lev .. attributes(attr) .. ">" .. s .. "</h" .. lev .. ">"
+end
+
+function BlockQuote(s)
+ return "<blockquote>\n" .. s .. "\n</blockquote>"
+end
+
+function HorizontalRule()
+ return "<hr/>"
+end
+
+function CodeBlock(s, attr)
+ -- If code block has class 'dot', pipe the contents through dot
+ -- and base64, and include the base64-encoded png as a data: URL.
+ if attr.class and string.match(' ' .. attr.class .. ' ',' dot ') then
+ local png = pipe("base64", pipe("dot -Tpng", s))
+ return '<img src="data:image/png;base64,' .. png .. '"/>'
+ -- otherwise treat as code (one could pipe through a highlighter)
+ else
+ return "<pre><code" .. attributes(attr) .. ">" .. escape(s) ..
+ "</code></pre>"
+ end
+end
+
+function BulletList(items)
+ local buffer = {}
+ for _, item in pairs(items) do
+ table.insert(buffer, "<li>" .. item .. "</li>")
+ end
+ return "<ul>\n" .. table.concat(buffer, "\n") .. "\n</ul>"
+end
+
+function OrderedList(items)
+ local buffer = {}
+ for _, item in pairs(items) do
+ table.insert(buffer, "<li>" .. item .. "</li>")
+ end
+ return "<ol>\n" .. table.concat(buffer, "\n") .. "\n</ol>"
+end
+
+-- Revisit association list STackValue instance.
+function DefinitionList(items)
+ local buffer = {}
+ for _,item in pairs(items) do
+ for k, v in pairs(item) do
+ table.insert(buffer,"<dt>" .. k .. "</dt>\n<dd>" ..
+ table.concat(v,"</dd>\n<dd>") .. "</dd>")
+ end
+ end
+ return "<dl>\n" .. table.concat(buffer, "\n") .. "\n</dl>"
+end
+
+-- Convert pandoc alignment to something HTML can use.
+-- align is AlignLeft, AlignRight, AlignCenter, or AlignDefault.
+function html_align(align)
+ if align == 'AlignLeft' then
+ return 'left'
+ elseif align == 'AlignRight' then
+ return 'right'
+ elseif align == 'AlignCenter' then
+ return 'center'
+ else
+ return 'left'
+ end
+end
+
+-- Caption is a string, aligns is an array of strings,
+-- widths is an array of floats, headers is an array of
+-- strings, rows is an array of arrays of strings.
+function Table(caption, aligns, widths, headers, rows)
+ local buffer = {}
+ local function add(s)
+ table.insert(buffer, s)
+ end
+ add("<table>")
+ if caption ~= "" then
+ add("<caption>" .. caption .. "</caption>")
+ end
+ if widths and widths[1] ~= 0 then
+ for _, w in pairs(widths) do
+ add('<col width="' .. string.format("%d%%", w * 100) .. '" />')
+ end
+ end
+ local header_row = {}
+ local empty_header = true
+ for i, h in pairs(headers) do
+ local align = html_align(aligns[i])
+ table.insert(header_row,'<th align="' .. align .. '">' .. h .. '</th>')
+ empty_header = empty_header and h == ""
+ end
+ if empty_header then
+ head = ""
+ else
+ add('<tr class="header">')
+ for _,h in pairs(header_row) do
+ add(h)
+ end
+ add('</tr>')
+ end
+ local class = "even"
+ for _, row in pairs(rows) do
+ class = (class == "even" and "odd") or "even"
+ add('<tr class="' .. class .. '">')
+ for i,c in pairs(row) do
+ add('<td align="' .. html_align(aligns[i]) .. '">' .. c .. '</td>')
+ end
+ add('</tr>')
+ end
+ add('</table')
+ return table.concat(buffer,'\n')
+end
+
+-- The following code will produce runtime warnings when you haven't defined
+-- all of the functions you need for the custom writer, so it's useful
+-- to include when you're working on a writer.
+local meta = {}
+meta.__index =
+ function(_, key)
+ io.stderr:write(string.format("WARNING: Undefined function '%s'\n",key))
+ return function() return "" end
+ end
+setmetatable(_G, meta)
+