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 } ;
46use crate :: ops:: lockfile:: LOCKFILE_NAME ;
57use crate :: ops:: registry:: RegistryOrIndex ;
6- use crate :: ops:: { CompileFilter , CompileOptions , NewOptions , Packages , VersionControl } ;
8+ use crate :: ops:: { self , CompileFilter , CompileOptions , NewOptions , Packages , VersionControl } ;
79use crate :: util:: important_paths:: find_root_manifest_for_wd;
810use crate :: util:: interning:: InternedString ;
911use crate :: util:: is_rustup;
@@ -20,6 +22,8 @@ use cargo_util_schemas::manifest::RegistryName;
2022use cargo_util_schemas:: manifest:: StringOrVec ;
2123use clap:: builder:: UnknownArgumentValueParser ;
2224use home:: cargo_home_with_cwd;
25+ use semver:: Version ;
26+ use std:: collections:: HashMap ;
2327use std:: ffi:: { OsStr , OsString } ;
2428use std:: path:: Path ;
2529use std:: path:: PathBuf ;
@@ -1174,6 +1178,122 @@ fn get_target_triples_from_rustc() -> CargoResult<Vec<clap_complete::CompletionC
11741178 . collect ( ) )
11751179}
11761180
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+
11771297#[ track_caller]
11781298pub fn ignore_unknown < T : Default > ( r : Result < T , clap:: parser:: MatchesError > ) -> T {
11791299 match r {
0 commit comments