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