119625d8cSopenharmony_ciuse std::ffi::OsStr; 219625d8cSopenharmony_ciuse std::ffi::OsString; 319625d8cSopenharmony_ciuse std::path::PathBuf; 419625d8cSopenharmony_ci 519625d8cSopenharmony_ciuse clap::{Args, Parser, Subcommand, ValueEnum}; 619625d8cSopenharmony_ci 719625d8cSopenharmony_ci/// A fictional versioning CLI 819625d8cSopenharmony_ci#[derive(Debug, Parser)] // requires `derive` feature 919625d8cSopenharmony_ci#[command(name = "git")] 1019625d8cSopenharmony_ci#[command(about = "A fictional versioning CLI", long_about = None)] 1119625d8cSopenharmony_cistruct Cli { 1219625d8cSopenharmony_ci #[command(subcommand)] 1319625d8cSopenharmony_ci command: Commands, 1419625d8cSopenharmony_ci} 1519625d8cSopenharmony_ci 1619625d8cSopenharmony_ci#[derive(Debug, Subcommand)] 1719625d8cSopenharmony_cienum Commands { 1819625d8cSopenharmony_ci /// Clones repos 1919625d8cSopenharmony_ci #[command(arg_required_else_help = true)] 2019625d8cSopenharmony_ci Clone { 2119625d8cSopenharmony_ci /// The remote to clone 2219625d8cSopenharmony_ci remote: String, 2319625d8cSopenharmony_ci }, 2419625d8cSopenharmony_ci /// Compare two commits 2519625d8cSopenharmony_ci Diff { 2619625d8cSopenharmony_ci #[arg(value_name = "COMMIT")] 2719625d8cSopenharmony_ci base: Option<OsString>, 2819625d8cSopenharmony_ci #[arg(value_name = "COMMIT")] 2919625d8cSopenharmony_ci head: Option<OsString>, 3019625d8cSopenharmony_ci #[arg(last = true)] 3119625d8cSopenharmony_ci path: Option<OsString>, 3219625d8cSopenharmony_ci #[arg( 3319625d8cSopenharmony_ci long, 3419625d8cSopenharmony_ci require_equals = true, 3519625d8cSopenharmony_ci value_name = "WHEN", 3619625d8cSopenharmony_ci num_args = 0..=1, 3719625d8cSopenharmony_ci default_value_t = ColorWhen::Auto, 3819625d8cSopenharmony_ci default_missing_value = "always", 3919625d8cSopenharmony_ci value_enum 4019625d8cSopenharmony_ci )] 4119625d8cSopenharmony_ci color: ColorWhen, 4219625d8cSopenharmony_ci }, 4319625d8cSopenharmony_ci /// pushes things 4419625d8cSopenharmony_ci #[command(arg_required_else_help = true)] 4519625d8cSopenharmony_ci Push { 4619625d8cSopenharmony_ci /// The remote to target 4719625d8cSopenharmony_ci remote: String, 4819625d8cSopenharmony_ci }, 4919625d8cSopenharmony_ci /// adds things 5019625d8cSopenharmony_ci #[command(arg_required_else_help = true)] 5119625d8cSopenharmony_ci Add { 5219625d8cSopenharmony_ci /// Stuff to add 5319625d8cSopenharmony_ci #[arg(required = true)] 5419625d8cSopenharmony_ci path: Vec<PathBuf>, 5519625d8cSopenharmony_ci }, 5619625d8cSopenharmony_ci Stash(StashArgs), 5719625d8cSopenharmony_ci #[command(external_subcommand)] 5819625d8cSopenharmony_ci External(Vec<OsString>), 5919625d8cSopenharmony_ci} 6019625d8cSopenharmony_ci 6119625d8cSopenharmony_ci#[derive(ValueEnum, Copy, Clone, Debug, PartialEq, Eq)] 6219625d8cSopenharmony_cienum ColorWhen { 6319625d8cSopenharmony_ci Always, 6419625d8cSopenharmony_ci Auto, 6519625d8cSopenharmony_ci Never, 6619625d8cSopenharmony_ci} 6719625d8cSopenharmony_ci 6819625d8cSopenharmony_ciimpl std::fmt::Display for ColorWhen { 6919625d8cSopenharmony_ci fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 7019625d8cSopenharmony_ci self.to_possible_value() 7119625d8cSopenharmony_ci .expect("no values are skipped") 7219625d8cSopenharmony_ci .get_name() 7319625d8cSopenharmony_ci .fmt(f) 7419625d8cSopenharmony_ci } 7519625d8cSopenharmony_ci} 7619625d8cSopenharmony_ci 7719625d8cSopenharmony_ci#[derive(Debug, Args)] 7819625d8cSopenharmony_ci#[command(args_conflicts_with_subcommands = true)] 7919625d8cSopenharmony_cistruct StashArgs { 8019625d8cSopenharmony_ci #[command(subcommand)] 8119625d8cSopenharmony_ci command: Option<StashCommands>, 8219625d8cSopenharmony_ci 8319625d8cSopenharmony_ci #[command(flatten)] 8419625d8cSopenharmony_ci push: StashPushArgs, 8519625d8cSopenharmony_ci} 8619625d8cSopenharmony_ci 8719625d8cSopenharmony_ci#[derive(Debug, Subcommand)] 8819625d8cSopenharmony_cienum StashCommands { 8919625d8cSopenharmony_ci Push(StashPushArgs), 9019625d8cSopenharmony_ci Pop { stash: Option<String> }, 9119625d8cSopenharmony_ci Apply { stash: Option<String> }, 9219625d8cSopenharmony_ci} 9319625d8cSopenharmony_ci 9419625d8cSopenharmony_ci#[derive(Debug, Args)] 9519625d8cSopenharmony_cistruct StashPushArgs { 9619625d8cSopenharmony_ci #[arg(short, long)] 9719625d8cSopenharmony_ci message: Option<String>, 9819625d8cSopenharmony_ci} 9919625d8cSopenharmony_ci 10019625d8cSopenharmony_cifn main() { 10119625d8cSopenharmony_ci let args = Cli::parse(); 10219625d8cSopenharmony_ci 10319625d8cSopenharmony_ci match args.command { 10419625d8cSopenharmony_ci Commands::Clone { remote } => { 10519625d8cSopenharmony_ci println!("Cloning {remote}"); 10619625d8cSopenharmony_ci } 10719625d8cSopenharmony_ci Commands::Diff { 10819625d8cSopenharmony_ci mut base, 10919625d8cSopenharmony_ci mut head, 11019625d8cSopenharmony_ci mut path, 11119625d8cSopenharmony_ci color, 11219625d8cSopenharmony_ci } => { 11319625d8cSopenharmony_ci if path.is_none() { 11419625d8cSopenharmony_ci path = head; 11519625d8cSopenharmony_ci head = None; 11619625d8cSopenharmony_ci if path.is_none() { 11719625d8cSopenharmony_ci path = base; 11819625d8cSopenharmony_ci base = None; 11919625d8cSopenharmony_ci } 12019625d8cSopenharmony_ci } 12119625d8cSopenharmony_ci let base = base 12219625d8cSopenharmony_ci .as_deref() 12319625d8cSopenharmony_ci .map(|s| s.to_str().unwrap()) 12419625d8cSopenharmony_ci .unwrap_or("stage"); 12519625d8cSopenharmony_ci let head = head 12619625d8cSopenharmony_ci .as_deref() 12719625d8cSopenharmony_ci .map(|s| s.to_str().unwrap()) 12819625d8cSopenharmony_ci .unwrap_or("worktree"); 12919625d8cSopenharmony_ci let path = path.as_deref().unwrap_or_else(|| OsStr::new("")); 13019625d8cSopenharmony_ci println!( 13119625d8cSopenharmony_ci "Diffing {}..{} {} (color={})", 13219625d8cSopenharmony_ci base, 13319625d8cSopenharmony_ci head, 13419625d8cSopenharmony_ci path.to_string_lossy(), 13519625d8cSopenharmony_ci color 13619625d8cSopenharmony_ci ); 13719625d8cSopenharmony_ci } 13819625d8cSopenharmony_ci Commands::Push { remote } => { 13919625d8cSopenharmony_ci println!("Pushing to {remote}"); 14019625d8cSopenharmony_ci } 14119625d8cSopenharmony_ci Commands::Add { path } => { 14219625d8cSopenharmony_ci println!("Adding {path:?}"); 14319625d8cSopenharmony_ci } 14419625d8cSopenharmony_ci Commands::Stash(stash) => { 14519625d8cSopenharmony_ci let stash_cmd = stash.command.unwrap_or(StashCommands::Push(stash.push)); 14619625d8cSopenharmony_ci match stash_cmd { 14719625d8cSopenharmony_ci StashCommands::Push(push) => { 14819625d8cSopenharmony_ci println!("Pushing {push:?}"); 14919625d8cSopenharmony_ci } 15019625d8cSopenharmony_ci StashCommands::Pop { stash } => { 15119625d8cSopenharmony_ci println!("Popping {stash:?}"); 15219625d8cSopenharmony_ci } 15319625d8cSopenharmony_ci StashCommands::Apply { stash } => { 15419625d8cSopenharmony_ci println!("Applying {stash:?}"); 15519625d8cSopenharmony_ci } 15619625d8cSopenharmony_ci } 15719625d8cSopenharmony_ci } 15819625d8cSopenharmony_ci Commands::External(args) => { 15919625d8cSopenharmony_ci println!("Calling out to {:?} with {:?}", &args[0], &args[1..]); 16019625d8cSopenharmony_ci } 16119625d8cSopenharmony_ci } 16219625d8cSopenharmony_ci 16319625d8cSopenharmony_ci // Continued program logic goes here... 16419625d8cSopenharmony_ci} 165