Skip to content

Commit ab4cf3d

Browse files
committed
feat(completion): help completion also for nested commands
1 parent 38cdd62 commit ab4cf3d

File tree

1 file changed

+34
-11
lines changed

1 file changed

+34
-11
lines changed

src/bin/cargo/commands/help.rs

Lines changed: 34 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -22,17 +22,9 @@ pub fn cli() -> Command {
2222
Arg::new("COMMAND")
2323
.num_args(1..)
2424
.action(ArgAction::Append)
25-
.add(clap_complete::ArgValueCandidates::new(|| {
26-
super::builtin()
27-
.iter()
28-
.map(|cmd| {
29-
let name = cmd.get_name();
30-
clap_complete::CompletionCandidate::new(name)
31-
.help(cmd.get_about().cloned())
32-
.hide(cmd.is_hide_set())
33-
})
34-
.collect()
35-
})),
25+
.add(clap_complete::ArgValueCandidates::new(
26+
get_completion_candidates,
27+
)),
3628
)
3729
}
3830

@@ -240,3 +232,34 @@ fn all_builtin_commands() -> HashMap<String, ManPageLookup> {
240232

241233
map
242234
}
235+
236+
/// Returns dash-joined names for nested commands,
237+
/// so they can be completed as single tokens.
238+
fn get_completion_candidates() -> Vec<clap_complete::CompletionCandidate> {
239+
fn walk(
240+
cmd: Command,
241+
prefix: Option<&String>,
242+
candidates: &mut Vec<clap_complete::CompletionCandidate>,
243+
) {
244+
let name = cmd.get_name();
245+
let key = match prefix {
246+
Some(prefix) => format!("{prefix}-{name}"),
247+
None => name.to_string(),
248+
};
249+
250+
for cmd in cmd.get_subcommands() {
251+
walk(cmd.clone(), Some(&key), candidates);
252+
}
253+
254+
let candidate = clap_complete::CompletionCandidate::new(&key)
255+
.help(cmd.get_about().cloned())
256+
.hide(cmd.is_hide_set());
257+
candidates.push(candidate);
258+
}
259+
260+
let mut candidates = Vec::new();
261+
for cmd in super::builtin() {
262+
walk(cmd, None, &mut candidates);
263+
}
264+
candidates
265+
}

0 commit comments

Comments
 (0)