From 5ada504d5667a6f17ee2631dd471b073b332dd33 Mon Sep 17 00:00:00 2001 From: Melody Horn Date: Mon, 26 Oct 2020 23:22:29 -0600 Subject: build spec in gemtext too --- etc/gemtext.lua | 297 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ etc/template.gmi | 1 + 2 files changed, 298 insertions(+) create mode 100644 etc/gemtext.lua create mode 100644 etc/template.gmi (limited to 'etc') diff --git a/etc/gemtext.lua b/etc/gemtext.lua new file mode 100644 index 0000000..5fdff59 --- /dev/null +++ b/etc/gemtext.lua @@ -0,0 +1,297 @@ +-- 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) diff --git a/etc/template.gmi b/etc/template.gmi new file mode 100644 index 0000000..36d66c2 --- /dev/null +++ b/etc/template.gmi @@ -0,0 +1 @@ +$body$ -- cgit v1.2.3