feat(cli): Allow completions for third-party subcommand names (#15961)

### What does this PR try to resolve?

This will complete the name for third-party subcommands, like
`cargo-release`. This does not complete their args

This is part of #14520.

### How to test and review this PR?
This commit is contained in:
Weihang Lo 2025-09-13 12:55:56 +00:00 committed by GitHub
commit b672b303a1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -11,6 +11,7 @@ use std::fmt::Write;
use super::commands;
use super::list_commands;
use super::third_party_subcommands;
use super::user_defined_aliases;
use crate::command_prelude::*;
use crate::util::is_rustup;
@ -703,7 +704,9 @@ See '<bright-cyan,bold>cargo help</> <cyan><<command>></>' for more information
.into_iter()
.map(|t| clap_complete::CompletionCandidate::new(t))
.collect::<Vec<_>>();
candidates.extend(get_alias_candidates());
if let Ok(gctx) = new_gctx_for_completions() {
candidates.extend(get_command_candidates(&gctx));
}
candidates
}))
.subcommands(commands::builtin())
@ -726,33 +729,31 @@ fn get_toolchains_from_rustup() -> Vec<String> {
stdout.lines().map(|line| format!("+{}", line)).collect()
}
fn get_alias_candidates() -> Vec<clap_complete::CompletionCandidate> {
if let Ok(gctx) = new_gctx_for_completions() {
let alias_map = user_defined_aliases(&gctx);
return alias_map
.iter()
.map(|(alias, cmd_info)| {
let help_text = match cmd_info {
CommandInfo::Alias { target } => {
let cmd_str = target
.iter()
.map(String::as_str)
.collect::<Vec<_>>()
.join(" ");
format!("alias for {}", cmd_str)
}
CommandInfo::BuiltIn { .. } => {
unreachable!("BuiltIn command shouldn't appear in alias map")
}
CommandInfo::External { .. } => {
unreachable!("External command shouldn't appear in alias map")
}
};
clap_complete::CompletionCandidate::new(alias.clone()).help(Some(help_text.into()))
})
.collect();
}
Vec::new()
fn get_command_candidates(gctx: &GlobalContext) -> Vec<clap_complete::CompletionCandidate> {
let mut commands = user_defined_aliases(gctx);
commands.extend(third_party_subcommands(gctx));
commands
.iter()
.map(|(name, cmd_info)| {
let help_text = match cmd_info {
CommandInfo::Alias { target } => {
let cmd_str = target
.iter()
.map(String::as_str)
.collect::<Vec<_>>()
.join(" ");
format!("alias for {}", cmd_str)
}
CommandInfo::BuiltIn { .. } => {
unreachable!("BuiltIn command shouldn't appear in alias map")
}
CommandInfo::External { path } => {
format!("from {}", path.display())
}
};
clap_complete::CompletionCandidate::new(name.clone()).help(Some(help_text.into()))
})
.collect()
}
#[test]