local lpeg = require("lpeg") lpeg.locale(lpeg) local V,P,C,S,B,Cs = lpeg.V,lpeg.P,lpeg.C,lpeg.S,lpeg.B,lpeg.Cs --Characters to escape in the body text local escapes = { ["&"] = "&", ["<"] = "<", [">"] = ">", } local esctbl = {} for char,_ in pairs(escapes) do table.insert(esctbl,char) end local escapematch = string.format("([%s])",table.concat(esctbl)) local function sanitize_item(capture) return escapes[capture] or capture end local function sanitize(text) local ret,_ = string.gsub(text,escapematch,sanitize_item) return ret end --Grammar local space = S" \t\r"^0 local special = P{ P"**" + P"''" + P"'''" + P"__" + P"==" + P"~~" + P"\n>" + P"\n<" + P"\n" + P"[code]" + P"[spoiler]" } local word = Cs((1 - special)^1) * space / sanitize --Generates a pattern that formats text inside matching 'seq' tags with format --ex wrap("^^",[[%s]]) --will wrap text "5^^3^^" as "53" local function wrap(seq,format) return P(seq) * Cs(((1 - P(seq)) * space)^1) * P(seq) * space / function(a) return string.format(format,sanitize(a)) end end --Generates a pattern that formats text inside opening and closing "name" tags --with a format, BB forum style local function tag(name,format) local start_tag = P(string.format("[%s]",name)) local end_tag = P(string.format("[/%s]",name)) return start_tag * Cs(((1 - end_tag) * space)^1) * end_tag * space / function(a) return string.format(format,sanitize(a)) end end local grammar = P{ "chunk"; --regular spoiler = wrap("**",[[%s]]), spoiler2 = tag("spoiler",[[%s]]), italic = wrap("''",[[%s]]), bold = wrap("'''",[[%s]]), underline = wrap("__",[[%s]]), heading = wrap("==",[[

%s

]]), strike = wrap("~~",[[%s]]), code = tag("code",[[
%s
]]), greentext = P">" * (B"\n>" + B">") * Cs((V"marked" + word)^0) / function(a) return string.format([[>%s]],a) end, pinktext = P"<" * (B"\n<" + B"<") * Cs((V"marked" + word)^0) / function(a) return string.format([[<%s]],a) end, marked = V"spoiler" + V"bold" + V"italic" + V"underline" + V"heading" + V"strike" + V"spoiler2" + V"code", plainline = (V"marked" + word)^0, line = Cs(V"greentext" + V"pinktext" + V"plainline" + P"") * P"\n" / function(a) return string.format("

%s",a) end, ending = C(P(1)^0) / sanitize, chunk = V"line"^0 * V"plainline" * V"ending" } --[=[ local text = [[ sanitize < things that could be tags like really badly words can include any'single item without=penalty Can you use '''one tag ==within== another tag'''? let's see if [spoiler]spoiler tags work[/spoiler] things might even __go over multiple lines__ blah Let's test out those [code] code tag,s and see how well they work here's ome preformated text [/code] >Or have blank lines one important thing is that greentext > should not start in the middle of a line >this next line is a green text, what if I include **markup** inside it? because of some of these restrictions **bold text cannot go over multiple lines** in a green text >greentext on the last line