local M = {} M.proto = "http" local function isHttp() return M.proto == "http" end local function isGemini() return M.proto == "gemini" end local function esc(s) s = s or "" s = s:gsub("&", "&") s = s:gsub("<", "<") s = s:gsub(">", ">") return s end M.p = function(s) s = s or "" if isHttp() then return "

" .. esc(s) .. "

" elseif isGemini() then return s end end M.h = function(level, s) level = tonumber(level) or 1 if level < 1 then level = 1 end if level > 6 then level = 6 end s = s or "" if isHttp() then return "" .. esc(s) .. "" elseif isGemini() then return string.rep("#", level) .. " " .. s end end M.codeblock = function(s) s = s or "" if isHttp() then return "
" .. esc(s) .. "
" elseif isGemini() then return "```\n" .. s .. "\n```" end end M.inline = function(s) s = s or "" if isHttp() then return "" .. esc(s) .. "" elseif isGemini() then return "`" .. s .. "`" end end M.link = function(text, url) text = text or "" url = url or "" if isHttp() then return "" .. esc(text) .. "" elseif isGemini() then return "=> " .. url .. " " .. text end end M.list = function(items, ordered) items = items or {} if isHttp() then local tag = ordered and "ol" or "ul" local out = "<" .. tag .. ">" for _, v in ipairs(items) do out = out .. "
  • " .. esc(v) .. "
  • " end out = out .. "" return out elseif isGemini() then local out = {} for i, v in ipairs(items) do if ordered then table.insert(out, i .. ". " .. v) else table.insert(out, "* " .. v) end end return table.concat(out, "\n") end end M.blockquote = function(s) s = s or "" if isHttp() then return "
    " .. esc(s) .. "
    " elseif isGemini() then return "> " .. s end end M.rule = function() if isHttp() then return "
    " elseif isGemini() then return "---" end end M.image = function(alt, src) alt = alt or "" src = src or "" if isHttp() then return "\""" elseif isGemini() then return "=> " .. src .. " " .. alt end end M.file = function(text, url) text = text or "" url = url or "" if isHttp() then return "" .. esc(text) .. "" elseif isGemini() then return "=> " .. url .. " " .. text end end M.note = function(text) text = text or "" if isHttp() then return "
    " .. esc(text) .. "
    " elseif isGemini() then local width = 31 local function wrap_line(line) local out = {} local i = 1 local len = #line if len == 0 then out[#out + 1] = "" return out end while i <= len do out[#out + 1] = line:sub(i, i + width - 1) i = i + width end return out end local lines = {} for line in (text .. "\n"):gmatch("(.-)\n") do local wrapped = wrap_line(line) for _, w in ipairs(wrapped) do lines[#lines + 1] = w end end local border = "+" .. string.rep("=", width + 2) .. "+" local empty = "|" .. string.rep(" ", width + 2) .. "|" local out = {} out[#out + 1] = border out[#out + 1] = empty for _, line in ipairs(lines) do local padding = width - #line out[#out + 1] = "| " .. line .. string.rep(" ", padding) .. " |" end out[#out + 1] = empty out[#out + 1] = border return table.concat(out, "\n") end end return M