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,122 @@ 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 ! [
1201
+ clap_complete:: CompletionCandidate :: new( name. to_string( ) ) . help(
1202
+ packages[ 0 ]
1203
+ . manifest( )
1204
+ . metadata( )
1205
+ . description
1206
+ . to_owned( )
1207
+ . map( From :: from) ,
1208
+ ) ,
1209
+ ] ;
1210
+ }
1211
+
1212
+ let version_map = HashMap :: < Version , Vec < Package > > :: new ( ) ;
1213
+ let version_map = packages. into_iter ( ) . fold ( version_map, |mut map, package| {
1214
+ map. entry ( package. version ( ) . to_owned ( ) )
1215
+ . or_insert_with ( Vec :: new)
1216
+ . push ( package) ;
1217
+ map
1218
+ } ) ;
1219
+
1220
+ version_map
1221
+ . into_iter ( )
1222
+ . flat_map ( |( version, packages) | {
1223
+ // For package name with duplicates but unique version
1224
+ if packages. len ( ) == 1 {
1225
+ return vec ! [ clap_complete:: CompletionCandidate :: new( format!(
1226
+ "{}@{}" ,
1227
+ name, version
1228
+ ) )
1229
+ . help(
1230
+ packages[ 0 ]
1231
+ . manifest( )
1232
+ . metadata( )
1233
+ . description
1234
+ . to_owned( )
1235
+ . map( From :: from) ,
1236
+ ) ] ;
1237
+ }
1238
+
1239
+ // For package name with duplicates and duplicate version
1240
+ packages
1241
+ . into_iter ( )
1242
+ . map ( |package| {
1243
+ clap_complete:: CompletionCandidate :: new ( format ! (
1244
+ "{}" ,
1245
+ package. package_id( ) . to_spec( )
1246
+ ) )
1247
+ . help (
1248
+ package
1249
+ . manifest ( )
1250
+ . metadata ( )
1251
+ . description
1252
+ . to_owned ( )
1253
+ . map ( From :: from) ,
1254
+ )
1255
+ } )
1256
+ . collect :: < Vec < _ > > ( )
1257
+ } )
1258
+ . collect :: < Vec < _ > > ( )
1259
+ } )
1260
+ . collect :: < Vec < _ > > ( )
1261
+ }
1262
+
1263
+ fn get_packages ( ) -> CargoResult < Vec < Package > > {
1264
+ let cwd = std:: env:: current_dir ( ) ?;
1265
+ let mut gctx = GlobalContext :: new ( shell:: Shell :: new ( ) , cwd. clone ( ) , cargo_home_with_cwd ( & cwd) ?) ;
1266
+ gctx. configure ( 0 , true , None , false , true , false , & None , & [ ] , & [ ] ) ?;
1267
+ let ws = Workspace :: new ( & find_root_manifest_for_wd ( & cwd) ?, & gctx) ?;
1268
+
1269
+ let requested_kinds = CompileKind :: from_requested_targets ( ws. gctx ( ) , & [ ] ) ?;
1270
+ let mut target_data = RustcTargetData :: new ( & ws, & requested_kinds) ?;
1271
+ // `cli_features.all_features` must be true in case that `specs` is empty.
1272
+ let cli_features = CliFeatures :: new_all ( true ) ;
1273
+ let has_dev_units = HasDevUnits :: Yes ;
1274
+ let force_all_targets = ForceAllTargets :: No ;
1275
+ let dry_run = true ;
1276
+
1277
+ let ws_resolve = ops:: resolve_ws_with_opts (
1278
+ & ws,
1279
+ & mut target_data,
1280
+ & requested_kinds,
1281
+ & cli_features,
1282
+ & [ ] ,
1283
+ has_dev_units,
1284
+ force_all_targets,
1285
+ dry_run,
1286
+ ) ?;
1287
+
1288
+ let packages = ws_resolve
1289
+ . pkg_set
1290
+ . packages ( )
1291
+ . map ( Clone :: clone)
1292
+ . collect :: < Vec < _ > > ( ) ;
1293
+
1294
+ Ok ( packages)
1295
+ }
1296
+
1177
1297
#[ track_caller]
1178
1298
pub fn ignore_unknown < T : Default > ( r : Result < T , clap:: parser:: MatchesError > ) -> T {
1179
1299
match r {
0 commit comments