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,155 @@ fn get_target_triples_from_rustc() -> CargoResult<Vec<clap_complete::CompletionC
11741178 . collect ( ) )
11751179}
11761180
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+
11771330#[ track_caller]
11781331pub fn ignore_unknown < T : Default > ( r : Result < T , clap:: parser:: MatchesError > ) -> T {
11791332 match r {
0 commit comments