1use core::fmt;
2use git2::{ErrorCode, Repository, RepositoryOpenFlags, Status, Statuses};
3use std::fmt::{Error, Formatter};
4use std::path::Path;
5
6struct GitStatus {
7 new: i32,
8 modified: i32,
9 deleted: i32,
10 renamed: i32,
11 type_changed: i32,
12 conflicted: i32,
13}
14
15impl fmt::Display for GitStatus {
16 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> {
17 let mut fmt_string = String::new();
18 if self.new != 0 {
20 fmt_string.push_str(format!("{}A", self.new).as_str())
21 }
22
23 if self.modified != 0 {
24 fmt_string.push_str(format!("{}M", self.modified).as_str())
25 }
26
27 if self.deleted != 0 {
28 fmt_string.push_str(format!("{}D", self.deleted).as_str())
29 }
30
31 if self.renamed != 0 {
32 fmt_string.push_str(format!("{}R", self.renamed).as_str())
33 }
34
35 if self.type_changed != 0 {
36 fmt_string.push_str(format!("{}T", self.type_changed).as_str())
37 }
38 if self.conflicted != 0 {
39 fmt_string.push_str(format!("{}C", self.conflicted).as_str())
40 }
41 write!(f, "{}", fmt_string)
42 }
43}
44
45pub fn repo() -> Option<Repository> {
46 let open_flags = RepositoryOpenFlags::all();
47 let paths: [&Path; 0] = []; match Repository::open_ext(".", open_flags, paths.iter()) {
49 Ok(repo) => Some(repo),
50 Err(_e) => None,
51 }
52}
53
54pub fn head_status(repo: &Repository) -> String {
55 let head = match repo.head() {
56 Ok(head) => Some(head),
57 Err(ref e) if e.code() == ErrorCode::UnbornBranch || e.code() == ErrorCode::NotFound => {
58 None
59 }
60 Err(_e) => None,
61 };
62
63 head.as_ref()
64 .and_then(|r| r.shorthand())
65 .unwrap_or("HEAD")
66 .to_string()
67}
68
69pub fn status(repo: &Repository) -> String {
70 let result = repo.statuses(None);
71
72 match result.as_ref() {
73 Ok(statuses) => format!("{}", git_status(statuses)),
74 Err(_e) => format!(""),
75 }
76}
77
78fn git_status(statuses: &Statuses) -> GitStatus {
79 let mut new = 0;
81 let mut modified = 0;
82 let mut renamed = 0;
83 let mut deleted = 0;
84 let mut type_changed = 0;
85 let mut conflicted = 0;
86
87 for entry in statuses.iter().filter(|e| e.status() != Status::CURRENT) {
88 match entry.status() {
89 s if s.contains(Status::INDEX_NEW) => new += 1,
90 s if s.contains(Status::INDEX_MODIFIED) => modified += 1,
91 s if s.contains(Status::INDEX_DELETED) => deleted += 1,
92 s if s.contains(Status::INDEX_RENAMED) => renamed += 1,
93 s if s.contains(Status::INDEX_TYPECHANGE) => type_changed += 1,
94 s if s.contains(Status::CONFLICTED) => conflicted += 1,
95 _ => (),
96 };
97
98 match entry.status() {
99 s if s.contains(git2::Status::WT_MODIFIED) => modified += 1,
100 s if s.contains(git2::Status::WT_DELETED) => deleted += 1,
101 s if s.contains(git2::Status::WT_RENAMED) => renamed += 1,
102 s if s.contains(git2::Status::WT_TYPECHANGE) => type_changed += 1,
103 _ => (),
104 };
105 }
106
107 GitStatus {
108 new,
109 modified,
110 renamed,
111 deleted,
112 type_changed,
113 conflicted,
114 }
115}