local babycode = {} local string_trim = require("lapis.util").trim local emoji = require("lib.babycode-emoji") local Parser = require("lib.babycode-parser") local function s_split(s, delimiter, max_matches, trim, allow_empty) local result = {} if s == "" then return result end trim = trim == nil and true or trim local tr = function(subj) if trim then return string_trim(subj) else return subj end end max_matches = max_matches or -1 allow_empty = allow_empty == nil and true or allow_empty if delimiter == "" then for i=1, #s do local c = s:sub(i, 1) if allow_empty or c ~= "" then table.insert(result, c) if max_matches > 0 and #result == max_matches then break end end end return result end local current_pos = 1 local delim_len = #delimiter while true do if max_matches > 0 and #result >= max_matches then break end ---@diagnostic disable-next-line: param-type-mismatch local start_pos, end_pos = s:find(delimiter, current_pos, true) if not start_pos then break end local substr = s:sub(current_pos, start_pos - 1) if allow_empty or substr ~= "" then table.insert(result, tr(substr)) end current_pos = end_pos + 1 end local substr = s:sub(current_pos) if allow_empty or substr ~= "" then table.insert(result, tr(substr)) end return result end local function list(tag, children) local list_body = children:gsub(" +\n", "
"):gsub("\n\n+", "\1") local list_items = s_split(list_body, "\1") local lis = "" for _, li in ipairs(list_items) do lis = lis .. "
  • " .. li .. "
  • " end return "<" .. tag .. ">" .. lis .. "" end local tags = { b = "$S", i = "$S", s = "$S", img = "
    %S
    ", url = "$S", quote = "
    $S
    ", code = function(children) local is_inline = children:match("\n") == nil if is_inline then return "" .. children .. "" else local t = string_trim(children) local button = (""):format(t) return "
    "..button..""..t.."
    " end end, ul = function(children) return list("ul", children) end, ol = function(children) return list("ol", children) end, } local text_only = { code = true, } ---renders babycode to html ---@param s string input babycode ---@param html_escape fun(s: string): string function to escape html function babycode.to_html(s, html_escape) -- normalize line ending chars local subj = string_trim(html_escape(s)):gsub("\r\n", "\n"):gsub("\r", "\n") local parser = Parser.new(subj) parser.valid_bbcode_tags = tags parser.valid_emotes = emoji parser.bbcode_tags_only_text_children = text_only local elements = parser:parse() local out = "" local function fold(element, nobr) if type(element) == "string" then if nobr then return element end return element:gsub(" +\n", "
    "):gsub("\n\n+", "

    ") end if element.type == "bbcode" then local c = "" for _, child in ipairs(element.children) do local _nobr = element.name == "code" or element.name == "ul" or element.name == "ol" c = c .. fold(child, _nobr) end local res = "" if type(tags[element.name]) == "string" then res = (tags[element.name]):gsub("%$S", c) if element.attribute then res = res:gsub("%$A", element.attribute) end return res elseif type(tags[element.name]) == "function" then res = tags[element.name](c, element.attribute) end return res elseif element.type == "link" then return ""..element.url.."" elseif element.type == "emote" then return emoji[element.name] elseif element.type == "ruler" then return "
    " end end for _, e in ipairs(elements) do out = out .. fold(e, false) end return out end return babycode