diff --git a/src/cargo/util/command_prelude.rs b/src/cargo/util/command_prelude.rs index 9b8ff13e7fd..4e083fc1db3 100644 --- a/src/cargo/util/command_prelude.rs +++ b/src/cargo/util/command_prelude.rs @@ -1,6 +1,6 @@ use crate::core::compiler::{BuildConfig, MessageFormat, TimingOutput}; use crate::core::resolver::CliFeatures; -use crate::core::{Edition, Workspace}; +use crate::core::{shell, Edition, Target, TargetKind, Workspace}; use crate::ops::lockfile::LOCKFILE_NAME; use crate::ops::registry::RegistryOrIndex; use crate::ops::{CompileFilter, CompileOptions, NewOptions, Packages, VersionControl}; @@ -19,6 +19,7 @@ use cargo_util_schemas::manifest::ProfileName; use cargo_util_schemas::manifest::RegistryName; use cargo_util_schemas::manifest::StringOrVec; use clap::builder::UnknownArgumentValueParser; +use home::cargo_home_with_cwd; use std::ffi::{OsStr, OsString}; use std::path::Path; use std::path::PathBuf; @@ -155,7 +156,11 @@ pub trait CommandExt: Sized { ) -> Self { self.arg_targets_lib_bin_example(lib, bin, bins, example, examples) ._arg(flag("tests", tests).help_heading(heading::TARGET_SELECTION)) - ._arg(optional_multi_opt("test", "NAME", test).help_heading(heading::TARGET_SELECTION)) + ._arg( + optional_multi_opt("test", "NAME", test) + .help_heading(heading::TARGET_SELECTION) + .add(clap_complete::ArgValueCandidates::new(get_test_candidates)), + ) ._arg(flag("benches", benches).help_heading(heading::TARGET_SELECTION)) ._arg( optional_multi_opt("bench", "NAME", bench).help_heading(heading::TARGET_SELECTION), @@ -1027,6 +1032,32 @@ pub fn lockfile_path( return Ok(Some(path)); } +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())), + _ => None, + }) + .collect::>() +} + +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 packages = ws.members().collect::>(); + + let targets = packages + .into_iter() + .flat_map(|pkg| pkg.targets().into_iter().cloned()) + .collect::>(); + + Ok(targets) +} + #[track_caller] pub fn ignore_unknown(r: Result) -> T { match r {