1use clap::{Parser, Subcommand, ValueHint};
2
3use crate::{cmds, constants, model, path};
4
5#[derive(Clone, Debug, Default, Parser)]
6#[command(name = constants::GARDEN)]
7#[command(author, version, about, long_about = None)]
8#[command(styles = clap_cargo::style::CLAP_STYLING)]
9pub struct MainOptions {
10 #[arg(
12 long,
13 require_equals = true,
14 num_args = 0..=1,
15 default_value_t = model::ColorMode::Auto,
16 default_missing_value = "true",
17 value_name = "WHEN",
18 value_parser = model::ColorMode::parse_from_str,
19 )]
20 pub color: model::ColorMode,
21
22 #[arg(long, short, value_hint = ValueHint::FilePath)]
24 pub config: Option<std::path::PathBuf>,
25
26 #[arg(long, short = 'C', value_hint = ValueHint::DirPath)]
28 pub chdir: Option<std::path::PathBuf>,
29
30 #[arg(long, short, action = clap::ArgAction::Append)]
32 pub debug: Vec<String>,
33
34 #[arg(long, short = 'D')]
36 pub define: Vec<String>,
37
38 #[arg(long, short, value_hint = ValueHint::DirPath)]
40 pub root: Option<std::path::PathBuf>,
41
42 #[arg(short, long)]
44 pub quiet: bool,
45
46 #[arg(short, long, action = clap::ArgAction::Count)]
48 pub verbose: u8,
49
50 #[command(subcommand)]
52 pub command: Command,
53}
54
55impl MainOptions {
56 pub fn new() -> Self {
58 Self::default()
59 }
60}
61
62pub fn debug_level(debug: &[String], name: &str) -> u8 {
64 debug.iter().filter(|&x| x == name).count() as u8
65}
66
67pub trait GardenOptions {
70 fn get_chdir(&self) -> &Option<std::path::PathBuf>;
71 fn get_color_mut(&mut self) -> &mut model::ColorMode;
72 fn get_config(&self) -> &Option<std::path::PathBuf>;
73 fn set_config(&mut self, path: std::path::PathBuf);
74 fn get_debug(&self) -> &[String];
75 fn get_root(&self) -> &Option<std::path::PathBuf>;
76 fn set_root(&mut self, path: std::path::PathBuf);
77
78 fn update(&mut self) {
80 self.get_color_mut().update();
81
82 if let Some(ref config) = self.get_config() {
83 if config.exists() {
84 self.set_config(path::abspath(config));
85 }
86 }
87 if let Some(ref root) = self.get_root() {
88 self.set_root(path::abspath(root));
89 }
90 if let Some(ref chdir) = self.get_chdir() {
91 if let Err(err) = std::env::set_current_dir(chdir) {
92 error!("could not chdir to {:?}: {}", chdir, err);
93 }
94 }
95 }
96
97 fn debug_level(&self, name: &str) -> u8 {
99 debug_level(self.get_debug(), name)
100 }
101}
102
103impl GardenOptions for MainOptions {
104 fn get_color_mut(&mut self) -> &mut model::ColorMode {
105 &mut self.color
106 }
107
108 fn get_config(&self) -> &Option<std::path::PathBuf> {
109 &self.config
110 }
111
112 fn set_config(&mut self, path: std::path::PathBuf) {
113 self.config = Some(path);
114 }
115
116 fn get_chdir(&self) -> &Option<std::path::PathBuf> {
117 &self.chdir
118 }
119
120 fn get_debug(&self) -> &[String] {
121 &self.debug
122 }
123
124 fn get_root(&self) -> &Option<std::path::PathBuf> {
125 &self.root
126 }
127
128 fn set_root(&mut self, root: std::path::PathBuf) {
129 self.root = Some(root);
130 }
131}
132
133#[derive(Default, Clone, Debug, Parser)]
135pub struct Arguments {
136 #[arg(allow_hyphen_values = true)]
137 pub args: Vec<String>,
138}
139
140#[derive(Clone, Debug, Subcommand)]
141pub enum Command {
142 Cmd(cmds::cmd::CmdOptions),
144 Completion(cmds::completion::CompletionOptions),
146 #[command(external_subcommand)]
148 Custom(Vec<String>),
149 Eval(cmds::eval::EvalOptions),
151 Exec(cmds::exec::ExecOptions),
153 Git(cmds::git::GitOptions),
155 Grow(cmds::grow::GrowOptions),
157 Gui(Arguments),
159 Init(cmds::init::InitOptions),
161 #[command(name = "ls")]
163 List(cmds::list::ListOptions),
164 Plant(cmds::plant::PlantOptions),
166 Prune(cmds::prune::PruneOptions),
168 #[command(alias = "sh")]
170 Shell(cmds::shell::ShellOptions),
171}
172
173impl std::default::Default for Command {
174 fn default() -> Self {
175 Command::Custom(vec![])
176 }
177}
178
179pub fn verbose_string(verbose: u8) -> String {
181 let mut verbose_str = "-".to_string();
182 verbose_str.reserve((verbose + 1) as usize);
183 for _ in 0..verbose {
184 verbose_str.push('v');
185 }
186 verbose_str
187}