use anyhow::Result;
use clap::{CommandFactory, Parser};
use clap_complete::generate;
use std::fs;
use std::io;
use std::path::PathBuf;
use rskiller::{Cli, ConfigLoader, ProjectScanner, InteractiveUI};
#[tokio::main]
async fn main() -> Result<()> {
let cli = Cli::parse();
if let Some(shell) = cli.completion {
let mut cmd = Cli::command();
generate(shell, &mut cmd, "rskiller", &mut io::stdout());
return Ok(());
}
if cli.print_config {
let loader = ConfigLoader::new();
let config = loader.load_merged_config()?;
let config_str = serde_json::to_string_pretty(&config)?;
println!("{}", config_str);
return Ok(());
}
if cli.init_config {
let format = cli.format.clone().into();
let sample_config = ConfigLoader::generate_sample_config(format)?;
let filename = match format {
rskiller::config::ConfigFormat::Toml => {
if cli.global {
if let Some(config_dir) = dirs::config_dir() {
let dir = config_dir.join("rskiller");
fs::create_dir_all(&dir)?;
dir.join("rskill.toml")
} else {
PathBuf::from("rskill.toml")
}
} else {
PathBuf::from("rskill.toml")
}
}
rskiller::config::ConfigFormat::Json => {
if cli.global {
if let Some(home_dir) = home::home_dir() {
home_dir.join(".rskillrc")
} else {
PathBuf::from(".rskillrc")
}
} else {
PathBuf::from(".rskillrc")
}
}
};
if filename.exists() {
eprintln!("Configuration file already exists: {}", filename.display());
eprintln!("Use --force to overwrite (not implemented yet)");
return Ok(());
}
fs::write(&filename, sample_config)?;
println!("Generated configuration file: {}", filename.display());
return Ok(());
}
if let Some(config_path) = &cli.validate_config {
let loader = ConfigLoader::new();
match loader.load_from_file(config_path) {
Ok(_) => println!("Configuration file is valid: {}", config_path.display()),
Err(e) => {
eprintln!("Configuration file is invalid: {}", e);
std::process::exit(1);
}
}
return Ok(());
}
if cli.config_info {
let loader = ConfigLoader::new();
println!("Configuration file search paths (in priority order):");
for (i, path) in loader.search_paths.iter().enumerate() {
let exists = if path.exists() { " (exists)" } else { "" };
println!(" {}. {}{}", i + 1, path.display(), exists);
}
return Ok(());
}
let loader = if let Some(config_path) = &cli.config {
ConfigLoader::with_paths(vec![config_path.clone()])
} else {
ConfigLoader::new()
};
let config = loader.load_merged_config()?;
let final_cli = Cli::from_config_and_args(config.clone());
let scanner = ProjectScanner::new(final_cli.clone(), config.clone());
if final_cli.list_only {
let projects = scanner.scan().await?;
scanner.print_projects(&projects).await?;
} else {
let mut ui = InteractiveUI::new(final_cli.clone(), config.clone());
ui.run().await?;
}
Ok(())
}