Files
ccde/apps/launcher.lua
2025-10-22 16:43:36 -07:00

122 lines
3.4 KiB
Lua
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

local window = require("libs.window")
local threading = require("libs.threading")
local x, y = term.getSize()
local win = window.create("Launcher", x / 3, y / 1.4, x / 2 - ((x / 3) / 2), y / 2 - ((y / 1.5) / 2))
win.decorations = false
win.draggable = false
win.alwaysOnTop = true
local apps = {}
-- tiny alphabetical boost based on the first AZ letter in the name
local function alpha_boost(name, scale)
scale = scale or 0.001 -- tune this: 0.001 ⇒ max boost ≈ 0.026 for 'a'
name = string.lower(name or "")
-- find first alphabetic char
local i = name:find("%a")
if not i then return 0 end
local ch = name:sub(i, i)
local byte = ch:byte()
-- map a..z -> 1..26; non-letters -> 0 boost
if byte < 97 or byte > 122 then return 0 end
local pos = byte - 96 -- 1 for 'a', 26 for 'z'
return (27 - pos) * scale -- 'a' highest, 'z' lowest
end
-- literal (plain) substring counter with optional overlap
local function count_sub(s, sub, overlap)
if sub == "" then return 0 end
local count, i = 0, 0
while true do
local j = string.find(s, sub, i + 1, true)
if not j then break end
count = count + 1
i = overlap and j or (j + #sub - 1)
end
return count
end
local function score(app, search)
local name = string.lower(app.name or "")
local q = string.lower(search or "")
local s = count_sub(name, q, true) * 2
if app.tags then
for _, tag in ipairs(app.tags) do
s = s + count_sub(string.lower(tag), q, true)
end
end
-- Optional extra nudge if the name starts with the query (nice UX)
if q ~= "" and name:sub(1, #q) == q then
s = s + 0.5
end
-- Alphabetical tiebreaker (very small)
s = s + alpha_boost(app.name)
return s
end
for _, f in ipairs(fs.list("/.apps")) do
local file = fs.open(fs.combine("/.apps", f), "r")
if file then
local v = textutils.unserialise(file.readAll())
if v and v.name and v.file then
apps[#apps + 1] = v
end
file.close()
end
end
local function clamp(v, lo, hi) return (v < lo) and lo or ((v > hi) and hi or v) end
sleep()
local search = ""
local scroll = 1
local runnning = true
function win.char(ch)
search = search .. ch
end
function win.key(key)
if key == keys.backspace then
search = search:sub(1, #search - 1)
elseif key == keys.up then
scroll = clamp(scroll - 1, 1, #apps)
elseif key == keys.down then
scroll = clamp(scroll + 1, 1, #apps)
elseif key == keys.enter then
local app = apps[scroll]
threading.addFromFile(app.file)
runnning = false
elseif key == keys.leftCtrl then
runnning = false
end
end
while runnning do
table.sort(apps, function(a, b) return score(a, search) > score(b, search) end)
win.setBackgroundColor(colors.gray)
win.clear()
for i, app in ipairs(apps) do
if i == scroll then
win.setBackgroundColor(colors.white)
win.setTextColor(colors.black)
else
win.setBackgroundColor(colors.gray)
win.setTextColor(colors.white)
end
win.setCursorPos(1, i)
win.clearLine()
win.write(app.name)
end
local _, y = win.getSize()
win.setCursorPos(1, y)
win.setTextColor(colors.white)
win.setBackgroundColor(colors.black)
win.clearLine()
win.write(search)
sleep()
end
win.close()