Last active
January 14, 2016 05:33
-
-
Save intelfx/203bb9b9eeb03396f621 to your computer and use it in GitHub Desktop.
LORCODE writer for Pandoc
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
-- This is a custom writer for pandoc for http://linux.org.ru | |
-- markup language. It has been dirty-hacked from the sample custom | |
-- writer which produced HTML output. | |
-- | |
-- 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. | |
-- 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" | |
end | |
-- This function is called once for the whole document. Parameters: | |
-- body is a string, metadata is a table, variables is a table. | |
-- This gives you a fragment. You could use the metadata table to | |
-- fill variables in a custom lua template. Or, pass `--template=...` | |
-- to pandoc, and pandoc will add do the template processing as | |
-- usual. | |
function Doc(body, metadata, variables) | |
local buffer = {} | |
local function add(s) | |
table.insert(buffer, s) | |
end | |
add(body) | |
if #notes > 0 then | |
add('[list=1]') | |
for _,note in pairs(notes) do | |
add(note) | |
end | |
add('[/list]') | |
end | |
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 s | |
end | |
function Space() | |
return " " | |
end | |
function LineBreak() | |
return "[br]\n" | |
end | |
function Emph(s) | |
return "[i]" .. s .. "[/i]" | |
end | |
function Strong(s) | |
return "[b]" .. s .. "[/b]" | |
end | |
function Strikeout(s) | |
return '[s]' .. s .. '[/s]' | |
end | |
function __Underline(s) | |
return '[u]' .. s .. '[/u]' | |
end | |
function Link(s, src, tit) | |
return "[url=" .. src .. "]" .. s .. "[/url]" | |
end | |
function Image(s, src, tit) | |
return Link(s,src,tit) | |
end | |
function Code(s, attr) | |
return "[inline]" .. s .. "[/inline]" | |
end | |
function Note(s) | |
local num = #notes + 1 | |
-- add a list item with the note to the note table. | |
table.insert(notes, '[*]' .. s) | |
-- return the footnote reference, linked to the note. | |
return '[[' .. num .. ']]' | |
end | |
function Plain(s) | |
return s | |
end | |
function Para(s) | |
return s .. Blocksep() | |
end | |
-- lev is an integer, the header level. | |
function Header(lev, s, attr) | |
if lev == 1 then | |
return Strong(__Underline(s)) .. Blocksep() | |
elseif lev == 2 then | |
return Strong(s) .. Blocksep() | |
elseif lev >= 3 then | |
return Emph(s) .. Blocksep() | |
end | |
end | |
function BlockQuote(s) | |
return '> ' .. s:gsub('%s*$', ''):gsub('\n', '\n> ') .. Blocksep() | |
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 Image('(dot graph)', 'data:image/png;base64,' .. png, '') | |
-- otherwise treat as code (one could pipe through a highlighter) | |
else | |
if attr.class and (attr.class ~= "") then | |
return '[code=' .. attr.class .. ']\n' .. s .. '\n[/code]' .. Blocksep() | |
else | |
return '[code]\n' .. s .. '\n[/code]' .. Blocksep() | |
end | |
end | |
end | |
function BulletList(items) | |
local buffer = {} | |
for _, item in pairs(items) do | |
table.insert(buffer, "[*] " .. item) | |
end | |
return "[list]\n" .. table.concat(buffer, "\n") .. "\n[/list]" .. Blocksep() | |
end | |
function OrderedList(items) | |
local buffer = {} | |
for _, item in pairs(items) do | |
table.insert(buffer, "[*] " .. item) | |
end | |
return "[list=1]\n" .. table.concat(buffer, "\n") .. "\n[/list]" .. Blocksep() | |
end | |
-- inspect = require ('inspect') | |
-- function _(arg) | |
-- print(inspect(arg)) | |
-- 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 utf8 = require ('utf8') | |
-- This is a rewrite of http://github.com/ozh/ascii-tables | |
local cTL, cTM, cTR | |
local cML, cMM, cMR | |
local cBL, cBM, cBR | |
local cH, cV | |
local sL, sM, sR | |
-- | |
-- | |
-- | |
cTL = "+"; | |
cTM = "+"; | |
cTR = "+"; | |
cML = "+"; | |
cMM = "+"; | |
cMR = "+"; | |
cBL = "+"; | |
cBM = "+"; | |
cBR = "+"; | |
cH = "="; | |
cV = "|"; | |
sL = "+"; | |
sM = "-"; | |
sR = "+"; | |
-- | |
-- | |
-- | |
-- compute widths of columns | |
local column_lengths = {} | |
for _, row in pairs(rows) do | |
for col_nr, cell in pairs(row) do | |
local length = utf8.width(cell) | |
if not column_lengths[col_nr] or column_lengths[col_nr] < length then | |
column_lengths[col_nr] = length | |
end | |
end | |
end | |
-- compute whether we have headers | |
local empty_header = true | |
for i, h in pairs(headers) do | |
if h ~= "" then | |
empty_header = false | |
break | |
end | |
end | |
-- output buffer | |
local buffer = {} | |
local function add(s) | |
table.insert(buffer, s) | |
end | |
local function add_separator_row(left, fill, middle, right) | |
local line = left | |
for i=1, #column_lengths do | |
line = line .. string.rep(fill, column_lengths[i] + 2) .. ((i < #column_lengths) and middle or right) | |
end | |
add (line) | |
end | |
local function add_text (left, cells, middle, right) | |
local line = left | |
for i=1, #column_lengths do | |
local padding = column_lengths[i] - utf8.width(cells[i]) | |
local text | |
if aligns[i] == 'AlignRight' then | |
text = string.rep(' ', padding) .. cells[i] | |
elseif aligns[i] == 'AlignCenter' then | |
local padding_left = math.floor (padding / 2) | |
local padding_right = padding - padding_left | |
text = string.rep(' ', padding_left) .. cells[i] .. string.rep(' ', padding_right) | |
else -- if aligns[i] == 'AlignLeft' | |
text = cells[i] .. string.rep(' ', padding) | |
end | |
line = line .. " " .. text .. " " .. ((i < #column_lengths) and middle or right) | |
end | |
add (line) | |
end | |
-- header and header separator (if exists) | |
if not empty_header then | |
add_separator_row(cTL, cH, cTM, cTR) | |
add_text(cV, headers, cV, cV) | |
add_separator_row(cML, cH, cMM, cMR) | |
else | |
add_separator_row(cTL, sM, cTM, cTR) | |
end | |
-- data rows | |
for i, row in pairs(rows) do | |
add_text(cV, row, cV, cV) | |
if i < #rows then | |
add_separator_row(sL, sM, sR, sR) | |
else | |
add_separator_row(cBL, cH, cBM, cBR) | |
end | |
end | |
return ((caption ~= "") and Header(3, caption) or "") .. "[pre]\n" .. table.concat(buffer, '\n') .. "\n[/pre]" .. Blocksep() | |
end | |
function DoubleQuoted(s) | |
return "«" .. s .. "»" | |
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) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment