2019-12-28 12:16:32 +01:00
|
|
|
local common = {}
|
|
|
|
|
|
|
|
|
|
|
|
function common.is_utf8_cont(char)
|
|
|
|
local byte = char:byte()
|
|
|
|
return byte >= 0x80 and byte < 0xc0
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
function common.utf8_chars(text)
|
|
|
|
return text:gmatch("[\0-\x7f\xc2-\xf4][\x80-\xbf]*")
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
function common.clamp(n, lo, hi)
|
|
|
|
return math.max(math.min(n, hi), lo)
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
function common.round(n)
|
|
|
|
return n >= 0 and math.floor(n + 0.5) or math.ceil(n - 0.5)
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
function common.lerp(a, b, t)
|
|
|
|
if type(a) ~= "table" then
|
|
|
|
return a + (b - a) * t
|
|
|
|
end
|
|
|
|
local res = {}
|
|
|
|
for k, v in pairs(b) do
|
|
|
|
res[k] = common.lerp(a[k], v, t)
|
|
|
|
end
|
|
|
|
return res
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
function common.color(str)
|
|
|
|
local r, g, b, a = str:match("#(%x%x)(%x%x)(%x%x)")
|
|
|
|
if r then
|
|
|
|
r = tonumber(r, 16)
|
|
|
|
g = tonumber(g, 16)
|
|
|
|
b = tonumber(b, 16)
|
|
|
|
a = 1
|
|
|
|
elseif str:match("rgba?%s*%([%d%s%.,]+%)") then
|
|
|
|
local f = str:gmatch("[%d.]+")
|
|
|
|
r = (f() or 0)
|
|
|
|
g = (f() or 0)
|
|
|
|
b = (f() or 0)
|
|
|
|
a = f() or 1
|
|
|
|
else
|
|
|
|
error(string.format("bad color string '%s'", str))
|
|
|
|
end
|
|
|
|
return r, g, b, a * 0xff
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
local function compare_score(a, b)
|
|
|
|
return a.score > b.score
|
|
|
|
end
|
|
|
|
|
|
|
|
local function fuzzy_match_items(items, needle)
|
|
|
|
local res = {}
|
2020-05-07 23:40:34 +02:00
|
|
|
for _, item in ipairs(items) do
|
2019-12-28 12:16:32 +01:00
|
|
|
local score = system.fuzzy_match(tostring(item), needle)
|
|
|
|
if score then
|
|
|
|
table.insert(res, { text = item, score = score })
|
|
|
|
end
|
|
|
|
end
|
|
|
|
table.sort(res, compare_score)
|
|
|
|
for i, item in ipairs(res) do
|
|
|
|
res[i] = item.text
|
|
|
|
end
|
|
|
|
return res
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
function common.fuzzy_match(haystack, needle)
|
|
|
|
if type(haystack) == "table" then
|
|
|
|
return fuzzy_match_items(haystack, needle)
|
|
|
|
end
|
|
|
|
return system.fuzzy_match(haystack, needle)
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
function common.path_suggest(text)
|
|
|
|
local path, name = text:match("^(.-)([^/\\]*)$")
|
2020-04-22 00:45:34 +02:00
|
|
|
local files = system.list_dir(path == "" and "." or path) or {}
|
2019-12-28 12:16:32 +01:00
|
|
|
local res = {}
|
|
|
|
for _, file in ipairs(files) do
|
|
|
|
file = path .. file
|
|
|
|
local info = system.get_file_info(file)
|
|
|
|
if info then
|
|
|
|
if info.type == "dir" then
|
2020-04-25 10:57:35 +02:00
|
|
|
file = file .. PATHSEP
|
2019-12-28 12:16:32 +01:00
|
|
|
end
|
|
|
|
if file:lower():find(text:lower(), nil, true) == 1 then
|
|
|
|
table.insert(res, file)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
return res
|
|
|
|
end
|
|
|
|
|
|
|
|
|
2020-12-07 18:06:58 +01:00
|
|
|
function common.dir_path_suggest(text)
|
|
|
|
local path, name = text:match("^(.-)([^/\\]*)$")
|
|
|
|
local files = system.list_dir(path == "" and "." or path) or {}
|
|
|
|
local res = {}
|
|
|
|
for _, file in ipairs(files) do
|
|
|
|
file = path .. file
|
|
|
|
local info = system.get_file_info(file)
|
|
|
|
if info and info.type == "dir" and file:lower():find(text:lower(), nil, true) == 1 then
|
|
|
|
table.insert(res, file)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
return res
|
|
|
|
end
|
|
|
|
|
|
|
|
|
2020-12-28 15:51:16 +01:00
|
|
|
function common.dir_list_suggest(text, dir_list)
|
|
|
|
local path, name = text:match("^(.-)([^/\\]*)$")
|
|
|
|
local res = {}
|
|
|
|
for _, dir_path in ipairs(dir_list) do
|
|
|
|
if dir_path:lower():find(text:lower(), nil, true) == 1 then
|
|
|
|
table.insert(res, dir_path)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
return res
|
|
|
|
end
|
|
|
|
|
|
|
|
|
2020-05-07 15:18:46 +02:00
|
|
|
function common.match_pattern(text, pattern, ...)
|
2020-05-07 11:27:37 +02:00
|
|
|
if type(pattern) == "string" then
|
|
|
|
return text:find(pattern, ...)
|
|
|
|
end
|
|
|
|
for _, p in ipairs(pattern) do
|
2020-05-07 15:18:46 +02:00
|
|
|
local s, e = common.match_pattern(text, p, ...)
|
2020-05-07 11:27:37 +02:00
|
|
|
if s then return s, e end
|
|
|
|
end
|
|
|
|
return false
|
|
|
|
end
|
|
|
|
|
|
|
|
|
2019-12-28 12:16:32 +01:00
|
|
|
function common.draw_text(font, color, text, align, x,y,w,h)
|
|
|
|
local tw, th = font:get_width(text), font:get_height(text)
|
|
|
|
if align == "center" then
|
|
|
|
x = x + (w - tw) / 2
|
|
|
|
elseif align == "right" then
|
|
|
|
x = x + (w - tw)
|
|
|
|
end
|
2020-05-03 17:48:35 +02:00
|
|
|
y = common.round(y + (h - th) / 2)
|
2019-12-28 12:16:32 +01:00
|
|
|
return renderer.draw_text(font, text, x, y, color), y + th
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
function common.bench(name, fn, ...)
|
|
|
|
local start = system.get_time()
|
|
|
|
local res = fn(...)
|
|
|
|
local t = system.get_time() - start
|
|
|
|
local ms = t * 1000
|
|
|
|
local per = (t / (1 / 60)) * 100
|
|
|
|
print(string.format("*** %-16s : %8.3fms %6.2f%%", name, ms, per))
|
|
|
|
return res
|
|
|
|
end
|
|
|
|
|
|
|
|
|
2020-12-19 23:53:29 +01:00
|
|
|
function common.home_encode(text)
|
2020-12-20 00:31:49 +01:00
|
|
|
if HOME then
|
|
|
|
local n = #HOME
|
|
|
|
if text:sub(1, n) == HOME and text:sub(n + 1, n + 1):match("[/\\\\]") then
|
|
|
|
return "~" .. text:sub(n + 1)
|
|
|
|
end
|
2020-12-19 23:53:29 +01:00
|
|
|
end
|
|
|
|
return text
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
function common.home_expand(text)
|
2020-12-20 00:31:49 +01:00
|
|
|
return HOME and text:gsub("^~", HOME) or text
|
2020-12-19 23:53:29 +01:00
|
|
|
end
|
|
|
|
|
|
|
|
|
2019-12-28 12:16:32 +01:00
|
|
|
return common
|