use crate::context::CliContext;
use crate::paths;
use anyhow::Result;
#[derive(Debug, Clone)]
pub struct FormatArgs {
pub check: bool,
}
pub async fn handle_format(ctx: &mut CliContext, args: &FormatArgs) -> Result<()> {
println!();
if args.check {
println!("đ Code Format Check");
} else {
println!("⨠Code Formatting");
}
println!("âââââââââââââââââââââââââââââââââââââââââââââââ");
println!();
if !ctx.is_project_initialized() {
return Err(anyhow::anyhow!(
"Not in a Mecha10 project directory.\n\
Run 'mecha10 init' to create a new project."
));
}
let project = ctx.project()?;
println!("Project: {}", project.root().display());
println!();
let mut all_passed = true;
println!("Formatting Rust code...");
let rustfmt_result = if args.check {
std::process::Command::new("cargo")
.args(["fmt", "--all", "--", "--check"])
.current_dir(project.root())
.status()
} else {
std::process::Command::new("cargo")
.args(["fmt", "--all"])
.current_dir(project.root())
.status()
};
match rustfmt_result {
Ok(status) if status.success() => {
if args.check {
println!("â
Rust code is formatted correctly");
} else {
println!("â
Rust code formatted");
}
}
Ok(_) => {
if args.check {
println!("â Rust code needs formatting");
println!(" Run: mecha10 format");
} else {
println!("â Rust formatting failed");
}
all_passed = false;
}
Err(e) => {
println!("â ī¸ Could not run rustfmt: {}", e);
println!(" Install with: rustup component add rustfmt");
}
}
println!();
println!("Formatting Python code...");
let python_dir = project.root().join(paths::framework::TASKRUNNER_DIR);
if python_dir.exists() {
let ruff_result = if args.check {
std::process::Command::new("ruff")
.args(["format", "--check", "."])
.current_dir(&python_dir)
.status()
} else {
std::process::Command::new("ruff")
.args(["format", "."])
.current_dir(&python_dir)
.status()
};
match ruff_result {
Ok(status) if status.success() => {
if args.check {
println!("â
Python code is formatted correctly");
} else {
println!("â
Python code formatted");
}
}
Ok(_) => {
if args.check {
println!("â Python code needs formatting");
println!(" Run: mecha10 format");
} else {
println!("â Python formatting failed");
}
all_passed = false;
}
Err(e) => {
println!("â ī¸ Could not run ruff: {}", e);
println!(" Install with: pip install ruff");
}
}
} else {
println!("âšī¸ No Python code found, skipping");
}
println!();
println!("Formatting GDScript code...");
let godot_dir = if let Ok(framework_path) = std::env::var("MECHA10_FRAMEWORK_PATH") {
std::path::PathBuf::from(framework_path).join(paths::framework::SIMULATION_GODOT_DIR)
} else {
project.root().join(paths::project::SIMULATION_GODOT_DIR)
};
if godot_dir.exists() {
let gdformat_result = if args.check {
std::process::Command::new("gdformat")
.args(["--check", "."])
.current_dir(&godot_dir)
.status()
} else {
std::process::Command::new("gdformat")
.arg(".")
.current_dir(&godot_dir)
.status()
};
match gdformat_result {
Ok(status) if status.success() => {
if args.check {
println!("â
GDScript code is formatted correctly");
} else {
println!("â
GDScript code formatted");
}
}
Ok(_) => {
if args.check {
println!("â GDScript code needs formatting");
} else {
println!("â GDScript formatting failed");
}
all_passed = false;
}
Err(_) => {
println!("âšī¸ gdformat not available, skipping");
}
}
} else {
println!("âšī¸ No GDScript code found, skipping");
}
println!();
println!("Formatting TOML files...");
let toml_files: Vec<_> = walkdir::WalkDir::new(project.root())
.into_iter()
.filter_map(|e| e.ok())
.filter(|e| {
let path = e.path();
path.extension().is_some_and(|ext| ext == "toml")
&& !path.to_string_lossy().contains("/target/")
&& !path.to_string_lossy().contains("/node_modules/")
})
.map(|e| e.path().to_path_buf())
.collect();
if toml_files.is_empty() {
println!("âšī¸ No TOML files found, skipping");
} else {
let taplo_result = if args.check {
std::process::Command::new("taplo")
.arg("format")
.arg("--check")
.args(&toml_files)
.current_dir(project.root())
.status()
} else {
std::process::Command::new("taplo")
.arg("format")
.args(&toml_files)
.current_dir(project.root())
.status()
};
match taplo_result {
Ok(status) if status.success() => {
if args.check {
println!("â
TOML files are formatted correctly");
} else {
println!("â
TOML files formatted");
}
}
Ok(_) => {
if args.check {
println!("â TOML files need formatting");
println!(" Run: mecha10 format");
} else {
println!("â TOML formatting failed");
}
all_passed = false;
}
Err(e) => {
println!("â ī¸ Could not run taplo: {}", e);
println!(" Install with: cargo install taplo-cli --locked");
}
}
}
println!();
println!("âââââââââââââââââââââââââââââââââââââââââââââââ");
if all_passed {
if args.check {
println!("â
All code is formatted correctly!");
} else {
println!("â
All code formatted successfully!");
}
} else {
if args.check {
println!("â Some code needs formatting");
println!();
println!("Run without --check to format:");
println!(" mecha10 format");
} else {
println!("â Some formatting operations failed");
}
return Err(anyhow::anyhow!("Formatting check failed"));
}
println!();
Ok(())
}