use anyhow::Result;
use clap::Parser;
use std::io::Write;
use futures_util::StreamExt;
mod git;
mod ai;
mod config;
#[derive(Parser)]
#[command(author, version, about)]
struct Cli {
#[arg(short, long)]
message: Option<String>,
#[arg(short, long, default_value = ".")]
path: String,
#[arg(short, long)]
body: bool,
#[arg(short = 'c', long)]
commit: bool,
#[arg(short = 'v', long = "verbose")]
verbose: bool,
#[arg(short = 's', long)]
summary: Option<String>,
#[arg(short = 'a', long)]
add: bool,
}
#[tokio::main]
async fn main() -> Result<()> {
let cli = Cli::parse();
let git_diff = git::GitDiff::new(&cli.path)?;
let diff_content = if let Some(base) = cli.summary {
git_diff.get_summary_diff(&base)?
} else {
let diff = git_diff.get_staged_diff(cli.add)?;
if diff.trim().is_empty() {
println!("Error: No staged changes found. Please use 'git add' command to stage your changes.");
return Ok(());
}
diff
};
let config = config::Config::new()?;
let ai_service = ai::AiService::new(
config.api_endpoint,
config.model,
config.api_key,
config.is_azure.unwrap_or(false),
config.api_version,
config.prompt
);
let mut commit_message = String::new();
let mut stream = ai_service.generate_commit_message(diff_content, cli.message, cli.body, cli.verbose).await?;
println!("Commit message:\n");
while let Some(content) = stream.next().await {
let content = content?;
if !content.is_empty() {
print!("{}", content);
std::io::stdout().flush()?;
commit_message.push_str(&content);
}
}
println!("\n");
if cli.commit {
if cli.add {
git_diff.add_all()?;
}
git_diff.commit(&commit_message)?;
println!("Successfully committed changes.");
} else {
print!("Do you want to commit these changes? [y/N] ");
std::io::stdout().flush()?;
let mut input = String::new();
std::io::stdin().read_line(&mut input)?;
if input.trim().to_lowercase() == "y" {
if cli.add {
git_diff.add_all()?;
}
git_diff.commit(&commit_message)?;
println!("Successfully committed changes.");
}
}
Ok(())
}