1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73
use crate::errors::*; use std::io::{self, Write}; use std::str::FromStr; pub fn read_line() -> Result<String> { let mut buf = String::new(); io::stdin().read_line(&mut buf)?; let buf = buf.trim().to_string(); Ok(buf) } pub fn question(text: &str) -> Result<String> { print!("\x1b[1m[\x1b[34m?\x1b[0;1m]\x1b[0m {}: ", text); io::stdout().flush()?; read_line() } pub fn question_opt(text: &str) -> Result<Option<String>> { let answer = question(text)?; if !answer.is_empty() { Ok(Some(answer)) } else { Ok(None) } } pub fn question_typed_opt<T: FromStr>(text: &str) -> Result<Option<T>> { let answer = question(text)?; if !answer.is_empty() { let answer = answer.parse() .map_err(|_| format_err!("Failed to parse input"))?; Ok(Some(answer)) } else { Ok(None) } } pub fn question_or<I: Into<String>>(text: &str, default: I) -> Result<String> { let default = default.into(); let answer = question(&format!("{} [{}]", text, default))?; if !answer.is_empty() { Ok(answer) } else { Ok(default) } } #[inline] fn yes_no(text: &str, default: bool) -> Result<bool> { let answer = question(text)?; let answer = answer.to_lowercase(); Ok(match answer.as_str() { "" => default, "y" => true, "n" => false, _ => bail!("invalid input"), }) } pub fn yes_else_no(text: &str) -> Result<bool> { yes_no(&format!("{} [Y/n]", text), true) } pub fn no_else_yes(text: &str) -> Result<bool> { yes_no(&format!("{} [y/N]", text), false) }