From c1c342db4030407ffb77deb2e2330d0fb3d86ead Mon Sep 17 00:00:00 2001 From: Ed Page Date: Fri, 12 Sep 2025 09:00:09 -0500 Subject: [PATCH 1/7] feat(complete): Report what package a build-target is from --- src/cargo/util/command_prelude.rs | 32 +++++++++++++++++++++---------- 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/src/cargo/util/command_prelude.rs b/src/cargo/util/command_prelude.rs index 7b1f678d699..46ab98380cf 100644 --- a/src/cargo/util/command_prelude.rs +++ b/src/cargo/util/command_prelude.rs @@ -1218,8 +1218,11 @@ fn get_example_candidates() -> Vec { get_targets_from_metadata() .unwrap_or_default() .into_iter() - .filter_map(|target| match target.kind() { - TargetKind::ExampleBin => Some(clap_complete::CompletionCandidate::new(target.name())), + .filter_map(|(pkg_name, target)| match target.kind() { + TargetKind::ExampleBin => Some( + clap_complete::CompletionCandidate::new(target.name()) + .help(Some(format!("(from {})", pkg_name).into())), + ), _ => None, }) .collect::>() @@ -1229,8 +1232,11 @@ fn get_bench_candidates() -> Vec { get_targets_from_metadata() .unwrap_or_default() .into_iter() - .filter_map(|target| match target.kind() { - TargetKind::Bench => Some(clap_complete::CompletionCandidate::new(target.name())), + .filter_map(|(pkg_name, target)| match target.kind() { + TargetKind::Bench => Some( + clap_complete::CompletionCandidate::new(target.name()) + .help(Some(format!("(from {})", pkg_name).into())), + ), _ => None, }) .collect::>() @@ -1240,8 +1246,11 @@ fn get_test_candidates() -> Vec { get_targets_from_metadata() .unwrap_or_default() .into_iter() - .filter_map(|target| match target.kind() { - TargetKind::Test => Some(clap_complete::CompletionCandidate::new(target.name())), + .filter_map(|(pkg_name, target)| match target.kind() { + TargetKind::Test => Some( + clap_complete::CompletionCandidate::new(target.name()) + .help(Some(format!("(from {})", pkg_name).into())), + ), _ => None, }) .collect::>() @@ -1251,14 +1260,17 @@ fn get_bin_candidates() -> Vec { get_targets_from_metadata() .unwrap_or_default() .into_iter() - .filter_map(|target| match target.kind() { - TargetKind::Bin => Some(clap_complete::CompletionCandidate::new(target.name())), + .filter_map(|(pkg_name, target)| match target.kind() { + TargetKind::Bin => Some( + clap_complete::CompletionCandidate::new(target.name()) + .help(Some(format!("(from {})", pkg_name).into())), + ), _ => None, }) .collect::>() } -fn get_targets_from_metadata() -> CargoResult> { +fn get_targets_from_metadata() -> CargoResult> { let cwd = std::env::current_dir()?; let gctx = GlobalContext::new(shell::Shell::new(), cwd.clone(), cargo_home_with_cwd(&cwd)?); let ws = Workspace::new(&find_root_manifest_for_wd(&cwd)?, &gctx)?; @@ -1267,7 +1279,7 @@ fn get_targets_from_metadata() -> CargoResult> { let targets = packages .into_iter() - .flat_map(|pkg| pkg.targets().into_iter().cloned()) + .flat_map(|pkg| pkg.targets().into_iter().cloned().map(|t| (pkg.name(), t))) .collect::>(); Ok(targets) From 1003008dcd14ebea800970e0a57cf66c986d6f19 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Fri, 12 Sep 2025 09:01:04 -0500 Subject: [PATCH 2/7] refactor(complete): Remove useless allocation --- src/cargo/util/command_prelude.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/cargo/util/command_prelude.rs b/src/cargo/util/command_prelude.rs index 46ab98380cf..62a0e4c6274 100644 --- a/src/cargo/util/command_prelude.rs +++ b/src/cargo/util/command_prelude.rs @@ -1275,10 +1275,8 @@ fn get_targets_from_metadata() -> CargoResult> { let gctx = GlobalContext::new(shell::Shell::new(), cwd.clone(), cargo_home_with_cwd(&cwd)?); let ws = Workspace::new(&find_root_manifest_for_wd(&cwd)?, &gctx)?; - let packages = ws.members().collect::>(); - - let targets = packages - .into_iter() + let targets = ws + .members() .flat_map(|pkg| pkg.targets().into_iter().cloned().map(|t| (pkg.name(), t))) .collect::>(); From 1d32564c025390f2598a4be22f10bf566c3071b5 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Fri, 12 Sep 2025 09:03:41 -0500 Subject: [PATCH 3/7] refactor(complete): Be consistent in how we initialize --- src/cargo/util/command_prelude.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/cargo/util/command_prelude.rs b/src/cargo/util/command_prelude.rs index 62a0e4c6274..4324438f41e 100644 --- a/src/cargo/util/command_prelude.rs +++ b/src/cargo/util/command_prelude.rs @@ -1194,8 +1194,8 @@ fn default_profile_candidates() -> Vec { fn get_feature_candidates() -> CargoResult> { let gctx = new_gctx_for_completions()?; - let manifest_path = find_root_manifest_for_wd(gctx.cwd())?; - let ws = Workspace::new(&manifest_path, &gctx)?; + + let ws = Workspace::new(&find_root_manifest_for_wd(gctx.cwd())?, &gctx)?; let mut feature_candidates = Vec::new(); // Process all packages in the workspace @@ -1271,9 +1271,9 @@ fn get_bin_candidates() -> Vec { } fn get_targets_from_metadata() -> CargoResult> { - let cwd = std::env::current_dir()?; - let gctx = GlobalContext::new(shell::Shell::new(), cwd.clone(), cargo_home_with_cwd(&cwd)?); - let ws = Workspace::new(&find_root_manifest_for_wd(&cwd)?, &gctx)?; + let gctx = new_gctx_for_completions()?; + + let ws = Workspace::new(&find_root_manifest_for_wd(gctx.cwd())?, &gctx)?; let targets = ws .members() @@ -1329,9 +1329,9 @@ fn get_target_triples_from_rustup() -> CargoResult CargoResult> { - let cwd = std::env::current_dir()?; - let gctx = GlobalContext::new(shell::Shell::new(), cwd.clone(), cargo_home_with_cwd(&cwd)?); - let ws = Workspace::new(&find_root_manifest_for_wd(&PathBuf::from(&cwd))?, &gctx); + let gctx = new_gctx_for_completions()?; + + let ws = Workspace::new(&find_root_manifest_for_wd(gctx.cwd())?, &gctx); let rustc = gctx.load_global_rustc(ws.as_ref().ok())?; From bbb8bec8761b6b071f15b58a7bdba012cc084e44 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Fri, 12 Sep 2025 09:07:24 -0500 Subject: [PATCH 4/7] refactor(complete): Simplify error handling --- src/cargo/util/command_prelude.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/cargo/util/command_prelude.rs b/src/cargo/util/command_prelude.rs index 4324438f41e..9465d437acd 100644 --- a/src/cargo/util/command_prelude.rs +++ b/src/cargo/util/command_prelude.rs @@ -253,8 +253,7 @@ pub trait CommandExt: Sized { .short('F') .help_heading(heading::FEATURE_SELECTION) .add(clap_complete::ArgValueCandidates::new(|| { - let candidates = get_feature_candidates(); - candidates.unwrap_or_default() + get_feature_candidates().unwrap_or_default() })), ) ._arg( From 35d05e8ad6f3958c93c572a23b34ecd96d35df6b Mon Sep 17 00:00:00 2001 From: Ed Page Date: Fri, 12 Sep 2025 09:15:25 -0500 Subject: [PATCH 5/7] refactor(complete): Remove meaningless completions --- src/cargo/util/command_prelude.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/cargo/util/command_prelude.rs b/src/cargo/util/command_prelude.rs index 9465d437acd..b9b51a5cb92 100644 --- a/src/cargo/util/command_prelude.rs +++ b/src/cargo/util/command_prelude.rs @@ -413,10 +413,7 @@ pub trait CommandExt: Sized { .value_name("VCS") .value_parser(["git", "hg", "pijul", "fossil", "none"]), ) - ._arg( - flag("bin", "Use a binary (application) template [default]") - .add(clap_complete::ArgValueCandidates::new(get_bin_candidates)), - ) + ._arg(flag("bin", "Use a binary (application) template [default]")) ._arg(flag("lib", "Use a library template")) ._arg( opt("edition", "Edition to set for the crate generated") From c775f3445d85209f20c018604b6305113ed04c25 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Fri, 12 Sep 2025 09:16:17 -0500 Subject: [PATCH 6/7] refactor(complete): Simplify crate completions --- src/cargo/util/command_prelude.rs | 103 +++++++++--------------------- 1 file changed, 31 insertions(+), 72 deletions(-) diff --git a/src/cargo/util/command_prelude.rs b/src/cargo/util/command_prelude.rs index b9b51a5cb92..00a2e04f3d2 100644 --- a/src/cargo/util/command_prelude.rs +++ b/src/cargo/util/command_prelude.rs @@ -4,7 +4,7 @@ use crate::core::compiler::{ BuildConfig, CompileKind, MessageFormat, RustcTargetData, TimingOutput, }; use crate::core::resolver::{CliFeatures, ForceAllTargets, HasDevUnits}; -use crate::core::{Edition, Package, Target, TargetKind, Workspace, profiles::Profiles, shell}; +use crate::core::{Edition, Package, TargetKind, Workspace, profiles::Profiles, shell}; use crate::ops::lockfile::LOCKFILE_NAME; use crate::ops::registry::RegistryOrIndex; use crate::ops::{self, CompileFilter, CompileOptions, NewOptions, Packages, VersionControl}; @@ -169,13 +169,17 @@ pub trait CommandExt: Sized { ._arg( optional_multi_opt("test", "NAME", test) .help_heading(heading::TARGET_SELECTION) - .add(clap_complete::ArgValueCandidates::new(get_test_candidates)), + .add(clap_complete::ArgValueCandidates::new(|| { + get_crate_candidates(TargetKind::Test).unwrap_or_default() + })), ) ._arg(flag("benches", benches).help_heading(heading::TARGET_SELECTION)) ._arg( optional_multi_opt("bench", "NAME", bench) .help_heading(heading::TARGET_SELECTION) - .add(clap_complete::ArgValueCandidates::new(get_bench_candidates)), + .add(clap_complete::ArgValueCandidates::new(|| { + get_crate_candidates(TargetKind::Bench).unwrap_or_default() + })), ) ._arg(flag("all-targets", all).help_heading(heading::TARGET_SELECTION)) } @@ -193,15 +197,17 @@ pub trait CommandExt: Sized { ._arg( optional_multi_opt("bin", "NAME", bin) .help_heading(heading::TARGET_SELECTION) - .add(clap_complete::ArgValueCandidates::new(get_bin_candidates)), + .add(clap_complete::ArgValueCandidates::new(|| { + get_crate_candidates(TargetKind::Bin).unwrap_or_default() + })), ) ._arg(flag("examples", examples).help_heading(heading::TARGET_SELECTION)) ._arg( optional_multi_opt("example", "NAME", example) .help_heading(heading::TARGET_SELECTION) - .add(clap_complete::ArgValueCandidates::new( - get_example_candidates, - )), + .add(clap_complete::ArgValueCandidates::new(|| { + get_crate_candidates(TargetKind::ExampleBin).unwrap_or_default() + })), ) } @@ -215,15 +221,17 @@ pub trait CommandExt: Sized { self._arg( optional_multi_opt("bin", "NAME", bin) .help_heading(heading::TARGET_SELECTION) - .add(clap_complete::ArgValueCandidates::new(get_bin_candidates)), + .add(clap_complete::ArgValueCandidates::new(|| { + get_crate_candidates(TargetKind::Bin).unwrap_or_default() + })), ) ._arg(flag("bins", bins).help_heading(heading::TARGET_SELECTION)) ._arg( optional_multi_opt("example", "NAME", example) .help_heading(heading::TARGET_SELECTION) - .add(clap_complete::ArgValueCandidates::new( - get_example_candidates, - )), + .add(clap_complete::ArgValueCandidates::new(|| { + get_crate_candidates(TargetKind::ExampleBin).unwrap_or_default() + })), ) ._arg(flag("examples", examples).help_heading(heading::TARGET_SELECTION)) } @@ -232,14 +240,16 @@ pub trait CommandExt: Sized { self._arg( optional_multi_opt("bin", "NAME", bin) .help_heading(heading::TARGET_SELECTION) - .add(clap_complete::ArgValueCandidates::new(get_bin_candidates)), + .add(clap_complete::ArgValueCandidates::new(|| { + get_crate_candidates(TargetKind::Bin).unwrap_or_default() + })), ) ._arg( optional_multi_opt("example", "NAME", example) .help_heading(heading::TARGET_SELECTION) - .add(clap_complete::ArgValueCandidates::new( - get_example_candidates, - )), + .add(clap_complete::ArgValueCandidates::new(|| { + get_crate_candidates(TargetKind::ExampleBin).unwrap_or_default() + })), ) } @@ -1210,63 +1220,7 @@ fn get_feature_candidates() -> CargoResult Vec { - get_targets_from_metadata() - .unwrap_or_default() - .into_iter() - .filter_map(|(pkg_name, target)| match target.kind() { - TargetKind::ExampleBin => Some( - clap_complete::CompletionCandidate::new(target.name()) - .help(Some(format!("(from {})", pkg_name).into())), - ), - _ => None, - }) - .collect::>() -} - -fn get_bench_candidates() -> Vec { - get_targets_from_metadata() - .unwrap_or_default() - .into_iter() - .filter_map(|(pkg_name, target)| match target.kind() { - TargetKind::Bench => Some( - clap_complete::CompletionCandidate::new(target.name()) - .help(Some(format!("(from {})", pkg_name).into())), - ), - _ => None, - }) - .collect::>() -} - -fn get_test_candidates() -> Vec { - get_targets_from_metadata() - .unwrap_or_default() - .into_iter() - .filter_map(|(pkg_name, target)| match target.kind() { - TargetKind::Test => Some( - clap_complete::CompletionCandidate::new(target.name()) - .help(Some(format!("(from {})", pkg_name).into())), - ), - _ => None, - }) - .collect::>() -} - -fn get_bin_candidates() -> Vec { - get_targets_from_metadata() - .unwrap_or_default() - .into_iter() - .filter_map(|(pkg_name, target)| match target.kind() { - TargetKind::Bin => Some( - clap_complete::CompletionCandidate::new(target.name()) - .help(Some(format!("(from {})", pkg_name).into())), - ), - _ => None, - }) - .collect::>() -} - -fn get_targets_from_metadata() -> CargoResult> { +fn get_crate_candidates(kind: TargetKind) -> CargoResult> { let gctx = new_gctx_for_completions()?; let ws = Workspace::new(&find_root_manifest_for_wd(gctx.cwd())?, &gctx)?; @@ -1274,6 +1228,11 @@ fn get_targets_from_metadata() -> CargoResult> { let targets = ws .members() .flat_map(|pkg| pkg.targets().into_iter().cloned().map(|t| (pkg.name(), t))) + .filter(|(_, target)| *target.kind() == kind) + .map(|(pkg_name, target)| { + clap_complete::CompletionCandidate::new(target.name()) + .help(Some(format!("(from {})", pkg_name).into())) + }) .collect::>(); Ok(targets) From 72946756315a420a2e19c0283bcedd280442b602 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Fri, 12 Sep 2025 09:24:31 -0500 Subject: [PATCH 7/7] fix(complete): Show local crates/features over other members Our options are: - Not offer these completions - Hide them - De-prioritize them Since someone could be using `--package`, I felt de-prioritizing would give the best experience. --- src/cargo/util/command_prelude.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/cargo/util/command_prelude.rs b/src/cargo/util/command_prelude.rs index 00a2e04f3d2..b70caa1552c 100644 --- a/src/cargo/util/command_prelude.rs +++ b/src/cargo/util/command_prelude.rs @@ -1210,8 +1210,14 @@ fn get_feature_candidates() -> CargoResult CargoResult>();