lnchr 0.2.1

A fuzzy terminal app launcher
use crossterm::event::{self, Event};
use std::collections::HashMap;

pub trait Provider {
    type Item;
    fn title(&self) -> &str;
    fn collect(&self) -> HashMap<String, Self::Item>;
    fn launch(&self, item: &Self::Item);
}

fn wait_for_key() {
    match crossterm::terminal::enable_raw_mode() {
        Ok(_) => (),
        Err(_) => return,
    }
    loop {
        if let Ok(Event::Key(_)) = event::read() {
            break;
        }
    }
    let _ = crossterm::terminal::disable_raw_mode();
}

pub fn run_provider<P: Provider>(provider: P) -> i32 {
    let title = provider.title();
    let history = crate::history::History::from_title(title);
    let items = provider.collect();
    if items.is_empty() {
        eprintln!("{}: no items found", title);
        eprint!("Press any key to close.");
        let _ = std::io::Write::flush(&mut std::io::stderr());
        wait_for_key();
        return 1;
    }
    let mut names: Vec<String> = items.keys().cloned().collect();
    names.sort_unstable();
    if let Some(ref history) = history {
        history.do_sort(&mut names);
    };
    let history_items = history.as_ref().map(|h| h.items()).unwrap_or(&[]);
    if let Some(selected) = crate::tui::search(names, title, history_items)
        && let Some(item) = items.get(&selected)
    {
        if let Some(mut history) = history {
            history.save(&selected);
        }
        provider.launch(item);
    }
    0
}