lnchr 0.2.0

A fuzzy terminal app launcher
use std::collections::HashMap;
use std::env;
use std::path::PathBuf;

use crate::desktop;
use crate::provider::{Provider, run_provider};

pub struct DesktopProvider;

impl Provider for DesktopProvider {
    type Item = desktop::DesktopInfo;

    fn title(&self) -> &str {
        "drun"
    }

    fn collect(&self) -> HashMap<String, desktop::DesktopInfo> {
        let data_home = env::var_os("XDG_DATA_HOME")
            .map(PathBuf::from)
            .unwrap_or_else(|| {
                let home = env::var_os("HOME").unwrap_or_default();
                PathBuf::from(home).join(".local").join("share")
            });

        let data_dirs = env::var_os("XDG_DATA_DIRS")
            .map(|p| env::split_paths(&p).collect::<Vec<_>>())
            .unwrap_or_else(|| {
                vec![
                    PathBuf::from("/usr/local/share"),
                    PathBuf::from("/usr/share"),
                ]
            });

        let mut applications_paths = Vec::new();
        for path in std::iter::once(&data_home).chain(data_dirs.iter()) {
            applications_paths.push(path.join("applications"));
        }

        let mut desktop_files = HashMap::new();
        for dir in &applications_paths {
            let Ok(entries) = dir.read_dir() else {
                continue;
            };
            for entry in entries.flatten() {
                let path = entry.path();
                if path.extension().is_some_and(|e| e == "desktop")
                    && path.is_file()
                    && let Some(info) = desktop::parse_desktop_info(&path)
                {
                    desktop_files.entry(info.name.clone()).or_insert(info);
                }
            }
        }
        desktop_files
    }

    fn launch(&self, item: &desktop::DesktopInfo) {
        desktop::launch(item);
    }
}

pub fn drun() -> i32 {
    run_provider(DesktopProvider)
}