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,155 @@ fn get_target_triples_from_rustc() -> CargoResult<Vec<clap_complete::CompletionC
1174
1178
. collect ( ) )
1175
1179
}
1176
1180
1181
+ pub fn get_pkg_id_spec_candidates ( ) -> Vec < clap_complete:: CompletionCandidate > {
1182
+ let mut candidates = vec ! [ ] ;
1183
+
1184
+ let package_map = HashMap :: < & str , Vec < Package > > :: new ( ) ;
1185
+ let package_map =
1186
+ get_packages ( )
1187
+ . unwrap_or_default ( )
1188
+ . into_iter ( )
1189
+ . fold ( package_map, |mut map, package| {
1190
+ map. entry ( package. name ( ) . as_str ( ) )
1191
+ . or_insert_with ( Vec :: new)
1192
+ . push ( package) ;
1193
+ map
1194
+ } ) ;
1195
+
1196
+ let unique_name_candidates = package_map
1197
+ . iter ( )
1198
+ . filter ( |( _name, packages) | packages. len ( ) == 1 )
1199
+ . map ( |( name, packages) | {
1200
+ clap_complete:: CompletionCandidate :: new ( name. to_string ( ) ) . help (
1201
+ packages[ 0 ]
1202
+ . manifest ( )
1203
+ . metadata ( )
1204
+ . description
1205
+ . to_owned ( )
1206
+ . map ( From :: from) ,
1207
+ )
1208
+ } )
1209
+ . collect :: < Vec < _ > > ( ) ;
1210
+
1211
+ let duplicate_name_pairs = package_map
1212
+ . iter ( )
1213
+ . filter ( |( _name, packages) | packages. len ( ) > 1 )
1214
+ . collect :: < Vec < _ > > ( ) ;
1215
+
1216
+ let mut duplicate_name_candidates = vec ! [ ] ;
1217
+ for ( name, packages) in duplicate_name_pairs {
1218
+ let mut version_count: HashMap < & Version , usize > = HashMap :: new ( ) ;
1219
+
1220
+ for package in packages {
1221
+ * version_count. entry ( package. version ( ) ) . or_insert ( 0 ) += 1 ;
1222
+ }
1223
+
1224
+ for package in packages {
1225
+ if let Some ( & count) = version_count. get ( package. version ( ) ) {
1226
+ if count == 1 {
1227
+ duplicate_name_candidates. push (
1228
+ clap_complete:: CompletionCandidate :: new ( format ! (
1229
+ "{}@{}" ,
1230
+ name,
1231
+ package. version( )
1232
+ ) )
1233
+ . help (
1234
+ package
1235
+ . manifest ( )
1236
+ . metadata ( )
1237
+ . description
1238
+ . to_owned ( )
1239
+ . map ( From :: from) ,
1240
+ ) ,
1241
+ ) ;
1242
+ } else {
1243
+ duplicate_name_candidates. push (
1244
+ clap_complete:: CompletionCandidate :: new ( format ! (
1245
+ "{}" ,
1246
+ package. package_id( ) . to_spec( )
1247
+ ) )
1248
+ . help (
1249
+ package
1250
+ . manifest ( )
1251
+ . metadata ( )
1252
+ . description
1253
+ . to_owned ( )
1254
+ . map ( From :: from) ,
1255
+ ) ,
1256
+ )
1257
+ }
1258
+ }
1259
+ }
1260
+ }
1261
+
1262
+ candidates. extend ( unique_name_candidates) ;
1263
+ candidates. extend ( duplicate_name_candidates) ;
1264
+
1265
+ candidates
1266
+ }
1267
+
1268
+ fn get_packages ( ) -> CargoResult < Vec < Package > > {
1269
+ let gctx = new_gctx_for_completions ( ) ?;
1270
+
1271
+ let ws = Workspace :: new ( & find_root_manifest_for_wd ( gctx. cwd ( ) ) ?, & gctx) ?;
1272
+
1273
+ let requested_kinds = CompileKind :: from_requested_targets ( ws. gctx ( ) , & [ ] ) ?;
1274
+ let mut target_data = RustcTargetData :: new ( & ws, & requested_kinds) ?;
1275
+ // `cli_features.all_features` must be true in case that `specs` is empty.
1276
+ let cli_features = CliFeatures :: new_all ( true ) ;
1277
+ let has_dev_units = HasDevUnits :: Yes ;
1278
+ let force_all_targets = ForceAllTargets :: No ;
1279
+ let dry_run = true ;
1280
+
1281
+ let ws_resolve = ops:: resolve_ws_with_opts (
1282
+ & ws,
1283
+ & mut target_data,
1284
+ & requested_kinds,
1285
+ & cli_features,
1286
+ & [ ] ,
1287
+ has_dev_units,
1288
+ force_all_targets,
1289
+ dry_run,
1290
+ ) ?;
1291
+
1292
+ let packages = ws_resolve
1293
+ . pkg_set
1294
+ . packages ( )
1295
+ . map ( Clone :: clone)
1296
+ . collect :: < Vec < _ > > ( ) ;
1297
+
1298
+ Ok ( packages)
1299
+ }
1300
+
1301
+ fn new_gctx_for_completions ( ) -> CargoResult < GlobalContext > {
1302
+ let cwd = std:: env:: current_dir ( ) ?;
1303
+ let mut gctx = GlobalContext :: new ( shell:: Shell :: new ( ) , cwd. clone ( ) , cargo_home_with_cwd ( & cwd) ?) ;
1304
+
1305
+ let verbose = 0 ;
1306
+ let quiet = true ;
1307
+ let color = None ;
1308
+ let frozen = false ;
1309
+ let locked = true ;
1310
+ let offline = false ;
1311
+ let target_dir = None ;
1312
+ let unstable_flags = & [ ] ;
1313
+ let cli_config = & [ ] ;
1314
+
1315
+ gctx. configure (
1316
+ verbose,
1317
+ quiet,
1318
+ color,
1319
+ frozen,
1320
+ locked,
1321
+ offline,
1322
+ & target_dir,
1323
+ unstable_flags,
1324
+ cli_config,
1325
+ ) ?;
1326
+
1327
+ Ok ( gctx)
1328
+ }
1329
+
1177
1330
#[ track_caller]
1178
1331
pub fn ignore_unknown < T : Default > ( r : Result < T , clap:: parser:: MatchesError > ) -> T {
1179
1332
match r {
0 commit comments