1use std::path::PathBuf;
4
5use anyhow::Result;
6use clap::{Parser, Subcommand};
7
8use crate::commands;
9
10#[derive(Debug, Parser)]
12#[command(
13 version,
14 about,
15 long_about = None
16)]
17pub struct Cli {
18 #[command(subcommand)]
20 pub command: Option<Commands>,
21 #[arg(short = 'C', long = "repo", global = true, value_name = "PATH")]
23 pub repo: Option<PathBuf>,
24 #[arg(short, long, global = true)]
26 pub verbose: bool,
27 #[arg(long, global = true, value_enum, default_value = "auto")]
29 pub theme: ThemeArg,
30 #[arg(long, global = true, value_enum, default_value = "auto")]
32 pub lang: LangArg,
33}
34
35#[derive(Debug, Clone, Copy, PartialEq, Eq, clap::ValueEnum, serde::Deserialize)]
37#[serde(rename_all = "lowercase")]
38pub enum LangArg {
39 Auto,
41 Zh,
43 En,
45}
46
47#[derive(Debug, Clone, Copy, PartialEq, Eq, clap::ValueEnum, serde::Deserialize)]
49#[serde(rename_all = "lowercase")]
50pub enum ThemeArg {
51 Auto,
53 Dark,
55 Light,
57}
58
59#[derive(Debug, Subcommand)]
61pub enum Commands {
62 Merge(commands::run::MergeArgs),
64 Rebase(commands::run::RebaseArgs),
66 Pull(commands::run::PullArgs),
68 CherryPick(commands::run::CherryPickArgs),
70 Revert(commands::run::RevertArgs),
72 File(commands::file::FileArgs),
74 Abort,
76 Completions(commands::completions::CompletionsArgs),
78}
79
80impl Cli {
81 pub fn run(self) -> Result<()> {
83 if let Some(Commands::Completions(args)) = &self.command {
86 commands::completions::run(args.shell);
87 return Ok(());
88 }
89 match self.lang {
92 LangArg::Zh => crate::i18n::init(crate::i18n::Lang::Zh),
93 LangArg::En => crate::i18n::init(crate::i18n::Lang::En),
94 LangArg::Auto => {}
95 }
96 let config = crate::config::load()?;
97 crate::i18n::init(match config.ui.lang {
98 Some(LangArg::Zh) => crate::i18n::Lang::Zh,
99 Some(LangArg::En) => crate::i18n::Lang::En,
100 _ => crate::i18n::detect(),
101 });
102 crate::ui::keymap::init(&config.keys)?;
103 crate::ui::init_theme_overrides(&config.theme)?;
104 crate::ui::init_editor(config.ui.editor.clone());
105
106 let verbose = self.verbose || config.ui.verbose.unwrap_or(false);
107 let dir = self.repo.unwrap_or_else(|| PathBuf::from("."));
108 let theme = match self.theme {
110 ThemeArg::Auto => config.ui.theme.unwrap_or(ThemeArg::Auto),
111 explicit => explicit,
112 };
113 let light = match theme {
114 ThemeArg::Light => true,
115 ThemeArg::Dark => false,
116 ThemeArg::Auto => crate::ui::detect_light(),
117 };
118 match self.command {
119 None => commands::menu::run(verbose, &dir, light),
120 Some(Commands::Merge(args)) => commands::run::merge(args, verbose, &dir, light),
121 Some(Commands::Rebase(args)) => commands::run::rebase(args, verbose, &dir, light),
122 Some(Commands::Pull(args)) => commands::run::pull(args, verbose, &dir, light),
123 Some(Commands::CherryPick(args)) => {
124 commands::run::cherry_pick(args, verbose, &dir, light)
125 }
126 Some(Commands::Revert(args)) => commands::run::revert(args, verbose, &dir, light),
127 Some(Commands::File(args)) => commands::file::run(args, light),
128 Some(Commands::Abort) => commands::abort::run(verbose, &dir),
129 Some(Commands::Completions(_)) => Ok(()),
131 }
132 }
133}