1use colored::Colorize;
7use indicatif::{ProgressBar, ProgressStyle};
8use parking_lot::Mutex;
9use std::fmt::Write;
10use std::time::Duration;
11
12use crate::theme;
13use crate::theme::gradient_string;
14use crate::theme::names::{gradients as gradient_names, tokens};
15
16pub mod rgb {
23 use crate::theme;
24 use crate::theme::names::tokens;
25
26 #[must_use]
28 pub fn accent_primary() -> (u8, u8, u8) {
29 theme::current()
30 .color(tokens::ACCENT_PRIMARY)
31 .to_rgb_tuple()
32 }
33
34 #[must_use]
36 pub fn accent_secondary() -> (u8, u8, u8) {
37 theme::current()
38 .color(tokens::ACCENT_SECONDARY)
39 .to_rgb_tuple()
40 }
41
42 #[must_use]
44 pub fn accent_tertiary() -> (u8, u8, u8) {
45 theme::current()
46 .color(tokens::ACCENT_TERTIARY)
47 .to_rgb_tuple()
48 }
49
50 #[must_use]
52 pub fn warning() -> (u8, u8, u8) {
53 theme::current().color(tokens::WARNING).to_rgb_tuple()
54 }
55
56 #[must_use]
58 pub fn success() -> (u8, u8, u8) {
59 theme::current().color(tokens::SUCCESS).to_rgb_tuple()
60 }
61
62 #[must_use]
64 pub fn error() -> (u8, u8, u8) {
65 theme::current().color(tokens::ERROR).to_rgb_tuple()
66 }
67
68 #[must_use]
70 pub fn text_primary() -> (u8, u8, u8) {
71 theme::current().color(tokens::TEXT_PRIMARY).to_rgb_tuple()
72 }
73
74 #[must_use]
76 pub fn text_secondary() -> (u8, u8, u8) {
77 theme::current()
78 .color(tokens::TEXT_SECONDARY)
79 .to_rgb_tuple()
80 }
81
82 #[must_use]
84 pub fn text_muted() -> (u8, u8, u8) {
85 theme::current().color(tokens::TEXT_MUTED).to_rgb_tuple()
86 }
87
88 #[must_use]
90 pub fn text_dim() -> (u8, u8, u8) {
91 theme::current().color(tokens::TEXT_DIM).to_rgb_tuple()
92 }
93}
94
95static QUIET_MODE: std::sync::LazyLock<Mutex<bool>> =
97 std::sync::LazyLock::new(|| Mutex::new(false));
98
99pub fn set_quiet_mode(enabled: bool) {
101 let mut quiet_mode = QUIET_MODE.lock();
102 *quiet_mode = enabled;
103}
104
105pub fn is_quiet_mode() -> bool {
107 *QUIET_MODE.lock()
108}
109
110#[must_use]
116pub fn create_spinner(message: &str) -> ProgressBar {
117 if is_quiet_mode() {
119 return ProgressBar::hidden();
120 }
121
122 let pb = ProgressBar::new_spinner();
123
124 if crate::agents::status::is_agent_mode_enabled() {
126 pb.set_style(
127 ProgressStyle::default_spinner()
128 .tick_chars("⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏")
129 .template("{spinner:.bright_cyan.bold} {msg}")
130 .expect("Could not set spinner style"),
131 );
132
133 pb.set_message("◎ Iris initializing...");
135
136 let pb_clone = pb.clone();
138 tokio::spawn(async move {
139 let mut interval = tokio::time::interval(tokio::time::Duration::from_millis(200));
140 loop {
141 interval.tick().await;
142 let status_message = crate::agents::status::IRIS_STATUS.get_for_spinner();
143 pb_clone.set_message(status_message.text);
144 }
145 });
146
147 pb.enable_steady_tick(Duration::from_millis(100));
148 } else {
149 pb.set_style(
150 ProgressStyle::default_spinner()
151 .tick_chars("✦✧✶✷✸✹✺✻✼✽")
152 .template("{spinner} {msg}")
153 .expect("Could not set spinner style"),
154 );
155 pb.set_message(message.to_string());
156 pb.enable_steady_tick(Duration::from_millis(100));
157 }
158
159 pb
160}
161
162pub fn print_info(message: &str) {
164 if !is_quiet_mode() {
165 let color = theme::current().color(tokens::INFO);
166 println!("{}", message.truecolor(color.r, color.g, color.b).bold());
167 }
168}
169
170pub fn print_warning(message: &str) {
172 if !is_quiet_mode() {
173 let color = theme::current().color(tokens::WARNING);
174 println!("{}", message.truecolor(color.r, color.g, color.b).bold());
175 }
176}
177
178pub fn print_error(message: &str) {
180 let color = theme::current().color(tokens::ERROR);
182 eprintln!("{}", message.truecolor(color.r, color.g, color.b).bold());
183}
184
185pub fn print_success(message: &str) {
187 if !is_quiet_mode() {
188 let color = theme::current().color(tokens::SUCCESS);
189 println!("{}", message.truecolor(color.r, color.g, color.b).bold());
190 }
191}
192
193pub fn print_version(version: &str) {
194 if !is_quiet_mode() {
195 let t = theme::current();
196 let purple = t.color(tokens::ACCENT_PRIMARY);
197 let cyan = t.color(tokens::ACCENT_SECONDARY);
198 let green = t.color(tokens::SUCCESS);
199
200 println!(
201 "{} {} {}",
202 "🔮 Git-Iris".truecolor(purple.r, purple.g, purple.b).bold(),
203 "version".truecolor(cyan.r, cyan.g, cyan.b),
204 version.truecolor(green.r, green.g, green.b)
205 );
206 }
207}
208
209pub fn print_bordered_content(content: &str) {
211 if !is_quiet_mode() {
212 let color = theme::current().color(tokens::ACCENT_PRIMARY);
213 println!("{}", "━".repeat(50).truecolor(color.r, color.g, color.b));
214 println!("{content}");
215 println!("{}", "━".repeat(50).truecolor(color.r, color.g, color.b));
216 }
217}
218
219pub fn print_message(message: &str) {
221 if !is_quiet_mode() {
222 println!("{message}");
223 }
224}
225
226pub fn print_newline() {
228 if !is_quiet_mode() {
229 println!();
230 }
231}
232
233#[must_use]
235pub fn create_gradient_text(text: &str) -> String {
236 if let Some(gradient) = theme::current().get_gradient(gradient_names::PRIMARY) {
237 gradient_string(text, gradient)
238 } else {
239 let gradient = vec![
241 (225, 53, 255), (200, 100, 255), (180, 150, 250), (150, 200, 245), (128, 255, 234), ];
247 apply_gradient(text, &gradient)
248 }
249}
250
251#[must_use]
253pub fn create_secondary_gradient_text(text: &str) -> String {
254 if let Some(gradient) = theme::current().get_gradient(gradient_names::WARM) {
255 gradient_string(text, gradient)
256 } else {
257 let gradient = vec![
259 (255, 106, 193), (255, 150, 180), (255, 200, 160), (248, 230, 140), (241, 250, 140), ];
265 apply_gradient(text, &gradient)
266 }
267}
268
269fn apply_gradient(text: &str, gradient: &[(u8, u8, u8)]) -> String {
270 let chars: Vec<char> = text.chars().collect();
271 let chars_len = chars.len();
272 let gradient_len = gradient.len();
273
274 let mut result = String::new();
275
276 if chars_len == 0 || gradient_len == 0 {
277 return result;
278 }
279
280 chars.iter().enumerate().fold(&mut result, |acc, (i, &c)| {
281 let index = if chars_len == 1 {
282 0
283 } else {
284 i * (gradient_len - 1) / (chars_len - 1)
285 };
286 let (r, g, b) = gradient[index];
287 write!(acc, "{}", c.to_string().truecolor(r, g, b)).expect("writing to string cannot fail");
288 acc
289 });
290
291 result
292}