desktop: hash entries the same way they compare, only parse *.desktop
Desktop derived Hash over every field but PartialEq compared only the name, violating the Hash/Eq contract the launcher's HashMap relies on (clippy denies this by default, so `cargo clippy` failed to build). Also skip directories and files without a .desktop extension (mimeinfo cache, .directory files, ...) and stop unwrapping non-UTF-8 paths. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5.1
parent
2bed8b7fac
commit
01af00b5ea
+20
-5
@@ -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<Desktop, Box<dyn Error>> {
|
||||
fn parse(f: &Path) -> Result<Desktop, Box<dyn Error>> {
|
||||
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<H: Hasher>(&self, state: &mut H) {
|
||||
self.name.hash(state)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn load_desktop_cache() -> Result<Vec<Desktop>, Box<dyn Error>> {
|
||||
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<Desktop> {
|
||||
let mut seen: HashSet<String> = 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")
|
||||
|
||||
Reference in New Issue
Block a user