use std::time::Duration;
use indicatif::{ProgressBar, ProgressStyle};
use anyhow::{Context, Result};
use git2::{Oid, Repository};
use ai::{commit, config};
use ai::commit::Session;
use clap::Parser;
use ai::hook::*;
#[tokio::main]
async fn main() -> Result<()> {
env_logger::init();
let args = Args::parse();
let max_tokens = config::APP.max_diff_tokens;
let pb = ProgressBar::new_spinner();
let repo = Repository::open_from_env().context("Failed to open repository")?;
if args.commit_type.is_some() {
return Ok(());
}
let style = ProgressStyle::default_spinner()
.tick_strings(&["-", "\\", "|", "/"])
.template("{spinner:.blue} {msg}")
.context("Failed to create progress bar style")?;
pb.set_style(style);
pb.set_message("Generating commit message...");
pb.enable_steady_tick(Duration::from_millis(150));
let tree = match args.sha1.as_deref() {
Some("HEAD") | None => repo.head().ok().and_then(|head| head.peel_to_tree().ok()),
Some(sha1) => {
repo
.find_object(Oid::from_str(sha1)?, None)
.ok()
.and_then(|obj| obj.peel_to_tree().ok())
},
};
let patch = repo.to_patch(tree, max_tokens).context("Failed to get patch")?;
if patch.is_empty() {
Err(HookError::EmptyDiffOutput)?;
}
let pb_clone = pb.clone();
ctrlc::set_handler(move || {
pb_clone.finish_and_clear();
console::Term::stdout().show_cursor().expect("Failed to show cursor");
std::process::exit(1);
})?;
let session = Session::load_from_repo(&repo).await.unwrap();
let response = commit::generate(patch.to_string(), session.into(), pb.clone().into()).await?;
args.commit_msg_file.write(response.response.trim().to_string()).unwrap();
response.session.save_to_repo(&repo).await.unwrap();
pb.finish_and_clear();
Ok(())
}