From ab8535cc578672f844419d25fc1cc8e8790f1aa8 Mon Sep 17 00:00:00 2001 From: littleblack111 Date: Sun, 10 Aug 2025 17:24:44 +0800 Subject: interal(query): move to Searchable module from https://github.com/caelestia-dots/shell license is GPL, this project don't have a license yet, will use GPL --- services/AppSearch.qml | 65 +++++--------------------------------------------- services/Clip.qml | 58 +++++++------------------------------------- 2 files changed, 15 insertions(+), 108 deletions(-) (limited to 'services') diff --git a/services/AppSearch.qml b/services/AppSearch.qml index 9cd10d4..8063e0f 100644 --- a/services/AppSearch.qml +++ b/services/AppSearch.qml @@ -1,18 +1,16 @@ pragma Singleton -import "../utils/levendist.js" as Levendist import Quickshell import Quickshell.Io import qs.config +import qs.components -/** - * - Eases fuzzy searching for applications by name - * - Guesses icon name for window class name - */ -Singleton { +Searchable { id: root - property int scoreThreshold: General.appSearchFuzzySearchThreshold + list: Array.from(DesktopEntries.applications.values).sort((a, b) => a.name.localeCompare(b.name)) + scoreThreshold: General.appSearchFuzzySearchThreshold + algorithm: Searchable.SearchAlgorithm.Levendist property var substitutions: ({ "code-url-handler": "visual-studio-code", @@ -45,60 +43,9 @@ Singleton { } ] - property var fuzzyQueryCache: ({}) property var iconExistsCache: ({}) property var guessIconCache: ({}) - readonly property list list: Array.from(DesktopEntries.applications.values).sort((a, b) => a.name.localeCompare(b.name)) - - /** - * Returns an Array for a given search. - * Results are cached by exact search string and, if the - * search starts with a previously cached key, uses that - * cached result as the source for filtering. - */ - function fuzzyQuery(search) { // search is expected to be .toLowerCase() - if (root.fuzzyQueryCache[search]) { - return root.fuzzyQueryCache[search]; - } - - let source = list; - let previousLists = Object.keys(root.fuzzyQueryCache).filter(key => key && search.startsWith(key)); - if (previousLists.length > 0) { - var longest = previousLists.reduce((a, b) => a.length >= b.length ? a : b); - source = root.fuzzyQueryCache[longest]; - } - - const p = [], f = []; - for (const s of source) { - const t = s.name.toLowerCase(); - if (t.startsWith(search)) { - p.push(s); - continue; - } - let pos = 0; - for (const c of search) { - pos = t.indexOf(c, pos); - if (pos < 0) { - pos = 0; - break; - } - pos++; - } - if (pos) - f.push({ - s, - score: Levendist.distance(search, t) - }); - } - const results = p.concat(f.sort((a, b) => a.score - b.score).map(({ - s - }) => s)); - - root.fuzzyQueryCache[search] = results; - return results; - } - function iconExists(iconName) { if (!iconName || iconName.length === 0) { return false; @@ -157,7 +104,7 @@ Singleton { } if (!result) { - const matches = root.fuzzyQuery(str); + const matches = root.query(str); if (matches.length > 0) { const candidate = matches[0].icon; if (root.iconExists(candidate)) { diff --git a/services/Clip.qml b/services/Clip.qml index 6fee97c..81fea60 100644 --- a/services/Clip.qml +++ b/services/Clip.qml @@ -3,11 +3,14 @@ pragma Singleton import Quickshell import Quickshell.Io import QtQuick -import "../utils/levendist.js" as Levendist +import qs.components -Singleton { +Searchable { id: root + key: "data" + algorithm: Searchable.SearchAlgorithm.Levendist + property list _clipHist: [] property list _clipImg: [] property list _clipImgIds: _clipImg.map(p => p.split("/").pop().split(".").shift()) @@ -16,9 +19,7 @@ Singleton { property string toCopy: "" property string decoded: "" - property var fuzzyQueryCache: ({}); - - property var clipHist: { + list: { const arr = []; if (!_clipHist?.length) return arr; @@ -42,7 +43,7 @@ Singleton { const n = parseInt(raw.slice(0, tab), 10); if (!Number.isNaN(n)) { idNum = n; - payload = raw.slice(tab + 1); // strip "ID" + payload = raw.slice(tab + 1); } } @@ -60,49 +61,8 @@ Singleton { return arr; } - function fuzzyQuery(search) { - if (!search) - return root.clipHist; - if (root.fuzzyQueryCache[search]) { - return root.fuzzyQueryCache[search]; - } - let source = root.clipHist; - let previousLists = Object.keys(root.fuzzyQueryCache).filter(key => key && search.startsWith(key)); - if (previousLists.length > 0) { - var longest = previousLists.reduce((a, b) => a.length >= b.length ? a : b); - source = root.fuzzyQueryCache[longest]; - } - const p = [], f = []; - for (const s of source) { - const t = (s.isImage ? "image" : (s.data || "")).toLowerCase(); - if (t.startsWith(search)) { - p.push(s); - continue; - } - let pos = 0; - for (const c of search) { - pos = t.indexOf(c, pos); - if (pos < 0) { - pos = 0; - break; - } - pos++; - } - if (pos) - f.push({ - s, - score: Levendist.distance(search, t) - }); - } - const results = p.concat(f.sort((a, b) => a.score - b.score).map(({s}) => s)); - root.fuzzyQueryCache[search] = results; - return results; - } - - component SClip_t: QtObject { - property int index - property bool isImage - property string data + function transformSearch(search: string): string { + return search.toLowerCase(); } function decodeAndCopy(text) { -- cgit v1.2.3