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()?)
}
}