enumselector 0.1.4

helpers for easy selection of items using skim
Documentation
use skim::prelude::*;
use std::fmt::Debug;
use std::io::Cursor;
use std::str::FromStr;

use strum::IntoEnumIterator;

pub fn select_item_with_formatter<T, F>(items: Vec<T>, formatter: F) -> Option<T>
where
    T: Clone,
    F: Fn(&T) -> String,
{
    let options = SkimOptionsBuilder::default()
        .height(Some("100%"))
        .reverse(true)
        .build()
        .unwrap();

    let input: Vec<String> = items.iter().map(|item| formatter(item)).collect();
    let input_str = input.join("\n");

    let item_reader = SkimItemReader::default();
    let skim_items = item_reader.of_bufread(Cursor::new(input_str));

    let selected_item = Skim::run_with(&options, Some(skim_items))?;
    if selected_item.is_abort {
        return None;
    }

    let selected_string = selected_item.selected_items.first()?.output().to_string();

    items
        .into_iter()
        .find(|item| formatter(item) == selected_string)
}

pub fn select_item<T>(items: Vec<T>) -> Option<T>
where
    T: Debug + Clone,
{
    select_item_with_formatter(items, |x| format!("{:?}", x))
}

pub trait EnumSelector: IntoEnumIterator + ToString + FromStr + std::fmt::Debug {
    fn select() -> Option<Self> {
        let options = SkimOptionsBuilder::default()
            .height(Some("50%"))
            .multi(false)
            .reverse(true)
            .build()
            .unwrap();

        let vec: Vec<String> = Self::iter().map(|x| x.to_string()).collect();
        let choices: String = vec.join("\n");
        let item_reader = SkimItemReader::default();
        let items = item_reader.of_bufread(Cursor::new(choices));

        let selected_item = Skim::run_with(&options, Some(items))?;
        if selected_item.is_abort {
            return None;
        }

        let selected_item: String = selected_item.selected_items.first()?.output().to_string();

        Some(Self::from_str(&selected_item).ok()?)
    }
}