11use  crate :: core:: compiler:: { BuildConfig ,  MessageFormat ,  TimingOutput } ; 
22use  crate :: core:: resolver:: CliFeatures ; 
3- use  crate :: core:: { Edition ,  Workspace } ; 
3+ use  crate :: core:: { shell ,   Edition ,  Workspace } ; 
44use  crate :: ops:: lockfile:: LOCKFILE_NAME ; 
55use  crate :: ops:: registry:: RegistryOrIndex ; 
66use  crate :: ops:: { CompileFilter ,  CompileOptions ,  NewOptions ,  Packages ,  VersionControl } ; 
@@ -19,6 +19,7 @@ use cargo_util_schemas::manifest::ProfileName;
1919use  cargo_util_schemas:: manifest:: RegistryName ; 
2020use  cargo_util_schemas:: manifest:: StringOrVec ; 
2121use  clap:: builder:: UnknownArgumentValueParser ; 
22+ use  home:: cargo_home_with_cwd; 
2223use  std:: ffi:: { OsStr ,  OsString } ; 
2324use  std:: path:: Path ; 
2425use  std:: path:: PathBuf ; 
@@ -261,7 +262,8 @@ pub trait CommandExt: Sized {
261262        } ; 
262263        self . _arg ( 
263264            optional_multi_opt ( "target" ,  "TRIPLE" ,  target) 
264-                 . help_heading ( heading:: COMPILATION_OPTIONS ) , 
265+                 . help_heading ( heading:: COMPILATION_OPTIONS ) 
266+                 . add ( clap_complete:: ArgValueCandidates :: new ( get_target_triple) ) , 
265267        ) 
266268        . _arg ( unsupported_short_arg) 
267269    } 
@@ -1027,6 +1029,63 @@ pub fn lockfile_path(
10271029    return  Ok ( Some ( path) ) ; 
10281030} 
10291031
1032+ fn  get_target_triple ( )  -> Vec < clap_complete:: CompletionCandidate >  { 
1033+     let  mut  candidates = Vec :: new ( ) ; 
1034+ 
1035+     if  is_rustup ( )  { 
1036+         if  let  Ok ( targets)  = get_targets_from_rustup ( )  { 
1037+             for  ( target,  installed)  in  targets { 
1038+                 candidates. push ( clap_complete:: CompletionCandidate :: new ( target) . hide ( !installed) ) ; 
1039+             } 
1040+         } 
1041+     }  else  { 
1042+         if  let  Ok ( targets)  = get_target_from_rustc ( )  { 
1043+             for  target in  targets { 
1044+                 candidates. push ( clap_complete:: CompletionCandidate :: new ( target) ) ; 
1045+             } 
1046+         } 
1047+     } 
1048+ 
1049+     candidates
1050+ } 
1051+ 
1052+ // Return `(String, bool)`` where the bool is true if the target is installed 
1053+ fn  get_targets_from_rustup ( )  -> CargoResult < Vec < ( String ,  bool ) > >  { 
1054+     let  output = std:: process:: Command :: new ( "rustup" ) 
1055+         . arg ( "target" ) 
1056+         . arg ( "list" ) 
1057+         . output ( ) ?; 
1058+ 
1059+     if  !output. status . success ( )  { 
1060+         return  Ok ( vec ! [ ] ) ; 
1061+     } 
1062+ 
1063+     let  stdout = String :: from_utf8 ( output. stdout ) ?; 
1064+ 
1065+     Ok ( stdout
1066+         . lines ( ) 
1067+         . map ( |line| { 
1068+             let  target = line. split_once ( ' ' ) ; 
1069+             match  target { 
1070+                 None  => ( line. to_owned ( ) ,  false ) , 
1071+                 Some ( ( target,  _installed) )  => ( target. to_owned ( ) ,  true ) , 
1072+             } 
1073+         } ) 
1074+         . collect ( ) ) 
1075+ } 
1076+ 
1077+ fn  get_target_from_rustc ( )  -> CargoResult < Vec < String > >  { 
1078+     let  cwd = std:: env:: current_dir ( ) ?; 
1079+     let  gctx = GlobalContext :: new ( shell:: Shell :: new ( ) ,  cwd. clone ( ) ,  cargo_home_with_cwd ( & cwd) ?) ; 
1080+     let  ws = Workspace :: new ( & find_root_manifest_for_wd ( & PathBuf :: from ( "." ) ) ?,  & gctx) ?; 
1081+ 
1082+     let  rustc = gctx. load_global_rustc ( Some ( & ws) ) ?; 
1083+     let  ( stdout,  _stderr)  =
1084+         rustc. cached_output ( rustc. process ( ) . arg ( "--print" ) . arg ( "target-list" ) ,  0 ) ?; 
1085+ 
1086+     Ok ( stdout. lines ( ) . map ( |line| line. to_owned ( ) ) . collect ( ) ) 
1087+ } 
1088+ 
10301089#[ track_caller]  
10311090pub  fn  ignore_unknown < T :  Default > ( r :  Result < T ,  clap:: parser:: MatchesError > )  -> T  { 
10321091    match  r { 
0 commit comments