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
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
// Source: ~/claudecode/openclaudecode/src/utils/cliArgs.ts
//! Parse a CLI flag value early, before Commander.js processes arguments.
//! Supports both space-separated (--flag value) and equals-separated (--flag=value) syntax.
//!
//! This function is intended for flags that must be parsed before init() runs,
//! such as --settings which affects configuration loading. For normal flag parsing,
//! rely on Commander.js which handles this automatically.
#![allow(dead_code)]
/// Parse a CLI flag value early, before Commander.js processes arguments.
/// Supports both space-separated (--flag value) and equals-separated (--flag=value) syntax.
///
/// # Arguments
/// * `flag_name` - The flag name including dashes (e.g. '--settings')
/// * `argv` - Optional argv array to parse (defaults to std::env::args())
///
/// # Returns
/// The value if found, None otherwise
pub fn eager_parse_cli_flag(flag_name: &str, argv: Option<&[String]>) -> Option<String> {
let argv_vec: Vec<String>;
let args = match argv {
Some(a) => a,
None => {
argv_vec = std::env::args().collect();
&argv_vec
}
};
for i in 0..args.len() {
let arg = &args[i];
// Handle --flag=value syntax
if arg.starts_with(&format!("{flag_name}=")) {
return Some(arg[flag_name.len() + 1..].to_string());
}
// Handle --flag value syntax
if arg == flag_name && i + 1 < args.len() {
return Some(args[i + 1].clone());
}
}
None
}
/// Handle the standard Unix `--` separator convention in CLI arguments.
///
/// When using Commander.js with `.pass_through_options()`, the `--` separator
/// is passed through as a positional argument rather than being consumed.
/// This means when a user runs:
/// `cmd --opt value name -- subcmd --flag arg`
///
/// Commander parses it as:
/// positional1 = "name", positional2 = "--", rest = ["subcmd", "--flag", "arg"]
///
/// This function corrects the parsing by extracting the actual command from
/// the rest array when the positional is `--`.
///
/// # Arguments
/// * `command_or_value` - The parsed positional that may be "--"
/// * `args` - The remaining arguments array
///
/// # Returns
/// Tuple of (corrected command, remaining args)
pub fn extract_args_after_double_dash(
command_or_value: &str,
args: Option<&[String]>,
) -> (String, Vec<String>) {
let args_vec: Vec<String>;
let args_slice = match args {
Some(a) => a,
None => {
args_vec = Vec::new();
&args_vec
}
};
if command_or_value == "--" && !args_slice.is_empty() {
let command = args_slice[0].clone();
let remaining = args_slice[1..].to_vec();
return (command, remaining);
}
(command_or_value.to_string(), args_slice.to_vec())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_eager_parse_cli_flag_equals() {
let argv = vec!["prog".to_string(), "--flag=value".to_string()];
assert_eq!(
eager_parse_cli_flag("--flag", Some(&argv)),
Some("value".to_string())
);
}
#[test]
fn test_eager_parse_cli_flag_space() {
let argv = vec![
"prog".to_string(),
"--flag".to_string(),
"value".to_string(),
];
assert_eq!(
eager_parse_cli_flag("--flag", Some(&argv)),
Some("value".to_string())
);
}
#[test]
fn test_eager_parse_cli_flag_not_found() {
let argv = vec!["prog".to_string(), "--other".to_string()];
assert_eq!(eager_parse_cli_flag("--flag", Some(&argv)), None);
}
#[test]
fn test_extract_args_after_double_dash() {
let args = vec![
"subcmd".to_string(),
"--flag".to_string(),
"arg".to_string(),
];
let (command, remaining) = extract_args_after_double_dash("--", Some(&args));
assert_eq!(command, "subcmd");
assert_eq!(remaining, vec!["--flag", "arg"]);
}
#[test]
fn test_extract_args_no_double_dash() {
let args = vec!["--flag".to_string(), "arg".to_string()];
let (command, remaining) = extract_args_after_double_dash("name", Some(&args));
assert_eq!(command, "name");
assert_eq!(remaining, vec!["--flag", "arg"]);
}
#[test]
fn test_extract_args_empty_args() {
let (command, remaining) = extract_args_after_double_dash("--", None);
assert_eq!(command, "--");
assert!(remaining.is_empty());
}
}