vnv/util/
mod.rs

1use colored::Colorize;
2use std::{
3    fmt::Display,
4    io::{self, Write},
5    str::FromStr,
6};
7
8pub enum CompareResult {
9    Less,
10    Greater,
11    Equal,
12}
13
14pub trait Compare {
15    fn cmp(&self, other: &f64) -> CompareResult;
16}
17
18impl Compare for f64 {
19    fn cmp(&self, other: &f64) -> CompareResult {
20        if (*self - other).abs() < 1e-9 {
21            CompareResult::Equal
22        } else if *self < *other {
23            CompareResult::Less
24        } else {
25            CompareResult::Greater
26        }
27    }
28}
29
30/// Trims quotes around the passed string
31///  
32/// # Examples
33/// ```
34/// let val = "\"something\"";
35///
36/// let result = vnv::util::trim_quotes(val);
37///
38/// assert_eq!(result, "something");
39/// ```
40pub fn trim_quotes(val: &str) -> String {
41    let mut trimmed = String::from(val);
42
43    let quote_start = val.find("\"");
44
45    if let Some(start) = quote_start {
46        let quote_end = val.rfind("\"");
47
48        if let Some(end) = quote_end {
49            trimmed = String::from(&val[start + 1..end]);
50        }
51    }
52
53    trimmed
54}
55
56/// Adds whitespace to the left of the number so that it meets the min_length provided
57///
58/// # Returns
59/// A left padding string containing the number
60///
61/// # Examples
62///
63/// ```
64/// let number = 1;
65///
66/// let result = vnv::util::number_pad(number, 3);
67///
68/// assert_eq!(result, "  1");
69/// ```
70pub fn number_pad(num: u32, min_length: usize) -> String {
71    let num_str = num.to_string();
72
73    let padding = min_length - num_str.len();
74
75    let mut result = String::new();
76
77    for _ in 0..padding {
78        result.push_str(" ");
79    }
80
81    result.push_str(&num_str);
82
83    result
84}
85
86pub fn request_value<T>(value: &mut T, message: &str)
87where
88    T: FromStr + Display,
89    <T as FromStr>::Err: std::fmt::Debug,
90{
91    printf(&format!(
92        "{message} {}",
93        value.to_string().truecolor(125, 125, 125)
94    ));
95
96    printf(&format!("\x1B[{}D", value.to_string().len()));
97
98    let mut input = String::new();
99
100    io::stdin().read_line(&mut input).unwrap();
101
102    input = input.trim().to_string();
103
104    if !input.is_empty() {
105        *value = input.parse::<T>().unwrap();
106    }
107}
108
109pub fn printf(message: &str) {
110    print!("{message}");
111    io::stdout().flush().unwrap();
112}
113
114pub enum Answer {
115    Yes,
116    No,
117}
118
119impl Answer {
120    pub fn to_string(&self) -> String {
121        match self {
122            Answer::Yes => String::from("y"),
123            Answer::No => String::from("N"),
124        }
125    }
126}
127
128/// Allows you to ask the user a yes or no question with a default answer
129pub fn ask_yes_no(question: &str, default: Answer) -> Answer {
130    let default_string = default.to_string();
131
132    printf(&format!(
133        "{question} y/N? {}",
134        default_string.truecolor(125, 125, 125)
135    ));
136
137    // Move back to before the default
138    printf(&format!("\x1B[{}D", default_string.len()));
139
140    let mut input = String::new();
141
142    io::stdin().read_line(&mut input).unwrap();
143
144    match input.trim().to_lowercase().as_str() {
145        "y" | "yes" => Answer::Yes,
146        "n" | "no" => Answer::No,
147        _ => default,
148    }
149}