local babycode = {}
---renders babycode to html
---@param s string input babycode
---@param escape_html fun(s: string): string function that escapes html
function babycode.to_html(s, escape_html)
if not s or s == "" then return "" end
-- extract code blocks first and store them as placeholders
-- don't want to process bbcode embedded into a code block
local code_blocks = {}
local inline_codes = {}
s = escape_html(s)
local text = s:gsub("%[code%](.-)%[/code%]", function(code)
local is_inline = code:match("\n") == nil
if is_inline then
table.insert(inline_codes, code)
return "\1ICODE:"..#inline_codes.."\1"
else
-- strip leading and trailing newlines, preserve others
local m, _ = code:gsub("^%s*(.-)%s*$", "%1")
table.insert(code_blocks, m)
return "\1CODE:"..#code_blocks.."\1"
end
end)
local url_tags = {}
-- replace `[url=https://example.com]Example[/url] tags
text = text:gsub("%[url=([^%]]+)%](.-)%[/url%]", function(url, label)
table.insert(url_tags, {url = url, label = label})
return "\1URL:"..#url_tags.."\1"
end)
-- replace `[url]https://example.com[/url] tags
-- text = text:gsub("%[url%]([^%]]+)%[/url%]", function(url)
-- return ''..url..''
-- end)
-- bold, italics, strikethrough
text = text:gsub("%[b%](.-)%[/b%]", "%1")
text = text:gsub("%[i%](.-)%[/i%]", "%1")
text = text:gsub("%[s%](.-)%[/s%]", "%1")
text = text:gsub("%[quote%](.-)%[/quote%]", "
%1") -- replace loose links text = text:gsub("(https?://[%w-_%.%?%.:/%+=&~%@#%%]+[%w-/])", function(url) if not text:find(']*>'..url..'') then return ''..url..'' end return url end) text = text:gsub("\1URL:(%d+)\1", function(n) local url = url_tags[tonumber(n)] return ("%s"):format(url.url, url.label) end) -- rule text = text:gsub("\n+%-%-%-", "
" .. button .. ""..code.."
"
end)
text = text:gsub("\1ICODE:(%d+)\1", function (n)
local code = inline_codes[tonumber(n)]
return "" .. code .. "
"
end)
return text
end
return babycode