backup_suite/ui/
colors.rs1use console::Style;
6
7#[derive(Debug, Clone, Copy, PartialEq)]
9pub enum ColorScheme {
10 Dark,
11 Light,
12 Auto,
13 HighContrast,
14}
15
16impl ColorScheme {
17 #[must_use]
19 pub fn detect() -> Self {
20 if let Ok(term) = std::env::var("TERM") {
21 if term.contains("256color") {
22 return Self::Auto;
23 }
24 }
25
26 if std::env::var("NO_COLOR").is_ok() {
28 return Self::HighContrast;
29 }
30
31 Self::Auto
32 }
33}
34
35pub struct ColorTheme {
37 scheme: ColorScheme,
38}
39
40impl ColorTheme {
41 #[must_use]
42 pub fn new(scheme: ColorScheme) -> Self {
43 Self { scheme }
44 }
45
46 #[must_use]
47 pub fn auto() -> Self {
48 Self::new(ColorScheme::detect())
49 }
50
51 #[must_use]
53 pub fn from_no_color(no_color: bool) -> Self {
54 if no_color {
55 Self::new(ColorScheme::HighContrast)
56 } else {
57 Self::auto()
58 }
59 }
60
61 #[must_use]
63 pub fn success(&self) -> Style {
64 match self.scheme {
65 ColorScheme::Dark | ColorScheme::Auto => Style::new().green(),
66 ColorScheme::Light => Style::new().green(),
67 ColorScheme::HighContrast => Style::new().bold(),
68 }
69 }
70
71 #[must_use]
73 pub fn error(&self) -> Style {
74 match self.scheme {
75 ColorScheme::Dark | ColorScheme::Auto => Style::new().red(),
76 ColorScheme::Light => Style::new().red(),
77 ColorScheme::HighContrast => Style::new().bold(),
78 }
79 }
80
81 #[must_use]
83 pub fn warning(&self) -> Style {
84 match self.scheme {
85 ColorScheme::Dark | ColorScheme::Auto => Style::new().yellow(),
86 ColorScheme::Light => Style::new().yellow(),
87 ColorScheme::HighContrast => Style::new().bold(),
88 }
89 }
90
91 #[must_use]
93 pub fn info(&self) -> Style {
94 match self.scheme {
95 ColorScheme::Dark | ColorScheme::Auto => Style::new().blue(),
96 ColorScheme::Light => Style::new().blue(),
97 ColorScheme::HighContrast => Style::new(),
98 }
99 }
100
101 #[must_use]
103 pub fn header(&self) -> Style {
104 match self.scheme {
105 ColorScheme::Dark | ColorScheme::Auto | ColorScheme::Light => Style::new().bold(),
106 ColorScheme::HighContrast => Style::new().bold(),
107 }
108 }
109
110 #[must_use]
112 pub fn highlight(&self) -> Style {
113 Style::new().bold()
114 }
115
116 #[must_use]
118 pub fn normal(&self) -> Style {
119 Style::new()
120 }
121
122 #[must_use]
124 pub fn dim(&self) -> Style {
125 match self.scheme {
126 ColorScheme::Dark => Style::new().dim(),
127 ColorScheme::Light => Style::new().dim(),
128 ColorScheme::Auto => Style::new().dim(),
129 ColorScheme::HighContrast => Style::new(),
130 }
131 }
132
133 #[must_use]
135 pub fn priority_high(&self) -> Style {
136 self.error() }
138
139 #[must_use]
140 pub fn priority_medium(&self) -> Style {
141 self.warning() }
143
144 #[must_use]
145 pub fn priority_low(&self) -> Style {
146 self.info() }
148}
149
150#[must_use]
152pub fn success(msg: &str) -> String {
153 ColorTheme::auto()
154 .success()
155 .apply_to(format!("[OK] {msg}"))
156 .to_string()
157}
158
159#[must_use]
161pub fn error(msg: &str) -> String {
162 ColorTheme::auto()
163 .error()
164 .apply_to(format!("[ERROR] {msg}"))
165 .to_string()
166}
167
168#[must_use]
170pub fn warning(msg: &str) -> String {
171 ColorTheme::auto()
172 .warning()
173 .apply_to(format!("[WARN] {msg}"))
174 .to_string()
175}
176
177#[must_use]
179pub fn info(msg: &str) -> String {
180 ColorTheme::auto()
181 .info()
182 .apply_to(format!("[INFO] {msg}"))
183 .to_string()
184}
185
186#[cfg(test)]
187mod tests {
188 use super::*;
189
190 #[test]
191 fn test_color_scheme_detection() {
192 let scheme = ColorScheme::detect();
193 assert!(matches!(
195 scheme,
196 ColorScheme::Auto | ColorScheme::HighContrast
197 ));
198 }
199
200 #[test]
201 fn test_theme_styles() {
202 let theme = ColorTheme::new(ColorScheme::Dark);
203
204 let _ = theme.success().apply_to("test");
206 let _ = theme.error().apply_to("test");
207 let _ = theme.warning().apply_to("test");
208 let _ = theme.info().apply_to("test");
209 }
210
211 #[test]
212 fn test_helper_functions() {
213 let _ = success("Test success");
215 let _ = error("Test error");
216 let _ = warning("Test warning");
217 let _ = info("Test info");
218 }
219}