git_x/
what.rs

1use std::process::Command;
2
3pub fn run(target: Option<String>) {
4    let target_branch = target.unwrap_or_else(get_default_target);
5
6    // Get current branch name
7    let current_branch_output = Command::new("git")
8        .args(["rev-parse", "--abbrev-ref", "HEAD"])
9        .output()
10        .expect("Failed to get current branch");
11    let current_branch = String::from_utf8_lossy(&current_branch_output.stdout)
12        .trim()
13        .to_string();
14
15    println!(
16        "{}",
17        format_branch_comparison(&current_branch, &target_branch)
18    );
19
20    // Get ahead/behind commit counts
21    let rev_list_output = Command::new("git")
22        .args([
23            "rev-list",
24            "--left-right",
25            "--count",
26            &format_rev_list_range(&target_branch, &current_branch),
27        ])
28        .output()
29        .expect("Failed to get ahead/behind count");
30    let output_str = String::from_utf8_lossy(&rev_list_output.stdout);
31    let (ahead, behind) = parse_commit_counts(&output_str);
32
33    let (ahead_msg, behind_msg) = format_commit_counts(&ahead, &behind);
34    println!("{ahead_msg}");
35    println!("{behind_msg}");
36
37    // Get diff summary
38    let diff_output = Command::new("git")
39        .args([
40            "diff",
41            "--name-status",
42            &format_rev_list_range(&target_branch, &current_branch),
43        ])
44        .output()
45        .expect("Failed to get diff");
46    let diff = String::from_utf8_lossy(&diff_output.stdout);
47
48    println!("Changes:");
49    for line in diff.lines() {
50        if let Some(formatted_line) = format_diff_line(line) {
51            println!("{formatted_line}");
52        }
53    }
54}
55
56// Helper function to get default target branch
57const DEFAULT_TARGET: &str = "main";
58
59pub fn get_default_target() -> String {
60    DEFAULT_TARGET.to_string()
61}
62
63// Helper function to format branch comparison header
64pub fn format_branch_comparison(current: &str, target: &str) -> String {
65    format!("Branch: {current} vs {target}")
66}
67
68// Helper function to format commit counts
69pub fn format_commit_counts(ahead: &str, behind: &str) -> (String, String) {
70    (
71        format!("+ {ahead} commits ahead"),
72        format!("- {behind} commits behind"),
73    )
74}
75
76// Helper function to format rev-list range
77pub fn format_rev_list_range(target: &str, current: &str) -> String {
78    format!("{target}...{current}")
79}
80
81// Helper function to parse ahead/behind counts
82pub fn parse_commit_counts(output: &str) -> (String, String) {
83    let mut counts = output.split_whitespace();
84    let behind = counts.next().unwrap_or("0").to_string();
85    let ahead = counts.next().unwrap_or("0").to_string();
86    (ahead, behind)
87}
88
89// Helper function to convert git status to symbol
90pub fn git_status_to_symbol(status: &str) -> &str {
91    match status {
92        "A" => "+",
93        "M" => "~",
94        "D" => "-",
95        other => other,
96    }
97}
98
99// Helper function to format diff line
100pub fn format_diff_line(line: &str) -> Option<String> {
101    let parts: Vec<&str> = line.split_whitespace().collect();
102    if parts.len() >= 2 {
103        let symbol = git_status_to_symbol(parts[0]);
104        Some(format!(" - {} {}", symbol, parts[1]))
105    } else {
106        None
107    }
108}