aboutsummaryrefslogtreecommitdiff
path: root/.config/awesome/ui/fresnel/lenses/src/application.rs
blob: 0cf6c1a7c7d62d7a5d467bc0546ad9be7270663d (plain)
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
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
use std::{
    fs::read_dir,
    path::PathBuf,
};

use freedesktop_entry_parser as fd;
use mlua::prelude::*;
use parking_lot::Mutex;
use rayon::prelude::*;
use url::Url;

use crate::entry::{
    entries_to_lua_table,
    Entry,
};

fn parse_entry<'a>(entry: fd::Entry, path: PathBuf) -> Result<Entry, ()> {
    let section = entry.section("Desktop Entry");
    let name = section.attr("Name").ok_or(())?.to_string();

    if section.attr("Type").ok_or(())? != "Application" {
        return Err(());
    }

    match section.attr("OnlyShowIn") {
        Some(_) => return Err(()),
        None => {}
    }

    match section.attr("Hidden") {
        Some(_) => return Err(()),
        None => {}
    }

    match section.attr("NoDisplay") {
        Some(_) => return Err(()),
        None => {}
    }

    let exec = section.attr("Exec").ok_or(())?.to_string();
    let mut new_exec = exec.clone();
    for (index, _) in exec.match_indices("%") {
        match exec.chars().nth(index + 1).unwrap().to_ascii_lowercase() {
            'i' => match section.attr("Icon") {
                Some(icon) => new_exec.replace_range(index..index + 2, &format!("--icon {}", icon)),
                None => {}
            },
            'c' => new_exec.replace_range(index..index + 2, &name),
            'k' => new_exec.replace_range(index..index + 2, Url::from_file_path(&path)?.as_str()),

            'f' | 'u' | 'v' | 'm' | 'd' | 'n' => new_exec.replace_range(index..index + 2, ""),
            _ => continue,
        }
    }

    Ok(Entry {
        message: name,
        exec: Some((
            new_exec,
            section
                .attr("Terminal")
                .unwrap_or("false")
                .parse()
                .map_err(drop)?,
        )),
        provider: "Application".to_string(),
    })
}

pub fn query(lua: &Lua, input: String) -> LuaResult<LuaTable> {
    let applications_dir = "/usr/share/applications";
    let entries = read_dir(applications_dir)?
        .map(|result| result.map(|e| e.path()))
        .collect::<Result<Vec<_>, std::io::Error>>()?;

    let entries = entries
        .into_iter()
        .filter(|e| match e.extension() {
            Some(ext) if ext == "desktop" => true,
            None | _ => false,
        })
        .collect::<Vec<_>>();

    let mut parsed_entries: Mutex<Vec<Entry>> = Mutex::new(Vec::new());

    entries.into_par_iter().for_each(|path| {
        let entry = match fd::parse_entry(&path) {
            Ok(entry) => entry,
            Err(_) => return,
        };

        match parse_entry(entry, path) {
            Ok(parsed_entry) => parsed_entries.lock().push(parsed_entry),
            Err(_) => return,
        }
    });

    Ok(entries_to_lua_table(
        parsed_entries
            .get_mut()
            .iter()
            .filter(|entry| entry.message.to_lowercase().contains(&input))
            .map(|entry| (*entry).clone())
            .collect(),
        lua,
    ))
}