Skip to content

Commit 7984efa

Browse files
committed
Auto merge of #14533 - shannmu:_bin_names, r=epage
feat: Add custom completer for completing bin names ### What does this PR try to resolve? Tracking issue #14520 Add custom completer for `cargo build --bin=<TAB>`
2 parents a9a418d + 93fc564 commit 7984efa

File tree

1 file changed

+55
-15
lines changed

1 file changed

+55
-15
lines changed

src/cargo/util/command_prelude.rs

+55-15
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use crate::core::compiler::{BuildConfig, MessageFormat, TimingOutput};
22
use crate::core::resolver::CliFeatures;
3-
use crate::core::{Edition, Workspace};
3+
use crate::core::{shell, Edition, Target, TargetKind, Workspace};
44
use crate::ops::lockfile::LOCKFILE_NAME;
55
use crate::ops::registry::RegistryOrIndex;
66
use crate::ops::{CompileFilter, CompileOptions, NewOptions, Packages, VersionControl};
@@ -19,6 +19,7 @@ use cargo_util_schemas::manifest::ProfileName;
1919
use cargo_util_schemas::manifest::RegistryName;
2020
use cargo_util_schemas::manifest::StringOrVec;
2121
use clap::builder::UnknownArgumentValueParser;
22+
use home::cargo_home_with_cwd;
2223
use std::ffi::{OsStr, OsString};
2324
use std::path::Path;
2425
use std::path::PathBuf;
@@ -173,7 +174,11 @@ pub trait CommandExt: Sized {
173174
) -> Self {
174175
self._arg(flag("lib", lib).help_heading(heading::TARGET_SELECTION))
175176
._arg(flag("bins", bins).help_heading(heading::TARGET_SELECTION))
176-
._arg(optional_multi_opt("bin", "NAME", bin).help_heading(heading::TARGET_SELECTION))
177+
._arg(
178+
optional_multi_opt("bin", "NAME", bin)
179+
.help_heading(heading::TARGET_SELECTION)
180+
.add(clap_complete::ArgValueCandidates::new(get_bin_candidates)),
181+
)
177182
._arg(flag("examples", examples).help_heading(heading::TARGET_SELECTION))
178183
._arg(
179184
optional_multi_opt("example", "NAME", example)
@@ -188,21 +193,27 @@ pub trait CommandExt: Sized {
188193
example: &'static str,
189194
examples: &'static str,
190195
) -> Self {
191-
self._arg(optional_multi_opt("bin", "NAME", bin).help_heading(heading::TARGET_SELECTION))
192-
._arg(flag("bins", bins).help_heading(heading::TARGET_SELECTION))
193-
._arg(
194-
optional_multi_opt("example", "NAME", example)
195-
.help_heading(heading::TARGET_SELECTION),
196-
)
197-
._arg(flag("examples", examples).help_heading(heading::TARGET_SELECTION))
196+
self._arg(
197+
optional_multi_opt("bin", "NAME", bin)
198+
.help_heading(heading::TARGET_SELECTION)
199+
.add(clap_complete::ArgValueCandidates::new(get_bin_candidates)),
200+
)
201+
._arg(flag("bins", bins).help_heading(heading::TARGET_SELECTION))
202+
._arg(
203+
optional_multi_opt("example", "NAME", example).help_heading(heading::TARGET_SELECTION),
204+
)
205+
._arg(flag("examples", examples).help_heading(heading::TARGET_SELECTION))
198206
}
199207

200208
fn arg_targets_bin_example(self, bin: &'static str, example: &'static str) -> Self {
201-
self._arg(optional_multi_opt("bin", "NAME", bin).help_heading(heading::TARGET_SELECTION))
202-
._arg(
203-
optional_multi_opt("example", "NAME", example)
204-
.help_heading(heading::TARGET_SELECTION),
205-
)
209+
self._arg(
210+
optional_multi_opt("bin", "NAME", bin)
211+
.help_heading(heading::TARGET_SELECTION)
212+
.add(clap_complete::ArgValueCandidates::new(get_bin_candidates)),
213+
)
214+
._arg(
215+
optional_multi_opt("example", "NAME", example).help_heading(heading::TARGET_SELECTION),
216+
)
206217
}
207218

208219
fn arg_features(self) -> Self {
@@ -333,7 +344,10 @@ pub trait CommandExt: Sized {
333344
.value_name("VCS")
334345
.value_parser(["git", "hg", "pijul", "fossil", "none"]),
335346
)
336-
._arg(flag("bin", "Use a binary (application) template [default]"))
347+
._arg(
348+
flag("bin", "Use a binary (application) template [default]")
349+
.add(clap_complete::ArgValueCandidates::new(get_bin_candidates)),
350+
)
337351
._arg(flag("lib", "Use a library template"))
338352
._arg(
339353
opt("edition", "Edition to set for the crate generated")
@@ -1027,6 +1041,32 @@ pub fn lockfile_path(
10271041
return Ok(Some(path));
10281042
}
10291043

1044+
fn get_bin_candidates() -> Vec<clap_complete::CompletionCandidate> {
1045+
get_targets_from_metadata()
1046+
.unwrap_or_default()
1047+
.into_iter()
1048+
.filter_map(|target| match target.kind() {
1049+
TargetKind::Bin => Some(clap_complete::CompletionCandidate::new(target.name())),
1050+
_ => None,
1051+
})
1052+
.collect::<Vec<_>>()
1053+
}
1054+
1055+
fn get_targets_from_metadata() -> CargoResult<Vec<Target>> {
1056+
let cwd = std::env::current_dir()?;
1057+
let gctx = GlobalContext::new(shell::Shell::new(), cwd.clone(), cargo_home_with_cwd(&cwd)?);
1058+
let ws = Workspace::new(&find_root_manifest_for_wd(&cwd)?, &gctx)?;
1059+
1060+
let packages = ws.members().collect::<Vec<_>>();
1061+
1062+
let targets = packages
1063+
.into_iter()
1064+
.flat_map(|pkg| pkg.targets().into_iter().cloned())
1065+
.collect::<Vec<_>>();
1066+
1067+
Ok(targets)
1068+
}
1069+
10301070
#[track_caller]
10311071
pub fn ignore_unknown<T: Default>(r: Result<T, clap::parser::MatchesError>) -> T {
10321072
match r {

0 commit comments

Comments
 (0)