diff --git a/package.json b/package.json index a5b3eb6..139e77e 100644 --- a/package.json +++ b/package.json @@ -14,6 +14,7 @@ }, "devDependencies": { "ags": "link:../../../../usr/share/ags/js", - "gnim-utils": "github:retrozinndev/gnim-utils" + "gnim-utils": "github:retrozinndev/gnim-utils", + "fuse.js": "^7.1.0" } } diff --git a/src/runner/Runner.tsx b/src/runner/Runner.tsx index 3c8c9c9..35c2602 100644 --- a/src/runner/Runner.tsx +++ b/src/runner/Runner.tsx @@ -31,7 +31,7 @@ export interface Plugin { /** runs when runner opens */ readonly init?: () => void; /** handle the user input to return results (does not include plugin's prefix) */ - readonly handle: (inputText: string) => (Result|Array|null|undefined); + readonly handle: (inputText: string, limit?: number) => (Result|Array|null|undefined); /** runs when runner closes */ readonly onClose?: () => void; /** prioritize this plugin's results over other results. @@ -171,7 +171,8 @@ function getPluginResults(input: string, limit?: number): Array { } const results = calledPlugins.map(plugin => plugin.handle( - plugin.prefix ? input.replace(plugin.prefix, "") : input) + plugin.prefix ? input.replace(plugin.prefix, "") : input), + limit ).filter(value => value !== undefined && value !== null).flat(1); return limit != null && limit > 0 ? diff --git a/src/runner/plugins/clipboard.ts b/src/runner/plugins/clipboard.ts index c2fa24e..b6990a1 100644 --- a/src/runner/plugins/clipboard.ts +++ b/src/runner/plugins/clipboard.ts @@ -1,33 +1,62 @@ import { Gtk } from "ags/gtk4"; -import { Clipboard } from "../../modules/clipboard"; +import { Clipboard, ClipboardItem } from "../../modules/clipboard"; import { Runner } from "../Runner"; import { jsx } from "ags/gtk4/jsx-runtime"; +import Fuse from "fuse.js"; -export const PluginClipboard = { - prefix: '>', - prioritize: true, - handle: (search) => { + +class _PluginClipboard implements Runner.Plugin { + #fuse!: Fuse; + prefix = '>'; + prioritize = true; + + init() { + const items: ReadonlyArray = [...Clipboard.getDefault().history]; + this.#fuse = new Fuse( + items, + { + keys: [ "id", "preview" ] satisfies Array, + ignoreDiacritics: false, + isCaseSensitive: false, + shouldSort: true, + useExtendedSearch: false + } + ); + } + + private clipboardResult(item: ClipboardItem): Runner.Result { + return { + icon: jsx(Gtk.Label, { + label: `${item.id}`, + css: "font-size: 16px; margin-right: 8px; font-weight: 600;" + }), + title: item.preview, + actionClick: () => Clipboard.getDefault().selectItem(item).catch((err: Error) => { + console.error(`Runner(Plugin/Clipboard): An error occurred while selecting clipboard item. Stderr:\n${ + err.message ? `${err.message}\n` : ""}Stack: ${err.stack}` + ); + }) + }; + } + + handle(search: string, limit?: number) { if(Clipboard.getDefault().history.length < 1) return { icon: "edit-paste-symbolic", title: "Clipboard is empty", description: "Copy something and it will be shown right here!" }; + + if(search.trim().length === 0) + return Clipboard.getDefault().history.map(item => + this.clipboardResult(item) + ); - return Clipboard.getDefault().history.filter(item => - // not the best way to search, but it works - Runner.regExMatch(search, item.id) || Runner.regExMatch(search, item.preview)).map((item) => ({ - icon: jsx(Gtk.Label, { - label: `${item.id}`, - css: "font-size: 16px; margin-right: 8px; font-weight: 600;" - }), - title: item.preview, - actionClick: () => Clipboard.getDefault().selectItem(item).catch((err: Error) => { - console.error(`Runner(Plugin/Clipboard): An error occurred while selecting clipboard item. Stderr:\n${ - err.message ? `${err.message}\n` : ""}Stack: ${err.stack}` - ); - }) - })); + return this.#fuse.search(search, { + limit: limit ?? Infinity + }).map(result => this.clipboardResult(result.item as ClipboardItem)) } -} as Runner.Plugin; +} + +export const PluginClipboard = new _PluginClipboard(); diff --git a/src/runner/plugins/wallpapers.ts b/src/runner/plugins/wallpapers.ts index 7e3696c..bd7fa6e 100644 --- a/src/runner/plugins/wallpapers.ts +++ b/src/runner/plugins/wallpapers.ts @@ -1,3 +1,4 @@ +import Fuse from "fuse.js"; import { Wallpaper } from "../../modules/wallpaper"; import { Runner } from "../Runner"; @@ -7,7 +8,8 @@ import Gio from "gi://Gio?version=2.0"; class _PluginWallpapers implements Runner.Plugin { prefix = "#"; prioritize = true; - #files: (Array|undefined); + #fuse!: Fuse; + #files!: Array; init() { this.#files = []; @@ -21,17 +23,34 @@ class _PluginWallpapers implements Runner.Plugin { this.#files.push(`${dir.get_path()}/${file.get_name()}`); } } + + this.#fuse = new Fuse( + this.#files as ReadonlyArray, + { + useExtendedSearch: false, + shouldSort: true, + isCaseSensitive: false + } + ); } - handle(search: string) { - if(this.#files!.length > 0) - return this.#files!.filter(file => - // also not the best way to search, but it works - Runner.regExMatch(search, file.split('/')[file.split('/').length-1]) - ).map(path => ({ - title: path.split('/')[path.split('/').length-1].replace(/\..*$/, ""), - actionClick: () => Wallpaper.getDefault().setWallpaper(path) - })); + private wallpaperResult(path: string): Runner.Result { + return { + title: path.split('/')[path.split('/').length-1].replace(/\..*$/, ""), + actionClick: () => Wallpaper.getDefault().setWallpaper(path) + }; + } + + handle(search: string, limit?: number) { + if(search.trim().length === 0) + return this.#files.map(path => + this.wallpaperResult(path) + ); + + if(this.#files.length > 0) + return this.#fuse.search(search, { + limit: limit ?? Infinity + }).map(result => this.wallpaperResult(result.item)); return { title: "No wallpapers found!",