Add command to use ai to generate commit msg

This commit is contained in:
extrawurst 2023-12-15 19:33:27 +01:00
parent 51d8f96348
commit c98ca240a6
7 changed files with 91 additions and 2 deletions

1
Cargo.lock generated
View file

@ -765,6 +765,7 @@ dependencies = [
"filetreelist",
"fuzzy-matcher",
"gh-emoji",
"git2-summarize",
"indexmap",
"itertools",
"log",

View file

@ -16,6 +16,7 @@ keywords = ["git", "gui", "cli", "terminal", "ui"]
[dependencies]
anyhow = "1.0"
asyncgit = { path = "./asyncgit", version = "0.24", default-features = false }
git2-summarize = { path = "./git2-summarize", version = "0.1"}
backtrace = "0.3"
bitflags = "1.3"
bugreport = "0.5"

View file

@ -9,7 +9,7 @@ use crate::{
error::Error,
error::Result,
hash,
sync::{get_stashes, repository::repo},
sync::{get_stashes, repository::repo, utils::bytes2string},
};
use easy_cast::Conv;
use git2::{
@ -398,6 +398,35 @@ fn raw_diff_to_file_diff(
Ok(res.into_inner())
}
///
pub fn unified_stage_diff(repo_path: &RepoPath) -> Result<String> {
scope_time!("unified_stage_diff");
let repo = repo(repo_path)?;
let diff = get_diff_raw(&repo, "*", true, false, None)?;
let mut output = String::with_capacity(32);
diff.print(DiffFormat::Patch, |_delta, _hunk, line| {
let prefix = match line.origin_value() {
git2::DiffLineType::Addition => "+",
git2::DiffLineType::Deletion => "-",
_ => "",
};
output.push_str(&format!(
"{}{}",
prefix,
bytes2string(line.content()).unwrap()
));
true
})?;
Ok(output)
}
const fn is_newline(c: char) -> bool {
c == '\n' || c == '\r'
}

View file

@ -62,7 +62,7 @@ pub use config::{
get_config_string, untracked_files_config,
ShowUntrackedFilesConfig,
};
pub use diff::get_diff_commit;
pub use diff::{get_diff_commit, unified_stage_diff};
pub use git2::BranchType;
pub use hooks::{
hooks_commit_msg, hooks_post_commit, hooks_pre_commit, HookResult,

View file

@ -59,6 +59,7 @@ pub struct CommitComponent {
commit_msg_history_idx: usize,
options: SharedOptions,
verify: bool,
open_ai_token: Option<String>,
}
const FIRST_LINE_LIMIT: usize = 50;
@ -90,6 +91,7 @@ impl CommitComponent {
commit_msg_history_idx: 0,
options,
verify: true,
open_ai_token: std::env::var("OPENAI_API_KEY").ok(),
}
}
@ -352,6 +354,30 @@ impl CommitComponent {
self.input.set_text(signed_msg);
}
}
fn commit_summarize(&mut self) -> Result<()> {
use std::result::Result::Ok;
if let Some(api_key) = self.open_ai_token.as_ref() {
let mut unified_diff =
sync::unified_stage_diff(&self.repo.borrow())?;
while unified_diff.len() > 3500 {
unified_diff.pop();
}
match git2_summarize::git_diff_summarize(
&api_key,
&unified_diff,
FIRST_LINE_LIMIT,
) {
Ok(msg) => self.input.set_text(msg),
Err(e) => bail!(e),
};
}
Ok(())
}
fn toggle_verify(&mut self) {
self.verify = !self.verify;
}
@ -539,6 +565,14 @@ impl Component for CommitComponent {
self.options.borrow().has_commit_msg_history(),
true,
));
out.push(CommandInfo::new(
strings::commands::commit_msg_summarize(
&self.key_config,
),
self.open_ai_token.is_some(),
true,
));
}
visibility_blocking(self)
@ -596,6 +630,15 @@ impl Component for CommitComponent {
self.key_config.keys.toggle_signoff,
) {
self.signoff_commit();
} else if key_match(
e,
self.key_config.keys.commit_msg_summarize,
) {
try_or_popup!(
self,
"commit summary error:",
self.commit_summarize()
);
}
// stop key event propagation
return Ok(EventState::Consumed);

View file

@ -120,6 +120,7 @@ pub struct KeysList {
pub view_submodule_parent: GituiKeyEvent,
pub update_submodule: GituiKeyEvent,
pub commit_history_next: GituiKeyEvent,
pub commit_msg_summarize: GituiKeyEvent,
}
#[rustfmt::skip]
@ -209,6 +210,7 @@ impl Default for KeysList {
view_submodule_parent: GituiKeyEvent::new(KeyCode::Char('p'), KeyModifiers::empty()),
update_submodule: GituiKeyEvent::new(KeyCode::Char('u'), KeyModifiers::empty()),
commit_history_next: GituiKeyEvent::new(KeyCode::Char('n'), KeyModifiers::CONTROL),
commit_msg_summarize: GituiKeyEvent::new(KeyCode::Char('g'), KeyModifiers::CONTROL),
}
}
}

View file

@ -965,6 +965,19 @@ pub mod commands {
CMD_GROUP_COMMIT_POPUP,
)
}
pub fn commit_msg_summarize(
key_config: &SharedKeyConfig,
) -> CommandText {
CommandText::new(
format!(
"Summarize [{}]",
key_config
.get_hint(key_config.keys.commit_msg_summarize),
),
"use openai chat-gpt to generate commit message",
CMD_GROUP_COMMIT_POPUP,
)
}
pub fn commit_enter(key_config: &SharedKeyConfig) -> CommandText {
CommandText::new(
format!(