Skip to content

Commit f7383f7

Browse files
committed
feat(clap_complete): Add support --flag bar and -f bar completion
1 parent 2f53bb3 commit f7383f7

File tree

2 files changed

+118
-66
lines changed

2 files changed

+118
-66
lines changed

clap_complete/src/dynamic/completer.rs

Lines changed: 91 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -76,11 +76,92 @@ pub fn complete(
7676
} else if arg.is_escape() {
7777
is_escaped = true;
7878
state = ParseState::ValueDone;
79-
} else if let Some(_long) = arg.to_long() {
80-
} else if let Some(_short) = arg.to_short() {
79+
} else if let Some((flag, value)) = arg.to_long() {
80+
if let Ok(flag) = flag {
81+
let opt = current_cmd.get_arguments().find(|a| {
82+
let longs = a.get_long_and_visible_aliases();
83+
let is_find = longs.map(|v| {
84+
let mut iter = v.into_iter();
85+
let s = iter.find(|s| *s == flag);
86+
s.is_some()
87+
});
88+
is_find.unwrap_or(false)
89+
});
90+
state = match opt.map(|o| o.get_action()) {
91+
Some(clap::ArgAction::Set) | Some(clap::ArgAction::Append) => {
92+
if value.is_some() {
93+
ParseState::ValueDone
94+
} else {
95+
ParseState::Opt(opt.unwrap().clone())
96+
}
97+
}
98+
Some(clap::ArgAction::SetTrue) | Some(clap::ArgAction::SetFalse) => {
99+
ParseState::ValueDone
100+
}
101+
Some(clap::ArgAction::Count) => ParseState::ValueDone,
102+
Some(clap::ArgAction::Version) => ParseState::ValueDone,
103+
Some(clap::ArgAction::Help)
104+
| Some(clap::ArgAction::HelpLong)
105+
| Some(clap::ArgAction::HelpShort) => ParseState::ValueDone,
106+
Some(_) => ParseState::ValueDone,
107+
None => ParseState::ValueDone,
108+
};
109+
} else {
110+
state = ParseState::ValueDone;
111+
}
112+
} else if let Some(mut short) = arg.to_short() {
113+
let mut takes_value = false;
114+
loop {
115+
if let Some(Ok(opt)) = short.next_flag() {
116+
let opt = current_cmd.get_arguments().find(|a| {
117+
let shorts = a.get_short_and_visible_aliases();
118+
let is_find = shorts.map(|v| {
119+
let mut iter = v.into_iter();
120+
let c = iter.find(|c| *c == opt);
121+
c.is_some()
122+
});
123+
is_find.unwrap_or(false)
124+
});
125+
126+
state = match opt.map(|o| o.get_action()) {
127+
Some(clap::ArgAction::Set) | Some(clap::ArgAction::Append) => {
128+
takes_value = true;
129+
if short.next_value_os().is_some() {
130+
ParseState::ValueDone
131+
} else {
132+
ParseState::Opt(opt.unwrap().clone())
133+
}
134+
}
135+
Some(clap::ArgAction::SetTrue) | Some(clap::ArgAction::SetFalse) => {
136+
ParseState::ValueDone
137+
}
138+
Some(clap::ArgAction::Count) => ParseState::ValueDone,
139+
Some(clap::ArgAction::Version) => ParseState::ValueDone,
140+
Some(clap::ArgAction::Help)
141+
| Some(clap::ArgAction::HelpShort)
142+
| Some(clap::ArgAction::HelpLong) => ParseState::ValueDone,
143+
Some(_) => ParseState::ValueDone,
144+
None => ParseState::ValueDone,
145+
};
146+
147+
if takes_value {
148+
break;
149+
}
150+
} else {
151+
state = ParseState::ValueDone;
152+
break;
153+
}
154+
}
81155
} else {
82-
pos_index += 1;
83-
state = ParseState::ValueDone;
156+
match state {
157+
ParseState::ValueDone | ParseState::Pos(_) => {
158+
pos_index += 1;
159+
state = ParseState::ValueDone;
160+
}
161+
ParseState::Opt(_) => {
162+
state = ParseState::ValueDone;
163+
}
164+
}
84165
}
85166
}
86167

@@ -97,6 +178,9 @@ enum ParseState {
97178

98179
/// Parsing a positional argument after `--`
99180
Pos(usize),
181+
182+
/// Parsing a optional flag argument
183+
Opt(clap::Arg),
100184
}
101185

102186
fn complete_arg(
@@ -200,6 +284,9 @@ fn complete_arg(
200284
completions.extend(complete_arg_value(arg.to_value(), positional, current_dir));
201285
}
202286
}
287+
ParseState::Opt(opt) => {
288+
completions.extend(complete_arg_value(arg.to_value(), &opt, current_dir));
289+
}
203290
}
204291
if completions.iter().any(|a| a.is_visible()) {
205292
completions.retain(|a| a.is_visible())

clap_complete/tests/testsuite/dynamic.rs

Lines changed: 27 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -324,103 +324,65 @@ fn suggest_argument_value() {
324324
assert_data_eq!(
325325
complete!(cmd, "--input [TAB]", current_dir = Some(testdir_path)),
326326
snapbox::str![
327-
"--input
328-
--format
329-
--count
330-
--help Print help
331-
-i
332-
-F
333-
-c
334-
-h Print help
335-
pos_a
336-
pos_b
337-
pos_c"
327+
"a_file
328+
b_file
329+
c_dir/
330+
d_dir/"
338331
],
339332
);
340333

341334
assert_data_eq!(
342335
complete!(cmd, "-i [TAB]", current_dir = Some(testdir_path)),
343336
snapbox::str![
344-
"--input
345-
--format
346-
--count
347-
--help Print help
348-
-i
349-
-F
350-
-c
351-
-h Print help
352-
pos_a
353-
pos_b
354-
pos_c"
337+
"a_file
338+
b_file
339+
c_dir/
340+
d_dir/"
355341
],
356342
);
357343

358344
assert_data_eq!(
359345
complete!(cmd, "--input a[TAB]", current_dir = Some(testdir_path)),
360-
snapbox::str![""],
346+
snapbox::str!["a_file"],
361347
);
362348

363349
assert_data_eq!(
364350
complete!(cmd, "-i b[TAB]", current_dir = Some(testdir_path)),
365-
snapbox::str![""],
351+
snapbox::str!["b_file"],
366352
);
367353

368354
assert_data_eq!(
369355
complete!(cmd, "--format [TAB]"),
370356
snapbox::str![
371-
"--input
372-
--format
373-
--count
374-
--help Print help
375-
-i
376-
-F
377-
-c
378-
-h Print help
379-
pos_a
380-
pos_b
381-
pos_c"
357+
"json
358+
yaml
359+
toml"
382360
],
383361
);
384362

385363
assert_data_eq!(
386364
complete!(cmd, "-F [TAB]"),
387365
snapbox::str![
388-
"--input
389-
--format
390-
--count
391-
--help Print help
392-
-i
393-
-F
394-
-c
395-
-h Print help
396-
pos_a
397-
pos_b
398-
pos_c"
366+
"json
367+
yaml
368+
toml"
399369
],
400370
);
401371

402-
assert_data_eq!(complete!(cmd, "--format j[TAB]"), snapbox::str![""],);
372+
assert_data_eq!(complete!(cmd, "--format j[TAB]"), snapbox::str!["json"],);
403373

404-
assert_data_eq!(complete!(cmd, "-F j[TAB]"), snapbox::str![""],);
374+
assert_data_eq!(complete!(cmd, "-F j[TAB]"), snapbox::str!["json"],);
405375

406-
assert_data_eq!(complete!(cmd, "--format t[TAB]"), snapbox::str![""],);
376+
assert_data_eq!(complete!(cmd, "--format t[TAB]"), snapbox::str!["toml"],);
407377

408-
assert_data_eq!(complete!(cmd, "-F t[TAB]"), snapbox::str![""],);
378+
assert_data_eq!(complete!(cmd, "-F t[TAB]"), snapbox::str!["toml"],);
409379

410380
assert_data_eq!(
411381
complete!(cmd, "-cccF [TAB]"),
412382
snapbox::str![
413-
"--input
414-
--format
415-
--count
416-
--help\tPrint help
417-
-i
418-
-F
419-
-c
420-
-h\tPrint help
421-
pos_a
422-
pos_b
423-
pos_c"
383+
"json
384+
yaml
385+
toml"
424386
]
425387
);
426388

@@ -434,7 +396,10 @@ pos_c"
434396
-i
435397
-F
436398
-c
437-
-h\tPrint help"
399+
-h\tPrint help
400+
pos_a
401+
pos_b
402+
pos_c"
438403
]
439404
);
440405
}

0 commit comments

Comments
 (0)