@@ -9,10 +9,12 @@ use rustup::dist::manifest::Component;
99use rustup:: utils:: utils:: { self , ExitCode } ;
1010use rustup:: { command, Cfg , Toolchain } ;
1111use std:: error:: Error ;
12- use std:: io:: { self , Write } ;
12+ use std:: fmt;
13+ use std:: io:: Write ;
1314use std:: iter;
1415use std:: path:: Path ;
1516use std:: process:: { self , Command } ;
17+ use std:: str:: FromStr ;
1618
1719fn handle_epipe ( res : Result < ( ) > ) -> Result < ( ) > {
1820 match res {
@@ -85,11 +87,12 @@ pub fn main() -> Result<()> {
8587 } ,
8688 ( "completions" , Some ( c) ) => {
8789 if let Some ( shell) = c. value_of ( "shell" ) {
88- cli ( ) . gen_completions_to (
89- "rustup" ,
90+ output_completion_script (
9091 shell. parse :: < Shell > ( ) . unwrap ( ) ,
91- & mut io:: stdout ( ) ,
92- ) ;
92+ c. value_of ( "command" )
93+ . and_then ( |cmd| cmd. parse :: < CompletionCommand > ( ) . ok ( ) )
94+ . unwrap_or ( CompletionCommand :: Rustup ) ,
95+ ) ?;
9396 }
9497 }
9598 ( _, _) => unreachable ! ( ) ,
@@ -442,40 +445,98 @@ pub fn cli() -> App<'static, 'static> {
442445 ) ;
443446 }
444447
448+ app = app
449+ . subcommand (
450+ SubCommand :: with_name ( "self" )
451+ . about ( "Modify the rustup installation" )
452+ . setting ( AppSettings :: VersionlessSubcommands )
453+ . setting ( AppSettings :: DeriveDisplayOrder )
454+ . setting ( AppSettings :: SubcommandRequiredElseHelp )
455+ . subcommand (
456+ SubCommand :: with_name ( "update" ) . about ( "Download and install updates to rustup" ) ,
457+ )
458+ . subcommand (
459+ SubCommand :: with_name ( "uninstall" )
460+ . about ( "Uninstall rustup." )
461+ . arg ( Arg :: with_name ( "no-prompt" ) . short ( "y" ) ) ,
462+ )
463+ . subcommand (
464+ SubCommand :: with_name ( "upgrade-data" )
465+ . about ( "Upgrade the internal data format." ) ,
466+ ) ,
467+ )
468+ . subcommand (
469+ SubCommand :: with_name ( "set" )
470+ . about ( "Alter rustup settings" )
471+ . setting ( AppSettings :: SubcommandRequiredElseHelp )
472+ . subcommand (
473+ SubCommand :: with_name ( "default-host" )
474+ . about ( "The triple used to identify toolchains when not specified" )
475+ . arg ( Arg :: with_name ( "host_triple" ) . required ( true ) ) ,
476+ ) ,
477+ )
478+ . subcommand (
479+ SubCommand :: with_name ( "self" )
480+ . about ( "Modify the rustup installation" )
481+ . setting ( AppSettings :: VersionlessSubcommands )
482+ . setting ( AppSettings :: DeriveDisplayOrder )
483+ . setting ( AppSettings :: SubcommandRequiredElseHelp )
484+ . subcommand (
485+ SubCommand :: with_name ( "update" ) . about ( "Download and install updates to rustup" ) ,
486+ )
487+ . subcommand (
488+ SubCommand :: with_name ( "uninstall" )
489+ . about ( "Uninstall rustup." )
490+ . arg ( Arg :: with_name ( "no-prompt" ) . short ( "y" ) ) ,
491+ )
492+ . subcommand (
493+ SubCommand :: with_name ( "upgrade-data" )
494+ . about ( "Upgrade the internal data format." ) ,
495+ ) ,
496+ )
497+ . subcommand (
498+ SubCommand :: with_name ( "telemetry" )
499+ . about ( "rustup telemetry commands" )
500+ . setting ( AppSettings :: Hidden )
501+ . setting ( AppSettings :: VersionlessSubcommands )
502+ . setting ( AppSettings :: DeriveDisplayOrder )
503+ . setting ( AppSettings :: SubcommandRequiredElseHelp )
504+ . subcommand ( SubCommand :: with_name ( "enable" ) . about ( "Enable rustup telemetry" ) )
505+ . subcommand ( SubCommand :: with_name ( "disable" ) . about ( "Disable rustup telemetry" ) )
506+ . subcommand ( SubCommand :: with_name ( "analyze" ) . about ( "Analyze stored telemetry" ) ) ,
507+ )
508+ . subcommand (
509+ SubCommand :: with_name ( "set" )
510+ . about ( "Alter rustup settings" )
511+ . setting ( AppSettings :: SubcommandRequiredElseHelp )
512+ . subcommand (
513+ SubCommand :: with_name ( "default-host" )
514+ . about ( "The triple used to identify toolchains when not specified" )
515+ . arg ( Arg :: with_name ( "host_triple" ) . required ( true ) ) ,
516+ ) ,
517+ ) ;
518+
519+ // Clap provides no good way to say that help should be printed in all
520+ // cases where an argument without a default is not provided. The following
521+ // creates lists out all the conditions where the "shell" argument are
522+ // provided and give the default of "rustup". This way if "shell" is not
523+ // provided then the help will still be printed.
524+ let completion_defaults = Shell :: variants ( )
525+ . iter ( )
526+ . map ( |& shell| ( "shell" , Some ( shell) , "rustup" ) )
527+ . collect :: < Vec < _ > > ( ) ;
528+
445529 app. subcommand (
446- SubCommand :: with_name ( "self" )
447- . about ( "Modify the rustup installation" )
448- . setting ( AppSettings :: VersionlessSubcommands )
449- . setting ( AppSettings :: DeriveDisplayOrder )
450- . setting ( AppSettings :: SubcommandRequiredElseHelp )
451- . subcommand (
452- SubCommand :: with_name ( "update" ) . about ( "Download and install updates to rustup" ) ,
453- )
454- . subcommand (
455- SubCommand :: with_name ( "uninstall" )
456- . about ( "Uninstall rustup." )
457- . arg ( Arg :: with_name ( "no-prompt" ) . short ( "y" ) ) ,
458- )
459- . subcommand (
460- SubCommand :: with_name ( "upgrade-data" ) . about ( "Upgrade the internal data format." ) ,
461- ) ,
462- )
463- . subcommand (
464- SubCommand :: with_name ( "set" )
465- . about ( "Alter rustup settings" )
466- . setting ( AppSettings :: SubcommandRequiredElseHelp )
467- . subcommand (
468- SubCommand :: with_name ( "default-host" )
469- . about ( "The triple used to identify toolchains when not specified" )
470- . arg ( Arg :: with_name ( "host_triple" ) . required ( true ) ) ,
471- ) ,
472- )
473- . subcommand (
474530 SubCommand :: with_name ( "completions" )
475531 . about ( "Generate completion scripts for your shell" )
476532 . after_help ( COMPLETIONS_HELP )
477533 . setting ( AppSettings :: ArgRequiredElseHelp )
478- . arg ( Arg :: with_name ( "shell" ) . possible_values ( & Shell :: variants ( ) ) ) ,
534+ . arg ( Arg :: with_name ( "shell" ) . possible_values ( & Shell :: variants ( ) ) )
535+ . arg (
536+ Arg :: with_name ( "command" )
537+ . possible_values ( & CompletionCommand :: variants ( ) )
538+ . default_value_ifs ( & completion_defaults[ ..] ) ,
539+ ) ,
479540 )
480541}
481542
@@ -1056,3 +1117,76 @@ fn set_default_host_triple(cfg: &Cfg, m: &ArgMatches<'_>) -> Result<()> {
10561117 cfg. set_default_host_triple ( m. value_of ( "host_triple" ) . expect ( "" ) ) ?;
10571118 Ok ( ( ) )
10581119}
1120+
1121+ #[ derive( Copy , Clone , Debug , PartialEq ) ]
1122+ pub enum CompletionCommand {
1123+ Rustup ,
1124+ Cargo ,
1125+ }
1126+
1127+ static COMPLETIONS : & [ ( & ' static str , CompletionCommand ) ] = & [
1128+ ( "rustup" , CompletionCommand :: Rustup ) ,
1129+ ( "cargo" , CompletionCommand :: Cargo ) ,
1130+ ] ;
1131+
1132+ impl CompletionCommand {
1133+ fn variants ( ) -> Vec < & ' static str > {
1134+ COMPLETIONS . iter ( ) . map ( |& ( s, _) | s) . collect :: < Vec < _ > > ( )
1135+ }
1136+ }
1137+
1138+ impl FromStr for CompletionCommand {
1139+ type Err = String ;
1140+
1141+ fn from_str ( s : & str ) -> std:: result:: Result < Self , Self :: Err > {
1142+ match COMPLETIONS
1143+ . iter ( )
1144+ . filter ( |& ( val, _) | val. eq_ignore_ascii_case ( s) )
1145+ . next ( )
1146+ {
1147+ Some ( & ( _, cmd) ) => Ok ( cmd) ,
1148+ None => {
1149+ let completion_options = COMPLETIONS
1150+ . iter ( )
1151+ . map ( |& ( v, _) | v)
1152+ . fold ( "" . to_owned ( ) , |s, v| format ! ( "{}{}, " , s, v) ) ;
1153+ Err ( format ! (
1154+ "[valid values: {}]" ,
1155+ completion_options. trim_end_matches( ", " )
1156+ ) )
1157+ }
1158+ }
1159+ }
1160+ }
1161+
1162+ impl fmt:: Display for CompletionCommand {
1163+ fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
1164+ match COMPLETIONS . iter ( ) . filter ( |& ( _, cmd) | cmd == self ) . next ( ) {
1165+ Some ( & ( val, _) ) => write ! ( f, "{}" , val) ,
1166+ None => unreachable ! ( ) ,
1167+ }
1168+ }
1169+ }
1170+
1171+ fn output_completion_script ( shell : Shell , command : CompletionCommand ) -> Result < ( ) > {
1172+ match command {
1173+ CompletionCommand :: Rustup => {
1174+ cli ( ) . gen_completions_to ( "rustup" , shell, & mut term2:: stdout ( ) ) ;
1175+ }
1176+ CompletionCommand :: Cargo => {
1177+ let script = match shell {
1178+ Shell :: Bash => "/etc/bash_completion.d/cargo" ,
1179+ Shell :: Zsh => "/share/zsh/site-functions/_cargo" ,
1180+ _ => return Err ( ErrorKind :: UnsupportedCompletionShell ( shell, command) . into ( ) ) ,
1181+ } ;
1182+
1183+ writeln ! (
1184+ & mut term2:: stdout( ) ,
1185+ "source $(rustc --print sysroot){}" ,
1186+ script,
1187+ ) ?;
1188+ }
1189+ }
1190+
1191+ Ok ( ( ) )
1192+ }
0 commit comments