1use anyhow::Result;
2use camino::Utf8PathBuf;
3use clap::builder::styling::{AnsiColor, Effects, Styles};
4use clap::{Parser, Subcommand};
5
6use crate::cmd;
7use crate::config::IconsMode;
8
9const HELP_STYLES: Styles = Styles::styled()
16 .header(AnsiColor::BrightCyan.on_default().effects(Effects::BOLD))
18 .usage(AnsiColor::BrightCyan.on_default().effects(Effects::BOLD))
21 .literal(AnsiColor::Magenta.on_default().effects(Effects::BOLD))
24 .placeholder(AnsiColor::Cyan.on_default())
26 .error(AnsiColor::Red.on_default().effects(Effects::BOLD))
27 .valid(AnsiColor::Green.on_default())
28 .invalid(AnsiColor::Yellow.on_default().effects(Effects::BOLD));
29
30#[derive(Parser, Debug)]
31#[command(version, about, long_about = None, styles = HELP_STYLES)]
32pub struct Cli {
33 #[arg(short, long, env = "YUI_SOURCE", global = true)]
35 pub source: Option<Utf8PathBuf>,
36
37 #[arg(short, long, action = clap::ArgAction::Count, global = true)]
39 pub verbose: u8,
40
41 #[command(subcommand)]
42 pub command: Command,
43}
44
45#[derive(Subcommand, Debug)]
46pub enum Command {
47 Init {
49 #[arg(long)]
51 git_hooks: bool,
52 },
53
54 Apply {
56 #[arg(long)]
57 dry_run: bool,
58 },
59
60 Render {
62 #[arg(long)]
64 check: bool,
65 #[arg(long)]
66 dry_run: bool,
67 },
68
69 Link {
71 #[arg(long)]
72 dry_run: bool,
73 },
74
75 Unlink { paths: Vec<Utf8PathBuf> },
77
78 Status {
80 #[arg(long, value_name = "MODE")]
82 icons: Option<IconsMode>,
83 #[arg(long)]
85 no_color: bool,
86 },
87
88 List {
90 #[arg(long)]
92 all: bool,
93 #[arg(long, value_name = "MODE")]
95 icons: Option<IconsMode>,
96 #[arg(long)]
98 no_color: bool,
99 },
100
101 Absorb {
103 target: Utf8PathBuf,
104 #[arg(long)]
105 dry_run: bool,
106 },
107
108 Doctor {
110 #[arg(long, value_name = "MODE")]
112 icons: Option<IconsMode>,
113 #[arg(long)]
115 no_color: bool,
116 },
117
118 GcBackup {
120 #[arg(long)]
122 older_than: Option<String>,
123 },
124
125 Hooks {
127 #[command(subcommand)]
128 action: HookAction,
129 },
130}
131
132#[derive(Subcommand, Debug)]
133pub enum HookAction {
134 List {
136 #[arg(long, value_name = "MODE")]
138 icons: Option<IconsMode>,
139 #[arg(long)]
141 no_color: bool,
142 },
143 Run {
148 name: Option<String>,
150 #[arg(long)]
152 force: bool,
153 },
154}
155
156impl Cli {
157 pub fn run(self) -> Result<()> {
158 let source = self.source;
159 match self.command {
160 Command::Init { git_hooks } => cmd::init(source, git_hooks),
161 Command::Apply { dry_run } => cmd::apply(source, dry_run),
162 Command::Render { check, dry_run } => cmd::render(source, check, dry_run),
163 Command::Link { dry_run } => cmd::link(source, dry_run),
164 Command::Unlink { paths } => cmd::unlink(source, paths),
165 Command::Status { icons, no_color } => cmd::status(source, icons, no_color),
166 Command::List {
167 all,
168 icons,
169 no_color,
170 } => cmd::list(source, all, icons, no_color),
171 Command::Absorb { target, dry_run } => cmd::absorb(source, target, dry_run),
172 Command::Doctor { icons, no_color } => cmd::doctor(source, icons, no_color),
173 Command::GcBackup { older_than } => cmd::gc_backup(source, older_than),
174 Command::Hooks { action } => match action {
175 HookAction::List { icons, no_color } => cmd::hooks_list(source, icons, no_color),
176 HookAction::Run { name, force } => cmd::hooks_run(source, name, force),
177 },
178 }
179 }
180}