diff --git a/src/app.ts b/src/app.ts index 361ca92..c14185b 100644 --- a/src/app.ts +++ b/src/app.ts @@ -281,7 +281,7 @@ you should use the socket in the XDG_RUNTIME_DIR/colorshell.sock for a faster re Wallpaper.getDefault(); Stylesheet.getDefault(); - console.log("Adding runner plugins"); + console.log("Runner: Adding plugins"); runnerPlugins.forEach(plugin => Runner.addPlugin(plugin)); createSubscription( diff --git a/src/runner/plugins/wallpapers.ts b/src/runner/plugins/wallpapers.ts index bd7fa6e..c3a3c7f 100644 --- a/src/runner/plugins/wallpapers.ts +++ b/src/runner/plugins/wallpapers.ts @@ -1,62 +1,156 @@ -import Fuse from "fuse.js"; +import Fuse, { IFuseOptions } from "fuse.js"; import { Wallpaper } from "../../modules/wallpaper"; import { Runner } from "../Runner"; import Gio from "gi://Gio?version=2.0"; +import GLib from "gi://GLib?version=2.0"; class _PluginWallpapers implements Runner.Plugin { prefix = "#"; prioritize = true; #fuse!: Fuse; - #files!: Array; + #files!: Array; + #dir: string = Wallpaper.getDefault().wallpapersPath; + #subdir: string|undefined = undefined; + readonly #options = { + useExtendedSearch: false, + shouldSort: true, + isCaseSensitive: false + } satisfies IFuseOptions; init() { this.#files = []; - const dir = Gio.File.new_for_path(Wallpaper.getDefault().wallpapersPath); + this.#subdir = undefined; + + const dir = Gio.File.new_for_path(this.#dir); if(dir.query_file_type(null, null) === Gio.FileType.DIRECTORY) { for(const file of dir.enumerate_children( "standard::*", - Gio.FileQueryInfoFlags.NOFOLLOW_SYMLINKS, + Gio.FileQueryInfoFlags.NONE, null )) { - this.#files.push(`${dir.get_path()}/${file.get_name()}`); + this.#files.push(file); } } this.#fuse = new Fuse( - this.#files as ReadonlyArray, - { - useExtendedSearch: false, - shouldSort: true, - isCaseSensitive: false - } + this.#files.map(inf => inf.get_name()) as ReadonlyArray, + this.#options ); } - private wallpaperResult(path: string): Runner.Result { + private result(info: Gio.FileInfo): Runner.Result { return { - title: path.split('/')[path.split('/').length-1].replace(/\..*$/, ""), - actionClick: () => Wallpaper.getDefault().setWallpaper(path) + title: `${info.get_display_name()}${info.get_file_type() === Gio.FileType.DIRECTORY ? "/" : ""}`, + icon: info.get_file_type() === Gio.FileType.DIRECTORY ? + "inode-directory-symbolic" + : undefined, + closeOnClick: info.get_file_type() !== Gio.FileType.DIRECTORY, + actionClick: () => { + if(info.get_file_type() === Gio.FileType.DIRECTORY) { + Runner.setEntryText( + this.#subdir !== undefined ? + `#${this.#subdir.startsWith('/') ? + this.#subdir + : `/${this.#subdir}`}/${info.get_name()}/` + : `#/${info.get_name()}/` + ); + return; + } + + Wallpaper.getDefault().setWallpaper( + `${Wallpaper.getDefault().wallpapersPath}/${ + this.#subdir ? `${this.#subdir}/` : "" + }${info.get_name()}` + ); + } }; } - handle(search: string, limit?: number) { - if(search.trim().length === 0) - return this.#files.map(path => - this.wallpaperResult(path) - ); + async handle(search: string, limit?: number) { + if(!GLib.file_test(this.#dir, GLib.FileTest.IS_DIR)) + return { + title: "No wallpapers found!", + description: "Define the WALLPAPERS variable in Hyprland or create ~/wallpapers", + icon: "image-missing-symbolic" + }; - if(this.#files.length > 0) - return this.#fuse.search(search, { - limit: limit ?? Infinity - }).map(result => this.wallpaperResult(result.item)); + this.#subdir = undefined; - return { - title: "No wallpapers found!", - description: "Define the $WALLPAPERS variable on Hyprland or create a ~/wallpapers directory", - icon: "image-missing-symbolic" - }; + if(search.startsWith('/')) { + let split = search.split('/').filter(s => s.trim() !== ""); + + search = split.length > 1 && !search.endsWith('/') ? + split[split.length - 1] + : ""; + split = split.filter(s => s !== search); + this.#subdir = split.join('/'); + + if(this.#subdir === undefined) { + this.#fuse = new Fuse( + this.#files.filter(inf => + inf.get_file_type() === Gio.FileType.DIRECTORY + ).map(inf => inf.get_name()) as ReadonlyArray, + this.#options + ); + + return this.#fuse.search(search.replace(/^\//, "")).map(r => { + const info = this.#files.filter(inf => + inf.get_name() === r.item + )[0]; + + return this.result(info); + }); + } + + // TODO: recursive search for subdirectories + + if(GLib.file_test(`${this.#dir}/${this.#subdir}`, GLib.FileTest.IS_DIR)) { + const dir = Gio.File.new_for_path(`${this.#dir}/${this.#subdir}`); + this.#files = []; + + for(const file of dir.enumerate_children( + "standard::*", + Gio.FileQueryInfoFlags.NONE, + null + )) { + this.#files.push(file); + } + + this.#fuse = new Fuse( + this.#files.map(n => n.get_name()) as ReadonlyArray, + this.#options + ); + } + } + + if(search.length < 1) + return this.#files.sort(s => + s.get_file_type() === Gio.FileType.DIRECTORY ? 1 : -1 + ).map(info => this.result(info)); + + + const results: Array = []; + + this.#fuse.search(search, { + limit: limit ?? Infinity + }).map(result => { + const info = this.#files.filter(inf => + inf.get_name() === result.item + )[0]; + + results.push(this.result(info)); + }); + + + if(results.length < 1) + return { + title: "No results found", + description: "Wallpaper with provided name was not found :(" + } satisfies Runner.Result; + + return results; } } diff --git a/src/window/bar/widgets/Status.tsx b/src/window/bar/widgets/Status.tsx index 0fab601..ceaab04 100644 --- a/src/window/bar/widgets/Status.tsx +++ b/src/window/bar/widgets/Status.tsx @@ -13,14 +13,14 @@ import AstalBluetooth from "gi://AstalBluetooth"; import AstalNetwork from "gi://AstalNetwork"; import AstalWp from "gi://AstalWp"; + export const Status = () => - ( - - openWins.includes("control-center") ? "open status" : "status" - )} - onClicked={() => Windows.getDefault().toggle("control-center")} - > + + openWins.includes("control-center") ? + "open status" + : "status" + )} onClicked={() => Windows.getDefault().toggle("control-center")}> + )} /> - - - + - - + + + + - - - ) as Gtk.Button; + + as Gtk.Button; function VolumeStatus(props: { class?: string;