local babycode = {}
local _escape_html = function(text)
return text:gsub("[&<>\"']", {
["&"] = "&",
["<"] = "<",
[">"] = ">",
['"'] = """,
["'"] = "'"
})
end
---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 code_count = 0
local text = s:gsub("%[code%](.-)%[/code%]", function(code)
code_count = code_count + 1
code_blocks[code_count] = code
return "\1CODE:"..code_count.."\1"
end)
-- replace `[url=https://example.com]Example[/url] tags
text = text:gsub("%[url=([^%]]+)%](.-)%[/url%]", function(url, label)
return ''..escape_html(label)..''
end)
-- replace `[url]https://example.com[/url] tags
text = text:gsub("%[url%]([^%]]+)%[/url%]", function(url)
return ''..escape_html(url)..''
end)
-- bold, italics, strikethrough
text = text:gsub("%[b%](.-)%[/b%]", "%1")
text = text:gsub("%[i%](.-)%[/i%]", "%1")
text = text:gsub("%[s%](.-)%[/s%]", "%1")
-- replace loose links
text = text:gsub("(https?://[%w-_%.%?%.:/%+=&~%@#%%]+[%w-/])", function(url)
if not text:find(']*>'..url..'') then
return ''..escape_html(url)..''
end
return url
end)
-- replace code block placeholders back with their original contents
text = text:gsub("\1CODE:(%d+)\1", function(n)
return "
"..code_blocks[tonumber(n)].."
"
end)
-- finally, normalize newlines replace them with