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
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
|
use clap::builder::{PossibleValuesParser, TypedValueParser, ValueParser};
use std::{io::stdin, ops::Deref};
pub mod account;
pub mod anti_censorship;
pub mod api_access;
pub mod auto_connect;
pub mod beta_program;
pub mod custom_list;
pub mod debug;
pub mod dns;
pub mod lan;
pub mod lockdown;
pub mod log;
pub mod patch;
pub mod proxies;
pub mod relay;
pub mod relay_constraints;
pub mod reset;
pub mod split_tunnel;
pub mod status;
pub mod tunnel;
pub mod tunnel_state;
pub mod version;
/// A value parser that parses "on" or "off" into a boolean
#[derive(Debug, Clone, Copy)]
pub struct BooleanOption {
state: bool,
on_label: &'static str,
off_label: &'static str,
}
impl Deref for BooleanOption {
type Target = bool;
fn deref(&self) -> &Self::Target {
&self.state
}
}
impl clap::builder::ValueParserFactory for BooleanOption {
type Parser = ValueParser;
/// A value parser that parses "on" or "off" into a `BooleanOption`
fn value_parser() -> Self::Parser {
Self::custom_parser("on", "off")
}
}
impl BooleanOption {
/// A value parser that parses `on_label` and `off_label` into a `BooleanOption`
fn custom_parser(on_label: &'static str, off_label: &'static str) -> ValueParser {
assert!(on_label != off_label);
ValueParser::new(
PossibleValuesParser::new([on_label, off_label])
.map(move |val| Self::with_labels(val == on_label, on_label, off_label)),
)
}
fn with_labels(state: bool, on_label: &'static str, off_label: &'static str) -> Self {
Self {
state,
on_label,
off_label,
}
}
}
impl From<bool> for BooleanOption {
fn from(state: bool) -> Self {
Self::with_labels(state, "on", "off")
}
}
impl std::fmt::Display for BooleanOption {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
if self.state {
self.on_label.fmt(f)
} else {
self.off_label.fmt(f)
}
}
}
async fn receive_confirmation(msg: &'static str, default: bool) -> bool {
let helper_str = match default {
true => "[Y/n]",
false => "[y/N]",
};
println!("{msg} {helper_str}");
tokio::task::spawn_blocking(move || {
loop {
let mut buf = String::new();
if let Err(e) = stdin().read_line(&mut buf) {
eprintln!("Couldn't read from STDIN: {e}");
return false;
}
match buf.trim().to_ascii_lowercase().as_str() {
"" => return default,
"y" | "ye" | "yes" => return true,
"n" | "no" => return false,
_ => eprintln!("Unexpected response. Please enter \"y\" or \"n\""),
}
}
})
.await
.unwrap()
}
|