util_rs/
input.rs

1use std::{
2    io::{self, Stdin, Write},
3    str::FromStr,
4};
5
6use crate::Ignore;
7
8pub use ux::{input, input_string, prompt};
9
10pub mod ux;
11
12#[derive(Debug)]
13pub struct Prompt<'msg> {
14    message: Option<&'msg str>,
15    buf: String,
16    std_in: Stdin,
17}
18
19impl<'msg> Prompt<'msg> {
20    pub fn msg(mut self, msg: &'msg str) -> Self {
21        self.message = Some(msg);
22        self
23    }
24}
25
26impl Default for Prompt<'_> {
27    fn default() -> Self {
28        Self::new()
29    }
30}
31
32impl Prompt<'_> {
33    pub fn new() -> Self {
34        Self {
35            message: None,
36            buf: String::new(),
37            std_in: io::stdin(),
38        }
39    }
40
41    fn run(&mut self) {
42        self.buf.clear();
43        if let Some(message) = self.message {
44            print!("{}", message);
45            io::stdout().flush().ignore();
46        }
47
48        self.std_in.read_line(&mut self.buf).ignore();
49    }
50
51    pub fn get<T: FromStr>(&mut self) -> Result<T, T::Err> {
52        self.get_str().parse()
53    }
54
55    pub fn get_str(&mut self) -> &str {
56        self.run();
57        self.buf.trim()
58    }
59
60    pub fn get_string(mut self) -> String {
61        self.run();
62        self.buf
63    }
64
65    pub fn get_until_ok<A, Ef>(&mut self, mut handle_error: Ef) -> A
66    where
67        A: FromStr,
68        Ef: FnMut(A::Err),
69    {
70        self.get().unwrap_or_else(|err| {
71            handle_error(err);
72            self.get_until_ok(handle_error)
73        })
74    }
75
76    pub fn get_until_ok_with<T, E, F, Ef>(&mut self, mut action: F, mut handle_error: Ef) -> T
77    where
78        F: FnMut(&str) -> Result<T, E>,
79        Ef: FnMut(E),
80    {
81        action(self.get_str()).unwrap_or_else(|err| {
82            handle_error(err);
83            self.get_until_ok_with(action, handle_error)
84        })
85    }
86}