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::lenses::entry::{ entries_to_lua_table, Entry, }; fn parse_entry(entry: &fd::Entry, path: &PathBuf) -> Result { let section = entry.section("Desktop Entry"); let name = section.attr("Name").ok_or(())?.to_string(); if section.attr("Type").ok_or(())? != "Application" { return Err(()); } if section.attr("OnlyShowIn").is_some() || section.attr("Hidden").is_some() || section.attr("NoDisplay").is_some() { return Err(()); } 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' => { if let Some(icon) = section.attr("Icon") { new_exec.replace_range(index..index + 2, &format!("--icon {icon}")); } } '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 { let applications_dir = "/usr/share/applications"; let entries = read_dir(applications_dir)? .map(|result| result.map(|e| e.path())) .collect::, std::io::Error>>()?; let entries = entries .into_iter() .filter(|e| matches!(e.extension(), Some(ext) if ext == "desktop")) .collect::>(); let mut parsed_entries: Mutex> = Mutex::new(Vec::new()); entries.into_par_iter().for_each(|path| { let Ok(entry) = fd::parse_entry(&path) else { return }; if let Ok(parsed_entry) = parse_entry(&entry, &path) { parsed_entries.lock().push(parsed_entry); } }); Ok(entries_to_lua_table( parsed_entries .get_mut() .iter() .filter(|entry| entry.message.to_lowercase().contains(&input)) .map(|entry| (*entry).clone()) .collect(), lua, )) }