Skip to main content

git_iris/types/
commit.rs

1//! Commit message types and formatting
2
3use schemars::JsonSchema;
4use serde::{Deserialize, Serialize};
5use std::fmt::Write;
6use textwrap;
7
8/// Model for commit message generation results
9#[derive(Serialize, Deserialize, JsonSchema, Debug, Clone)]
10pub struct GeneratedMessage {
11    /// Optional emoji for the commit message
12    pub emoji: Option<String>,
13    /// Commit message title/subject line
14    pub title: String,
15    /// Detailed commit message body
16    pub message: String,
17    /// Brief completion status message for the UI (e.g., "Auth refactor ready.")
18    #[serde(default)]
19    pub completion_message: Option<String>,
20}
21
22impl GeneratedMessage {
23    pub(crate) fn subject(&self) -> String {
24        let title = self.title_without_repeated_emoji();
25
26        match self
27            .emoji
28            .as_deref()
29            .map(str::trim)
30            .filter(|emoji| !emoji.is_empty())
31        {
32            Some(emoji) => format!("{emoji} {title}"),
33            None => title.to_string(),
34        }
35    }
36
37    pub(crate) fn title_without_repeated_emoji(&self) -> &str {
38        let mut title = self.title.trim_start();
39
40        let Some(emoji) = self
41            .emoji
42            .as_deref()
43            .map(str::trim)
44            .filter(|emoji| !emoji.is_empty())
45        else {
46            return title;
47        };
48
49        while let Some(rest) = title.strip_prefix(emoji) {
50            title = rest.trim_start();
51        }
52
53        title
54    }
55}
56
57/// Formats a commit message from a `GeneratedMessage`
58#[must_use]
59pub fn format_commit_message(response: &GeneratedMessage) -> String {
60    let mut message = String::new();
61
62    write!(&mut message, "{}", response.subject()).expect("write to string should not fail");
63    message.push_str("\n\n");
64
65    let wrapped_message = textwrap::wrap(&response.message, 78);
66    for line in wrapped_message {
67        message.push_str(&line);
68        message.push('\n');
69    }
70
71    message
72}