zen_console_input/
selection.rs

1//! Provides functionality for getting a selection from a list of options.
2
3use std::io::{self, Write};
4
5/// Opinionated struct for handling selection input from the user.
6pub struct Selection {
7    message: String,
8    options: Vec<String>,
9}
10
11impl Selection {
12    pub(crate) fn new() -> Self {
13        Selection {
14            message: String::new(),
15            options: Vec::new(),
16        }
17    }
18
19    /// Sets the prompt message for the selection.
20    pub fn message(mut self, msg: &str) -> Self {
21        self.message = msg.to_string();
22        self
23    }
24
25    /// Sets the list of options for the selection.
26    pub fn options(mut self, opts: Vec<String>) -> Self {
27        self.options = opts;
28        self
29    }
30
31    /// Gets the selected option from the user.
32    pub fn get_selection(&self) -> String {
33        println!("{}", self.message);
34        for (i, option) in self.options.iter().enumerate() {
35            println!("{}. {}", i + 1, option);
36        }
37
38        loop {
39            print!("Enter your choice (1-{}): ", self.options.len());
40            io::stdout().flush().unwrap();
41
42            let mut input = String::new();
43            io::stdin().read_line(&mut input).unwrap();
44            let input = input.trim();
45
46            if let Ok(choice) = input.parse::<usize>() {
47                if choice > 0 && choice <= self.options.len() {
48                    return self.options[choice - 1].clone();
49                }
50            }
51
52            println!("Invalid choice. Please try again.");
53        }
54    }
55}
56
57#[cfg(test)]
58mod tests {
59    use super::*;
60
61    #[test]
62    fn test_selection_options() {
63        let selection = Selection::new().message("Choose a color").options(vec![
64            "Red".to_string(),
65            "Green".to_string(),
66            "Blue".to_string(),
67        ]);
68        assert_eq!(selection.message, "Choose a color");
69        assert_eq!(selection.options, vec!["Red", "Green", "Blue"]);
70    }
71}