echo_comment/
cli.rs

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    /// Script file to process
17    pub script: String,
18
19    /// Arguments to pass to the script
20    #[arg(trailing_var_arg = true, allow_hyphen_values = true)]
21    pub script_args: Vec<String>,
22
23    /// Shell to use (default: bash)
24    #[arg(long = "shell", short = 's')]
25    pub shell: Option<String>,
26
27    /// Shell flags (e.g., "-euo pipefail")
28    #[arg(long = "shell-flags")]
29    pub shell_flags: Option<String>,
30
31    /// Color name or ANSI code for comments (e.g., "red", "green", "bold-blue")
32    #[arg(long = "color", short = 'c')]
33    pub color: Option<String>,
34
35    /// Enable verbose debug output
36    #[arg(long = "verbose", short = 'v')]
37    pub verbose: bool,
38}
39
40impl Args {
41    /// Convert CLI args to Config
42    pub fn to_config(&self) -> Config {
43        let mut config = Config::from_env(); // Still respect env vars as fallback
44
45        // CLI args override env vars
46        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
62/// Run the CLI with the specified mode and binary name for usage messages
63pub fn run_cli(mode: Mode) {
64    // Parse arguments with clap - much simpler approach
65    let args = Args::parse();
66
67    // Run the script processing
68    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    // Read the input script
80    let content = fs::read_to_string(&args.script).map_err(|e| EchoCommentError::FileRead {
81        path: args.script.clone(),
82        source: e,
83    })?;
84
85    // Convert CLI args to config
86    let config = args.to_config();
87    if args.verbose {
88        eprintln!("Using config: {:?}", config);
89    }
90
91    // Process the content with config
92    let processed_content = process_script_content_with_config(&content, mode, &config)?;
93
94    // Run the processed script
95    let runner = ScriptRunner::new();
96    runner.run_script(&processed_content, &args.script_args)?;
97
98    Ok(())
99}