1use std::io::{Write, stderr, stdout};
4
5use clap::{Arg, ArgAction, ArgMatches, Command, command};
6use serde_json::json;
7
8use crate::config::Config;
9use crate::subcommands;
10
11pub fn get_clap_app() -> Command {
13 command!()
14 .arg(
15 Arg::new("verbose")
16 .short('v')
17 .long("verbose")
18 .action(ArgAction::SetTrue)
19 .global(true)
20 .help("Enable verbose mode."),
21 )
22 .arg(
23 Arg::new("json")
24 .short('j')
25 .long("json")
26 .action(ArgAction::SetTrue)
27 .global(true)
28 .help("Output subcommand results in JSON."),
29 )
30 .arg(
31 Arg::new("untracked")
32 .short('u')
33 .long("untracked")
34 .action(ArgAction::SetTrue)
35 .conflicts_with("nountracked")
36 .global(true)
37 .help("Show untracked files in output."),
38 )
39 .arg(
40 Arg::new("nountracked")
41 .short('t')
42 .long("nountracked")
43 .action(ArgAction::SetTrue)
44 .conflicts_with("untracked")
45 .global(true)
46 .help("Don't show untracked files in output."),
47 )
48 .subcommands(
49 subcommands::get_subcommands()
50 .iter()
51 .map(|(cmd, desc)| {
52 let mut subcmd = Command::new(*cmd).about(*desc);
53 if *cmd == "ignore" {
54 subcmd = subcmd.arg(
55 Arg::new("pattern")
56 .help("Pattern to add to global.ignore (matches paths containing this string)")
57 .required(true)
58 .index(1),
59 );
60 }
61 subcmd
62 }),
63 )
64}
65
66fn merge_args_with_config(config: &mut Config, matches: &ArgMatches) {
68 if matches.get_flag("verbose") {
69 config.verbose = true;
70 }
71 if matches.get_flag("untracked") {
72 config.show_untracked = true;
73 }
74 if matches.get_flag("nountracked") {
75 config.show_untracked = false;
76 }
77}
78
79pub fn run_from_command_line() -> i32 {
84 let clap_app = get_clap_app();
85 let matches = clap_app.get_matches();
86 let mut config = Config::new();
87 merge_args_with_config(&mut config, &matches);
88
89 let args = matches.subcommand().and_then(|(name, sub_matches)| {
91 if name == "ignore" {
92 sub_matches.get_one::<String>("pattern").map(|s| s.as_str())
93 } else {
94 None
95 }
96 });
97
98 let report = subcommands::run(matches.subcommand_name(), config, args);
99 let use_json = matches.get_flag("json");
100 match report {
101 Ok(rep) => {
102 if use_json {
103 rep.print_json(&mut stdout());
104 } else {
105 rep.print(&mut stdout());
106 }
107 0
108 }
109 Err(err) => {
110 if use_json {
111 let out = json!({
112 "error": true,
113 "message": format!("{}", err)
114 });
115 writeln!(&mut stderr(), "{:#}", out).unwrap();
116 } else {
117 writeln!(&mut stderr(), "{}", err).unwrap();
118 }
119 1
120 }
121 }
122}