1use std::ffi::OsString;
2
3use clap::{Parser, error::ErrorKind};
4
5use crate::cli::{Cli, MemoCommand, OutputMode};
6use crate::errors::AppError;
7
8pub fn run() -> i32 {
9 run_with_args(std::env::args_os())
10}
11
12pub fn run_with_args<I, T>(args: I) -> i32
13where
14 I: IntoIterator<Item = T>,
15 T: Into<OsString> + Clone,
16{
17 let cli = match Cli::try_parse_from(args) {
18 Ok(cli) => cli,
19 Err(err) => {
20 let kind = err.kind();
21 match kind {
22 ErrorKind::DisplayHelp | ErrorKind::DisplayVersion => {
23 print!("{err}");
24 return 0;
25 }
26 _ => {
27 eprint!("{err}");
28 return 64;
29 }
30 }
31 }
32 };
33
34 if let MemoCommand::Completion(args) = cli.command {
35 return crate::completion::run(args.shell);
36 }
37
38 let output_mode = match cli.resolve_output_mode() {
39 Ok(mode) => mode,
40 Err(err) => {
41 eprintln!("{}", err.message());
42 return err.exit_code();
43 }
44 };
45
46 match crate::commands::run(&cli, output_mode) {
47 Ok(()) => 0,
48 Err(err) => report_error(&cli, output_mode, &err),
49 }
50}
51
52fn report_error(cli: &Cli, output_mode: OutputMode, err: &AppError) -> i32 {
53 if output_mode.is_json()
54 && let Err(output_err) =
55 crate::output::emit_json_error(cli.schema_version(), cli.command_id(), err)
56 {
57 eprintln!("{}", output_err.message());
58 }
59
60 if !output_mode.is_json() {
61 eprintln!("{}", err.message());
62 }
63
64 err.exit_code()
65}