local html = require'garkup.html' local T = html.T local extensions = {} local function prose(S, text) -- this may be a hack local replacements = {} local SO, SI = "\x0e", "\x0f" -- if debugview then SO,SI = "\x1b[7m", "\x1b[0m" end local function emplace(s) table.insert(replacements, s) return SO .. #replacements .. SI end -- no way to match 'after ws or at start of string' -- so, just add ws to start and end of string -- this may also be a hack text = ' ' .. text .. ' ' local function simple_sub(delim, tagname) return { "(%s)"..delim..'(.-)'..delim..'(%W)', -- wo wimple function(a,x,b) return a..emplace(T[tagname](x))..b end } end local function extension(str) local verb, rest = str:match("^{(%w+);%s*(.*)}$") if verb then return emplace(extensions[verb](S, rest)) end local verbonly = str:match("^{(%w+)}$") if verbonly then return emplace(extensions[verbonly](S)) end error("invalid extension syntax: "..str) end local subs = { { "%b{}", extension }, simple_sub('%*', 'strong'), simple_sub('_', 'em'), simple_sub('`', 'code'), } for i, row in ipairs(subs) do local pattern,replacement = row[1], row[2] text = text:gsub(pattern,replacement) end text = text:gsub("^%s*",""):gsub("%s*$","") -- print(text) local insects = {""} local n = 1 while n <= #text do local _, nn, id = text:find('^'..SO:gsub("%[","%%[").."(%d+)"..SI:gsub("%[","%%["), n) if nn then table.insert(insects, replacements[tonumber(id)]) table.insert(insects, "") n = nn + 1 else local c = text:sub(n,n) -- print("'"..c.."'") insects[#insects] = insects[#insects] .. c n = n + 1 end end -- for i,n in ipairs(insects) do print(i,type(n),n) end return insects end extensions.fn = function(S,text) S.footnotes = S.footnotes or {} local n = #S.footnotes + 1 local link_id = "fnref_"..n local note_id = "fn_"..n S.footnotes[n] = true -- for nested footnotes S.footnotes[n] = T.li({id=note_id}, { prose(S,text), html.safe" ", T.a({href="#"..link_id, role="doc-backlink"}, html.safe"↩︎")}) return T.sup({id=link_id}, T.a({href="#"..note_id, role='doc-noteref'}, '('..n..')')) end extensions.fns = function(S) if not S.footnotes then return "" end return {T.hr"", T.ol({class="footnotes"},S.footnotes)} end extensions.meta = function(S,text) local fn = assert(load(string.format("return {%s}", text),"meta", "t")) S.meta = fn() end extensions.a = function(S,text) local url, ni = text:match("(%S+)%s*()") local body = prose(S, text:sub(ni)) return T.a({href=url},body) end setmetatable(extensions, {__index = function(t, k) return function(S, text) io.stderr:write("warning: unknown extension "..k.."\n") return text end end}) return prose