use std::io::{self, IsTerminal, Write};
pub fn confirm(question: &str) -> bool {
if !io::stdin().is_terminal() {
return false;
}
loop {
print!("{question} [y/N] ");
let _ = io::stdout().flush();
let mut answer = String::new();
if io::stdin().read_line(&mut answer).unwrap_or(0) == 0 {
println!();
return false;
}
match answer.trim().to_ascii_lowercase().as_str() {
"" | "n" | "no" => return false,
"y" | "yes" => return true,
_ => println!("Please answer y or n."),
}
}
}
pub fn choose(question: &str, options: &[&str]) -> String {
let default = options.first().copied().unwrap_or_default().to_string();
if !io::stdin().is_terminal() {
return default;
}
loop {
println!("{question}");
for (i, option) in options.iter().enumerate() {
let note = if i == 0 { " (default)" } else { "" };
println!(" {}) {option}{note}", i + 1);
}
print!("> ");
let _ = io::stdout().flush();
let mut answer = String::new();
if io::stdin().read_line(&mut answer).unwrap_or(0) == 0 {
println!();
return default;
}
let answer = answer.trim().to_ascii_lowercase();
if answer.is_empty() {
return default;
}
if let Some(picked) = answer
.parse::<usize>()
.ok()
.and_then(|n| options.get(n.wrapping_sub(1)))
{
return (*picked).to_string();
}
if let Some(picked) = options.iter().find(|o| o.eq_ignore_ascii_case(&answer)) {
return (*picked).to_string();
}
println!(
"Please answer with a number or one of: {}.",
options.join(", ")
);
}
}