1use clap::{Parser, Subcommand};
2
3#[derive(Subcommand, Debug)]
4pub enum CliCommands {
5 Open {
7 #[arg()]
9 file: Option<String>,
10 },
11 Info {
13 #[arg(short, long)]
15 file: Option<String>,
16 },
17 Export {
19 #[arg(short, long)]
21 file: Option<String>,
22 #[arg(short = 'F', long)]
24 format: String,
25 #[arg(short, long)]
27 output: String,
28 },
29}
30
31#[derive(Parser, Debug)]
32#[command(name = "mcraw-tui", about = "Cross-platform TUI for MotionCam .mcraw files")]
33pub struct Cli {
34 #[arg(short, long)]
36 pub file: Option<String>,
37
38 #[command(subcommand)]
40 pub command: Option<CliCommands>,
41
42 #[arg(short = 'n', long)]
44 pub frames: Option<usize>,
45
46 #[arg(short, long, global = true)]
48 pub verbose: bool,
49
50 #[arg(short, long)]
52 pub output: Option<String>,
53}
54
55impl Cli {
56 pub fn resolve(self) -> ResolvedCli {
58 match self.command {
59 Some(cmd) => ResolvedCli::Command(cmd.resolve_with_top_level(self.file)),
60 None => {
61 if let Some(ref file) = self.file {
62 ResolvedCli::Command(CliCommands::Open { file: Some(file.clone()) })
63 } else {
64 ResolvedCli::NoFile
65 }
66 }
67 }
68 }
69
70 pub fn validate_export_format(format: &str) -> Result<(), String> {
72 let valid = ["dng", "prores", "h264", "hevc"];
73 let lower = format.to_lowercase();
74 if valid.contains(&lower.as_str()) {
75 Ok(())
76 } else {
77 Err(format!(
78 "Invalid export format '{}'. Valid formats: {}",
79 format,
80 valid.join(", ")
81 ))
82 }
83 }
84}
85
86impl CliCommands {
87 fn resolve_with_top_level(self, top_level_file: Option<String>) -> Self {
89 match self {
90 CliCommands::Open { file } => CliCommands::Open {
91 file: file.or(top_level_file),
92 },
93 CliCommands::Info { file } => CliCommands::Info {
94 file: file.or(top_level_file),
95 },
96 CliCommands::Export { file, format, output } => CliCommands::Export {
97 file: file.or(top_level_file),
98 format,
99 output,
100 },
101 }
102 }
103}
104
105pub enum ResolvedCli {
106 Command(CliCommands),
107 NoFile,
108}