Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
58c11b9
feat: add launch function for desktop entries
oknozor Jun 2, 2022
2b0fb2d
feat: launch desktop entries via dbus
oknozor Jun 2, 2022
62ba13c
chore: add MPD-2.0 license
oknozor Jun 2, 2022
0fab5e5
refactor: use compile time env var for vulkan icd base path
oknozor Jun 3, 2022
53e82a1
refactor: remove prefer_non_default arg gpu and use desktop entry att…
oknozor Jun 3, 2022
caa1db5
fix: fork process instead of spawning with std::process::Command
oknozor Jun 6, 2022
c69c7bd
hello
wiiznokes Jun 5, 2024
477ce38
fix compile
wiiznokes Jun 6, 2024
dc493c7
upgrade the behavior of get_entry_score
wiiznokes Jun 6, 2024
ec76f18
add 2 tests
wiiznokes Jun 6, 2024
0cdb67f
add launch_with_uris variant
wiiznokes Jun 6, 2024
21f86a0
change export, remove test, add licence on top
wiiznokes Jun 6, 2024
e8459b7
add actions support
wiiznokes Jun 6, 2024
2eaacb8
add not_show_in, directly return a Vec when field is a list
wiiznokes Jun 6, 2024
7d349d9
add current_desktop, Eq and Hash
wiiznokes Jun 6, 2024
5c24bcb
add logs, include name and exec, lower min score
wiiznokes Jun 7, 2024
fc93a84
fix log
wiiznokes Jun 7, 2024
8de5926
remove exec + lower min score + remove exec
wiiznokes Jun 8, 2024
1ee14ea
remove some files specific to exec
wiiznokes Jun 8, 2024
d70abc1
remove Name from match + add last part of id
wiiznokes Jun 8, 2024
251de84
replace all - with .
wiiznokes Jun 8, 2024
430409d
remove replace, add exec field, add malus
wiiznokes Jun 8, 2024
33fdccb
Update matching.rs
wiiznokes Jun 8, 2024
6bc0995
clean code for release
wiiznokes Jun 8, 2024
bbc39fb
malus for last part of id
wiiznokes Jun 8, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "freedesktop-desktop-entry"
version = "0.5.4"
version = "0.6.0"
authors = ["Michael Aaron Murphy <[email protected]>"]
edition = "2021"
homepage = "https://github.com/pop-os/freedesktop-desktop-entry"
Expand All @@ -18,3 +18,4 @@ textdistance = "1.0.2"
strsim = "0.11.1"
thiserror = "1"
xdg = "2.4.0"
log = "0.4.21"
10 changes: 5 additions & 5 deletions src/decoder.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
// Copyright 2021 System76 <[email protected]>
// SPDX-License-Identifier: MPL-2.0

use std::{
borrow::Cow,
collections::BTreeMap,
Expand Down Expand Up @@ -68,10 +71,7 @@ impl<'a> DesktopEntry<'a> {
}

/// Return an owned [`DesktopEntry`]
pub fn from_path<L>(
path: PathBuf,
locales: &[L],
) -> Result<DesktopEntry<'static>, DecodeError>
pub fn from_path<L>(path: PathBuf, locales: &[L]) -> Result<DesktopEntry<'static>, DecodeError>
where
L: AsRef<str>,
{
Expand Down Expand Up @@ -194,7 +194,7 @@ where
}

/// Ex: if a locale equal fr_FR, add fr
fn add_generic_locales<'a, L: AsRef<str>>(locales: &'a [L]) -> Vec<&'a str> {
fn add_generic_locales<L: AsRef<str>>(locales: &[L]) -> Vec<&str> {
let mut v = Vec::with_capacity(locales.len() + 1);

for l in locales {
Expand Down
1 change: 0 additions & 1 deletion src/iter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@ impl Iterator for Iter {
Err(_) => continue,
}
}


return None;
}
Expand Down
143 changes: 109 additions & 34 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,10 @@ mod iter;

pub mod matching;

#[cfg(test)]
mod test;

pub use self::iter::Iter;
use std::borrow::Cow;
use std::collections::BTreeMap;
use std::hash::{Hash, Hasher};

use std::path::{Path, PathBuf};
use xdg::BaseDirectories;
Expand All @@ -24,18 +22,30 @@ pub type Locale<'a> = Cow<'a, str>;
pub type LocaleMap<'a> = BTreeMap<Locale<'a>, Value<'a>>;
pub type Value<'a> = Cow<'a, str>;

#[derive(Debug, Clone)]
#[derive(Debug, Clone, Eq)]
pub struct DesktopEntry<'a> {
pub appid: Cow<'a, str>,
pub groups: Groups<'a>,
pub path: Cow<'a, Path>,
pub ubuntu_gettext_domain: Option<Cow<'a, str>>,
}

impl Hash for DesktopEntry<'_> {
fn hash<H: Hasher>(&self, state: &mut H) {
self.appid.hash(state);
}
}

impl PartialEq for DesktopEntry<'_> {
fn eq(&self, other: &Self) -> bool {
self.appid == other.appid
}
}

impl DesktopEntry<'_> {
/// Construct a new [`DesktopEntry`] from an appid. The name field will be
/// set to that appid.
pub fn from_appid<'a>(appid: &'a str) -> DesktopEntry<'a> {
pub fn from_appid(appid: &str) -> DesktopEntry<'_> {
let mut de = DesktopEntry {
appid: Cow::Borrowed(appid),
groups: Groups::default(),
Expand Down Expand Up @@ -77,12 +87,10 @@ impl<'a> DesktopEntry<'a> {
DesktopEntry {
appid: Cow::Owned(self.appid.to_string()),
groups: new_groups,
ubuntu_gettext_domain: if let Some(ubuntu_gettext_domain) = &self.ubuntu_gettext_domain
{
Some(Cow::Owned(ubuntu_gettext_domain.to_string()))
} else {
None
},
ubuntu_gettext_domain: self
.ubuntu_gettext_domain
.as_ref()
.map(|ubuntu_gettext_domain| Cow::Owned(ubuntu_gettext_domain.to_string())),
path: Cow::Owned(self.path.to_path_buf()),
}
}
Expand All @@ -93,9 +101,9 @@ impl<'a> DesktopEntry<'a> {
self.appid.as_ref()
}

/// A desktop entry field is any field under the `[Desktop Entry]` section.
/// A desktop entry field if any field under the `[Desktop Entry]` section.
pub fn desktop_entry(&'a self, key: &str) -> Option<&'a str> {
Self::entry(self.groups.get("Desktop Entry"), key).map(|e| e.as_ref())
Self::entry(self.groups.get("Desktop Entry"), key)
}

pub fn desktop_entry_localized<L: AsRef<str>>(
Expand Down Expand Up @@ -154,27 +162,35 @@ impl<'a> DesktopEntry<'a> {
self.desktop_entry("Exec")
}

/// Return categories separated by `;`
pub fn categories(&'a self) -> Option<&'a str> {
/// Return categories
pub fn categories(&'a self) -> Option<Vec<&'a str>> {
self.desktop_entry("Categories")
.map(|e| e.split(';').collect())
}

/// Return keywords separated by `;`
pub fn keywords<L: AsRef<str>>(&'a self, locales: &[L]) -> Option<Cow<'a, str>> {
self.desktop_entry_localized("Keywords", locales)
/// Return keywords
pub fn keywords<L: AsRef<str>>(&'a self, locales: &[L]) -> Option<Vec<Cow<'a, str>>> {
self.localized_entry_splitted(self.groups.get("Desktop Entry"), "Keywords", locales)
}

/// Return mime types separated by `;`
pub fn mime_type(&'a self) -> Option<&'a str> {
/// Return mime types
pub fn mime_type(&'a self) -> Option<Vec<&'a str>> {
self.desktop_entry("MimeType")
.map(|e| e.split(';').collect())
}

pub fn no_display(&'a self) -> bool {
self.desktop_entry_bool("NoDisplay")
}

pub fn only_show_in(&'a self) -> Option<&'a str> {
pub fn only_show_in(&'a self) -> Option<Vec<&'a str>> {
self.desktop_entry("OnlyShowIn")
.map(|e| e.split(';').collect())
}

pub fn not_show_in(&'a self) -> Option<Vec<&'a str>> {
self.desktop_entry("NotShowIn")
.map(|e| e.split(';').collect())
}

pub fn flatpak(&'a self) -> Option<&'a str> {
Expand All @@ -201,9 +217,9 @@ impl<'a> DesktopEntry<'a> {
self.desktop_entry("Type")
}

/// Return actions separated by `;`
pub fn actions(&'a self) -> Option<&'a str> {
pub fn actions(&'a self) -> Option<Vec<&'a str>> {
self.desktop_entry("Actions")
.map(|e| e.split(';').collect())
}

/// An action is defined as `[Desktop Action actions-name]` where `action-name`
Expand All @@ -214,7 +230,7 @@ impl<'a> DesktopEntry<'a> {
/// Name=Open a New Window
/// ```
/// you will need to call
/// ```rust
/// ```ignore
/// entry.action_entry("new-window", "Name")
/// ```
pub fn action_entry(&'a self, action: &str, key: &str) -> Option<&'a str> {
Expand Down Expand Up @@ -266,13 +282,7 @@ impl<'a> DesktopEntry<'a> {
key: &str,
locales: &[L],
) -> Option<Cow<'a, str>> {
let Some(group) = group else {
return None;
};

let Some((default_value, locale_map)) = group.get(key) else {
return None;
};
let (default_value, locale_map) = group?.get(key)?;

for locale in locales {
match locale_map.get(locale.as_ref()) {
Expand All @@ -287,9 +297,43 @@ impl<'a> DesktopEntry<'a> {
}
}
if let Some(domain) = ubuntu_gettext_domain {
return Some(Cow::Owned(dgettext(domain, &default_value)));
return Some(Cow::Owned(dgettext(domain, default_value)));
}
Some(default_value.clone())
}

pub fn localized_entry_splitted<L: AsRef<str>>(
&self,
group: Option<&'a KeyMap<'a>>,
key: &str,
locales: &[L],
) -> Option<Vec<Cow<'a, str>>> {
let (default_value, locale_map) = group?.get(key)?;

for locale in locales {
match locale_map.get(locale.as_ref()) {
Some(value) => {
return Some(value.split(';').map(Cow::Borrowed).collect());
}
None => {
if let Some(pos) = memchr::memchr(b'_', locale.as_ref().as_bytes()) {
if let Some(value) = locale_map.get(&locale.as_ref()[..pos]) {
return Some(value.split(';').map(Cow::Borrowed).collect());
}
}
}
}
}
if let Some(domain) = &self.ubuntu_gettext_domain {
return Some(
dgettext(domain, default_value)
.split(';')
.map(|e| Cow::Owned(e.to_string()))
.collect(),
);
}
return Some(default_value.clone());

Some(default_value.split(';').map(Cow::Borrowed).collect())
}
}

Expand Down Expand Up @@ -403,9 +447,40 @@ pub fn get_languages_from_env() -> Vec<String> {
l
}

pub fn current_desktop() -> Option<Vec<String>> {
std::env::var("XDG_CURRENT_DESKTOP").ok().map(|x| {
let x = x.to_ascii_lowercase();
if x == "unity" {
vec!["gnome".to_string()]
} else {
x.split(':').map(|e| e.to_string()).collect()
}
})
}

#[test]
fn locales_env_test() {
fn add_field() {
let appid = "appid";
let de = DesktopEntry::from_appid(appid);

assert_eq!(de.appid, appid);
assert_eq!(de.name(&[] as &[&str]).unwrap(), appid);

let s = get_languages_from_env();

println!("{:?}", s);
}

#[test]
fn env_with_locale() {
let locales = &["fr_FR"];

let de = DesktopEntry::from_path(PathBuf::from("tests/org.mozilla.firefox.desktop"), locales)
.unwrap();

assert_eq!(de.generic_name(locales).unwrap(), "Navigateur Web");

let locales = &["nb"];

assert_eq!(de.generic_name(locales).unwrap(), "Web Browser");
}
Loading