343 lines
9.9 KiB
Lua
343 lines
9.9 KiB
Lua
local tHex = require("tHex")
|
|
local sub,find,reverse,rep,insert,len = string.sub,string.find,string.reverse,string.rep,table.insert,string.len
|
|
|
|
local function splitString(str, delimiter)
|
|
local results = {}
|
|
if str == "" or delimiter == "" then
|
|
return results
|
|
end
|
|
local start = 1
|
|
local delim_start, delim_end = find(str, delimiter, start)
|
|
while delim_start do
|
|
insert(results, sub(str, start, delim_start - 1))
|
|
start = delim_end + 1
|
|
delim_start, delim_end = find(str, delimiter, start)
|
|
end
|
|
insert(results, sub(str, start))
|
|
return results
|
|
end
|
|
|
|
local function removeTags(input)
|
|
return input:gsub("{[^}]+}", "")
|
|
end
|
|
|
|
|
|
local function wrapText(str, width)
|
|
str = removeTags(str)
|
|
if(str=="")or(width==0)then
|
|
return {""}
|
|
end
|
|
local uniqueLines = splitString(str, "\n")
|
|
local result = {}
|
|
for k, v in pairs(uniqueLines) do
|
|
if #v == 0 then
|
|
table.insert(result, "")
|
|
else
|
|
while #v > width do
|
|
local last_space = width
|
|
for i = width, 1, -1 do
|
|
if sub(v, i, i) == " " then
|
|
last_space = i
|
|
break
|
|
end
|
|
end
|
|
|
|
if last_space == width then
|
|
local line = sub(v, 1, last_space - 1) .. "-"
|
|
table.insert(result, line)
|
|
v = sub(v, last_space)
|
|
else
|
|
local line = sub(v, 1, last_space - 1)
|
|
table.insert(result, line)
|
|
v = sub(v, last_space + 1)
|
|
end
|
|
|
|
if #v <= width then
|
|
break
|
|
end
|
|
end
|
|
if #v > 0 then
|
|
table.insert(result, v)
|
|
end
|
|
end
|
|
end
|
|
return result
|
|
end
|
|
|
|
--- Coonverts a string with special tags to a table with colors and text
|
|
-- @param input The string to convert
|
|
-- @return A table with the following structure: { {text = "Hello", color = colors.red}, {text = "World", color = colors.blue} }
|
|
local function convertRichText(input)
|
|
local parsedResult = {}
|
|
local currentPosition = 1
|
|
local rawPosition = 1
|
|
|
|
while currentPosition <= #input do
|
|
local closestColor, closestBgColor
|
|
local color, bgColor
|
|
local colorEnd, bgColorEnd
|
|
|
|
for colorName, _ in pairs(colors) do
|
|
local fgPattern = "{fg:" .. colorName.."}"
|
|
local bgColorPattern = "{bg:" .. colorName.."}"
|
|
local colorStart, colorEndCandidate = input:find(fgPattern, currentPosition)
|
|
local bgColorStart, bgColorEndCandidate = input:find(bgColorPattern, currentPosition)
|
|
|
|
if colorStart and (not closestColor or colorStart < closestColor) then
|
|
closestColor = colorStart
|
|
color = colorName
|
|
colorEnd = colorEndCandidate
|
|
end
|
|
|
|
if bgColorStart and (not closestBgColor or bgColorStart < closestBgColor) then
|
|
closestBgColor = bgColorStart
|
|
bgColor = colorName
|
|
bgColorEnd = bgColorEndCandidate
|
|
end
|
|
end
|
|
|
|
local nextPosition
|
|
if closestColor and (not closestBgColor or closestColor < closestBgColor) then
|
|
nextPosition = closestColor
|
|
elseif closestBgColor then
|
|
nextPosition = closestBgColor
|
|
else
|
|
nextPosition = #input + 1
|
|
end
|
|
|
|
local text = input:sub(currentPosition, nextPosition - 1)
|
|
if #text > 0 then
|
|
table.insert(parsedResult, {
|
|
color = nil,
|
|
bgColor = nil,
|
|
text = text,
|
|
position = rawPosition
|
|
})
|
|
rawPosition = rawPosition + #text
|
|
currentPosition = currentPosition + #text
|
|
end
|
|
|
|
if closestColor and (not closestBgColor or closestColor < closestBgColor) then
|
|
table.insert(parsedResult, {
|
|
color = color,
|
|
bgColor = nil,
|
|
text = "",
|
|
position = rawPosition,
|
|
})
|
|
currentPosition = colorEnd + 1
|
|
elseif closestBgColor then
|
|
table.insert(parsedResult, {
|
|
color = nil,
|
|
bgColor = bgColor,
|
|
text = "",
|
|
position = rawPosition,
|
|
})
|
|
currentPosition = bgColorEnd + 1
|
|
else
|
|
break
|
|
end
|
|
end
|
|
|
|
return parsedResult
|
|
end
|
|
|
|
--- Wrapts text with special color tags, like {fg:red} or {bg:blue} to multiple lines
|
|
--- @param text string Text to wrap
|
|
--- @param width number Width of the line
|
|
--- @return table Table of lines
|
|
local function wrapRichText(text, width)
|
|
local colorData = convertRichText(text)
|
|
local formattedLines = {}
|
|
local x, y = 1, 1
|
|
local currentColor, currentBgColor
|
|
|
|
local function addFormattedEntry(entry)
|
|
table.insert(formattedLines, {
|
|
x = x,
|
|
y = y,
|
|
text = entry.text,
|
|
color = entry.color or currentColor,
|
|
bgColor = entry.bgColor or currentBgColor
|
|
})
|
|
end
|
|
|
|
for _, entry in ipairs(colorData) do
|
|
if entry.color then
|
|
currentColor = entry.color
|
|
elseif entry.bgColor then
|
|
currentBgColor = entry.bgColor
|
|
else
|
|
local words = splitString(entry.text, " ")
|
|
|
|
for i, word in ipairs(words) do
|
|
local wordLength = #word
|
|
|
|
if i > 1 then
|
|
if x + 1 + wordLength <= width then
|
|
addFormattedEntry({ text = " " })
|
|
x = x + 1
|
|
else
|
|
x = 1
|
|
y = y + 1
|
|
end
|
|
end
|
|
|
|
while wordLength > 0 do
|
|
local line = word:sub(1, width - x + 1)
|
|
word = word:sub(width - x + 2)
|
|
wordLength = #word
|
|
|
|
addFormattedEntry({ text = line })
|
|
|
|
if wordLength > 0 then
|
|
x = 1
|
|
y = y + 1
|
|
else
|
|
x = x + #line
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
if x > width then
|
|
x = 1
|
|
y = y + 1
|
|
end
|
|
end
|
|
|
|
return formattedLines
|
|
end
|
|
|
|
|
|
|
|
|
|
return {
|
|
getTextHorizontalAlign = function(text, width, textAlign, replaceChar)
|
|
text = sub(text, 1, width)
|
|
local offset = width - len(text)
|
|
if (textAlign == "right") then
|
|
text = rep(replaceChar or " ", offset) .. text
|
|
elseif (textAlign == "center") then
|
|
text = rep(replaceChar or " ", math.floor(offset / 2)) .. text .. rep(replaceChar or " ", math.floor(offset / 2))
|
|
text = text .. (len(text) < width and (replaceChar or " ") or "")
|
|
else
|
|
text = text .. rep(replaceChar or " ", offset)
|
|
end
|
|
return text
|
|
end,
|
|
|
|
getTextVerticalAlign = function(h, textAlign)
|
|
local offset = 0
|
|
if (textAlign == "center") then
|
|
offset = math.ceil(h / 2)
|
|
if (offset < 1) then
|
|
offset = 1
|
|
end
|
|
end
|
|
if (textAlign == "bottom") then
|
|
offset = h
|
|
end
|
|
if(offset<1)then offset=1 end
|
|
return offset
|
|
end,
|
|
|
|
orderedTable = function(t)
|
|
local newTable = {}
|
|
for _, v in pairs(t) do
|
|
newTable[#newTable+1] = v
|
|
end
|
|
return newTable
|
|
end,
|
|
|
|
rpairs = function(t)
|
|
return function(t, i)
|
|
i = i - 1
|
|
if i ~= 0 then
|
|
return i, t[i]
|
|
end
|
|
end, t, #t + 1
|
|
end,
|
|
|
|
tableCount = function(t)
|
|
local n = 0
|
|
if(t~=nil)then
|
|
for k,v in pairs(t)do
|
|
n = n + 1
|
|
end
|
|
end
|
|
return n
|
|
end,
|
|
|
|
splitString = splitString,
|
|
removeTags = removeTags,
|
|
|
|
wrapText = wrapText,
|
|
|
|
convertRichText = convertRichText,
|
|
|
|
--- Writes text with special color tags
|
|
--- @param obj object The object to write to
|
|
--- @param x number X-Position
|
|
--- @param y number Y-Position
|
|
--- @param text string The text to write
|
|
writeRichText = function(obj, x, y, text)
|
|
local richText = convertRichText(text)
|
|
if(#richText==0)then
|
|
obj:addText(x, y, text)
|
|
return
|
|
end
|
|
|
|
local defaultFG, defaultBG = obj:getForeground(), obj:getBackground()
|
|
for _,v in pairs(richText)do
|
|
obj:addText(x+v.position-1, y, v.text)
|
|
if(v.color~=nil)then
|
|
obj:addFG(x+v.position-1, y, tHex[colors[v.color] ]:rep(#v.text))
|
|
defaultFG = colors[v.color]
|
|
else
|
|
obj:addFG(x+v.position-1, y, tHex[defaultFG]:rep(#v.text))
|
|
end
|
|
if(v.bgColor~=nil)then
|
|
obj:addBG(x+v.position-1, y, tHex[colors[v.bgColor] ]:rep(#v.text))
|
|
defaultBG = colors[v.bgColor]
|
|
else
|
|
if(defaultBG~=false)then
|
|
obj:addBG(x+v.position-1, y, tHex[defaultBG]:rep(#v.text))
|
|
end
|
|
end
|
|
end
|
|
end,
|
|
|
|
wrapRichText = wrapRichText,
|
|
|
|
--- Writes wrapped Text with special tags.
|
|
--- @param obj object The object to write to
|
|
--- @param x number X-Position
|
|
--- @param y number Y-Position
|
|
--- @param text string Text
|
|
--- @param width number Width
|
|
--- @param height number Height
|
|
writeWrappedText = function(obj, x, y, text, width, height)
|
|
local wrapped = wrapRichText(text, width)
|
|
for _,v in pairs(wrapped)do
|
|
if(v.y>height)then
|
|
break
|
|
end
|
|
if(v.text~=nil)then
|
|
obj:addText(x+v.x-1, y+v.y-1, v.text)
|
|
end
|
|
if(v.color~=nil)then
|
|
obj:addFG(x+v.x-1, y+v.y-1, tHex[colors[v.color] ]:rep(#v.text))
|
|
end
|
|
if(v.bgColor~=nil)then
|
|
obj:addBG(x+v.x-1, y+v.y-1, tHex[colors[v.bgColor] ]:rep(#v.text))
|
|
end
|
|
end
|
|
end,
|
|
|
|
--- Returns a random UUID.
|
|
--- @return string UUID.
|
|
uuid = function()
|
|
return string.gsub(string.format('%x-%x-%x-%x-%x', math.random(0, 0xffff), math.random(0, 0xffff), math.random(0, 0xffff), math.random(0, 0x0fff) + 0x4000, math.random(0, 0x3fff) + 0x8000), ' ', '0')
|
|
end
|
|
|
|
} |