1use clap::Parser;
2
3#[derive(Parser, Debug)]
4#[command(author,version, about = "cargo-e is for Example.", long_about = None)]
5#[command(disable_version_flag = true)]
6pub struct Cli {
7 #[arg(
13 long,
14 num_args = 0..=1,
15 default_value_t = RunAll::NotSpecified,
16 default_missing_value ="",
17 value_parser,
18 help = "Run all optionally specifying run time (in seconds) per target. \
19 If the flag is present without a value, run forever."
20 )]
21 pub run_all: RunAll,
22
23 #[arg(long, help = "Build and run in release mode.")]
24 pub release: bool,
25 #[arg(long, help = "Suppress cargo output when running the sample.")]
26 pub quiet: bool,
27 #[clap(
32 long,
33 help = "If enabled, pre-build the examples before executing them."
34 )]
35 pub pre_build: bool,
36
37 #[arg(
39 long,
40 short = 'v',
41 help = "Print version and feature flags in JSON format."
42 )]
43 pub version: bool,
44
45 #[arg(
46 long,
47 short = 't',
48 help = "Launch the text-based user interface (TUI)."
49 )]
50 pub tui: bool,
51
52 #[arg(long, short = 'w', help = "Operate on the entire workspace.")]
53 pub workspace: bool,
54
55 #[arg(
57 long = "pX",
58 default_value_t = false,
59 value_parser = clap::value_parser!(bool),
60 help = "Print the exit code of the process when run. (default: false)"
61 )]
62 pub print_exit_code: bool,
63
64 #[arg(
66 long = "pN",
67 default_value_t = false,
68 value_parser = clap::value_parser!(bool),
69 help = "Print the program name before execution. (default: false)"
70 )]
71 pub print_program_name: bool,
72
73 #[arg(
75 long = "pI",
76 default_value_t = true,
77 value_parser = clap::value_parser!(bool),
78 help = "Print the user instruction. (default: true)"
79 )]
80 pub print_instruction: bool,
81
82 #[arg(
83 long,
84 short = 'p',
85 default_value_t = true,
86 help = "Enable or disable paging (default: enabled)."
87 )]
88 pub paging: bool,
89
90 #[arg(
91 long,
92 short = 'r',
93 default_value_t = false,
94 help = "Relative numbers (default: enabled)."
95 )]
96 pub relative_numbers: bool,
97
98 #[arg(
99 long = "wait",
100 short = 'W',
101 default_value_t = 5,
102 help = "Set wait time in seconds (default: 5)."
103 )]
104 pub wait: u64,
105
106 #[arg(help = "Specify an explicit example to run.")]
107 pub explicit_example: Option<String>,
108
109 #[arg(last = true, help = "Additional arguments passed to the command.")]
110 pub extra: Vec<String>,
111}
112
113pub fn print_version_and_features() {
115 let version = option_env!("CARGO_PKG_VERSION").unwrap_or("unknown");
117
118 let mut features = Vec::new();
121
122 if cfg!(feature = "tui") {
123 features.push("tui");
124 } else {
125 features.push("!tui");
126 }
127 if cfg!(feature = "concurrent") {
128 features.push("concurrent");
129 } else {
130 features.push("!concurrent");
131 }
132 if cfg!(target_os = "windows") {
133 features.push("windows");
134 } else {
135 features.push("!windows");
136 }
137 if cfg!(feature = "equivalent") {
138 features.push("equivalent");
139 } else {
140 features.push("!equivalent");
141 }
142
143 let json_features = format!(
144 "[{}]",
145 features
146 .iter()
147 .map(|f| format!("\"{}\"", f))
148 .collect::<Vec<String>>()
149 .join(", ")
150 );
151 println!("cargo-e {}", version);
152 println!("{}", json_features);
153 std::process::exit(0);
154}
155
156pub fn get_feature_flags() -> Vec<&'static str> {
159 let mut flags = Vec::new();
160 if cfg!(feature = "tui") {
161 flags.push("tui");
162 } else {
163 flags.push("!tui");
164 }
165 if cfg!(feature = "concurrent") {
166 flags.push("concurrent");
167 } else {
168 flags.push("!concurrent");
169 }
170 if cfg!(target_os = "windows") {
171 flags.push("windows");
172 } else {
173 flags.push("!windows");
174 }
175 if cfg!(feature = "equivalent") {
176 flags.push("equivalent");
177 } else {
178 flags.push("!equivalent");
179 }
180 flags
181}
182
183use std::str::FromStr;
184
185#[derive(Debug, Clone, PartialEq)]
187pub enum RunAll {
188 NotSpecified,
190 Forever,
192 Timeout(u64),
194}
195
196impl Default for RunAll {
197 fn default() -> Self {
198 RunAll::NotSpecified
199 }
200}
201
202impl FromStr for RunAll {
203 type Err = String;
204 fn from_str(s: &str) -> Result<Self, Self::Err> {
205 if s.is_empty() {
207 Ok(RunAll::Forever)
208 } else if s.eq_ignore_ascii_case("not_specified") {
209 Ok(RunAll::NotSpecified)
210 } else {
211 s.parse::<u64>()
213 .map(RunAll::Timeout)
214 .map_err(|e| e.to_string())
215 }
216 }
217}
218
219impl std::fmt::Display for RunAll {
220 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
221 match self {
222 RunAll::NotSpecified => write!(f, "not_specified"),
223 RunAll::Forever => write!(f, "forever"),
224 RunAll::Timeout(secs) => write!(f, "{}", secs),
225 }
226 }
227}