aboutsummaryrefslogtreecommitdiff
path: root/.config/awesome/quarrel/native/src/lenses/application.rs
diff options
context:
space:
mode:
Diffstat (limited to '.config/awesome/quarrel/native/src/lenses/application.rs')
-rw-r--r--.config/awesome/quarrel/native/src/lenses/application.rs108
1 files changed, 84 insertions, 24 deletions
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<RecommendedWatcher> = OnceLock::new();
+
#[derive(Default)]
-pub struct Application(pub Cache);
+pub struct Application {
+ cache: RwLock<Cache>,
+ should_interrupt: AtomicBool,
+}
impl Lense for Application {
const NAME: &str = "Application";
- fn get_cache(&self) -> &Cache {
- &self.0
+ fn init() -> Arc<Self> {
+ 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
+ }
+
+ #[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::<Self>(),
+ 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::<Self>(),
+ err
+ );
+ Cache::Stale
+ }
+ }
+ }
+
+ #[inline]
+ fn set_interrupt(&self, interrupt: bool) {
+ // self.should_interrupt.store(interrupt, Ordering::Relaxed)
}
- fn set_cache(&mut self, cache: Cache) {
- self.0 = cache;
+ #[inline]
+ fn get_interrupt(&self) -> bool {
+ false
+ // self.should_interrupt.load(Ordering::Relaxed)
}
- fn query(_: &Lua, input: String) -> Result<Vec<Entry>, anyhow::Error> {
- let applications_dir = "/usr/share/applications";
- let entries = read_dir(applications_dir)?
+ fn entries(&self, _: &Lua, _: String) -> Result<Entries, anyhow::Error> {
+ let entries = read_dir(APPS_DIR)?
.map(|result| result.map(|e| e.path()))
.collect::<Result<Vec<_>, std::io::Error>>()?;
- let parsed_entries: Vec<Entry> = 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();
+ .filter_map(|path| parse_entry(path).ok().flatten())
+ .collect::<Vec<Entry>>()
+ .into();
- Ok(
- parsed_entries
- .into_iter()
- .filter(|entry| entry.message.to_lowercase().contains(&input.to_lowercase()))
- .collect(),
- )
+ Ok(parsed_entries)
}
}
fn parse_entry(path: PathBuf) -> Result<Option<Entry>, ()> {
let Ok(entry) = fd::parse_entry(&path) else {
- return Err(())
+ return Err(());
};
let section = entry.section("Desktop Entry");