1
- use crate :: core:: compiler:: { BuildConfig , MessageFormat , TimingOutput } ;
2
- use crate :: core:: resolver:: CliFeatures ;
3
- use crate :: core:: { shell, Edition , Target , TargetKind , Workspace } ;
1
+ use crate :: core:: compiler:: {
2
+ BuildConfig , CompileKind , MessageFormat , RustcTargetData , TimingOutput ,
3
+ } ;
4
+ use crate :: core:: resolver:: { CliFeatures , ForceAllTargets , HasDevUnits } ;
5
+ use crate :: core:: { shell, Edition , Package , Target , TargetKind , Workspace } ;
4
6
use crate :: ops:: lockfile:: LOCKFILE_NAME ;
5
7
use crate :: ops:: registry:: RegistryOrIndex ;
6
- use crate :: ops:: { CompileFilter , CompileOptions , NewOptions , Packages , VersionControl } ;
8
+ use crate :: ops:: { self , CompileFilter , CompileOptions , NewOptions , Packages , VersionControl } ;
7
9
use crate :: util:: important_paths:: find_root_manifest_for_wd;
8
10
use crate :: util:: interning:: InternedString ;
9
11
use crate :: util:: is_rustup;
@@ -20,6 +22,8 @@ use cargo_util_schemas::manifest::RegistryName;
20
22
use cargo_util_schemas:: manifest:: StringOrVec ;
21
23
use clap:: builder:: UnknownArgumentValueParser ;
22
24
use home:: cargo_home_with_cwd;
25
+ use semver:: Version ;
26
+ use std:: collections:: HashMap ;
23
27
use std:: ffi:: { OsStr , OsString } ;
24
28
use std:: path:: Path ;
25
29
use std:: path:: PathBuf ;
@@ -1174,6 +1178,93 @@ fn get_target_triples_from_rustc() -> CargoResult<Vec<clap_complete::CompletionC
1174
1178
. collect ( ) )
1175
1179
}
1176
1180
1181
+ pub fn get_package_candidates ( ) -> Vec < clap_complete:: CompletionCandidate > {
1182
+ let package_map = HashMap :: < & str , Vec < Package > > :: new ( ) ;
1183
+
1184
+ let package_map =
1185
+ get_packages ( )
1186
+ . unwrap_or_default ( )
1187
+ . into_iter ( )
1188
+ . fold ( package_map, |mut map, package| {
1189
+ map. entry ( package. name ( ) . as_str ( ) )
1190
+ . or_insert_with ( Vec :: new)
1191
+ . push ( package) ;
1192
+ map
1193
+ } ) ;
1194
+
1195
+ package_map
1196
+ . into_iter ( )
1197
+ . flat_map ( |( name, packages) | {
1198
+ // For unique package name
1199
+ if packages. len ( ) == 1 {
1200
+ return vec ! [ clap_complete:: CompletionCandidate :: new( name. to_string( ) ) ] ;
1201
+ }
1202
+
1203
+ let version_map = HashMap :: < Version , Vec < Package > > :: new ( ) ;
1204
+ let version_map = packages. into_iter ( ) . fold ( version_map, |mut map, package| {
1205
+ map. entry ( package. version ( ) . to_owned ( ) )
1206
+ . or_insert_with ( Vec :: new)
1207
+ . push ( package) ;
1208
+ map
1209
+ } ) ;
1210
+
1211
+ version_map
1212
+ . into_iter ( )
1213
+ . flat_map ( |( version, packages) | {
1214
+ // For package name with duplicates but unique version
1215
+ if packages. len ( ) == 1 {
1216
+ return vec ! [ clap_complete:: CompletionCandidate :: new( format!(
1217
+ "{}@{}" ,
1218
+ name, version
1219
+ ) ) ] ;
1220
+ }
1221
+
1222
+ // For package name with duplicates and duplicate version
1223
+ packages
1224
+ . into_iter ( )
1225
+ . map ( |package| format ! ( "{}" , package. package_id( ) . to_spec( ) ) )
1226
+ . map ( clap_complete:: CompletionCandidate :: new)
1227
+ . collect :: < Vec < _ > > ( )
1228
+ } )
1229
+ . collect :: < Vec < _ > > ( )
1230
+ } )
1231
+ . collect :: < Vec < _ > > ( )
1232
+ }
1233
+
1234
+ fn get_packages ( ) -> CargoResult < Vec < Package > > {
1235
+ let cwd = std:: env:: current_dir ( ) ?;
1236
+ let mut gctx = GlobalContext :: new ( shell:: Shell :: new ( ) , cwd. clone ( ) , cargo_home_with_cwd ( & cwd) ?) ;
1237
+ gctx. configure ( 0 , true , None , false , true , false , & None , & [ ] , & [ ] ) ?;
1238
+ let ws = Workspace :: new ( & find_root_manifest_for_wd ( & cwd) ?, & gctx) ?;
1239
+
1240
+ let requested_kinds = CompileKind :: from_requested_targets ( ws. gctx ( ) , & [ ] ) ?;
1241
+ let mut target_data = RustcTargetData :: new ( & ws, & requested_kinds) ?;
1242
+ // `cli_features.all_features` must be true in case that `specs` is empty.
1243
+ let cli_features = CliFeatures :: new_all ( true ) ;
1244
+ let has_dev_units = HasDevUnits :: Yes ;
1245
+ let force_all_targets = ForceAllTargets :: No ;
1246
+ let dry_run = true ;
1247
+
1248
+ let ws_resolve = ops:: resolve_ws_with_opts (
1249
+ & ws,
1250
+ & mut target_data,
1251
+ & requested_kinds,
1252
+ & cli_features,
1253
+ & [ ] ,
1254
+ has_dev_units,
1255
+ force_all_targets,
1256
+ dry_run,
1257
+ ) ?;
1258
+
1259
+ let packages = ws_resolve
1260
+ . pkg_set
1261
+ . packages ( )
1262
+ . map ( Clone :: clone)
1263
+ . collect :: < Vec < _ > > ( ) ;
1264
+
1265
+ Ok ( packages)
1266
+ }
1267
+
1177
1268
#[ track_caller]
1178
1269
pub fn ignore_unknown < T : Default > ( r : Result < T , clap:: parser:: MatchesError > ) -> T {
1179
1270
match r {
0 commit comments