1use std::{
2 fs::OpenOptions,
3 io::{self, Write},
4};
5
6use anyhow::{ensure, Context, Result};
7use camino::{Utf8Path, Utf8PathBuf};
8use clap::{Args, CommandFactory, Parser, ValueHint};
9use clap_complete::Shell;
10
11#[derive(Parser)]
12#[command(name = "cargo", bin_name = "cargo")]
13enum Cli {
14 #[command(subcommand)]
15 Hatch(Command),
16}
17
18#[derive(Parser)]
19#[command(about, author, version)]
20pub enum Command {
21 Init {
23 name: Option<String>,
25 },
26 List,
28 New {
30 bookmark: String,
32 #[command(flatten)]
33 flags: CreationFlags,
34 },
35 Git {
37 #[arg(long)]
39 folder: Option<Utf8PathBuf>,
40 url: String,
42 #[command(flatten)]
43 flags: CreationFlags,
44 },
45 Local {
47 #[arg(value_hint = ValueHint::DirPath)]
49 path: Utf8PathBuf,
50 #[command(flatten)]
51 flags: CreationFlags,
52 },
53 Completions {
55 #[arg(value_enum)]
57 shell: Shell,
58 },
59 Manpages {
61 #[arg(value_hint = ValueHint::DirPath)]
65 dir: Utf8PathBuf,
66 },
67}
68
69#[derive(Args)]
70pub struct CreationFlags {
71 pub name: Option<Utf8PathBuf>,
77 #[arg(short, long)]
79 pub update_deps: bool,
80}
81
82#[must_use]
83pub fn parse() -> Command {
84 let Cli::Hatch(cmd) = Cli::parse();
85 cmd
86}
87
88pub fn completions(shell: Shell) {
90 clap_complete::generate(
91 shell,
92 &mut Cli::command(),
93 env!("CARGO_PKG_NAME"),
94 &mut io::stdout().lock(),
95 );
96}
97
98pub fn manpages(dir: &Utf8Path) -> Result<()> {
101 fn print(dir: &Utf8Path, app: &clap::Command) -> Result<()> {
102 let name = app.get_display_name().unwrap_or_else(|| app.get_name());
103 let out = dir.join(format!("{name}.1"));
104 let mut out = OpenOptions::new()
105 .write(true)
106 .create_new(true)
107 .open(&out)
108 .with_context(|| format!("the file `{out}` already exists"))?;
109
110 clap_mangen::Man::new(app.clone()).render(&mut out)?;
111 out.flush()?;
112
113 for sub in app.get_subcommands() {
114 print(dir, sub)?;
115 }
116
117 Ok(())
118 }
119
120 ensure!(dir.try_exists()?, "target directory doesn't exist");
121
122 let mut app = Command::command();
123 app.build();
124
125 print(dir, &app)
126}
127
128#[cfg(test)]
129mod tests {
130 use super::Cli;
131
132 #[test]
133 fn verify_cli() {
134 use clap::CommandFactory;
135 Cli::command().debug_assert();
136 }
137}