diff --git a/src/cargo/util/command_prelude.rs b/src/cargo/util/command_prelude.rs index 77169a432fc..db5ee14bc29 100644 --- a/src/cargo/util/command_prelude.rs +++ b/src/cargo/util/command_prelude.rs @@ -246,7 +246,11 @@ pub trait CommandExt: Sized { "Space or comma separated list of features to activate", ) .short('F') - .help_heading(heading::FEATURE_SELECTION), + .help_heading(heading::FEATURE_SELECTION) + .add(clap_complete::ArgValueCandidates::new(|| { + let candidates = get_feature_candidates(); + candidates.unwrap_or_default() + })), ) ._arg( flag("all-features", "Activate all available features") @@ -1169,6 +1173,28 @@ 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 mut feature_candidates = Vec::new(); + + // Process all packages in the workspace + for package in ws.members() { + let package_name = package.name(); + + // Add direct features with package info + for feature_name in package.summary().features().keys() { + feature_candidates.push( + clap_complete::CompletionCandidate::new(feature_name) + .help(Some(format!("(from {})", package_name).into())), + ); + } + } + + Ok(feature_candidates) +} + fn get_example_candidates() -> Vec { get_targets_from_metadata() .unwrap_or_default()