• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use std::ffi::OsString;
2 use std::path::PathBuf;
3 
4 use clap::{arg, Command};
5 
cli() -> Command6 fn cli() -> Command {
7     Command::new("git")
8         .about("A fictional versioning CLI")
9         .subcommand_required(true)
10         .arg_required_else_help(true)
11         .allow_external_subcommands(true)
12         .subcommand(
13             Command::new("clone")
14                 .about("Clones repos")
15                 .arg(arg!(<REMOTE> "The remote to clone"))
16                 .arg_required_else_help(true),
17         )
18         .subcommand(
19             Command::new("diff")
20                 .about("Compare two commits")
21                 .arg(arg!(base: [COMMIT]))
22                 .arg(arg!(head: [COMMIT]))
23                 .arg(arg!(path: [PATH]).last(true))
24                 .arg(
25                     arg!(--color <WHEN>)
26                         .value_parser(["always", "auto", "never"])
27                         .num_args(0..=1)
28                         .require_equals(true)
29                         .default_value("auto")
30                         .default_missing_value("always"),
31                 ),
32         )
33         .subcommand(
34             Command::new("push")
35                 .about("pushes things")
36                 .arg(arg!(<REMOTE> "The remote to target"))
37                 .arg_required_else_help(true),
38         )
39         .subcommand(
40             Command::new("add")
41                 .about("adds things")
42                 .arg_required_else_help(true)
43                 .arg(arg!(<PATH> ... "Stuff to add").value_parser(clap::value_parser!(PathBuf))),
44         )
45         .subcommand(
46             Command::new("stash")
47                 .args_conflicts_with_subcommands(true)
48                 .args(push_args())
49                 .subcommand(Command::new("push").args(push_args()))
50                 .subcommand(Command::new("pop").arg(arg!([STASH])))
51                 .subcommand(Command::new("apply").arg(arg!([STASH]))),
52         )
53 }
54 
push_args() -> Vec<clap::Arg>55 fn push_args() -> Vec<clap::Arg> {
56     vec![arg!(-m --message <MESSAGE>)]
57 }
58 
main()59 fn main() {
60     let matches = cli().get_matches();
61 
62     match matches.subcommand() {
63         Some(("clone", sub_matches)) => {
64             println!(
65                 "Cloning {}",
66                 sub_matches.get_one::<String>("REMOTE").expect("required")
67             );
68         }
69         Some(("diff", sub_matches)) => {
70             let color = sub_matches
71                 .get_one::<String>("color")
72                 .map(|s| s.as_str())
73                 .expect("defaulted in clap");
74 
75             let mut base = sub_matches.get_one::<String>("base").map(|s| s.as_str());
76             let mut head = sub_matches.get_one::<String>("head").map(|s| s.as_str());
77             let mut path = sub_matches.get_one::<String>("path").map(|s| s.as_str());
78             if path.is_none() {
79                 path = head;
80                 head = None;
81                 if path.is_none() {
82                     path = base;
83                     base = None;
84                 }
85             }
86             let base = base.unwrap_or("stage");
87             let head = head.unwrap_or("worktree");
88             let path = path.unwrap_or("");
89             println!("Diffing {base}..{head} {path} (color={color})");
90         }
91         Some(("push", sub_matches)) => {
92             println!(
93                 "Pushing to {}",
94                 sub_matches.get_one::<String>("REMOTE").expect("required")
95             );
96         }
97         Some(("add", sub_matches)) => {
98             let paths = sub_matches
99                 .get_many::<PathBuf>("PATH")
100                 .into_iter()
101                 .flatten()
102                 .collect::<Vec<_>>();
103             println!("Adding {paths:?}");
104         }
105         Some(("stash", sub_matches)) => {
106             let stash_command = sub_matches.subcommand().unwrap_or(("push", sub_matches));
107             match stash_command {
108                 ("apply", sub_matches) => {
109                     let stash = sub_matches.get_one::<String>("STASH");
110                     println!("Applying {stash:?}");
111                 }
112                 ("pop", sub_matches) => {
113                     let stash = sub_matches.get_one::<String>("STASH");
114                     println!("Popping {stash:?}");
115                 }
116                 ("push", sub_matches) => {
117                     let message = sub_matches.get_one::<String>("message");
118                     println!("Pushing {message:?}");
119                 }
120                 (name, _) => {
121                     unreachable!("Unsupported subcommand `{}`", name)
122                 }
123             }
124         }
125         Some((ext, sub_matches)) => {
126             let args = sub_matches
127                 .get_many::<OsString>("")
128                 .into_iter()
129                 .flatten()
130                 .collect::<Vec<_>>();
131             println!("Calling out to {ext:?} with {args:?}");
132         }
133         _ => unreachable!(), // If all subcommands are defined above, anything else is unreachable!()
134     }
135 
136     // Continued program logic goes here...
137 }
138