forked from Shinonome/dots-hyprland
Rearrange for tidier structure (#2212)
This commit is contained in:
@@ -0,0 +1,150 @@
|
||||
pragma Singleton
|
||||
|
||||
import qs.modules.common
|
||||
import qs.modules.common.functions
|
||||
import Quickshell
|
||||
|
||||
/**
|
||||
* - Eases fuzzy searching for applications by name
|
||||
* - Guesses icon name for window class name
|
||||
*/
|
||||
Singleton {
|
||||
id: root
|
||||
property bool sloppySearch: Config.options?.search.sloppy ?? false
|
||||
property real scoreThreshold: 0.2
|
||||
property var substitutions: ({
|
||||
"code-url-handler": "visual-studio-code",
|
||||
"Code": "visual-studio-code",
|
||||
"gnome-tweaks": "org.gnome.tweaks",
|
||||
"pavucontrol-qt": "pavucontrol",
|
||||
"wps": "wps-office2019-kprometheus",
|
||||
"wpsoffice": "wps-office2019-kprometheus",
|
||||
"footclient": "foot",
|
||||
})
|
||||
property var regexSubstitutions: [
|
||||
{
|
||||
"regex": /^steam_app_(\d+)$/,
|
||||
"replace": "steam_icon_$1"
|
||||
},
|
||||
{
|
||||
"regex": /Minecraft.*/,
|
||||
"replace": "minecraft"
|
||||
},
|
||||
{
|
||||
"regex": /.*polkit.*/,
|
||||
"replace": "system-lock-screen"
|
||||
},
|
||||
{
|
||||
"regex": /gcr.prompter/,
|
||||
"replace": "system-lock-screen"
|
||||
}
|
||||
]
|
||||
|
||||
readonly property list<DesktopEntry> list: Array.from(DesktopEntries.applications.values)
|
||||
.sort((a, b) => a.name.localeCompare(b.name))
|
||||
|
||||
readonly property var preppedNames: list.map(a => ({
|
||||
name: Fuzzy.prepare(`${a.name} `),
|
||||
entry: a
|
||||
}))
|
||||
|
||||
readonly property var preppedIcons: list.map(a => ({
|
||||
name: Fuzzy.prepare(`${a.icon} `),
|
||||
entry: a
|
||||
}))
|
||||
|
||||
function fuzzyQuery(search: string): var { // Idk why list<DesktopEntry> doesn't work
|
||||
if (root.sloppySearch) {
|
||||
const results = list.map(obj => ({
|
||||
entry: obj,
|
||||
score: Levendist.computeScore(obj.name.toLowerCase(), search.toLowerCase())
|
||||
})).filter(item => item.score > root.scoreThreshold)
|
||||
.sort((a, b) => b.score - a.score)
|
||||
return results
|
||||
.map(item => item.entry)
|
||||
}
|
||||
|
||||
return Fuzzy.go(search, preppedNames, {
|
||||
all: true,
|
||||
key: "name"
|
||||
}).map(r => {
|
||||
return r.obj.entry
|
||||
});
|
||||
}
|
||||
|
||||
function iconExists(iconName) {
|
||||
if (!iconName || iconName.length == 0) return false;
|
||||
return (Quickshell.iconPath(iconName, true).length > 0)
|
||||
&& !iconName.includes("image-missing");
|
||||
}
|
||||
|
||||
function getReverseDomainNameAppName(str) {
|
||||
return str.split('.').slice(-1)[0]
|
||||
}
|
||||
|
||||
function getKebabNormalizedAppName(str) {
|
||||
return str.toLowerCase().replace(/\s+/g, "-");
|
||||
}
|
||||
|
||||
function guessIcon(str) {
|
||||
if (!str || str.length == 0) return "image-missing";
|
||||
|
||||
// Quickshell's desktop entry lookup
|
||||
const entry = DesktopEntries.heuristicLookup(str);
|
||||
if (entry) return entry.icon;
|
||||
|
||||
// Normal substitutions
|
||||
if (substitutions[str]) return substitutions[str];
|
||||
if (substitutions[str.toLowerCase()]) return substitutions[str.toLowerCase()];
|
||||
|
||||
// Regex substitutions
|
||||
for (let i = 0; i < regexSubstitutions.length; i++) {
|
||||
const substitution = regexSubstitutions[i];
|
||||
const replacedName = str.replace(
|
||||
substitution.regex,
|
||||
substitution.replace,
|
||||
);
|
||||
if (replacedName != str) return replacedName;
|
||||
}
|
||||
|
||||
// Icon exists -> return as is
|
||||
if (iconExists(str)) return str;
|
||||
|
||||
|
||||
// Simple guesses
|
||||
const lowercased = str.toLowerCase();
|
||||
if (iconExists(lowercased)) return lowercased;
|
||||
|
||||
const reverseDomainNameAppName = getReverseDomainNameAppName(str);
|
||||
if (iconExists(reverseDomainNameAppName)) return reverseDomainNameAppName;
|
||||
|
||||
const lowercasedDomainNameAppName = reverseDomainNameAppName.toLowerCase();
|
||||
if (iconExists(lowercasedDomainNameAppName)) return lowercasedDomainNameAppName;
|
||||
|
||||
const kebabNormalizedGuess = getKebabNormalizedAppName(str);
|
||||
if (iconExists(kebabNormalizedGuess)) return kebabNormalizedGuess;
|
||||
|
||||
|
||||
// Search in desktop entries
|
||||
const iconSearchResults = Fuzzy.go(str, preppedIcons, {
|
||||
all: true,
|
||||
key: "name"
|
||||
}).map(r => {
|
||||
return r.obj.entry
|
||||
});
|
||||
if (iconSearchResults.length > 0) {
|
||||
const guess = iconSearchResults[0].icon
|
||||
if (iconExists(guess)) return guess;
|
||||
}
|
||||
|
||||
const nameSearchResults = root.fuzzyQuery(str);
|
||||
if (nameSearchResults.length > 0) {
|
||||
const guess = nameSearchResults[0].icon
|
||||
if (iconExists(guess)) return guess;
|
||||
}
|
||||
|
||||
|
||||
// Give up
|
||||
return str;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user