File size: 4,203 Bytes
b6a38d7 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 |
DefineClass.MarkdownParser = {
__parents = { "PropertyObject" },
properties = {
{ category = "General", id = "TextColor", editor = "color", default = RGB(80, 80, 80) },
{ category = "General", id = "BoldColor", editor = "color", default = RGB(0, 0, 0) },
{ category = "General", id = "ItalicColor", editor = "color", default = RGB(45, 45, 45) },
{ category = "General", id = "HyperlinkColor", editor = "color", default = RGB(0, 0, 238) },
{ category = "General", id = "HeadingFont1", editor = "text", default = "Heading1" },
{ category = "General", id = "HeadingFont2", editor = "text", default = "Heading2" },
{ category = "General", id = "HeadingFont3", editor = "text", default = "Heading3" },
{ category = "General", id = "HeadingFont4", editor = "text", default = "Heading4" },
},
text = "",
output = "",
paragraph = "",
empty_lines = 0,
numbered_entries = 0,
}
local function md_match_and_replace(text, pattern, fn)
while true do
local idx1, idx2 = text:find(pattern)
if not idx1 or not idx2 then
break
end
text = text:sub(1, idx1-1) .. fn(text:match(pattern, idx1)) .. text:sub(idx2+1)
end
return text
end
function MarkdownParser:ParseParagraph(text)
text = md_match_and_replace(text, "%*%*([^%*]+)%*%*", function(bold)
local r, g, b, a = GetRGBA(self.BoldColor)
return string.format("<color %s %s %s %s>", r, g, b, a) .. self:ParseParagraph(bold) .. "</color>"
end)
text = md_match_and_replace(text, "%*([^%*]+)%*", function(italic)
local r, g, b, a = GetRGBA(self.ItalicColor)
return string.format("<color %s %s %s %s>", r, g, b, a) .. self:ParseParagraph(italic) .. "</color>"
end)
-- [link text](href)
text = md_match_and_replace(text, "%[([^%]]+)%]%(([^%)]+)%)", function(link_text, link_ref)
local r, g, b, a = GetRGBA(self.HyperlinkColor)
return string.format("<color %s %s %s><h OpenUrl %s %s %s %s underline>", r, g, b, link_ref:gsub(" ", "+"), r, g, b) .. link_text .. "</h></color>"
end)
return text
end
function MarkdownParser:ParseLine(line)
local level, text = line:match("^ ?(#+) ([^\n]+)")
if level and text then
level = #level
if not level or level > 4 then
return
end
local fontstyle = self["HeadingFont" .. level]
local r, g, b, a = GetRGBA(self.BoldColor)
return string.format("<style %s><color %s %s %s %s>", fontstyle, r, g, b, a) .. self:ParseParagraph(text) .. "</color></style>\n"
end
local bullet_text = line:match(" %* (.+)") or line:match("%+ (.+)")
if bullet_text then
return " • " .. self:ParseParagraph(bullet_text) .. "\n"
end
local num_text = line:match(" %d+%. (.+)")
if num_text then
self.numbered_entries = self.numbered_entries + 1
return " " .. self.numbered_entries .. ". " .. self:ParseParagraph(num_text) .. "\n", "do_not_clear_counter"
end
end
function MarkdownParser:ApplyParagraph()
self.output = self.output .. self:ParseParagraph(self.paragraph)
self.paragraph = ""
end
function MarkdownParser:ParseTopLevelLine(line)
if not line then
self:ApplyParagraph()
return
end
if line:trim_spaces() == "" then
self.empty_lines = self.empty_lines + 1
return
end
if self.empty_lines > 1 then
self.empty_lines = 0
self:ApplyParagraph()
self.output = self.output .. "\n"
end
local line_parsed, do_not_clear_counter = self:ParseLine(line)
if not do_not_clear_counter then
self.numbered_entries = 0
end
if line_parsed then
self:ApplyParagraph()
self.output = self.output .. line_parsed
return
end
self.paragraph = self.paragraph .. line .. "\n"
end
function MarkdownParser:ConvertText(input)
local r, g, b, a = GetRGBA(self.TextColor)
self.output = string.format("<color %s %s %s %s>", r, g, b, a)
local current_idx = 1
while current_idx < #input do
local idx = input:find("\n", current_idx) or #input + 1
local line = input:sub(current_idx, idx-1)
current_idx = idx + 1
self:ParseTopLevelLine(line)
end
self:ParseTopLevelLine(nil)
self.output = self.output .. "</color>"
return self.output
end
function ParseMarkdown(input, properties)
properties = properties and table.copy(properties) or {}
local parser = MarkdownParser:new(properties)
return parser:ConvertText(input)
end |