| 
						 
							
							
							
						 
					 | 
				
			
			 | 
			 | 
			
				@@ -1,16 +1,82 @@
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				local babycode = {}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				local string_trim = require("lapis.util").trim
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				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 get_list_items(list_body, escape_html)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  list_body = list_body:gsub("  +%s*\r?\n", "<br>")
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  list_body = list_body:gsub("(%S)(\r?\n\r?\n)\r?\n*", "%1\1")
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  local list_items = s_split(list_body, "\1")
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  local lis = ""
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  for _, li in ipairs(list_items) do
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    local rendered = babycode.to_html(li, escape_html)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    lis = lis .. "<li>" .. rendered .. "</li>"
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  end
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  return lis
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				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
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  local text = escape_html(s)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  -- extract code blocks 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)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  text = text:gsub("%[code%](.-)%[/code%]", function(code)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    local is_inline = code:match("\n") == nil
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    if is_inline then
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      table.insert(inline_codes, code)
 | 
			
		
		
	
	
		
			
				
					
					| 
						
					 | 
				
			
			 | 
			 | 
			
				@@ -23,10 +89,17 @@ function babycode.to_html(s, escape_html)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    end
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  end)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  text = text:gsub("  %s?\r?\n", "<br>")
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  -- normalize newlines
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  text = text:gsub("\r?\n\r?\n+", "<br>")
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  text = text:gsub("%[ul%](.-)%[/ul%]", function(list_body)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    return "<ul>" .. get_list_items(list_body, escape_html) .. "</ul>"
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  end)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  text = text:gsub("%[ol%](.-)%[/ol%]", function(list_body)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    return "<ol>" .. get_list_items(list_body, escape_html) .. "</ol>"
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  end)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  -- normalize newlines, attempt #4
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  text = text:gsub("  +%s*\r?\n", "<br>")
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  text = text:gsub("(%S)(\r?\n\r?\n)\r?\n*", "%1<br><br>")
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  local url_tags = {}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  -- replace `[url=https://example.com]Example[/url] tags
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  text = text:gsub("%[url=([^%]]+)%](.-)%[/url%]", function(url, label)
 | 
			
		
		
	
	
		
			
				
					
					| 
						
					 | 
				
			
			 | 
			 | 
			
				@@ -40,8 +113,6 @@ function babycode.to_html(s, escape_html)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  text = text:gsub("%[s%](.-)%[/s%]", "<del>%1</del>")
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  -- these can be nested, so replace open and closed separately
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  -- text = text:gsub("%[quote%]", "<blockquote>")
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  -- text = text:gsub("%[/quote%]", "</blockquote>")
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  text = text:gsub("%[(/?)quote%]", "<%1blockquote>")
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  -- replace loose links
 | 
			
		
		
	
	
		
			
				
					
					| 
						
					 | 
				
			
			 | 
			 | 
			
				 
 |