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)]
8pub struct MainOptions {
9 #[arg(
11 long,
12 require_equals = true,
13 num_args = 0..=1,
14 default_value_t = model::ColorMode::Auto,
15 default_missing_value = "true",
16 value_name = "WHEN",
17 value_parser = model::ColorMode::parse_from_str,
18 )]
19 pub color: model::ColorMode,
20
21 #[arg(long, short, value_hint = ValueHint::FilePath)]
23 pub config: Option<std::path::PathBuf>,
24
25 #[arg(long, short = 'C', value_hint = ValueHint::DirPath)]
27 pub chdir: Option<std::path::PathBuf>,
28
29 #[arg(long, short, action = clap::ArgAction::Append)]
31 pub debug: Vec<String>,
32
33 #[arg(long, short = 'D')]
35 pub define: Vec<String>,
36
37 #[arg(long, short, value_hint = ValueHint::DirPath)]
39 pub root: Option<std::path::PathBuf>,
40
41 #[arg(short, long)]
43 pub quiet: bool,
44
45 #[arg(short, long, action = clap::ArgAction::Count)]
47 pub verbose: u8,
48
49 #[command(subcommand)]
51 pub command: Command,
52}
53
54impl MainOptions {
55 pub fn new() -> Self {
57 Self::default()
58 }
59}
60
61pub fn debug_level(debug: &[String], name: &str) -> u8 {
63 debug.iter().filter(|&x| x == name).count() as u8
64}
65
66pub trait GardenOptions {
69 fn get_chdir(&self) -> &Option<std::path::PathBuf>;
70 fn get_color_mut(&mut self) -> &mut model::ColorMode;
71 fn get_config(&self) -> &Option<std::path::PathBuf>;
72 fn set_config(&mut self, path: std::path::PathBuf);
73 fn get_debug(&self) -> &[String];
74 fn get_root(&self) -> &Option<std::path::PathBuf>;
75 fn set_root(&mut self, path: std::path::PathBuf);
76
77 fn update(&mut self) {
79 self.get_color_mut().update();
80
81 if let Some(ref config) = self.get_config() {
82 if config.exists() {
83 self.set_config(path::abspath(config));
84 }
85 }
86 if let Some(ref root) = self.get_root() {
87 self.set_root(path::abspath(root));
88 }
89 if let Some(ref chdir) = self.get_chdir() {
90 if let Err(err) = std::env::set_current_dir(chdir) {
91 error!("could not chdir to {:?}: {}", chdir, err);
92 }
93 }
94 }
95
96 fn debug_level(&self, name: &str) -> u8 {
98 debug_level(self.get_debug(), name)
99 }
100}
101
102impl GardenOptions for MainOptions {
103 fn get_color_mut(&mut self) -> &mut model::ColorMode {
104 &mut self.color
105 }
106
107 fn get_config(&self) -> &Option<std::path::PathBuf> {
108 &self.config
109 }
110
111 fn set_config(&mut self, path: std::path::PathBuf) {
112 self.config = Some(path);
113 }
114
115 fn get_chdir(&self) -> &Option<std::path::PathBuf> {
116 &self.chdir
117 }
118
119 fn get_debug(&self) -> &[String] {
120 &self.debug
121 }
122
123 fn get_root(&self) -> &Option<std::path::PathBuf> {
124 &self.root
125 }
126
127 fn set_root(&mut self, root: std::path::PathBuf) {
128 self.root = Some(root);
129 }
130}
131
132#[derive(Default, Clone, Debug, Parser)]
134pub struct Arguments {
135 #[arg(allow_hyphen_values = true)]
136 pub args: Vec<String>,
137}
138
139#[derive(Clone, Debug, Subcommand)]
140pub enum Command {
141 Cmd(cmds::cmd::CmdOptions),
143 Completion(cmds::completion::CompletionOptions),
145 #[command(external_subcommand)]
147 Custom(Vec<String>),
148 Eval(cmds::eval::EvalOptions),
150 Exec(cmds::exec::ExecOptions),
152 Grow(cmds::grow::GrowOptions),
154 Gui(Arguments),
156 Init(cmds::init::InitOptions),
158 #[command(name = "ls")]
160 List(cmds::list::ListOptions),
161 Plant(cmds::plant::PlantOptions),
163 Prune(cmds::prune::PruneOptions),
165 #[command(alias = "sh")]
167 Shell(cmds::shell::ShellOptions),
168}
169
170impl std::default::Default for Command {
171 fn default() -> Self {
172 Command::Custom(vec![])
173 }
174}
175
176pub fn verbose_string(verbose: u8) -> String {
178 let mut verbose_str = "-".to_string();
179 verbose_str.reserve((verbose + 1) as usize);
180 for _ in 0..verbose {
181 verbose_str.push('v');
182 }
183 verbose_str
184}