Files
wldash/src/desktop.rs
T

112 lines
3.4 KiB
Rust
Raw Normal View History

2019-08-29 01:03:48 +02:00
extern crate ini;
use ini::{Ini, ParseOption};
use std::cmp::Ordering;
use std::env;
use std::error::Error;
use std::io::Error as io_error;
use std::io::ErrorKind;
2021-12-25 18:47:15 +01:00
use walkdir::WalkDir;
2019-08-29 01:03:48 +02:00
2020-01-02 18:38:23 +00:00
#[derive(Clone, Debug, Eq, Hash)]
2019-08-29 01:03:48 +02:00
pub struct Desktop {
pub entry_type: String,
pub name: String,
pub no_display: bool,
pub hidden: bool,
pub exec: Option<String>,
pub url: Option<String>,
pub term: bool,
2020-01-02 17:19:37 +00:00
pub keywords: Vec<String>,
2019-08-29 01:03:48 +02:00
}
impl Desktop {
fn parse(f: &str) -> Result<Desktop, Box<dyn Error>> {
2019-09-06 21:54:04 +02:00
let file = Ini::load_from_file_opt(
f,
ParseOption {
enabled_quote: false,
enabled_escape: false,
},
)?;
2019-10-02 16:24:28 +02:00
match file.section(Some("Desktop Entry")) {
2019-08-29 01:03:48 +02:00
Some(desktop) => Ok(Desktop {
entry_type: desktop.get("Type").unwrap_or(&"".to_string()).to_string(),
name: desktop.get("Name").unwrap_or(&"".to_string()).to_string(),
term: desktop.get("Terminal").unwrap_or(&"".to_string()) == "true",
no_display: desktop.get("NoDisplay").unwrap_or(&"".to_string()) == "true",
hidden: desktop.get("Hidden").unwrap_or(&"".to_string()) == "true",
exec: desktop.get("Exec").map(|x| x.to_string()),
url: desktop.get("URL").map(|x| x.to_string()),
2020-01-08 11:31:56 +01:00
keywords: desktop
.get("Keywords")
.map(|x| {
2020-04-22 01:31:22 +02:00
x.split(';')
2020-01-08 11:31:56 +01:00
.map(|y| y.trim().to_string())
.filter(|z| z != "")
.collect()
})
2020-04-22 01:31:22 +02:00
.unwrap_or_else(|| vec![]),
2019-08-29 01:03:48 +02:00
}),
None => Err(Box::new(io_error::new(
ErrorKind::NotFound,
"no desktop entry in file",
))),
}
}
fn parse_dir(d: &str) -> Result<Vec<Desktop>, Box<dyn Error>> {
2019-10-02 16:24:28 +02:00
let mut files: Vec<Desktop> = Vec::with_capacity(16);
2021-12-25 18:47:15 +01:00
for entry in WalkDir::new(d) {
2019-08-29 01:03:48 +02:00
let entry = entry?;
let path = entry.path();
if let Ok(d) = Desktop::parse(path.to_str().unwrap()) {
files.push(d)
}
}
Ok(files)
}
}
impl Ord for Desktop {
fn cmp(&self, other: &Self) -> Ordering {
self.name.cmp(&other.name)
}
}
impl PartialOrd for Desktop {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl PartialEq for Desktop {
fn eq(&self, other: &Self) -> bool {
self.name == other.name
}
}
pub fn load_desktop_files() -> Vec<Desktop> {
let home = env::var_os("HOME").unwrap().into_string().unwrap();
2019-09-03 17:18:07 +02:00
let xdg_data_home = match env::var_os("XDG_DATA_HOME") {
Some(s) => s.into_string().unwrap(),
2020-04-22 01:31:22 +02:00
None => format!("{}/.local/share", home),
2019-09-03 17:18:07 +02:00
};
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(),
};
std::iter::once(xdg_data_home.as_str())
2020-04-22 01:31:22 +02:00
.chain(xdg_data_dirs.split(':'))
2019-09-03 17:18:07 +02:00
.map(|p| Desktop::parse_dir(&format!("{}/applications", p)))
2019-08-29 01:03:48 +02:00
.filter_map(Result::ok)
.flatten()
.filter(|d| {
!d.hidden && !d.no_display && (d.entry_type == "Application" || d.entry_type == "Link")
})
.collect()
}