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}