From d7c66522cf365f516babcfeb1d4a2d36c3ea41af Mon Sep 17 00:00:00 2001 From: delta Date: Wed, 29 Oct 2025 16:35:38 +0100 Subject: a small refactor --- .../quarrel/native/src/lenses/application.rs | 110 ++++++++++++++++----- 1 file changed, 85 insertions(+), 25 deletions(-) (limited to '.config/awesome/quarrel/native/src/lenses/application.rs') diff --git a/.config/awesome/quarrel/native/src/lenses/application.rs b/.config/awesome/quarrel/native/src/lenses/application.rs index 89b7bb4..38a7762 100644 --- a/.config/awesome/quarrel/native/src/lenses/application.rs +++ b/.config/awesome/quarrel/native/src/lenses/application.rs @@ -1,58 +1,118 @@ use std::{ - fs::read_dir, path::PathBuf + any::type_name, + fs::read_dir, + path::PathBuf, + sync::{ + atomic::{ + AtomicBool, + Ordering, + }, + Arc, + OnceLock, + RwLock, + }, }; use freedesktop_entry_parser as fd; use mlua::prelude::*; +use notify::RecommendedWatcher; use rayon::prelude::*; use url::Url; use crate::lenses::{ - Entry, - Lense, - Cache + Cache, Entries, Entry, Lense }; +static APPS_DIR: &'static str = "/usr/share/applications"; +static WATCHER: OnceLock = OnceLock::new(); + #[derive(Default)] -pub struct Application(pub Cache); +pub struct Application { + cache: RwLock, + should_interrupt: AtomicBool, +} impl Lense for Application { const NAME: &str = "Application"; - fn get_cache(&self) -> &Cache { - &self.0 + fn init() -> Arc { + let this = Arc::new(Application::default()); + let watcher_this = this.clone(); + WATCHER + .set( + notify::recommended_watcher(move |event| { + match event { + Ok(_) => { + // We don't care what specifically changed, just that *it did* + watcher_this.set_cache(Cache::Stale); + } + Err(err) => { + eprintln!("Watch error: {:?}", err) + } + } + }) + .expect("Failed to instantiate a watcher"), + ) + .expect("Failed to set a watcher"); + this } - fn set_cache(&mut self, cache: Cache) { - self.0 = cache; + #[inline] + fn set_cache(&self, cache: Cache) { + if let Err(err) = self.cache.write().map(|mut place| *place = cache) { + eprintln!( + "Failed to write cache value for {}: {:?}", + type_name::(), + err + ) + } + } + + #[inline] + fn get_cache(&self) -> Cache { + match self.cache.read() { + Ok(ok) => ok.clone(), + Err(err) => { + eprintln!( + "Failed to read cache value for {}: {:?}", + type_name::(), + err + ); + Cache::Stale + } + } } - fn query(_: &Lua, input: String) -> Result, anyhow::Error> { - let applications_dir = "/usr/share/applications"; - let entries = read_dir(applications_dir)? + #[inline] + fn set_interrupt(&self, interrupt: bool) { + // self.should_interrupt.store(interrupt, Ordering::Relaxed) + } + + #[inline] + fn get_interrupt(&self) -> bool { + false + // self.should_interrupt.load(Ordering::Relaxed) + } + + fn entries(&self, _: &Lua, _: String) -> Result { + let entries = read_dir(APPS_DIR)? .map(|result| result.map(|e| e.path())) .collect::, std::io::Error>>()?; - let parsed_entries: Vec = entries + let parsed_entries: Entries = entries .into_par_iter() .filter(|path| path.extension().is_some_and(|ext| ext == "desktop")) - .filter_map(|path| { - parse_entry(path).ok().flatten() - }) - .collect(); - - Ok( - parsed_entries - .into_iter() - .filter(|entry| entry.message.to_lowercase().contains(&input.to_lowercase())) - .collect(), - ) + .filter_map(|path| parse_entry(path).ok().flatten()) + .collect::>() + .into(); + + Ok(parsed_entries) } } fn parse_entry(path: PathBuf) -> Result, ()> { let Ok(entry) = fd::parse_entry(&path) else { - return Err(()) + return Err(()); }; let section = entry.section("Desktop Entry"); -- cgit v1.2.3