use std::marker::PhantomData;
use crate::{
Buffer,
Paint,
Conciliator,
List,
Print,
Pushable
};
pub trait Input {
type T;
fn prompt(&self, buffer: &mut Buffer);
fn validate(&self, user_input: &str) -> Option<Self::T>;
fn print<C: Conciliator + ?Sized>(&mut self, con: &C) {
let _ = con;
}
}
pub struct Confirm<Q, M> {
question: Q,
marker: PhantomData<M>,
default: bool
}
pub struct Select<Q, M, L> {
list: Option<L>,
question: Q,
marker: PhantomData<M>,
len: usize
}
#[derive(Clone, Copy)]
pub enum AbortRetryContinue {
Abort,
Retry,
Continue
}
impl Input for AbortRetryContinue {
type T = Self;
fn prompt(&self, buffer: &mut Buffer) {
buffer
.push_bold("A")
.push_plain("bort, ")
.push_bold("R")
.push_plain("etry, or ")
.push_bold("C")
.push_plain("ontinue?");
match *self {
Self::Abort => buffer.push_plain(" [A/r/c]: "),
Self::Retry => buffer.push_plain(" [a/R/c]: "),
Self::Continue => buffer.push_plain(" [a/r/C]: ")
};
}
fn validate(&self, user_input: &str) -> Option<Self::T> {
match user_input {
"" => Some(*self),
"a" | "A" => Some(Self::Abort),
"r" | "R" => Some(Self::Retry),
"c" | "C" => Some(Self::Continue),
_ => None
}
}
}
impl<'s> Input for &'s str {
type T = String;
fn prompt(&self, buffer: &mut Buffer) {
buffer
.push_plain(self)
.push_plain(": ");
}
fn validate(&self, user_input: &str) -> Option<String> {
Some(user_input.to_owned())
}
}
impl<Q, M> Confirm<Q, M> {
pub fn new(default: bool, question: Q) -> Self {
Self {question, marker: PhantomData, default}
}
pub fn default_no(question: Q) -> Self {
Self {question, marker: PhantomData, default: false}
}
pub fn default_yes(question: Q) -> Self {
Self {question, marker: PhantomData, default: true}
}
}
impl<Q, M> Input for Confirm<Q, M>
where for<'a> &'a Q: Pushable<M>
{
type T = bool;
fn prompt(&self, buffer: &mut Buffer) {
buffer
.push(&self.question)
.push_plain(if self.default {" [Y/n]: "} else {" [y/N]: "});
}
fn validate(&self, user_input: &str) -> Option<bool> {
match user_input {
"" => Some(self.default),
"y" | "Y" => Some(true),
"n" | "N" => Some(false),
_ => None
}
}
}
impl<Q, M, H, I, T, F, P> Select<Q, M, List<H, I, F, P>>
where
I: ExactSizeIterator<Item = T>,
List<H, I, F, P>: Print
{
pub fn new(list: List<H, I, F, P>, question: Q) -> Self {
Self {
len: list.len(),
list: Some(list),
marker: PhantomData,
question
}
}
}
impl<Q, M, H, I, F, P> Input for Select<Q, M, List<H, I, F, P>>
where List<H, I, F, P>: Print,
Q: Pushable<M>
{
type T = usize;
fn prompt(&self, buffer: &mut Buffer) {
self.question.push_into(buffer);
buffer
.push_plain(" [1 - ")
.push_plain(&self.len)
.push_plain("]: ");
}
fn validate(&self, user_input: &str) -> Option<usize> {
user_input
.parse()
.ok()
.filter(|&i| i > 0)
.map(|i: usize| i - 1)
.filter(|i| (0..self.len).contains(i))
}
fn print<C: Conciliator + ?Sized>(&mut self, con: &C) {
if let Some(list) = self.list.take() {
list.print(con);
}
}
}