From 66e66e19ad980cf8fc627d16e15462fc35ac98d5 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Tue, 4 Apr 2023 01:53:02 +0200 Subject: [PATCH] launcher: Cache desktop files --- Cargo.lock | 149 +++++++++++++++++++++++++++++++++++++++- Cargo.toml | 1 + src/main.rs | 12 ++-- src/utils/desktop.rs | 37 +++++----- src/utils/mod.rs | 1 + src/utils/xdg.rs | 39 +++++++++++ src/widgets/launcher.rs | 27 +++++--- 7 files changed, 234 insertions(+), 32 deletions(-) create mode 100644 src/utils/xdg.rs diff --git a/Cargo.lock b/Cargo.lock index bc7e17c..5d7a96b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8,6 +8,17 @@ version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "330223a1aecc308757b9926e9391c9b47f8ef2dbd8aea9df88312aea18c5e8d6" +[[package]] +name = "ahash" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c99f64d1e06488f620f932677e24bc6e2897582980441ae90a671415bd7ec2f" +dependencies = [ + "cfg-if", + "once_cell", + "version_check", +] + [[package]] name = "android_system_properties" version = "0.1.5" @@ -211,6 +222,15 @@ version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56899898ce76aaf4a0f24d914c97ea6ed976d42fec6ad33fcbb0a1103e07b2b0" +[[package]] +name = "float-cmp" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98de4bbd547a563b716d8dfa9aad1cb19bfab00f4fa09a6a4ed21dbcf44ce9c4" +dependencies = [ + "num-traits", +] + [[package]] name = "fontconfig" version = "0.6.0" @@ -239,12 +259,31 @@ dependencies = [ "version_check", ] +[[package]] +name = "halfbrown" +version = "0.1.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e2a3c70a9c00cc1ee87b54e89f9505f73bb17d63f1b25c9a462ba8ef885444f" +dependencies = [ + "hashbrown 0.13.2", + "serde", +] + [[package]] name = "hashbrown" version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +[[package]] +name = "hashbrown" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" +dependencies = [ + "ahash", +] + [[package]] name = "iana-time-zone" version = "0.1.53" @@ -276,7 +315,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1885e79c1fc4b10f0e172c475f458b7f7b93061064d98c3293e98c5ba0c8b399" dependencies = [ "autocfg", - "hashbrown", + "hashbrown 0.12.3", ] [[package]] @@ -310,6 +349,70 @@ version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +[[package]] +name = "lexical-core" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2cde5de06e8d4c2faabc400238f9ae1c74d5412d03a7bd067645ccbc47070e46" +dependencies = [ + "lexical-parse-float", + "lexical-parse-integer", + "lexical-util", + "lexical-write-float", + "lexical-write-integer", +] + +[[package]] +name = "lexical-parse-float" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "683b3a5ebd0130b8fb52ba0bdc718cc56815b6a097e28ae5a6997d0ad17dc05f" +dependencies = [ + "lexical-parse-integer", + "lexical-util", + "static_assertions", +] + +[[package]] +name = "lexical-parse-integer" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d0994485ed0c312f6d965766754ea177d07f9c00c9b82a5ee62ed5b47945ee9" +dependencies = [ + "lexical-util", + "static_assertions", +] + +[[package]] +name = "lexical-util" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5255b9ff16ff898710eb9eb63cb39248ea8a5bb036bea8085b1a767ff6c4e3fc" +dependencies = [ + "static_assertions", +] + +[[package]] +name = "lexical-write-float" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accabaa1c4581f05a3923d1b4cfd124c329352288b7b9da09e766b0668116862" +dependencies = [ + "lexical-util", + "lexical-write-integer", + "static_assertions", +] + +[[package]] +name = "lexical-write-integer" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1b6f3d1f4422866b68192d62f77bc5c700bee84f3069f2469d7bc8c77852446" +dependencies = [ + "lexical-util", + "static_assertions", +] + [[package]] name = "libc" version = "0.2.138" @@ -684,6 +787,17 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d721eca97ac802aa7777b701877c8004d950fc142651367300d21c1cc0194744" +dependencies = [ + "itoa", + "ryu", + "serde", +] + [[package]] name = "serde_yaml" version = "0.9.17" @@ -714,6 +828,26 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "43b2853a4d09f215c24cc5489c992ce46052d359b5109343cbafbf26bc62f8a3" +[[package]] +name = "simd-json" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e3375b6c3d8c048ba09c8b4b6c3f1d3f35e06b71db07d231c323943a949e1b8" +dependencies = [ + "halfbrown", + "lexical-core", + "serde", + "serde_json", + "simdutf8", + "value-trait", +] + +[[package]] +name = "simdutf8" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f27f6278552951f1f2b8cf9da965d10969b2efdea95a6ec47987ab46edfe263a" + [[package]] name = "slotmap" version = "1.0.6" @@ -837,6 +971,18 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bc7ed8ba44ca06be78ea1ad2c3682a43349126c8818054231ee6f4748012aed2" +[[package]] +name = "value-trait" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "995de1aa349a0dc50f4aa40870dce12961a30229027230bad09acd2843edbe9e" +dependencies = [ + "float-cmp", + "halfbrown", + "itoa", + "ryu", +] + [[package]] name = "vec_map" version = "0.8.2" @@ -1102,6 +1248,7 @@ dependencies = [ "serde", "serde_yaml", "shlex", + "simd-json", "unicode-segmentation", "walkdir", "wayland-client", diff --git a/Cargo.toml b/Cargo.toml index 34c3fcb..c3d038c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -36,3 +36,4 @@ libpulse-binding = "2.26" serde = { version = "1.0", features = ["derive"] } serde_yaml = "0.9" +simd-json = "0.7" diff --git a/src/main.rs b/src/main.rs index 143d048..7ac3e6b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -26,6 +26,7 @@ use fonts::{FontMap, MaybeFontMap}; use keyboard::{KeyRepeatSource, RepeatMessage}; use state::State; use widgets::{Geometry, Widget}; +use utils::{xdg, desktop::{load_desktop_files, write_desktop_cache}}; use std::{env, rc::Rc, thread}; @@ -44,13 +45,17 @@ fn main() { None => Config::generate_v2(false), Some(s) => panic!("unknown argument: {}", s), }; - let home = env::var_os("HOME").unwrap().into_string().unwrap(); - match File::create(format!("{}/.config/wldash/config.yml", home)) { + match File::create(format!("{}/wldash/config.yml", xdg::config_folder())) { Ok(f) => serde_yaml::to_writer(f, &config).unwrap(), Err(_) => panic!("uh"), } std::process::exit(0); } + Some(ref s) if s == "desktop-refresh" => { + let v = load_desktop_files(); + write_desktop_cache(&v).unwrap(); + std::process::exit(0); + } Some(_) => panic!("unknown argument"), None => break, } @@ -126,8 +131,7 @@ fn main() { let mut fm = FontMap::new(); - let home = env::var_os("HOME").unwrap().into_string().unwrap(); - let config: Config = match File::open(format!("{}/.config/wldash/config.yml", home)) { + let config: Config = match File::open(format!("{}/wldash/config.yml", xdg::config_folder())) { Ok(f) => serde_yaml::from_reader(f).unwrap(), Err(_) => panic!("configuration file missing"), }; diff --git a/src/utils/desktop.rs b/src/utils/desktop.rs index 9b14706..a63c58f 100644 --- a/src/utils/desktop.rs +++ b/src/utils/desktop.rs @@ -1,17 +1,19 @@ use std::{ cmp::Ordering, collections::HashSet, - env, error::Error, - fs::read_to_string, + fs::{read_to_string, File}, io::{Error as io_error, ErrorKind}, }; +use serde::{self, Deserialize, Serialize}; +use simd_json; use walkdir::WalkDir; -use crate::utils::inish; +use crate::utils::{inish, xdg}; -#[derive(Clone, Debug, Eq, Hash)] +#[derive(Serialize, Deserialize, Clone, Debug, Eq, Hash)] +#[serde(rename_all = "snake_case")] pub struct Desktop { pub entry_type: String, pub name: String, @@ -72,19 +74,22 @@ impl PartialEq for Desktop { } } +pub fn load_desktop_cache() -> Result, Box> { + match File::open(format!("{}/wldash/desktop.json", xdg::cache_folder())) { + Ok(f) => simd_json::from_reader(f).map_err(|e| e.into()), + Err(e) => Err(e.into()) + } +} + +pub fn write_desktop_cache(v: &Vec) -> Result<(), Box> { + match File::create(format!("{}/wldash/desktop.json", xdg::cache_folder())) { + Ok(f) => simd_json::to_writer(f, v).map_err(|e| e.into()), + Err(e) => Err(e.into()) + } +} + pub fn load_desktop_files() -> Vec { - let home = env::var_os("HOME").unwrap().into_string().unwrap(); - - let xdg_data_home = match env::var_os("XDG_DATA_HOME") { - Some(s) => s.into_string().unwrap(), - None => format!("{}/.local/share", home), - }; - let xdg_data_dirs = match env::var_os("XDG_DATA_DIRS") { - Some(s) => s.into_string().unwrap(), - None => "/usr/local/share:/usr/share".to_string(), - }; - - let dirs = std::iter::once(xdg_data_home.as_str()).chain(xdg_data_dirs.split(':')); + let dirs = xdg::data_folders(); let mut desktop: Vec = Vec::new(); let mut seen: HashSet = HashSet::new(); diff --git a/src/utils/mod.rs b/src/utils/mod.rs index 6dbe5d9..bb7cf87 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -1,2 +1,3 @@ pub mod desktop; +pub mod xdg; mod inish; diff --git a/src/utils/xdg.rs b/src/utils/xdg.rs new file mode 100644 index 0000000..f5a2662 --- /dev/null +++ b/src/utils/xdg.rs @@ -0,0 +1,39 @@ +use std::env; + +pub fn cache_folder() -> String { + match env::var_os("XDG_CACHE_HOME") { + Some(s) => s.into_string().unwrap(), + None => { + let home = env::var_os("HOME").unwrap().into_string().unwrap(); + format!("{}/.cache", home) + } + } +} + + +pub fn config_folder() -> String { + match env::var_os("XDG_CONFIG_HOME") { + Some(s) => s.into_string().unwrap(), + None => { + let home = env::var_os("HOME").unwrap().into_string().unwrap(); + format!("{}/.config", home) + } + } +} + +pub fn data_folders() -> Vec { + let xdg_data_home = match env::var_os("XDG_DATA_HOME") { + Some(s) => s.into_string().unwrap(), + None => { + let home = env::var_os("HOME").unwrap().into_string().unwrap(); + format!("{}/.local/share", home) + } + }; + let xdg_data_dirs = match env::var_os("XDG_DATA_DIRS") { + Some(s) => s.into_string().unwrap(), + None => "/usr/local/share:/usr/share".to_string(), + }; + + // Eww. + std::iter::once(xdg_data_home.to_string()).chain(xdg_data_dirs.split(':').map(|x| x.to_string())).collect() +} diff --git a/src/widgets/launcher.rs b/src/widgets/launcher.rs index 1531062..c312afa 100644 --- a/src/widgets/launcher.rs +++ b/src/widgets/launcher.rs @@ -2,7 +2,6 @@ use std::{ cmp::{max, min, Ordering}, collections::HashMap, default::Default, - env, fs::{read_to_string, File}, io::Write, process::{exit, Command}, @@ -16,7 +15,10 @@ use crate::{ event::{Event, Events, PointerButton, PointerEvent}, fonts::FontMap, keyboard::{keysyms, KeyEvent}, - utils::desktop::{load_desktop_files, Desktop}, + utils::{ + desktop::{load_desktop_files, load_desktop_cache, write_desktop_cache, Desktop}, + xdg, + }, widgets::{Geometry, Widget}, }; @@ -221,7 +223,14 @@ impl Launcher { .name("desktopini".to_string()) .spawn(move || { let mut options = options.lock().unwrap(); - *options = load_desktop_files(); + *options = match load_desktop_cache() { + Ok(v) => v, + Err(_) => { + let v = load_desktop_files(); + write_desktop_cache(&v).unwrap(); + v + } + }; drop(options); let mut events = events.lock().unwrap(); events.add_event(Event::LauncherUpdate); @@ -432,8 +441,7 @@ impl Calc { thread::Builder::new() .name("calc".to_string()) .spawn(move || { - let home = env::var_os("HOME").unwrap().into_string().unwrap(); - let s = match read_to_string(format!("{}/.cache/wldash/calc", home)) { + let s = match read_to_string(format!("{}/wldash/calc", xdg::cache_folder())) { Ok(s) => s, _ => return, }; @@ -455,8 +463,7 @@ impl Calc { } fn sync(&self) { - let home = env::var_os("HOME").unwrap().into_string().unwrap(); - let mut f = match File::create(format!("{}/.cache/wldash/calc", home)) { + let mut f = match File::create(format!("{}/wldash/calc", xdg::cache_folder())) { Ok(f) => f, _ => return, }; @@ -634,8 +641,7 @@ impl Interface { std::process::exit(0); } - let home = env::var_os("HOME").unwrap().into_string().unwrap(); - if let Ok(mut f) = File::create(format!("{}/.cache/wldash/prompt", home)) { + if let Ok(mut f) = File::create(format!("{}/wldash/prompt", xdg::cache_folder())) { write!(f, "{}", self.inner.prompt.input).unwrap(); f.sync_data().unwrap(); } @@ -666,8 +672,7 @@ impl Interface { widget.update(&self.inner); } keysyms::XKB_KEY_r if event.modifiers.ctrl => { - let home = env::var_os("HOME").unwrap().into_string().unwrap(); - if let Ok(s) = read_to_string(format!("{}/.cache/wldash/prompt", home)) { + if let Ok(s) = read_to_string(format!("{}/wldash/prompt", xdg::cache_folder())) { self.inner.prompt.set(&s); } }