diff --git a/src/utils/desktop.rs b/src/utils/desktop.rs index 5074760..5d887b0 100644 --- a/src/utils/desktop.rs +++ b/src/utils/desktop.rs @@ -3,7 +3,9 @@ use std::{ collections::HashSet, error::Error, fs::{read_to_string, File}, + hash::{Hash, Hasher}, io::{Error as io_error, ErrorKind}, + path::Path, }; use serde::{self, Deserialize, Serialize}; @@ -12,7 +14,7 @@ use walkdir::WalkDir; use crate::utils::{inish, xdg}; -#[derive(Serialize, Deserialize, Clone, Debug, Eq, Hash)] +#[derive(Serialize, Deserialize, Clone, Debug, Eq)] #[serde(rename_all = "snake_case")] pub struct Desktop { pub entry_type: String, @@ -26,7 +28,7 @@ pub struct Desktop { } impl Desktop { - fn parse(f: &str) -> Result> { + fn parse(f: &Path) -> Result> { let s = read_to_string(f)?; let config = inish::parse(&s)?; match config.get("Desktop Entry") { @@ -74,6 +76,13 @@ impl PartialEq for Desktop { } } +// Must agree with PartialEq: equal entries (same name) must hash equally. +impl Hash for Desktop { + fn hash(&self, state: &mut H) { + self.name.hash(state) + } +} + 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()), @@ -95,9 +104,15 @@ pub fn load_desktop_files() -> Vec { let mut seen: HashSet = HashSet::new(); for dir in dirs { - for entry in WalkDir::new(format!("{}/applications", dir)) { - if let Ok(entry) = entry { - if let Ok(d) = Desktop::parse(entry.path().to_str().unwrap()) { + for entry in WalkDir::new(format!("{}/applications", dir)).into_iter().flatten() { + // Entries are often symlinks, so only rule out directories. + if entry.file_type().is_dir() + || entry.path().extension().and_then(|e| e.to_str()) != Some("desktop") + { + continue; + } + { + if let Ok(d) = Desktop::parse(entry.path()) { if d.hidden || d.no_display || (d.entry_type != "Application" && d.entry_type != "Link")