use core::fmt;
use inquire::{Confirm, InquireError, Select, Text};
use thiserror::Error;
#[derive(Debug, Error)]
pub enum PromptError {
#[error("cannot prompt text")]
Text(#[source] InquireError),
#[error("cannot prompt boolean")]
Bool(#[source] InquireError),
#[error("cannot prompt item from list")]
Item(#[source] InquireError),
}
pub type PromptResult<T> = Result<T, PromptError>;
pub fn text<T: AsRef<str>>(prompt: T, default: Option<T>) -> PromptResult<String> {
let mut prompt = Text::new(prompt.as_ref());
if let Some(default) = default.as_ref() {
prompt = prompt.with_default(default.as_ref())
}
prompt.prompt().map_err(PromptError::Text)
}
pub fn some_text<T: AsRef<str>>(prompt: T, default: Option<T>) -> PromptResult<Option<String>> {
let mut prompt = Text::new(prompt.as_ref());
if let Some(default) = default.as_ref() {
prompt = prompt.with_default(default.as_ref())
}
prompt.prompt_skippable().map_err(PromptError::Text)
}
pub fn bool(prompt: impl AsRef<str>, default: bool) -> PromptResult<bool> {
Confirm::new(prompt.as_ref())
.with_default(default)
.prompt()
.map_err(PromptError::Bool)
}
pub fn item<T: fmt::Display + Eq>(
prompt: impl AsRef<str>,
items: impl IntoIterator<Item = T>,
default: Option<T>,
) -> PromptResult<T> {
let items: Vec<_> = items.into_iter().collect();
let default = if let Some(default) = default.as_ref() {
items
.iter()
.enumerate()
.find_map(|(i, item)| if item == default { Some(i) } else { None })
} else {
None
};
let mut prompt = Select::new(prompt.as_ref(), items).without_filtering();
if let Some(default) = default.as_ref() {
prompt = prompt.with_starting_cursor(*default);
}
prompt.prompt().map_err(PromptError::Item)
}