Skip to main content

bctx_forge/awareness/
git.rs

1use super::{AwarenessMap, EcosystemAwareness};
2use once_cell::sync::Lazy;
3use regex::Regex;
4
5static STATS_RE: Lazy<Regex> = Lazy::new(|| {
6    Regex::new(r"(\d+) files? changed(?:, (\d+) insertions?\(\+\))?(?:, (\d+) deletions?\(-\))?")
7        .unwrap()
8});
9static BRANCH_RE: Lazy<Regex> = Lazy::new(|| Regex::new(r"On branch (.+)").unwrap());
10static AHEAD_BEHIND_RE: Lazy<Regex> =
11    Lazy::new(|| Regex::new(r"Your branch is (ahead|behind).+by (\d+) commit").unwrap());
12static COMMIT_RE: Lazy<Regex> = Lazy::new(|| Regex::new(r"^([0-9a-f]{7,40})\s+(.+)$").unwrap());
13
14pub struct GitAwareness;
15
16impl EcosystemAwareness for GitAwareness {
17    fn matches(&self, program: &str, _args: &[String]) -> bool {
18        matches!(
19            program.split('/').next_back().unwrap_or(program),
20            "git" | "gh" | "jj"
21        )
22    }
23
24    fn extract(&self, stdout: &str, stderr: &str, exit_code: i32) -> AwarenessMap {
25        let mut map = AwarenessMap::new("vcs", "git");
26        map.insert("exit_code", exit_code.to_string());
27
28        let combined = format!("{stdout}\n{stderr}");
29
30        if let Some(cap) = BRANCH_RE.captures(&combined) {
31            map.insert("branch", cap[1].trim().to_string());
32        }
33        if let Some(cap) = STATS_RE.captures(&combined) {
34            map.insert("files_changed", cap[1].to_string());
35            if let Some(ins) = cap.get(2) {
36                map.insert("insertions", ins.as_str().to_string());
37            }
38            if let Some(del) = cap.get(3) {
39                map.insert("deletions", del.as_str().to_string());
40            }
41        }
42        if let Some(cap) = AHEAD_BEHIND_RE.captures(&combined) {
43            map.insert("ahead_behind", cap[1].to_string());
44            map.insert("ahead_behind_count", cap[2].to_string());
45        }
46
47        let commit_count = COMMIT_RE.captures_iter(stdout).count();
48        if commit_count > 0 {
49            map.insert("commit_count", commit_count.to_string());
50        }
51
52        map
53    }
54}