Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion src/bin/cargo/commands/clean.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,18 @@ use cargo::core::global_cache_tracker::GlobalCacheTracker;
use cargo::ops::CleanContext;
use cargo::ops::{self, CleanOptions};
use cargo::util::print_available_packages;
use clap_complete::ArgValueCandidates;
use std::time::Duration;

pub fn cli() -> Command {
subcommand("clean")
.about("Remove artifacts that cargo has generated in the past")
.arg_doc("Whether or not to clean just the documentation directory")
.arg_silent_suggestion()
.arg_package_spec_simple("Package to clean artifacts for")
.arg_package_spec_simple(
"Package to clean artifacts for",
ArgValueCandidates::new(get_pkg_name_candidates),
)
.arg_release("Whether or not to clean release artifacts")
.arg_profile("Clean artifacts of the specified profile")
.arg_target_triple("Target triple to clean output for")
Expand Down
2 changes: 2 additions & 0 deletions src/bin/cargo/commands/package.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use crate::command_prelude::*;
use cargo::ops;
use cargo::ops::PackageMessageFormat;
use cargo::ops::PackageOpts;
use clap_complete::ArgValueCandidates;

pub fn cli() -> Command {
subcommand("package")
Expand Down Expand Up @@ -44,6 +45,7 @@ pub fn cli() -> Command {
"Package(s) to assemble",
"Assemble all packages in the workspace",
"Don't assemble specified packages",
ArgValueCandidates::new(get_ws_member_candidates),
)
.arg_features()
.arg_target_triple("Build for the target triple")
Expand Down
2 changes: 2 additions & 0 deletions src/bin/cargo/commands/publish.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use crate::command_prelude::*;

use cargo::ops::{self, PublishOpts};
use cargo_credential::Secret;
use clap_complete::ArgValueCandidates;

pub fn cli() -> Command {
subcommand("publish")
Expand All @@ -27,6 +28,7 @@ pub fn cli() -> Command {
"Package(s) to publish",
"Publish all packages in the workspace",
"Don't publish specified packages",
ArgValueCandidates::new(get_ws_member_candidates),
)
.arg_features()
.arg_parallel()
Expand Down
7 changes: 6 additions & 1 deletion src/bin/cargo/commands/tree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use cargo::ops::Packages;
use cargo::ops::tree::{self, DisplayDepth, EdgeKind};
use cargo::util::CargoResult;
use cargo::util::print_available_packages;
use clap_complete::ArgValueCandidates;
use std::collections::HashSet;
use std::str::FromStr;

Expand Down Expand Up @@ -36,7 +37,10 @@ pub fn cli() -> Command {
"SPEC",
"Invert the tree direction and focus on the given package",
)
.short('i'),
.short('i')
.add(clap_complete::ArgValueCandidates::new(
get_pkg_id_spec_candidates,
)),
)
.arg(multi_opt(
"prune",
Expand Down Expand Up @@ -88,6 +92,7 @@ pub fn cli() -> Command {
"Package to be used as the root of the tree",
"Display the tree for all packages in the workspace",
"Exclude specific workspace members",
ArgValueCandidates::new(get_pkg_id_spec_candidates),
)
.arg_features()
.arg(flag("all-targets", "Deprecated, use --target=all instead").hide(true))
Expand Down
42 changes: 39 additions & 3 deletions src/bin/cargo/commands/uninstall.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
use crate::command_prelude::*;

use cargo::ops;
use cargo::{CargoResult, core::PackageId, ops};
use clap_complete::ArgValueCandidates;

use std::collections::BTreeSet;

pub fn cli() -> Command {
subcommand("uninstall")
Expand All @@ -15,7 +18,10 @@ pub fn cli() -> Command {
)
.arg(opt("root", "Directory to uninstall packages from").value_name("DIR"))
.arg_silent_suggestion()
.arg_package_spec_simple("Package to uninstall")
.arg_package_spec_simple(
"Package to uninstall",
ArgValueCandidates::new(get_installed_package_candidates),
)
.arg(
multi_opt("bin", "NAME", "Only uninstall the binary NAME")
.help_heading(heading::TARGET_SELECTION),
Expand Down Expand Up @@ -52,7 +58,7 @@ fn get_installed_crates() -> Vec<clap_complete::CompletionCandidate> {
fn get_installed_crates_() -> Option<Vec<clap_complete::CompletionCandidate>> {
let mut candidates = Vec::new();

let gctx = GlobalContext::default().ok()?;
let gctx = new_gctx_for_completions().ok()?;

let root = ops::resolve_root(None, &gctx).ok()?;

Expand All @@ -66,3 +72,33 @@ fn get_installed_crates_() -> Option<Vec<clap_complete::CompletionCandidate>> {

Some(candidates)
}

fn get_installed_package_candidates() -> Vec<clap_complete::CompletionCandidate> {
get_installed_packages()
.unwrap_or_default()
.into_iter()
.map(|(pkg, bins)| {
let single_binary = bins.iter().next().take_if(|_| bins.len() == 1);

let help = if single_binary.is_some_and(|bin| bin == pkg.name().as_str()) {
None
} else {
let binaries = bins.into_iter().collect::<Vec<_>>().as_slice().join(", ");
Some(binaries)
};

clap_complete::CompletionCandidate::new(pkg.name().as_str()).help(help.map(From::from))
})
.collect()
}

fn get_installed_packages() -> CargoResult<Vec<(PackageId, BTreeSet<String>)>> {
let gctx = new_gctx_for_completions()?;
let root = ops::resolve_root(None, &gctx)?;

let tracker = ops::InstallTracker::load(&gctx, &root)?;
Ok(tracker
.all_installed_bins()
.map(|(package_id, bins)| (*package_id, bins.clone()))
.collect())
}
79 changes: 72 additions & 7 deletions src/cargo/util/command_prelude.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,12 @@ use cargo_util_schemas::manifest::ProfileName;
use cargo_util_schemas::manifest::RegistryName;
use cargo_util_schemas::manifest::StringOrVec;
use clap::builder::UnknownArgumentValueParser;
use clap_complete::ArgValueCandidates;
use home::cargo_home_with_cwd;
use indexmap::IndexSet;
use itertools::Itertools;
use semver::Version;
use std::collections::{HashMap, HashSet};
use std::collections::{BTreeMap, HashMap, HashSet};
use std::ffi::{OsStr, OsString};
use std::path::Path;
use std::path::PathBuf;
Expand Down Expand Up @@ -60,7 +61,13 @@ pub trait CommandExt: Sized {
all: &'static str,
exclude: &'static str,
) -> Self {
self.arg_package_spec_no_all(package, all, exclude)._arg(
self.arg_package_spec_no_all(
package,
all,
exclude,
ArgValueCandidates::new(get_ws_member_candidates),
)
._arg(
flag("all", "Alias for --workspace (deprecated)")
.help_heading(heading::PACKAGE_SELECTION),
)
Expand All @@ -74,6 +81,7 @@ pub trait CommandExt: Sized {
package: &'static str,
all: &'static str,
exclude: &'static str,
package_completion: ArgValueCandidates,
) -> Self {
let unsupported_short_arg = {
let value_parser = UnknownArgumentValueParser::suggest_arg("--exclude");
Expand All @@ -84,17 +92,28 @@ pub trait CommandExt: Sized {
.action(ArgAction::SetTrue)
.hide(true)
};
self.arg_package_spec_simple(package)
self.arg_package_spec_simple(package, package_completion)
._arg(flag("workspace", all).help_heading(heading::PACKAGE_SELECTION))
._arg(multi_opt("exclude", "SPEC", exclude).help_heading(heading::PACKAGE_SELECTION))
._arg(
multi_opt("exclude", "SPEC", exclude)
.help_heading(heading::PACKAGE_SELECTION)
.add(clap_complete::ArgValueCandidates::new(
get_ws_member_candidates,
)),
)
._arg(unsupported_short_arg)
}

fn arg_package_spec_simple(self, package: &'static str) -> Self {
fn arg_package_spec_simple(
self,
package: &'static str,
package_completion: ArgValueCandidates,
) -> Self {
self._arg(
optional_multi_opt("package", "SPEC", package)
.short('p')
.help_heading(heading::PACKAGE_SELECTION),
.help_heading(heading::PACKAGE_SELECTION)
.add(package_completion),
)
}

Expand All @@ -103,7 +122,10 @@ pub trait CommandExt: Sized {
optional_opt("package", package)
.short('p')
.value_name("SPEC")
.help_heading(heading::PACKAGE_SELECTION),
.help_heading(heading::PACKAGE_SELECTION)
.add(clap_complete::ArgValueCandidates::new(|| {
get_ws_member_candidates()
})),
)
}

Expand Down Expand Up @@ -1313,6 +1335,29 @@ fn get_target_triples_from_rustc() -> CargoResult<Vec<clap_complete::CompletionC
.collect())
}

pub fn get_ws_member_candidates() -> Vec<clap_complete::CompletionCandidate> {
get_ws_member_packages()
.unwrap_or_default()
.into_iter()
.map(|pkg| {
clap_complete::CompletionCandidate::new(pkg.name().as_str()).help(
pkg.manifest()
.metadata()
.description
.to_owned()
.map(From::from),
)
})
.collect::<Vec<_>>()
}

fn get_ws_member_packages() -> CargoResult<Vec<Package>> {
let gctx = new_gctx_for_completions()?;
let ws = Workspace::new(&find_root_manifest_for_wd(gctx.cwd())?, &gctx)?;
let packages = ws.members().map(Clone::clone).collect::<Vec<_>>();
Ok(packages)
}

pub fn get_pkg_id_spec_candidates() -> Vec<clap_complete::CompletionCandidate> {
let mut candidates = vec![];

Expand Down Expand Up @@ -1400,6 +1445,26 @@ pub fn get_pkg_id_spec_candidates() -> Vec<clap_complete::CompletionCandidate> {
candidates
}

pub fn get_pkg_name_candidates() -> Vec<clap_complete::CompletionCandidate> {
let packages: BTreeMap<_, _> = get_packages()
.unwrap_or_default()
.into_iter()
.map(|package| {
(
package.name(),
package.manifest().metadata().description.clone(),
)
})
.collect();

packages
.into_iter()
.map(|(name, description)| {
clap_complete::CompletionCandidate::new(name.as_str()).help(description.map(From::from))
})
.collect()
}

fn get_packages() -> CargoResult<Vec<Package>> {
let gctx = new_gctx_for_completions()?;

Expand Down