1use nu_ansi_term::{AnsiString as ANSIString, Style};
8
9use crate::fs::fields as f;
10use crate::output::cell::{DisplayWidth, TextCell};
11
12impl f::Git {
13 pub fn render(self, colours: &dyn Colours) -> TextCell {
14 TextCell {
15 width: DisplayWidth::from(2),
16 contents: vec![self.staged.render(colours), self.unstaged.render(colours)].into(),
17 }
18 }
19}
20
21impl f::GitStatus {
22 fn render(self, colours: &dyn Colours) -> ANSIString<'static> {
23 #[rustfmt::skip]
24 return match self {
25 Self::NotModified => colours.not_modified().paint("-"),
26 Self::New => colours.new().paint("N"),
27 Self::Modified => colours.modified().paint("M"),
28 Self::Deleted => colours.deleted().paint("D"),
29 Self::Renamed => colours.renamed().paint("R"),
30 Self::TypeChange => colours.type_change().paint("T"),
31 Self::Ignored => colours.ignored().paint("I"),
32 Self::Conflicted => colours.conflicted().paint("U"),
33 };
34 }
35}
36
37pub trait Colours {
38 fn not_modified(&self) -> Style;
39 #[allow(clippy::new_ret_no_self, clippy::wrong_self_convention)]
42 fn new(&self) -> Style;
43 fn modified(&self) -> Style;
44 fn deleted(&self) -> Style;
45 fn renamed(&self) -> Style;
46 fn type_change(&self) -> Style;
47 fn ignored(&self) -> Style;
48 fn conflicted(&self) -> Style;
49}
50
51impl f::SubdirGitRepo {
52 pub fn render(self, colours: &dyn RepoColours) -> TextCell {
53 let branch_name = match self.branch {
54 Some(name) => match name.as_ref() {
55 "main" | "master" => colours.branch_main().paint(name),
56 _ => colours.branch_other().paint(name),
57 },
58 None => colours.no_repo().paint("-"),
59 };
60
61 if let Some(status) = self.status {
62 TextCell {
63 width: DisplayWidth::from(2) + DisplayWidth::from(branch_name.as_str()),
64 contents: vec![
65 status.render(colours),
66 Style::default().paint(" "),
67 branch_name,
68 ]
69 .into(),
70 }
71 } else {
72 TextCell {
73 width: DisplayWidth::from(branch_name.as_str()),
74 contents: vec![branch_name].into(),
75 }
76 }
77 }
78}
79
80impl f::SubdirGitRepoStatus {
81 pub fn render(self, colours: &dyn RepoColours) -> ANSIString<'static> {
82 match self {
83 Self::NoRepo => colours.no_repo().paint("-"),
84 Self::GitClean => colours.git_clean().paint("|"),
85 Self::GitDirty => colours.git_dirty().paint("+"),
86 }
87 }
88}
89
90pub trait RepoColours {
91 fn branch_main(&self) -> Style;
92 fn branch_other(&self) -> Style;
93 fn no_repo(&self) -> Style;
94 fn git_clean(&self) -> Style;
95 fn git_dirty(&self) -> Style;
96}
97
98#[cfg(test)]
99pub mod test {
100 use super::Colours;
101 use crate::fs::fields as f;
102 use crate::output::cell::{DisplayWidth, TextCell};
103
104 use nu_ansi_term::Color::*;
105 use nu_ansi_term::Style;
106
107 struct TestColours;
108
109 impl Colours for TestColours {
110 fn not_modified(&self) -> Style {
111 Fixed(90).normal()
112 }
113 fn new(&self) -> Style {
114 Fixed(91).normal()
115 }
116 fn modified(&self) -> Style {
117 Fixed(92).normal()
118 }
119 fn deleted(&self) -> Style {
120 Fixed(93).normal()
121 }
122 fn renamed(&self) -> Style {
123 Fixed(94).normal()
124 }
125 fn type_change(&self) -> Style {
126 Fixed(95).normal()
127 }
128 fn ignored(&self) -> Style {
129 Fixed(96).normal()
130 }
131 fn conflicted(&self) -> Style {
132 Fixed(97).normal()
133 }
134 }
135
136 #[test]
137 fn git_blank() {
138 let stati = f::Git {
139 staged: f::GitStatus::NotModified,
140 unstaged: f::GitStatus::NotModified,
141 };
142
143 let expected = TextCell {
144 width: DisplayWidth::from(2),
145 contents: vec![Fixed(90).paint("-"), Fixed(90).paint("-")].into(),
146 };
147
148 assert_eq!(expected, stati.render(&TestColours));
149 }
150
151 #[test]
152 fn git_new_changed() {
153 let stati = f::Git {
154 staged: f::GitStatus::New,
155 unstaged: f::GitStatus::Modified,
156 };
157
158 let expected = TextCell {
159 width: DisplayWidth::from(2),
160 contents: vec![Fixed(91).paint("N"), Fixed(92).paint("M")].into(),
161 };
162
163 assert_eq!(expected, stati.render(&TestColours));
164 }
165}