1use std::fmt;
2
3use git2::StatusOptions;
4use ratatui::{
5 style::{
6 Color, Stylize,
7 palette::material::WHITE,
8 },
9 text::Line,
10};
11
12use crate::git::kit::KitRepo;
13
14#[derive(Debug)]
15pub struct KitStatus {
16 pub files: Vec<(String, git2::Status)>,
17 pub pretty: Vec<(String, String)>,
18}
19
20impl KitStatus {
21 pub fn new(repo: &KitRepo) -> Self {
22 let mut opts = StatusOptions::new();
23 opts.include_untracked(true)
24 .recurse_untracked_dirs(true)
25 .include_ignored(false);
26
27 let empty = Self {
28 files: vec![],
29 pretty: vec![("".to_owned(), "no files changes".to_owned())],
30 };
31
32 if let Ok(statuses) = repo.inner.statuses(Some(&mut opts)) {
33 if statuses.is_empty() {
34 return empty;
35 }
36
37 let files: Vec<(String, git2::Status)> = statuses
38 .iter()
39 .map(|entry| {
40 let path = entry.path().unwrap_or("(no path)").to_string();
41 let status = entry.status();
42 (path, status)
43 })
44 .collect();
45 let pretty = KitStatus::pretty(&files);
46 Self { files, pretty }
47 } else {
48 empty
50 }
51 }
52
53 fn pretty(files: &Vec<(String, git2::Status)>) -> Vec<(String, String)> {
55 let mut path_status: Vec<(String, String)> = Vec::new();
56
57 for (path, status) in files {
58 let code = match status {
59 s if s.contains(git2::Status::WT_NEW) => "??",
60 s if s.contains(git2::Status::INDEX_NEW) => "A ",
61 s if s.contains(git2::Status::WT_MODIFIED) => " M",
62 s if s.contains(git2::Status::INDEX_MODIFIED) => "M ",
63 s if s.contains(git2::Status::WT_DELETED) => " D",
64 s if s.contains(git2::Status::INDEX_DELETED) => "D ",
65 _ => " ",
66 };
67 path_status.push((path.to_string(), code.to_string()));
68 }
69 path_status
70 }
71
72 pub fn tui_print(&self) -> Vec<Line<'_>> {
74 let lines: Vec<Line<'_>> = self
75 .pretty
76 .iter()
77 .map(|(path, code)| {
78 let line = Line::from(vec![
79 format!("{}", code).fg(Color::Green),
80 " ".into(),
81 format!(" @ {}", path).fg(WHITE),
82 ]);
83 line
84 })
85 .collect();
86 lines
87 }
88}
89
90impl fmt::Display for KitStatus {
91 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
92 if self.files.is_empty() {
93 return write!(f, "Your branch is clean.");
94 }
95
96 for (path, status) in &self.files {
97 let code = match *status {
99 s if s.contains(git2::Status::WT_NEW) => "??",
100 s if s.contains(git2::Status::INDEX_NEW) => "A ",
101 s if s.contains(git2::Status::WT_MODIFIED) => " M",
102 s if s.contains(git2::Status::INDEX_MODIFIED) => "M ",
103 s if s.contains(git2::Status::WT_DELETED) => " D",
104 s if s.contains(git2::Status::INDEX_DELETED) => "D ",
105 _ => " ",
106 };
107 writeln!(f, "{} {}", code, path)?;
108 }
109 Ok(())
110 }
111}