Skip to content

Commit c3f74fd

Browse files
refactor: replace copied versions of package arg with completer argument
1 parent 06a6b10 commit c3f74fd

File tree

6 files changed

+67
-105
lines changed

6 files changed

+67
-105
lines changed

src/bin/cargo/commands/clean.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,18 @@ use cargo::core::global_cache_tracker::GlobalCacheTracker;
66
use cargo::ops::CleanContext;
77
use cargo::ops::{self, CleanOptions};
88
use cargo::util::print_available_packages;
9+
use clap_complete::ArgValueCandidates;
910
use std::time::Duration;
1011

1112
pub fn cli() -> Command {
1213
subcommand("clean")
1314
.about("Remove artifacts that cargo has generated in the past")
1415
.arg_doc("Whether or not to clean just the documentation directory")
1516
.arg_silent_suggestion()
16-
.arg_clean_package_spec_simple("Package to clean artifacts for")
17+
.arg_package_spec_simple(
18+
"Package to clean artifacts for",
19+
ArgValueCandidates::new(Vec::new), // TODO(completions): implement dynamic completion for `cargo clean -p`
20+
)
1721
.arg_release("Whether or not to clean release artifacts")
1822
.arg_profile("Clean artifacts of the specified profile")
1923
.arg_target_triple("Target triple to clean output for")

src/bin/cargo/commands/package.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use crate::command_prelude::*;
33
use cargo::ops;
44
use cargo::ops::PackageMessageFormat;
55
use cargo::ops::PackageOpts;
6+
use clap_complete::ArgValueCandidates;
67

78
pub fn cli() -> Command {
89
subcommand("package")
@@ -44,6 +45,7 @@ pub fn cli() -> Command {
4445
"Package(s) to assemble",
4546
"Assemble all packages in the workspace",
4647
"Don't assemble specified packages",
48+
ArgValueCandidates::new(get_ws_member_candidates),
4749
)
4850
.arg_features()
4951
.arg_target_triple("Build for the target triple")

src/bin/cargo/commands/publish.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use crate::command_prelude::*;
22

33
use cargo::ops::{self, PublishOpts};
44
use cargo_credential::Secret;
5+
use clap_complete::ArgValueCandidates;
56

67
pub fn cli() -> Command {
78
subcommand("publish")
@@ -27,6 +28,7 @@ pub fn cli() -> Command {
2728
"Package(s) to publish",
2829
"Publish all packages in the workspace",
2930
"Don't publish specified packages",
31+
ArgValueCandidates::new(get_ws_member_candidates),
3032
)
3133
.arg_features()
3234
.arg_parallel()

src/bin/cargo/commands/tree.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ use cargo::ops::Packages;
77
use cargo::ops::tree::{self, DisplayDepth, EdgeKind};
88
use cargo::util::CargoResult;
99
use cargo::util::print_available_packages;
10+
use clap_complete::ArgValueCandidates;
1011
use std::collections::HashSet;
1112
use std::str::FromStr;
1213

@@ -87,10 +88,11 @@ pub fn cli() -> Command {
8788
.short('V')
8889
.hide(true),
8990
)
90-
.arg_dependency_package_spec_no_all(
91+
.arg_package_spec_no_all(
9192
"Package to be used as the root of the tree",
9293
"Display the tree for all packages in the workspace",
9394
"Exclude specific workspace members",
95+
ArgValueCandidates::new(get_dependency_package_candidates),
9496
)
9597
.arg_features()
9698
.arg(flag("all-targets", "Deprecated, use --target=all instead").hide(true))

src/bin/cargo/commands/uninstall.rs

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
use crate::command_prelude::*;
22

3-
use cargo::ops;
3+
use cargo::{CargoResult, core::PackageId, ops};
4+
use clap_complete::ArgValueCandidates;
5+
6+
use std::collections::BTreeSet;
47

58
pub fn cli() -> Command {
69
subcommand("uninstall")
@@ -15,7 +18,10 @@ pub fn cli() -> Command {
1518
)
1619
.arg(opt("root", "Directory to uninstall packages from").value_name("DIR"))
1720
.arg_silent_suggestion()
18-
.arg_installed_package_spec_simple("Package to uninstall")
21+
.arg_package_spec_simple(
22+
"Package to uninstall",
23+
ArgValueCandidates::new(get_installed_package_candidates),
24+
)
1925
.arg(
2026
multi_opt("bin", "NAME", "Only uninstall the binary NAME")
2127
.help_heading(heading::TARGET_SELECTION),
@@ -52,7 +58,7 @@ fn get_installed_crates() -> Vec<clap_complete::CompletionCandidate> {
5258
fn get_installed_crates_() -> Option<Vec<clap_complete::CompletionCandidate>> {
5359
let mut candidates = Vec::new();
5460

55-
let gctx = GlobalContext::default().ok()?;
61+
let gctx = new_gctx_for_completions().ok()?;
5662

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

@@ -66,3 +72,32 @@ fn get_installed_crates_() -> Option<Vec<clap_complete::CompletionCandidate>> {
6672

6773
Some(candidates)
6874
}
75+
76+
fn get_installed_packages() -> CargoResult<Vec<(PackageId, BTreeSet<String>)>> {
77+
let gctx = new_gctx_for_completions()?;
78+
let root = ops::resolve_root(None, &gctx)?;
79+
80+
let tracker = ops::InstallTracker::load(&gctx, &root)?;
81+
Ok(tracker
82+
.all_installed_bins()
83+
.map(|(package_id, bins)| (*package_id, bins.clone()))
84+
.collect())
85+
}
86+
fn get_installed_package_candidates() -> Vec<clap_complete::CompletionCandidate> {
87+
get_installed_packages()
88+
.unwrap_or_default()
89+
.into_iter()
90+
.map(|(pkg, bins)| {
91+
let single_binary = bins.iter().next().take_if(|_| bins.len() == 1);
92+
93+
let help = if single_binary.is_some_and(|bin| bin == pkg.name().as_str()) {
94+
None
95+
} else {
96+
let binaries = bins.into_iter().collect::<Vec<_>>().as_slice().join(", ");
97+
Some(binaries)
98+
};
99+
100+
clap_complete::CompletionCandidate::new(pkg.name().as_str()).help(help.map(From::from))
101+
})
102+
.collect()
103+
}

src/cargo/util/command_prelude.rs

Lines changed: 17 additions & 100 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,13 @@
11
use crate::CargoResult;
2+
use crate::core::Dependency;
23
use crate::core::compiler::{
34
BuildConfig, CompileKind, MessageFormat, RustcTargetData, TimingOutput,
45
};
56
use crate::core::resolver::{CliFeatures, ForceAllTargets, HasDevUnits};
6-
use crate::core::{Dependency, PackageId};
77
use crate::core::{Edition, Package, TargetKind, Workspace, profiles::Profiles, shell};
88
use crate::ops::lockfile::LOCKFILE_NAME;
99
use crate::ops::registry::RegistryOrIndex;
10-
use crate::ops::{
11-
self, CompileFilter, CompileOptions, InstallTracker, NewOptions, Packages, VersionControl,
12-
resolve_root,
13-
};
10+
use crate::ops::{self, CompileFilter, CompileOptions, NewOptions, Packages, VersionControl};
1411
use crate::util::important_paths::find_root_manifest_for_wd;
1512
use crate::util::interning::InternedString;
1613
use crate::util::is_rustup;
@@ -26,11 +23,12 @@ use cargo_util_schemas::manifest::ProfileName;
2623
use cargo_util_schemas::manifest::RegistryName;
2724
use cargo_util_schemas::manifest::StringOrVec;
2825
use clap::builder::UnknownArgumentValueParser;
26+
use clap_complete::ArgValueCandidates;
2927
use home::cargo_home_with_cwd;
3028
use indexmap::IndexSet;
3129
use itertools::Itertools;
3230
use semver::Version;
33-
use std::collections::{BTreeSet, HashMap, HashSet};
31+
use std::collections::{HashMap, HashSet};
3432
use std::ffi::{OsStr, OsString};
3533
use std::path::Path;
3634
use std::path::PathBuf;
@@ -63,7 +61,13 @@ pub trait CommandExt: Sized {
6361
all: &'static str,
6462
exclude: &'static str,
6563
) -> Self {
66-
self.arg_package_spec_no_all(package, all, exclude)._arg(
64+
self.arg_package_spec_no_all(
65+
package,
66+
all,
67+
exclude,
68+
ArgValueCandidates::new(get_ws_member_candidates),
69+
)
70+
._arg(
6771
flag("all", "Alias for --workspace (deprecated)")
6872
.help_heading(heading::PACKAGE_SELECTION),
6973
)
@@ -77,6 +81,7 @@ pub trait CommandExt: Sized {
7781
package: &'static str,
7882
all: &'static str,
7983
exclude: &'static str,
84+
package_completion: ArgValueCandidates,
8085
) -> Self {
8186
let unsupported_short_arg = {
8287
let value_parser = UnknownArgumentValueParser::suggest_arg("--exclude");
@@ -87,7 +92,7 @@ pub trait CommandExt: Sized {
8792
.action(ArgAction::SetTrue)
8893
.hide(true)
8994
};
90-
self.arg_package_spec_simple(package)
95+
self.arg_package_spec_simple(package, package_completion)
9196
._arg(flag("workspace", all).help_heading(heading::PACKAGE_SELECTION))
9297
._arg(
9398
multi_opt("exclude", "SPEC", exclude)
@@ -99,75 +104,16 @@ pub trait CommandExt: Sized {
99104
._arg(unsupported_short_arg)
100105
}
101106

102-
fn arg_dependency_package_spec_no_all(
107+
fn arg_package_spec_simple(
103108
self,
104109
package: &'static str,
105-
all: &'static str,
106-
exclude: &'static str,
110+
package_completion: ArgValueCandidates,
107111
) -> Self {
108-
let unsupported_short_arg = {
109-
let value_parser = UnknownArgumentValueParser::suggest_arg("--exclude");
110-
Arg::new("unsupported-short-exclude-flag")
111-
.help("")
112-
.short('x')
113-
.value_parser(value_parser)
114-
.action(ArgAction::SetTrue)
115-
.hide(true)
116-
};
117-
self.arg_dependency_package_spec_simple(package)
118-
._arg(flag("workspace", all).help_heading(heading::PACKAGE_SELECTION))
119-
._arg(
120-
multi_opt("exclude", "SPEC", exclude)
121-
.help_heading(heading::PACKAGE_SELECTION)
122-
.add(clap_complete::ArgValueCandidates::new(
123-
get_ws_member_candidates,
124-
)),
125-
)
126-
._arg(unsupported_short_arg)
127-
}
128-
129-
fn arg_package_spec_simple(self, package: &'static str) -> Self {
130112
self._arg(
131113
optional_multi_opt("package", "SPEC", package)
132114
.short('p')
133115
.help_heading(heading::PACKAGE_SELECTION)
134-
.add(clap_complete::ArgValueCandidates::new(
135-
get_ws_member_candidates,
136-
)),
137-
)
138-
}
139-
140-
fn arg_installed_package_spec_simple(self, package: &'static str) -> Self {
141-
self._arg(
142-
optional_multi_opt("package", "SPEC", package)
143-
.short('p')
144-
.help_heading(heading::PACKAGE_SELECTION)
145-
.add(clap_complete::ArgValueCandidates::new(
146-
get_installed_package_candidates,
147-
)),
148-
)
149-
}
150-
151-
fn arg_dependency_package_spec_simple(self, package: &'static str) -> Self {
152-
self._arg(
153-
optional_multi_opt("package", "SPEC", package)
154-
.short('p')
155-
.help_heading(heading::PACKAGE_SELECTION)
156-
.add(clap_complete::ArgValueCandidates::new(
157-
get_dependency_package_candidates,
158-
)),
159-
)
160-
}
161-
162-
fn arg_clean_package_spec_simple(self, package: &'static str) -> Self {
163-
// TODO(completions): add dynamic completions for `cargo clean -p`
164-
self._arg(
165-
optional_multi_opt("package", "SPEC", package)
166-
.short('p')
167-
.help_heading(heading::PACKAGE_SELECTION)
168-
.add(
169-
clap_complete::ArgValueCandidates::new(Vec::new), // TODO(complete): implement dynamic completion for `cargo clean -p`
170-
),
116+
.add(package_completion),
171117
)
172118
}
173119

@@ -1566,7 +1512,7 @@ fn get_ws_member_packages() -> CargoResult<Vec<Package>> {
15661512
Ok(packages)
15671513
}
15681514

1569-
fn get_ws_member_candidates() -> Vec<clap_complete::CompletionCandidate> {
1515+
pub fn get_ws_member_candidates() -> Vec<clap_complete::CompletionCandidate> {
15701516
get_ws_member_packages()
15711517
.unwrap_or_default()
15721518
.into_iter()
@@ -1582,35 +1528,6 @@ fn get_ws_member_candidates() -> Vec<clap_complete::CompletionCandidate> {
15821528
.collect::<Vec<_>>()
15831529
}
15841530

1585-
fn get_installed_packages() -> CargoResult<Vec<(PackageId, BTreeSet<String>)>> {
1586-
let gctx = new_gctx_for_completions()?;
1587-
let root = resolve_root(None, &gctx)?;
1588-
1589-
let tracker = InstallTracker::load(&gctx, &root)?;
1590-
Ok(tracker
1591-
.all_installed_bins()
1592-
.map(|(package_id, bins)| (*package_id, bins.clone()))
1593-
.collect())
1594-
}
1595-
fn get_installed_package_candidates() -> Vec<clap_complete::CompletionCandidate> {
1596-
get_installed_packages()
1597-
.unwrap_or_default()
1598-
.into_iter()
1599-
.map(|(pkg, bins)| {
1600-
let single_binary = bins.iter().next().take_if(|_| bins.len() == 1);
1601-
1602-
let help = if single_binary.is_some_and(|bin| bin == pkg.name().as_str()) {
1603-
None
1604-
} else {
1605-
let binaries = bins.into_iter().collect::<Vec<_>>().as_slice().join(", ");
1606-
Some(binaries)
1607-
};
1608-
1609-
clap_complete::CompletionCandidate::new(pkg.name().as_str()).help(help.map(From::from))
1610-
})
1611-
.collect()
1612-
}
1613-
16141531
pub fn get_dependency_package_candidates() -> Vec<clap_complete::CompletionCandidate> {
16151532
get_packages()
16161533
.unwrap_or_default()

0 commit comments

Comments
 (0)