use anyhow::Result;
use colored::*;
use std::path::Path;
#[derive(Clone, Debug)]
pub enum TargetOp {
List,
Add { name: String },
Remove { name: String },
Default { name: String },
}
pub fn handle_target_command(op: &Option<TargetOp>) -> Result<()> {
let config_path = Path::new("cx.toml");
match op {
None | Some(TargetOp::List) => {
println!(
"{} {}",
"🎯".cyan(),
"Available Cross-Compilation Targets".bold()
);
println!("{}", "─".repeat(50).dimmed());
println!();
println!(
" {} (MSVC) - Windows 64-bit",
"windows-x64".green().bold()
);
println!(
" {} (MinGW) - Windows 64-bit GNU",
"windows-x64-gnu".green()
);
println!(" {} (GCC/Clang) - Linux 64-bit", "linux-x64".blue());
println!(" {} (Cross) - Linux ARM64", "linux-arm64".blue());
println!(" {} (Clang) - macOS Intel", "macos-x64".magenta());
println!(
" {} (Clang) - macOS Apple Silicon",
"macos-arm64".magenta()
);
println!(" {} (Emscripten) - WebAssembly", "wasm32".yellow());
println!(" {} (ESP-IDF) - ESP32 Microcontroller", "esp32".red());
println!();
if config_path.exists()
&& let Ok(content) = std::fs::read_to_string(config_path)
{
if content.contains("[targets]") || content.contains("targets =") {
println!("{} Project targets configured", "✓".green());
} else {
println!(
"{} No targets configured. Use {} to add one.",
"!".yellow(),
"cx target add <name>".cyan()
);
}
}
println!();
println!(
"Usage: {} or {}",
"cx target add <name>".cyan(),
"cx build --target <name>".cyan()
);
}
Some(TargetOp::Add { name }) => {
if !config_path.exists() {
println!(
"{} No cx.toml found. Run {} first.",
"x".red(),
"cx init".cyan()
);
return Ok(());
}
let valid_targets = [
"windows-x64",
"windows-x64-gnu",
"linux-x64",
"linux-arm64",
"macos-x64",
"macos-arm64",
"wasm32",
"esp32",
];
if !valid_targets.contains(&name.as_str()) {
println!(
"{} Unknown target '{}'. Run {} to see available targets.",
"x".red(),
name,
"cx target list".cyan()
);
return Ok(());
}
let mut content = std::fs::read_to_string(config_path)?;
if content.contains(&format!("\"{}\"", name)) {
println!("{} Target '{}' already configured.", "!".yellow(), name);
return Ok(());
}
if !content.contains("[targets]") {
content.push_str(&format!("\n[targets]\nlist = [\"{}\"]\n", name));
} else {
content = content.replace("list = [", &format!("list = [\"{}\", ", name));
}
std::fs::write(config_path, content)?;
println!("{} Added target: {}", "✓".green(), name.cyan());
println!(
" Build with: {}",
format!("cx build --target {}", name).yellow()
);
}
Some(TargetOp::Remove { name }) => {
if !config_path.exists() {
println!("{} No cx.toml found.", "x".red());
return Ok(());
}
let content = std::fs::read_to_string(config_path)?;
let new_content = content
.replace(&format!("\"{}\", ", name), "")
.replace(&format!(", \"{}\"", name), "")
.replace(&format!("\"{}\"", name), "");
std::fs::write(config_path, new_content)?;
println!("{} Removed target: {}", "✓".green(), name);
}
Some(TargetOp::Default { name }) => {
if !config_path.exists() {
println!("{} No cx.toml found.", "x".red());
return Ok(());
}
let mut content = std::fs::read_to_string(config_path)?;
if content.contains("default_target") {
let re = regex::Regex::new(r#"default_target\s*=\s*"[^"]*""#).unwrap();
content = re
.replace(&content, &format!("default_target = \"{}\"", name))
.to_string();
} else if content.contains("[targets]") {
content = content.replace(
"[targets]",
&format!("[targets]\ndefault_target = \"{}\"", name),
);
} else {
content.push_str(&format!("\n[targets]\ndefault_target = \"{}\"\n", name));
}
std::fs::write(config_path, content)?;
println!("{} Set default target: {}", "✓".green(), name.cyan());
}
}
Ok(())
}