use std::{borrow::Cow, fmt::Display};
pub trait ChoicePrompter {
fn choose<C: Display>(&self, msg: ChoicePrompt<'_, C>) -> Option<C>;
}
pub struct Choice<'a, C: Display> {
pub option: C,
pub format: Option<Cow<'a, str>>,
}
impl<C: Display> Choice<'_, C> {
pub fn into_value(self) -> C {
self.option
}
}
impl<C: Display> Display for Choice<'_, C> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
if let Some(cow) = &self.format {
cow.fmt(f)
} else {
self.option.fmt(f)
}
}
}
impl<'a, C: Display> Choice<'a, C> {
pub fn new(option: C) -> Self {
Self {
option,
format: None,
}
}
pub fn with_format(mut self, format: impl Into<Cow<'a, str>>) -> Self {
self.format = Some(format.into());
self
}
}
impl<T: Display> From<T> for Choice<'_, T> {
fn from(value: T) -> Self {
Choice {
option: value,
format: None,
}
}
}
pub struct ChoicePrompt<'a, C: Display> {
pub prompt: Cow<'a, str>,
pub options: Vec<Choice<'a, C>>,
pub default: usize,
}
impl<'a, C: Display> ChoicePrompt<'a, C> {
#[must_use]
pub fn new(prompt: Cow<'a, str>) -> Self {
Self {
prompt,
options: Vec::new(),
default: 0,
}
}
pub fn with_options<I>(mut self, options: I) -> Self
where
I: IntoIterator,
I::Item: Into<Choice<'a, C>>,
{
self.options = options.into_iter().map(Into::into).collect();
self
}
pub fn with_added_option(mut self, option: impl Into<Choice<'a, C>>) -> Self {
self.options.push(option.into());
self
}
#[must_use]
pub fn with_default_index(mut self, index: usize) -> Self {
self.default = index;
self
}
}