Desktop Action support for the Applications plugin

This commit is contained in:
Kirottu
2023-04-08 11:13:12 +03:00
parent c74235a841
commit 8467c1b1e5
4 changed files with 165 additions and 66 deletions

57
Cargo.lock generated
View File

@@ -37,7 +37,7 @@ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"rustc_version 0.4.0", "rustc_version 0.4.0",
"syn", "syn 1.0.107",
"typed-arena", "typed-arena",
] ]
@@ -101,6 +101,8 @@ dependencies = [
"abi_stable", "abi_stable",
"anyrun-plugin", "anyrun-plugin",
"fuzzy-matcher", "fuzzy-matcher",
"ron",
"serde",
"sublime_fuzzy", "sublime_fuzzy",
] ]
@@ -113,7 +115,7 @@ dependencies = [
"core_extensions", "core_extensions",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn", "syn 1.0.107",
] ]
[[package]] [[package]]
@@ -352,7 +354,7 @@ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"scratch", "scratch",
"syn", "syn 1.0.107",
] ]
[[package]] [[package]]
@@ -369,7 +371,7 @@ checksum = "3e7e2adeb6a0d4a282e581096b06e1791532b7d576dcde5ccd9382acf55db8e6"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn", "syn 1.0.107",
] ]
[[package]] [[package]]
@@ -380,7 +382,7 @@ checksum = "3418329ca0ad70234b9735dc4ceed10af4df60eff9c8e7b06cb5e520d92c3535"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn", "syn 1.0.107",
] ]
[[package]] [[package]]
@@ -509,7 +511,7 @@ checksum = "bdfb8ce053d86b91919aad980c220b1fb8401a9394410e1c289ed7e66b61835d"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn", "syn 1.0.107",
] ]
[[package]] [[package]]
@@ -686,7 +688,7 @@ dependencies = [
"proc-macro-error", "proc-macro-error",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn", "syn 1.0.107",
] ]
[[package]] [[package]]
@@ -790,7 +792,7 @@ dependencies = [
"proc-macro-error", "proc-macro-error",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn", "syn 1.0.107",
] ]
[[package]] [[package]]
@@ -1267,7 +1269,7 @@ checksum = "b501e44f11665960c7e7fcf062c7d96a14ade4aa98116c004b2e37b5be7d736c"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn", "syn 1.0.107",
] ]
[[package]] [[package]]
@@ -1433,7 +1435,7 @@ dependencies = [
"proc-macro-error-attr", "proc-macro-error-attr",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn", "syn 1.0.107",
"version_check", "version_check",
] ]
@@ -1450,18 +1452,18 @@ dependencies = [
[[package]] [[package]]
name = "proc-macro2" name = "proc-macro2"
version = "1.0.49" version = "1.0.56"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "57a8eca9f9c4ffde41714334dee777596264c7825420f521abc92b5b5deb63a5" checksum = "2b63bdb0cd06f1f4dedf69b254734f9b45af66e4a031e42a7480257d9898b435"
dependencies = [ dependencies = [
"unicode-ident", "unicode-ident",
] ]
[[package]] [[package]]
name = "quote" name = "quote"
version = "1.0.23" version = "1.0.26"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b" checksum = "4424af4bf778aae2051a77b60283332f386554255d722233d09fbfc7e30da2fc"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
] ]
@@ -1676,22 +1678,22 @@ dependencies = [
[[package]] [[package]]
name = "serde" name = "serde"
version = "1.0.152" version = "1.0.159"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bb7d1f0d3021d347a83e556fc4683dea2ea09d87bccdf88ff5c12545d89d5efb" checksum = "3c04e8343c3daeec41f58990b9d77068df31209f2af111e059e9fe9646693065"
dependencies = [ dependencies = [
"serde_derive", "serde_derive",
] ]
[[package]] [[package]]
name = "serde_derive" name = "serde_derive"
version = "1.0.152" version = "1.0.159"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "af487d118eecd09402d70a5d72551860e788df87b464af30e5ea6a38c75c541e" checksum = "4c614d17805b093df4b147b51339e7e44bf05ef59fba1e45d83500bcfb4d8585"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn", "syn 2.0.13",
] ]
[[package]] [[package]]
@@ -1792,6 +1794,17 @@ dependencies = [
"unicode-ident", "unicode-ident",
] ]
[[package]]
name = "syn"
version = "2.0.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4c9da457c5285ac1f936ebd076af6dac17a61cfe7826f2076b4d015cf47bc8ec"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]] [[package]]
name = "system-deps" name = "system-deps"
version = "6.0.3" version = "6.0.3"
@@ -1845,7 +1858,7 @@ checksum = "1fb327af4685e4d03fa8cbcf1716380da910eeb2bb8be417e7f9fd3fb164f36f"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn", "syn 1.0.107",
] ]
[[package]] [[package]]
@@ -2120,7 +2133,7 @@ dependencies = [
"once_cell", "once_cell",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn", "syn 1.0.107",
"wasm-bindgen-shared", "wasm-bindgen-shared",
] ]
@@ -2154,7 +2167,7 @@ checksum = "07bc0c051dc5f23e307b13285f9d75df86bfdf816c5721e573dec1f9b8aa193c"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn", "syn 1.0.107",
"wasm-bindgen-backend", "wasm-bindgen-backend",
"wasm-bindgen-shared", "wasm-bindgen-shared",
] ]

View File

@@ -13,3 +13,5 @@ anyrun-plugin = { path = "../../anyrun-plugin" }
abi_stable = "0.11.1" abi_stable = "0.11.1"
sublime_fuzzy = "0.7.0" sublime_fuzzy = "0.7.0"
fuzzy-matcher = "0.3.7" fuzzy-matcher = "0.3.7"
ron = "0.8.0"
serde = { version = "1.0.159", features = ["derive"] }

View File

@@ -2,7 +2,13 @@ use abi_stable::std_types::{ROption, RString, RVec};
use anyrun_plugin::{anyrun_interface::HandleResult, *}; use anyrun_plugin::{anyrun_interface::HandleResult, *};
use fuzzy_matcher::FuzzyMatcher; use fuzzy_matcher::FuzzyMatcher;
use scrubber::DesktopEntry; use scrubber::DesktopEntry;
use std::process::Command; use serde::Deserialize;
use std::{fs, process::Command};
#[derive(Deserialize, Default)]
pub struct Config {
desktop_actions: bool,
}
mod scrubber; mod scrubber;
@@ -25,8 +31,22 @@ pub fn handler(selection: Match, entries: &mut Vec<(DesktopEntry, u64)>) -> Hand
HandleResult::Close HandleResult::Close
} }
pub fn init(_config_dir: RString) -> Vec<(DesktopEntry, u64)> { pub fn init(config_dir: RString) -> Vec<(DesktopEntry, u64)> {
scrubber::scrubber().expect("Failed to load desktop entries!") let config: Config = match fs::read_to_string(format!("{}/applications.ron", config_dir)) {
Ok(content) => ron::from_str(&content).unwrap_or_else(|why| {
eprintln!("Error parsing applications plugin config: {}", why);
Config::default()
}),
Err(why) => {
eprintln!("Error reading applications plugin config: {}", why);
Config::default()
}
};
scrubber::scrubber(config).unwrap_or_else(|why| {
eprintln!("Failed to load desktop entries: {}", why);
Vec::new()
})
} }
pub fn get_matches(input: RString, entries: &mut Vec<(DesktopEntry, u64)>) -> RVec<Match> { pub fn get_matches(input: RString, entries: &mut Vec<(DesktopEntry, u64)>) -> RVec<Match> {

View File

@@ -1,5 +1,7 @@
use std::{collections::HashMap, env, ffi::OsStr, fs, io}; use std::{collections::HashMap, env, ffi::OsStr, fs, io};
use crate::Config;
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct DesktopEntry { pub struct DesktopEntry {
pub exec: String, pub exec: String,
@@ -12,24 +14,43 @@ const FIELD_CODE_LIST: &[&str] = &[
]; ];
impl DesktopEntry { impl DesktopEntry {
fn from_dir_entry(entry: &fs::DirEntry) -> Option<Self> { fn from_dir_entry(entry: &fs::DirEntry, config: &Config) -> Vec<Self> {
if entry.path().extension() == Some(OsStr::new("desktop")) { if entry.path().extension() == Some(OsStr::new("desktop")) {
let content = match fs::read_to_string(entry.path()) { let content = match fs::read_to_string(entry.path()) {
Ok(content) => content, Ok(content) => content,
Err(_) => return None, Err(_) => return Vec::new(),
}; };
let mut map = HashMap::new(); let lines = content.lines().collect::<Vec<_>>();
for line in content.lines() {
if line.starts_with("[") && line != "[Desktop Entry]" { let sections = lines
break; .split_inclusive(|line| line.starts_with('['))
.collect::<Vec<_>>();
let mut line = None;
let mut new_sections = Vec::new();
for section in sections.iter() {
if let Some(line) = line {
let mut section = section.to_vec();
section.insert(0, line);
section.pop();
new_sections.push(section);
} }
let (key, val) = match line.split_once("=") { line = Some(section.last().unwrap_or(&""));
Some(keyval) => keyval, }
None => continue,
}; let mut ret = Vec::new();
let entry = match new_sections.iter().find_map(|section| {
if section[0].starts_with("[Desktop Entry]") {
let mut map = HashMap::new();
for line in section.iter().skip(1) {
if let Some((key, val)) = line.split_once('=') {
map.insert(key, val); map.insert(key, val);
} }
}
if map.get("Type")? == &"Application" if map.get("Type")? == &"Application"
&& match map.get("NoDisplay") { && match map.get("NoDisplay") {
@@ -40,6 +61,7 @@ impl DesktopEntry {
Some(DesktopEntry { Some(DesktopEntry {
exec: { exec: {
let mut exec = map.get("Exec")?.to_string(); let mut exec = map.get("Exec")?.to_string();
for field_code in FIELD_CODE_LIST { for field_code in FIELD_CODE_LIST {
exec = exec.replace(field_code, ""); exec = exec.replace(field_code, "");
} }
@@ -57,10 +79,53 @@ impl DesktopEntry {
} else { } else {
None None
} }
}) {
Some(entry) => entry,
None => return Vec::new(),
};
if config.desktop_actions {
for section in new_sections {
let mut map = HashMap::new();
for line in section.iter().skip(1) {
if let Some((key, val)) = line.split_once('=') {
map.insert(key, val);
} }
} }
pub fn scrubber() -> Result<Vec<(DesktopEntry, u64)>, Box<dyn std::error::Error>> { if section[0].starts_with("[Desktop Action") {
ret.push(DesktopEntry {
exec: match map.get("Exec") {
Some(exec) => {
let mut exec = exec.to_string();
for field_code in FIELD_CODE_LIST {
exec = exec.replace(field_code, "");
}
exec
}
None => continue,
},
name: match map.get("Name") {
Some(name) => format!("{}: {}", entry.name, name),
None => continue,
},
icon: entry.icon.clone(),
})
}
}
}
ret.push(entry);
ret
} else {
Vec::new()
}
}
}
pub fn scrubber(config: Config) -> Result<Vec<(DesktopEntry, u64)>, Box<dyn std::error::Error>> {
// Create iterator over all the files in the XDG_DATA_DIRS // Create iterator over all the files in the XDG_DATA_DIRS
// XDG compliancy is cool // XDG compliancy is cool
let mut paths: Vec<Result<fs::DirEntry, io::Error>> = match env::var("XDG_DATA_DIRS") { let mut paths: Vec<Result<fs::DirEntry, io::Error>> = match env::var("XDG_DATA_DIRS") {
@@ -68,7 +133,7 @@ pub fn scrubber() -> Result<Vec<(DesktopEntry, u64)>, Box<dyn std::error::Error>
// The vec for all the DirEntry objects // The vec for all the DirEntry objects
let mut paths = Vec::new(); let mut paths = Vec::new();
// Parse the XDG_DATA_DIRS variable and list files of all the paths // Parse the XDG_DATA_DIRS variable and list files of all the paths
for dir in data_dirs.split(":") { for dir in data_dirs.split(':') {
match fs::read_dir(format!("{}/applications/", dir)) { match fs::read_dir(format!("{}/applications/", dir)) {
Ok(dir) => { Ok(dir) => {
paths.extend(dir); paths.extend(dir);
@@ -102,20 +167,19 @@ pub fn scrubber() -> Result<Vec<(DesktopEntry, u64)>, Box<dyn std::error::Error>
} }
}; };
paths.extend(fs::read_dir(&user_path)?); paths.extend(fs::read_dir(user_path)?);
// Keeping track of the entries
let mut id = 0;
Ok(paths Ok(paths
.iter() .iter()
.filter_map(|entry| { .filter_map(|entry| {
id += 1;
let entry = match entry { let entry = match entry {
Ok(entry) => entry, Ok(entry) => entry,
Err(_why) => return None, Err(_why) => return None,
}; };
DesktopEntry::from_dir_entry(entry).map(|val| (val, id)) Some(DesktopEntry::from_dir_entry(entry, &config))
}) })
.flatten()
.enumerate()
.map(|(i, val)| (val, i as u64))
.collect()) .collect())
} }