Skip to content

Commit

Permalink
feat: Add custom completer for completing bin names
Browse files Browse the repository at this point in the history
  • Loading branch information
shannmu committed Sep 11, 2024
1 parent e7ca9be commit 5d06e69
Showing 1 changed file with 64 additions and 15 deletions.
79 changes: 64 additions & 15 deletions src/cargo/util/command_prelude.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use crate::util::{
print_available_packages, print_available_tests,
};
use crate::CargoResult;
use anyhow::bail;
use anyhow::{anyhow, bail};
use cargo_util::paths;
use cargo_util_schemas::manifest::ProfileName;
use cargo_util_schemas::manifest::RegistryName;
Expand Down Expand Up @@ -173,7 +173,11 @@ pub trait CommandExt: Sized {
) -> Self {
self._arg(flag("lib", lib).help_heading(heading::TARGET_SELECTION))
._arg(flag("bins", bins).help_heading(heading::TARGET_SELECTION))
._arg(optional_multi_opt("bin", "NAME", bin).help_heading(heading::TARGET_SELECTION))
._arg(
optional_multi_opt("bin", "NAME", bin)
.help_heading(heading::TARGET_SELECTION)
.add(clap_complete::ArgValueCandidates::new(get_bin_candidates)),
)
._arg(flag("examples", examples).help_heading(heading::TARGET_SELECTION))
._arg(
optional_multi_opt("example", "NAME", example)
Expand All @@ -188,21 +192,27 @@ pub trait CommandExt: Sized {
example: &'static str,
examples: &'static str,
) -> Self {
self._arg(optional_multi_opt("bin", "NAME", bin).help_heading(heading::TARGET_SELECTION))
._arg(flag("bins", bins).help_heading(heading::TARGET_SELECTION))
._arg(
optional_multi_opt("example", "NAME", example)
.help_heading(heading::TARGET_SELECTION),
)
._arg(flag("examples", examples).help_heading(heading::TARGET_SELECTION))
self._arg(
optional_multi_opt("bin", "NAME", bin)
.help_heading(heading::TARGET_SELECTION)
.add(clap_complete::ArgValueCandidates::new(get_bin_candidates)),
)
._arg(flag("bins", bins).help_heading(heading::TARGET_SELECTION))
._arg(
optional_multi_opt("example", "NAME", example).help_heading(heading::TARGET_SELECTION),
)
._arg(flag("examples", examples).help_heading(heading::TARGET_SELECTION))
}

fn arg_targets_bin_example(self, bin: &'static str, example: &'static str) -> Self {
self._arg(optional_multi_opt("bin", "NAME", bin).help_heading(heading::TARGET_SELECTION))
._arg(
optional_multi_opt("example", "NAME", example)
.help_heading(heading::TARGET_SELECTION),
)
self._arg(
optional_multi_opt("bin", "NAME", bin)
.help_heading(heading::TARGET_SELECTION)
.add(clap_complete::ArgValueCandidates::new(get_bin_candidates)),
)
._arg(
optional_multi_opt("example", "NAME", example).help_heading(heading::TARGET_SELECTION),
)
}

fn arg_features(self) -> Self {
Expand Down Expand Up @@ -333,7 +343,10 @@ pub trait CommandExt: Sized {
.value_name("VCS")
.value_parser(["git", "hg", "pijul", "fossil", "none"]),
)
._arg(flag("bin", "Use a binary (application) template [default]"))
._arg(
flag("bin", "Use a binary (application) template [default]")
.add(clap_complete::ArgValueCandidates::new(get_bin_candidates)),
)
._arg(flag("lib", "Use a library template"))
._arg(
opt("edition", "Edition to set for the crate generated")
Expand Down Expand Up @@ -1027,6 +1040,42 @@ pub fn lockfile_path(
return Ok(Some(path));
}

fn get_bin_candidates() -> Vec<clap_complete::CompletionCandidate> {
get_bins_from_manifest()
.map(|bins| {
bins.into_iter()
.map(|bin| clap_complete::CompletionCandidate::new(bin))
.collect()
})
.unwrap_or(vec![])
}

fn get_bins_from_manifest() -> Option<Vec<String>> {
let manifest = get_manifest_with_table().ok()?;
let mut bins = vec![];

let bins_array = manifest.get("bin")?.as_array()?;

for bin in bins_array {
let name = bin.as_table()?.get("name")?.as_str()?;
bins.push(name.to_owned());
}

Some(bins)
}

fn get_manifest_with_table() -> CargoResult<toml::Table> {
let menifest = env!("CARGO_MANIFEST_DIR");
let menifest = Path::new(menifest).join("Cargo.toml");

let value = toml::from_str::<toml::Value>(&std::fs::read_to_string(menifest)?)?;

match value {
toml::Value::Table(table) => Ok(table),
_ => Err(anyhow!("Error parsing Cargo.toml")),
}
}

#[track_caller]
pub fn ignore_unknown<T: Default>(r: Result<T, clap::parser::MatchesError>) -> T {
match r {
Expand Down

0 comments on commit 5d06e69

Please sign in to comment.