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
use std::{
    io::{self, Write},
    str::FromStr,
};

/// Get a standard text input from the user. Appears inline, returns the trimmed user string
///
/// # Panics
/// This function panics if it fails to flush stdout or to read stdin
#[must_use]
pub fn get_text_input(prompt: &str) -> String {
    print!("{prompt}");
    io::stdout().flush().expect("Failed to flush line");

    let mut input = String::new();

    io::stdin()
        .read_line(&mut input)
        .expect("Failed to read line");

    input.trim().to_string()
}

/// Get a standard text input from the user. Appears inline. Directly passes the result from `str.parse()`. If you want to keep prompting until the user submits a value that fits the chosen type
///
/// ## Errors
/// Returns the result of a parse method, so the error will depend on what you want to parse to
pub fn get_text_input_as<Output: FromStr>(prompt: &str) -> Result<Output, Output::Err> {
    get_text_input(prompt).parse()
}

/// Get a standard text input from the user. Unlike [`get_text_input_as`], this function will continue prompting until the user submits a value that fits the chosen type
#[must_use]
pub fn persistent_get_text_input_as<Output: FromStr>(prompt: &str) -> Output {
    loop {
        match get_text_input_as::<Output>(prompt) {
            Ok(user_output) => return user_output,
            Err(_) => continue,
        }
    }
}