dampen_cli/commands/
run.rs

1#![allow(clippy::print_stderr, clippy::print_stdout)]
2
3//! Run command - launches development mode with interpreted execution
4//!
5//! This command wraps `cargo run` with the `interpreted` feature flag enabled,
6//! providing fast iteration with hot-reload capabilities.
7
8use std::path::Path;
9use std::process::Command;
10
11/// Run command arguments
12#[derive(clap::Args)]
13pub struct RunArgs {
14    /// Package to run (if workspace has multiple binaries)
15    #[arg(short, long)]
16    package: Option<String>,
17
18    /// Arguments to pass to the application
19    #[arg(last = true)]
20    app_args: Vec<String>,
21
22    /// Verbose output
23    #[arg(short, long)]
24    verbose: bool,
25
26    /// Run with release optimizations
27    #[arg(long)]
28    release: bool,
29
30    /// Additional features to enable (beyond interpreted)
31    #[arg(long, value_delimiter = ',')]
32    features: Vec<String>,
33}
34
35/// Execute the run command
36///
37/// This command launches the application in development/interpreted mode
38/// by invoking `cargo run` with the `interpreted` feature flag.
39///
40/// # Mode Behavior
41///
42/// - **Interpreted Mode** (default): Runtime XML parsing with hot-reload support
43/// - Fast compilation and iteration
44/// - Preserves application state during UI changes
45/// - Ideal for development and prototyping
46///
47/// # Examples
48///
49/// ```bash
50/// # Basic run in interpreted mode
51/// dampen run
52///
53/// # Run specific package in workspace
54/// dampen run -p my-app
55///
56/// # Pass arguments to the application
57/// dampen run -- --window-size 800x600
58///
59/// # Enable additional features
60/// dampen run --features tokio,logging
61/// ```
62pub fn execute(args: &RunArgs) -> Result<(), String> {
63    // Check if Cargo.toml exists
64    if !Path::new("Cargo.toml").exists() {
65        return Err("Cargo.toml not found. Are you in a Rust project directory?".to_string());
66    }
67
68    if args.verbose {
69        eprintln!("Running in development mode (interpreted)...");
70        eprintln!("Mode: {}", if args.release { "release" } else { "debug" });
71    }
72
73    // Build the cargo command
74    let mut cmd = Command::new("cargo");
75    cmd.arg("run");
76
77    // Add package specification if provided
78    if let Some(ref package) = args.package {
79        cmd.arg("-p").arg(package);
80    }
81
82    // Add release flag if requested
83    if args.release {
84        cmd.arg("--release");
85    }
86
87    // Add verbose flag if requested
88    if args.verbose {
89        cmd.arg("--verbose");
90    }
91
92    // Build features list: always include 'interpreted', plus any user-specified features
93    let mut all_features = vec!["interpreted".to_string()];
94    all_features.extend(args.features.clone());
95
96    // Add features flag
97    cmd.arg("--features").arg(all_features.join(","));
98
99    // Add application arguments if provided
100    if !args.app_args.is_empty() {
101        cmd.arg("--");
102        cmd.args(&args.app_args);
103    }
104
105    // Execute cargo run
106    if args.verbose {
107        let features_str = all_features.join(",");
108        eprintln!("Executing: cargo run --features {}", features_str);
109        if !args.app_args.is_empty() {
110            eprintln!("Application args: {:?}", args.app_args);
111        }
112    }
113
114    let status = cmd
115        .status()
116        .map_err(|e| format!("Failed to execute cargo: {}", e))?;
117
118    if !status.success() {
119        return Err("Run command failed".to_string());
120    }
121
122    Ok(())
123}