From 0b44fe028e5d50c77b9bd0cac81b0031a7699519 Mon Sep 17 00:00:00 2001 From: wiiznokes <78230769+wiiznokes@users.noreply.github.com> Date: Sat, 1 Jun 2024 17:51:17 +0200 Subject: [PATCH] move matching code in fde --- .vscode/settings.json | 3 + Cargo.toml | 5 +- src/desktop.rs | 162 +++++++++++++----------------------------- 3 files changed, 55 insertions(+), 115 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index a06e580a..88d643c5 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,4 +1,7 @@ { "rust-analyzer.check.overrideCommand": ["just", "check-json"], "git-blame.gitWebUrl": "", + "rust-analyzer.cargo.features": [ + "desktop" + ] } diff --git a/Cargo.toml b/Cargo.toml index 6d6dc73e..45812334 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -32,7 +32,6 @@ desktop = [ "dep:freedesktop-desktop-entry", "dep:mime", "dep:shlex", - "dep:textdistance", ] # Enables keycode serialization serde-keycode = ["iced_core/serde"] @@ -88,7 +87,6 @@ palette = "0.7.3" rfd = { version = "0.14.0", optional = true } serde = { version = "1.0.180", features = ["derive"] } slotmap = "1.0.6" -textdistance = { version = "1.0.2", optional = true } thiserror = "1.0.44" tokio = { version = "1.24.2", optional = true } tracing = "0.1" @@ -176,3 +174,6 @@ dirs = "5.0.1" [patch."https://github.com/pop-os/libcosmic"] libcosmic = { path = "./" } + +# [patch.crates-io] +# freedesktop-desktop-entry = { path = "../freedesktop-desktop-entry" } \ No newline at end of file diff --git a/src/desktop.rs b/src/desktop.rs index d14f7c72..c6d6d3b0 100644 --- a/src/desktop.rs +++ b/src/desktop.rs @@ -1,9 +1,8 @@ -pub use freedesktop_desktop_entry::DesktopEntry; -use iced_widget::canvas::path::lyon_path::geom::euclid::approxord::min; +pub use freedesktop_desktop_entry as fde; +use freedesktop_desktop_entry::{DesktopEntry, MatchAppIdOptions}; pub use mime::Mime; use std::{ borrow::Cow, - cmp::max, ffi::OsStr, path::{Path, PathBuf}, }; @@ -64,6 +63,28 @@ pub struct DesktopEntryData { pub prefers_dgpu: bool, } +pub fn load_desktop_file<'a>( + locale: impl Into>, + path: impl AsRef, +) -> Option { + let path = path.as_ref(); + std::fs::read_to_string(path).ok().and_then(|input| { + DesktopEntry::decode(path, &input) + .ok() + .map(|de| DesktopEntryData::from_desktop_entry(locale, PathBuf::from(path), &de)) + }) +} + +pub fn load_applications_filtered<'a, F: FnMut(&DesktopEntry) -> bool>( + locale: impl Into>, + mut filter: F, +) -> Vec { + let locale = locale.into(); + fde::Iter::new(fde::default_paths()) + .filter_map(|path| load_desktop_file(locale, path)) + .collect() +} + pub fn load_applications<'a>( locale: impl Into>, include_no_display: bool, @@ -82,33 +103,6 @@ pub fn app_id_or_fallback_matches(app_id: &str, entry: &DesktopEntryData) -> boo || app_id.to_lowercase() == entry.name.to_lowercase() } -/// From 0 to 1. -/// 1 is a perfect match. -fn match_entry(id: &str, de: &DesktopEntry) -> f32 { - let cmp = |id, de| { - let lcsstr = textdistance::str::lcsstr(id, de); - lcsstr as f32 / (max(id.len(), de.len())) as f32 - }; - - fn max_f32(a: f32, b: f32) -> f32 { - if a > b { - return a; - } else { - b - } - } - - let id = id.to_lowercase(); - let de_id = de.appid.to_lowercase(); - let de_wm_class = de.startup_wm_class().unwrap_or_default().to_lowercase(); - let de_name = de.name(None).unwrap_or_default().to_lowercase(); - - return max_f32( - cmp(&id, &de_id), - max_f32(cmp(&id, &de_wm_class), cmp(&id, &de_name)), - ); -} - /// The result will be in the same order of `app_ids` pub fn load_applications_for_app_ids<'a, I: AsRef>( locale: impl Into>, @@ -128,107 +122,49 @@ pub fn load_applications_for_app_ids<'a, I: AsRef>( let all_desktop_entries = all_desktop_entries_string .iter() - .filter_map(|(path, content)| DesktopEntry::decode(&path, &content).ok()) + .filter_map(|(path, content)| { + DesktopEntry::decode(&path, &content).ok().and_then(|de| { + if !include_no_display && de.no_display() { + None + } else { + Some(de) + } + }) + }) .collect::>(); let mut applications = Vec::new(); - let locale = locale.into(); for id in app_ids { - let mut max_score = None; - let mut second_max_score = 0.; - - for de in &all_desktop_entries { - if !include_no_display && de.no_display() { - continue; - } - - let score = match_entry(id.as_ref(), de); - - match max_score { - Some((prev_max_score, _)) => { - if prev_max_score < score { - second_max_score = prev_max_score; - max_score = Some((score, de)); - } - } - None => { - max_score = Some((score, de)); - } - } - - if score > 0.99 { - break; - } - } - - let mut has_matched = false; - if let Some((max_score, de)) = max_score { - let entropy = max_score - second_max_score; - - // println!("{id}: {max_score}:{entropy}: {}", de.appid); - - if max_score > 0.7 || entropy > 0.15 && max_score > 0.2 { + match fde::try_match_app_id( + id.as_ref(), + &all_desktop_entries, + MatchAppIdOptions::default(), + ) { + Some(de) => { applications.push(DesktopEntryData::from_desktop_entry( locale, Some(de.path.to_path_buf()), de, )); - has_matched = true; } - } - - if fill_missing_ones && !has_matched { - applications.push(DesktopEntryData { - id: id.as_ref().to_string(), - name: id.as_ref().to_string(), - icon: IconSource::default(), - ..Default::default() - }); + None => { + if fill_missing_ones { + applications.push(DesktopEntryData { + id: id.as_ref().to_string(), + name: id.as_ref().to_string(), + icon: IconSource::default(), + ..Default::default() + }); + } + } } } applications } -pub fn load_applications_filtered<'a, F: FnMut(&DesktopEntry) -> bool>( - locale: impl Into>, - mut filter: F, -) -> Vec { - let locale = locale.into(); - - freedesktop_desktop_entry::Iter::new(freedesktop_desktop_entry::default_paths()) - .filter_map(|path| { - std::fs::read_to_string(&path).ok().and_then(|input| { - DesktopEntry::decode(&path, &input).ok().and_then(|de| { - if !filter(&de) { - return None; - } - - Some(DesktopEntryData::from_desktop_entry( - locale, - path.clone(), - &de, - )) - }) - }) - }) - .collect() -} - -pub fn load_desktop_file<'a>( - locale: impl Into>, - path: impl AsRef, -) -> Option { - let path = path.as_ref(); - std::fs::read_to_string(path).ok().and_then(|input| { - DesktopEntry::decode(path, &input) - .ok() - .map(|de| DesktopEntryData::from_desktop_entry(locale, PathBuf::from(path), &de)) - }) -} - impl DesktopEntryData { fn from_desktop_entry<'a>( locale: impl Into>,