1use std::path::PathBuf;
2
3use clap::{Args, Subcommand, ValueEnum};
4
5#[derive(Copy, Clone, Debug, Eq, PartialEq, ValueEnum)]
6pub enum PresetTemplateKind {
7 App,
8 Shell,
9 Sys,
10}
11
12#[derive(Copy, Clone, Debug, Eq, PartialEq, ValueEnum)]
13pub enum PresetValidationFormat {
14 Text,
15 Json,
16}
17
18#[derive(Args, Debug)]
19pub struct ExportCommand {
20 #[arg(value_name = "DIR")]
22 pub dir: Option<PathBuf>,
23 #[arg(long, short = 'f')]
25 pub force: bool,
26}
27
28#[derive(Args, Debug)]
29pub struct CopyCommand {
30 #[arg(value_name = "KIND/NAME", value_parser = parse_copy_target)]
32 pub target: String,
33 #[arg(long, short = 'f')]
35 pub force: bool,
36}
37
38pub(crate) fn parse_copy_target(value: &str) -> Result<String, String> {
39 if value.contains('\\') {
40 return Err(format!(
41 "invalid preset target '{value}': expected app/name, shell/name, or sys/name"
42 ));
43 }
44
45 let mut parts = value.split('/');
46 let kind = parts.next().unwrap_or_default();
47 let name = parts.next().unwrap_or_default();
48 if parts.next().is_some()
49 || !matches!(kind, "app" | "shell" | "sys")
50 || name.is_empty()
51 || matches!(name, "." | "..")
52 {
53 return Err(format!(
54 "invalid preset target '{value}': expected app/name, shell/name, or sys/name"
55 ));
56 }
57 Ok(value.to_string())
58}
59
60#[derive(Args, Debug)]
61pub struct LinkCommand {
62 #[arg(value_name = "PATH")]
64 pub path: PathBuf,
65 #[arg(long)]
67 pub create: bool,
68 #[arg(long)]
70 pub live: bool,
71}
72
73#[derive(Args, Debug)]
74pub struct OverlayLinkCommand {
75 #[arg(value_name = "PATH", conflicts_with = "git")]
77 pub path: Option<PathBuf>,
78 #[arg(long, value_name = "URL")]
81 pub git: Option<String>,
82 #[arg(long, value_name = "BRANCH", requires = "git")]
84 pub branch: Option<String>,
85 #[arg(long)]
87 pub create: bool,
88}
89
90#[derive(Subcommand, Debug)]
91pub enum OverlayCommands {
92 Link(OverlayLinkCommand),
94 Unlink,
96 Info,
98}
99
100#[derive(Subcommand, Debug)]
101pub enum PresetCommands {
102 New {
104 #[arg(value_enum)]
105 kind: PresetTemplateKind,
106 #[arg(long, short = 'f')]
108 force: bool,
109 },
110 Validate {
112 #[arg(value_name = "PATH", default_value = ".")]
114 path: PathBuf,
115 #[arg(long, value_enum, default_value_t = PresetValidationFormat::Text)]
117 format: PresetValidationFormat,
118 },
119 Export(ExportCommand),
121 Copy(CopyCommand),
123 Link(LinkCommand),
125 Unlink,
127 Overlay {
129 #[command(subcommand)]
130 command: OverlayCommands,
131 },
132 Pull,
134}