1use crate::{
2 Config, EchoCommentError, Mode, Result, color::resolve_color,
3 process_script_content_with_config, runner::ScriptRunner,
4};
5use clap::Parser;
6use std::fs;
7
8#[derive(Parser)]
9#[command(
10 author,
11 version,
12 about = "A bidirectional bash interpreter that converts comments ↔ echo statements"
13)]
14#[command(arg_required_else_help = true)]
15pub struct Args {
16 pub script: String,
18
19 #[arg(trailing_var_arg = true, allow_hyphen_values = true)]
21 pub script_args: Vec<String>,
22
23 #[arg(long = "shell", short = 's')]
25 pub shell: Option<String>,
26
27 #[arg(long = "shell-flags")]
29 pub shell_flags: Option<String>,
30
31 #[arg(long = "color", short = 'c')]
33 pub color: Option<String>,
34
35 #[arg(long = "verbose", short = 'v')]
37 pub verbose: bool,
38}
39
40impl Args {
41 pub fn to_config(&self) -> Config {
43 let mut config = Config::from_env(); if let Some(shell) = &self.shell {
47 config.shell = shell.clone();
48 }
49
50 if let Some(flags) = &self.shell_flags {
51 config.shell_flags = flags.split_whitespace().map(|s| s.to_string()).collect();
52 }
53
54 if let Some(color) = &self.color {
55 config.comment_color = Some(resolve_color(color));
56 }
57
58 config
59 }
60}
61
62pub fn run_cli(mode: Mode) {
64 let args = Args::parse();
66
67 if let Err(e) = run_script_with_args(&args, mode) {
69 eprintln!("Error: {}", e);
70 std::process::exit(1);
71 }
72}
73
74fn run_script_with_args(args: &Args, mode: Mode) -> Result<()> {
75 if args.verbose {
76 eprintln!("Processing script: {} in mode: {:?}", args.script, mode);
77 }
78
79 let content = fs::read_to_string(&args.script).map_err(|e| EchoCommentError::FileRead {
81 path: args.script.clone(),
82 source: e,
83 })?;
84
85 let config = args.to_config();
87 if args.verbose {
88 eprintln!("Using config: {:?}", config);
89 }
90
91 let processed_content = process_script_content_with_config(&content, mode, &config)?;
93
94 let runner = ScriptRunner::new();
96 runner.run_script(&processed_content, &args.script_args)?;
97
98 Ok(())
99}