use std::fmt::Display;
use std::io::{self, Write};
use unicode_width::UnicodeWidthStr;
use yansi::Paint;
pub struct FormElement<T: Display, Q: Display> {
pub name: T,
pub description: Option<Q>,
}
impl<T: Display, Q: Display> FormElement<T, Q> {
#[must_use]
pub fn new(name: T, description: Option<Q>) -> Self {
Self { name, description }
}
pub fn display(list: &[Self]) {
match termsize::get() {
Some(size) => {
let mut len = 0;
for i in list {
len = len.max(UnicodeWidthStr::width(i.name.to_string().as_str()));
}
let nwidth = list.len().to_string().len();
let columns = usize::from(size.cols) / (len + 6 + 1);
for (n, i) in list.iter().enumerate() {
if n % columns == 0 {
println!();
}
let mut nstr = Paint::blue(n).bold().to_string();
nstr.push(')');
print!(
"{:<nwidth$} {:width$}",
nstr,
i.name,
nwidth = nwidth + 11,
width = len + 5 - nwidth,
);
}
}
None => {
for (n, i) in list.iter().enumerate() {
println!(
"{} {}{}",
n,
i.name,
i.description
.as_ref()
.map(|x| format!("- {}", x))
.unwrap_or_default(),
);
}
}
}
}
#[must_use]
pub fn run<'a>(list: &'a [Self]) -> io::Result<&'a Self> {
Self::display(list);
loop {
print!("\nEnter Choice <`r` to reprint, `dNN` for description> : ");
io::stdout().flush()?;
let mut buffer = String::new();
io::stdin().read_line(&mut buffer)?;
match buffer.trim().chars().next() {
Some('r') => Self::display(list),
Some('d') => match buffer.trim().get(1..).unwrap_or_default().parse::<usize>() {
Ok(n) => match list.get(n) {
Some(val) => println!(
"{}",
val.description
.as_ref()
.map(|x| x.to_string())
.unwrap_or("No description available".to_string())
),
None => println!("{}", Paint::red("Invalid Choice")),
},
Err(_) => {
println!("{}", Paint::red("Please enter a valid number"));
}
},
_ => match buffer.parse::<usize>() {
Ok(n) => match list.get(n) {
Some(val) => return Ok(val),
None => println!("{}", Paint::red("Invalid Choice")),
},
Err(_) => {
println!("{}", Paint::red("Please enter a valid number"));
}
},
}
}
}
}