1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
use failure::Error;
use glib::Sender;
use glib::{get_system_data_dirs, get_user_data_dir};
use log::{debug, info};
use regex::Regex;
use std::fs;
use std::path::{Path, PathBuf};
use std::process::Command;
use walkdir::{DirEntry, WalkDir};
lazy_static! {
static ref RE_TYPEAPPLICATION: Regex = Regex::new(r"\nType=.*Application.*\n").unwrap();
static ref RE_EXECCOMMAND: Regex = Regex::new(r"\nExec=(.*)\n").unwrap();
}
pub fn get_apps() -> Option<Vec<PathBuf>> {
let mut dirs = get_system_data_dirs();
match get_user_data_dir() {
Some(ud) => dirs.push(ud),
None => info!("get_user_data_dir() empty"),
}
debug!("dirs: {:?}", dirs);
let mut apps: Vec<PathBuf> = Vec::new();
for dir in dirs {
for entry in WalkDir::new(dir)
.into_iter()
.filter_map(|e| e.ok())
.filter(|e| is_desktop(e) && is_xdg_application(e))
{
debug!("{}", entry.path().display());
apps.push(entry.path().to_path_buf());
}
}
Some(apps)
}
pub fn get_apps_incremental(tx: Sender<Vec<String>>) {
let mut dirs = get_system_data_dirs();
match get_user_data_dir() {
Some(ud) => dirs.push(ud),
None => info!("get_user_data_dir() empty"),
}
debug!("dirs: {:?}", dirs);
for dir in dirs {
for entry in WalkDir::new(dir)
.into_iter()
.filter_map(|e| e.ok())
.filter(|e| is_desktop(e) && is_xdg_application(e))
{
debug!("{}", entry.path().display());
tx.send(vec![String::from(entry.path().to_str().unwrap())]);
}
}
}
pub fn launch_application(path: &Path) -> Result<(), Error> {
let f = fs::read_to_string(path).unwrap();
let cap = RE_EXECCOMMAND.captures(&f).unwrap();
let line = &cap[1];
debug!("Executing: {}", line);
Command::new("sh")
.arg("-c")
.arg(&line)
.spawn()
.expect("Failed to launch process.");
Ok(())
}
fn is_desktop(entry: &DirEntry) -> bool {
entry
.file_name()
.to_str()
.map(|s| s.ends_with(".desktop"))
.unwrap_or(false)
}
fn is_xdg_application(entry: &DirEntry) -> bool {
let f = fs::read_to_string(entry.path());
match f {
Err(_) => false,
Ok(f) => RE_TYPEAPPLICATION.is_match(&f),
}
}