// Allow dead code, until we've fully implemented CLI/error handling #![allow(dead_code)] use std::io::{stderr, stdin, Write}; use crate::util::error::{quit_error, ErrorHints}; /// Prompt the user to enter some value. /// The prompt that is shown should be passed to `msg`, /// excluding the `:` suffix. pub fn prompt(msg: &str) -> String { // Show the prompt eprint!("{msg}: "); let _ = stderr().flush(); // Get the input let mut input = String::new(); if let Err(err) = stdin() .read_line(&mut input) .map_err(|err| -> anyhow::Error { err.into() }) { quit_error( err.context("failed to read input from prompt"), ErrorHints::default(), ); } // Trim and return input.trim().to_owned() } /// Prompt the user for a question, allowing a yes or now answer. /// True is returned if yes was answered, false if no. /// /// A default may be given, which is chosen if no-interact mode is /// enabled, or if enter was pressed by the user without entering anything. pub fn prompt_yes(msg: &str, def: Option) -> bool { // Define the available options string let options = format!( "[{}/{}]", match def { Some(def) if def => "Y", _ => "y", }, match def { Some(def) if !def => "N", _ => "n", } ); // Get the user input let answer = prompt(&format!("{msg} {options}")); // Assume the default if the answer is empty if answer.is_empty() { if let Some(def) = def { return def; } } // Derive a boolean and return match derive_bool(&answer) { Some(answer) => answer, None => prompt_yes(msg, def), } } /// Try to derive true or false (yes or no) from the given input. /// None is returned if no boolean could be derived accurately. fn derive_bool(input: &str) -> Option { // Process the input let input = input.trim().to_lowercase(); // Handle short or incomplete answers match input.as_str() { "y" | "ye" | "t" | "1" => return Some(true), "n" | "f" | "0" => return Some(false), _ => {} } // Handle complete answers with any suffix if input.starts_with("yes") || input.starts_with("true") { return Some(true); } if input.starts_with("no") || input.starts_with("false") { return Some(false); } // The answer could not be determined, return none None }