From 785eafd646cb73d2e4a88fbec5a876fe26d7616c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lera=20Elvo=C3=A9?= Date: Sun, 18 May 2025 19:55:07 +0300 Subject: [PATCH] add bbcode support --- lib/babycode.lua | 62 ++++++++++++++++++++++++++++++++++++++ util.lua | 7 ++++- views/threads/thread.etlua | 2 +- 3 files changed, 69 insertions(+), 2 deletions(-) create mode 100644 lib/babycode.lua diff --git a/lib/babycode.lua b/lib/babycode.lua new file mode 100644 index 0000000..afbb9a4 --- /dev/null +++ b/lib/babycode.lua @@ -0,0 +1,62 @@ +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
+ text = text:gsub("\r?\n\r?\n+", "
"):gsub("\r?\n", "
") + + return text +end + +return babycode diff --git a/util.lua b/util.lua index 4e37e13..704f22c 100644 --- a/util.lua +++ b/util.lua @@ -1,12 +1,15 @@ local util = {} local magick = require("magick") local db = require("lapis.db") +local html_escape = require("lapis.html").escape local Avatars = require("models").Avatars local Users = require("models").Users local Posts = require("models").Posts local PostHistory = require("models").PostHistory +local babycode = require("lib.babycode") + util.TransientUser = { is_admin = function (self) return false @@ -109,10 +112,12 @@ function util.create_post(thread_id, user_id, content) current_revision_id = db.NULL, }) + local bb_content = babycode.to_html(content, html_escape) + local revision = PostHistory:create({ post_id = post.id, user_id = user_id, - content = content, + content = bb_content, is_initial_revision = true, }) diff --git a/views/threads/thread.etlua b/views/threads/thread.etlua index b7a948e..4e56839 100644 --- a/views/threads/thread.etlua +++ b/views/threads/thread.etlua @@ -2,7 +2,7 @@
">
<%= post.username %>
-

<%- require("lapis.html").escape(post.content):gsub("\n", "
") %>

+

<%- post.content %>

<% end %>