repositories / dotfiles
dotfiles
bugabingas dorkfiles
owned by admin
quickshell/nuguland/launch.js
Raw// launch.js — pure app-launcher logic: normalize, fuzzy rank, desktop-entry mapping.
// NO I/O. Dual-mode: node `require` (tests) + QML import.
var GLYPH_APP = "\uF135"; // rocket fallback when themed icon misses
function normalize(text) {
return String(text == null ? "" : text).trim().toLowerCase();
}
function prefixIntent(raw) {
return { intent: "app", query: String(raw == null ? "" : raw).trim() };
}
function isWordChar(ch) {
return /[a-z0-9]/.test(ch);
}
function subsequenceMatch(q, t) {
var qi = 0;
var positions = [];
for (var ti = 0; ti < t.length && qi < q.length; ti++) {
if (t.charAt(ti) === q.charAt(qi)) {
positions.push(ti);
qi++;
}
}
if (qi < q.length)
return { matched: false, firstIndex: -1, contiguous: 0, boundaryHits: 0 };
var contiguous = 0;
var boundaryHits = 0;
for (var i = 0; i < positions.length; i++) {
var p = positions[i];
if (i > 0 && positions[i] === positions[i - 1] + 1)
contiguous++;
if (p === 0 || !isWordChar(t.charAt(p - 1)))
boundaryHits++;
}
return { matched: true, firstIndex: positions[0], contiguous: contiguous, boundaryHits: boundaryHits };
}
function fuzzyScore(query, title, boost) {
var b = Number(boost) || 0;
var q = normalize(query);
var t = normalize(title);
if (q.length === 0)
return b;
if (t === q)
return b + 1000;
if (t.indexOf(q) === 0)
return b + 800 - t.length;
var m = subsequenceMatch(q, t);
if (m.matched) {
var allBoundary = m.boundaryHits === q.length;
var base = allBoundary ? 600 : 350;
return b + base + m.contiguous * 10 + m.boundaryHits * 15 - m.firstIndex;
}
return -1;
}
function list(value) {
var out = [];
var src = value || [];
for (var i = 0; i < src.length; i++) {
var text = String(src[i] || "").trim();
if (text.length > 0)
out.push(text);
}
return out;
}
function commandList(value) {
var out = [];
var src = value || [];
for (var i = 0; i < src.length; i++)
out.push(String(src[i]));
return out;
}
function primaryCategory(categories) {
var skip = { Qt: true, KDE: true, GNOME: true, GTK: true, Application: true, Core: true };
for (var i = 0; i < categories.length; i++) {
var cat = categories[i];
if (!skip[cat])
return cat;
}
return categories[0] || "App";
}
function buildDesktopActions(actions) {
var rows = [];
var src = actions || [];
for (var i = 0; i < src.length; i++) {
var a = src[i];
if (!a || !a.name)
continue;
rows.push({
id: String(a.id || a.name),
title: String(a.name),
icon: String(a.icon || ""),
exec: String(a.execString || ""),
execArgv: commandList(a.command)
});
}
return rows;
}
function buildApps(entries) {
var rows = [];
var src = entries || [];
for (var i = 0; i < src.length; i++) {
var e = src[i];
if (!e || !e.name)
continue;
var id = String(e.id || e.name);
var categories = list(e.categories);
var keywords = list(e.keywords);
var genericName = String(e.genericName || "");
var comment = String(e.comment || "");
var kind = genericName || primaryCategory(categories);
var category = primaryCategory(categories);
var actions = buildDesktopActions(e.actions);
rows.push({
id: "app:" + id,
title: String(e.name),
subtitle: kind + (category && category !== kind ? " · " + category : ""),
genericName: genericName,
comment: comment,
desktopId: id,
desktopPath: id + ".desktop",
startupClass: String(e.startupClass || ""),
exec: String(e.execString || ""),
execArgv: commandList(e.command),
workingDirectory: String(e.workingDirectory || ""),
icon: String(e.icon || ""),
terminal: !!e.runInTerminal,
categories: categories,
keywords: keywords,
actions: actions,
details: [
{ label: "category", value: category },
{ label: "keywords", value: keywords.slice(0, 4).join("; ") || "—" },
{ label: "terminal", value: e.runInTerminal ? "yes" : "no" }
],
searchText: [e.name, genericName, comment, id, e.startupClass].concat(categories).concat(keywords).join(" "),
route: "desktop-entry"
});
}
rows.sort(function (a, b) {
return String(a.title).localeCompare(String(b.title));
});
return rows;
}
function shapeRow(row, provider, score) {
var next = Object.assign({}, row || {});
next.provider = "app";
next.iconRole = "desktop-entry";
next.verb = "open";
next.glyph = GLYPH_APP;
next.score = score;
next.keyboard = true;
return next;
}
function rankResults(rawQuery, sources) {
var apps = (sources || {}).apps || [];
var intent = prefixIntent(rawQuery);
var query = intent.query;
var results = [];
for (var i = 0; i < apps.length; i++) {
var app = apps[i];
var score = Math.max(
fuzzyScore(query, app.title, 900),
fuzzyScore(query, app.searchText || app.title, 760)
);
if (score >= 0)
results.push(shapeRow(app, "app", score));
}
results.sort(function (x, y) {
return y.score - x.score || String(x.title).localeCompare(String(y.title));
});
return {
results: results,
selectedIndex: results.length > 0 ? 0 : -1,
providerIntent: intent.intent
};
}
if (typeof module !== 'undefined' && module.exports) {
module.exports = {
normalize: normalize,
prefixIntent: prefixIntent,
subsequenceMatch: subsequenceMatch,
fuzzyScore: fuzzyScore,
buildDesktopActions: buildDesktopActions,
buildApps: buildApps,
shapeRow: shapeRow,
rankResults: rankResults
};
}