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
111 GcBackup {
113 #[arg(long)]
115 older_than: Option<String>,
116 },
117
118 Hooks {
120 #[command(subcommand)]
121 action: HookAction,
122 },
123}
124
125#[derive(Subcommand, Debug)]
126pub enum HookAction {
127 List,
129 Run {
134 name: Option<String>,
136 #[arg(long)]
138 force: bool,
139 },
140}
141
142impl Cli {
143 pub fn run(self) -> Result<()> {
144 let source = self.source;
145 match self.command {
146 Command::Init { git_hooks } => cmd::init(source, git_hooks),
147 Command::Apply { dry_run } => cmd::apply(source, dry_run),
148 Command::Render { check, dry_run } => cmd::render(source, check, dry_run),
149 Command::Link { dry_run } => cmd::link(source, dry_run),
150 Command::Unlink { paths } => cmd::unlink(source, paths),
151 Command::Status { icons, no_color } => cmd::status(source, icons, no_color),
152 Command::List {
153 all,
154 icons,
155 no_color,
156 } => cmd::list(source, all, icons, no_color),
157 Command::Absorb { target, dry_run } => cmd::absorb(source, target, dry_run),
158 Command::Doctor => cmd::doctor(source),
159 Command::GcBackup { older_than } => cmd::gc_backup(source, older_than),
160 Command::Hooks { action } => match action {
161 HookAction::List => cmd::hooks_list(source),
162 HookAction::Run { name, force } => cmd::hooks_run(source, name, force),
163 },
164 }
165 }
166}