cli/lib/utils/
remaining_flags.rs1use std::collections::BTreeMap;
4
5#[derive(Clone, Debug, Default, PartialEq, Eq)]
6pub struct CommanderOption {
7 pub short: Option<String>,
8 pub long: String,
9}
10
11pub fn get_remaining_flags(
12 raw_args: &[String],
13 consumed_options: &[CommanderOption],
14 consumed_values: &BTreeMap<String, String>,
15) -> Vec<String> {
16 let start = raw_args
17 .iter()
18 .position(|item| item.starts_with("--"))
19 .unwrap_or(0);
20
21 raw_args[start..]
22 .iter()
23 .enumerate()
24 .filter_map(|(index, item)| {
25 if consumed_options
26 .iter()
27 .any(|option| option.short.as_deref() == Some(item) || option.long == *item)
28 {
29 return None;
30 }
31
32 if let Some(previous) = index
33 .checked_sub(1)
34 .and_then(|previous| raw_args[start..].get(previous))
35 {
36 let previous_key =
37 camel_case_flag(&previous.replace("--", "").replacen("no", "", 1));
38 if consumed_values
39 .get(&previous_key)
40 .is_some_and(|value| value == item)
41 {
42 return None;
43 }
44 }
45
46 Some(item.clone())
47 })
48 .collect()
49}
50
51pub fn get_remaining_flags_simple(raw_args: &[String], consumed_options: &[&str]) -> Vec<String> {
52 let options = consumed_options
53 .iter()
54 .map(|option| CommanderOption {
55 short: None,
56 long: (*option).to_string(),
57 })
58 .collect::<Vec<_>>();
59 get_remaining_flags(raw_args, &options, &BTreeMap::new())
60}
61
62pub fn camel_case_flag(flag: &str) -> String {
63 let mut words = flag.split('-');
64 let Some(first) = words.next() else {
65 return String::new();
66 };
67
68 words.fold(first.to_string(), |mut output, word| {
69 let mut chars = word.chars();
70 if let Some(first_char) = chars.next() {
71 output.push(first_char.to_ascii_uppercase());
72 output.push_str(chars.as_str());
73 }
74 output
75 })
76}