-- Invoke with: pandoc -t gemtext.lua -- Tables to store links and footnotes, so they can be included correctly. local links = {} 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 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('') for _,note in pairs(notes) do add(note) end 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 SoftBreak() return " " end function LineBreak() return "\n" end function Emph(s) return "_" .. s .. "_" end function Strong(s) return "**" .. s .. "**" end function Subscript(s) return "_" .. s end function Superscript(s) return "^" .. s end function SmallCaps(s) return s end function Strikeout(s) return '~~' .. s .. '~~' end function Link(s, tgt, tit, attr) if tgt:match("%.html$") and not tgt:match("^https?://") then tgt = tgt:gsub("%.html$", ".gmi") end table.insert(links, "=> " .. tgt .. " " .. s) return s end function Image(s, src, tit, attr) table.insert(links, "=> " .. src .. " [IMG] " .. s) return s end function Code(s, attr) return "`" .. s .. "`" end function InlineMath(s) return "\\(" .. s .. "\\)" end function DisplayMath(s) return "\\[" .. s .. "\\]" end function SingleQuoted(s) return "‘" .. s .. "’" end function DoubleQuoted(s) return "“" .. s .. "”" end function Note(s) local num = #notes + 1 local num_fn = string.gsub(num, '0', '⁰') :gsub('1', '¹') :gsub('2', '²') :gsub('3', '³') :gsub('4', '⁴') :gsub('5', '⁵') :gsub('6', '⁶') :gsub('7', '⁷') :gsub('8', '⁸') :gsub('9', '⁹') -- add a list item with the note to the note table. table.insert(notes, num_fn .. ' ' .. s) -- return the footnote reference, linked to the note. return num_fn end function Span(s, attr) return s end function RawInline(format, str) if format == "gemtext" then return str else return '' end end function Cite(s, cs) local ids = {} for _,cit in ipairs(cs) do table.insert(ids, cit.citationId) end return s .. ids:concat(",") end function Plain(s) return s end function Para(s) local finished = s .. "\n" if #links > 0 then local link_text = links[1]:match('=> [^ ]+ (.+)') if link_text == s and #links == 1 then finished = links[1] .. "\n" else finished = finished .. table.concat(links, "\n") .. "\n" end end links = {} return finished end -- lev is an integer, the header level. function Header(lev, s, attr) return string.rep("#", lev) .. " " .. s .. "\n" end function BlockQuote(s) return "> " .. s:gsub("\n", "\n> "):gsub("\n> $", "\n") end function HorizontalRule() return "-----\n" end function LineBlock(ls) return table.concat(ls, '\n') .. "\n" end function CodeBlock(s, attr) return "```\n" .. s .. "\n```\n" end function BulletList(items) local buffer = {} for _, item in pairs(items) do local finished = false if #links > 0 then local link_text = links[1]:match('=> [^ ]+ (.+)') if link_text == item then table.insert(buffer, links[1]) table.remove(links, 1) finished = true end end if not finished then table.insert(buffer, "* " .. item) for _,link in pairs(links) do table.insert(buffer, link) end links = {} end end return table.concat(buffer, "\n") .. "\n" end function OrderedList(items) local buffer = {} for i, item in pairs(items) do table.insert(buffer, i .. ". " .. item) end return table.concat(buffer, "\n") .. "\n" end function DefinitionList(items) local buffer = {} for _,item in pairs(items) do local k, v = next(item) table.insert(buffer, k .. ":\n" .. table.concat(v, "\n")) end return table.concat(buffer, "\n") .. "\n" end function CaptionedImage(src, tit, caption, attr) return '=> ' .. src .. ' [IMG] ' .. caption .. '\n' 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("") if caption ~= "" then add("") end if widths and widths[1] ~= 0 then for _, w in pairs(widths) do add('') end end local header_row = {} local empty_header = true for i, h in pairs(headers) do table.insert(header_row,'') empty_header = empty_header and h == "" end if empty_header then head = "" else add('') for _,h in pairs(header_row) do add(h) end add('') end local class = "even" for _, row in pairs(rows) do class = (class == "even" and "odd") or "even" add('') for i,c in pairs(row) do add('') end add('') end add('
" .. caption .. "
' .. h .. '
' .. c .. '
') return table.concat(buffer,'\n') .. "\n" end function RawBlock(format, str) if format == "gemtext" then return str else return '' end end function Div(s, attr) 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)