use colored::Colorize;
use indicatif::{ProgressBar, ProgressStyle};
use parking_lot::Mutex;
use std::fmt::Write;
use std::time::Duration;
use crate::theme;
use crate::theme::gradient_string;
use crate::theme::names::{gradients as gradient_names, tokens};
pub mod rgb {
use crate::theme;
use crate::theme::names::tokens;
#[must_use]
pub fn accent_primary() -> (u8, u8, u8) {
theme::current()
.color(tokens::ACCENT_PRIMARY)
.to_rgb_tuple()
}
#[must_use]
pub fn accent_secondary() -> (u8, u8, u8) {
theme::current()
.color(tokens::ACCENT_SECONDARY)
.to_rgb_tuple()
}
#[must_use]
pub fn accent_tertiary() -> (u8, u8, u8) {
theme::current()
.color(tokens::ACCENT_TERTIARY)
.to_rgb_tuple()
}
#[must_use]
pub fn warning() -> (u8, u8, u8) {
theme::current().color(tokens::WARNING).to_rgb_tuple()
}
#[must_use]
pub fn success() -> (u8, u8, u8) {
theme::current().color(tokens::SUCCESS).to_rgb_tuple()
}
#[must_use]
pub fn error() -> (u8, u8, u8) {
theme::current().color(tokens::ERROR).to_rgb_tuple()
}
#[must_use]
pub fn text_primary() -> (u8, u8, u8) {
theme::current().color(tokens::TEXT_PRIMARY).to_rgb_tuple()
}
#[must_use]
pub fn text_secondary() -> (u8, u8, u8) {
theme::current()
.color(tokens::TEXT_SECONDARY)
.to_rgb_tuple()
}
#[must_use]
pub fn text_muted() -> (u8, u8, u8) {
theme::current().color(tokens::TEXT_MUTED).to_rgb_tuple()
}
#[must_use]
pub fn text_dim() -> (u8, u8, u8) {
theme::current().color(tokens::TEXT_DIM).to_rgb_tuple()
}
}
static QUIET_MODE: std::sync::LazyLock<Mutex<bool>> =
std::sync::LazyLock::new(|| Mutex::new(false));
pub fn set_quiet_mode(enabled: bool) {
let mut quiet_mode = QUIET_MODE.lock();
*quiet_mode = enabled;
}
pub fn is_quiet_mode() -> bool {
*QUIET_MODE.lock()
}
#[must_use]
pub fn create_spinner(message: &str) -> ProgressBar {
if is_quiet_mode() {
return ProgressBar::hidden();
}
let pb = ProgressBar::new_spinner();
if crate::agents::status::is_agent_mode_enabled() {
pb.set_style(
ProgressStyle::default_spinner()
.tick_chars("⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏")
.template("{spinner:.bright_cyan.bold} {msg}")
.expect("Could not set spinner style"),
);
pb.set_message("◎ Iris initializing...");
let pb_clone = pb.clone();
tokio::spawn(async move {
let mut interval = tokio::time::interval(tokio::time::Duration::from_millis(200));
loop {
interval.tick().await;
let status_message = crate::agents::status::IRIS_STATUS.get_for_spinner();
pb_clone.set_message(status_message.text);
}
});
pb.enable_steady_tick(Duration::from_millis(100));
} else {
pb.set_style(
ProgressStyle::default_spinner()
.tick_chars("✦✧✶✷✸✹✺✻✼✽")
.template("{spinner} {msg}")
.expect("Could not set spinner style"),
);
pb.set_message(message.to_string());
pb.enable_steady_tick(Duration::from_millis(100));
}
pb
}
pub fn print_info(message: &str) {
if !is_quiet_mode() {
let color = theme::current().color(tokens::INFO);
println!("{}", message.truecolor(color.r, color.g, color.b).bold());
}
}
pub fn print_warning(message: &str) {
if !is_quiet_mode() {
let color = theme::current().color(tokens::WARNING);
println!("{}", message.truecolor(color.r, color.g, color.b).bold());
}
}
pub fn print_error(message: &str) {
let color = theme::current().color(tokens::ERROR);
eprintln!("{}", message.truecolor(color.r, color.g, color.b).bold());
}
pub fn print_success(message: &str) {
if !is_quiet_mode() {
let color = theme::current().color(tokens::SUCCESS);
println!("{}", message.truecolor(color.r, color.g, color.b).bold());
}
}
pub fn print_version(version: &str) {
if !is_quiet_mode() {
let t = theme::current();
let purple = t.color(tokens::ACCENT_PRIMARY);
let cyan = t.color(tokens::ACCENT_SECONDARY);
let green = t.color(tokens::SUCCESS);
println!(
"{} {} {}",
"🔮 Git-Iris".truecolor(purple.r, purple.g, purple.b).bold(),
"version".truecolor(cyan.r, cyan.g, cyan.b),
version.truecolor(green.r, green.g, green.b)
);
}
}
pub fn print_bordered_content(content: &str) {
if !is_quiet_mode() {
let color = theme::current().color(tokens::ACCENT_PRIMARY);
println!("{}", "━".repeat(50).truecolor(color.r, color.g, color.b));
println!("{content}");
println!("{}", "━".repeat(50).truecolor(color.r, color.g, color.b));
}
}
pub fn print_message(message: &str) {
if !is_quiet_mode() {
println!("{message}");
}
}
pub fn print_newline() {
if !is_quiet_mode() {
println!();
}
}
#[must_use]
pub fn create_gradient_text(text: &str) -> String {
if let Some(gradient) = theme::current().get_gradient(gradient_names::PRIMARY) {
gradient_string(text, gradient)
} else {
let gradient = vec![
(225, 53, 255), (200, 100, 255), (180, 150, 250), (150, 200, 245), (128, 255, 234), ];
apply_gradient(text, &gradient)
}
}
#[must_use]
pub fn create_secondary_gradient_text(text: &str) -> String {
if let Some(gradient) = theme::current().get_gradient(gradient_names::WARM) {
gradient_string(text, gradient)
} else {
let gradient = vec![
(255, 106, 193), (255, 150, 180), (255, 200, 160), (248, 230, 140), (241, 250, 140), ];
apply_gradient(text, &gradient)
}
}
fn apply_gradient(text: &str, gradient: &[(u8, u8, u8)]) -> String {
let chars: Vec<char> = text.chars().collect();
let chars_len = chars.len();
let gradient_len = gradient.len();
let mut result = String::new();
if chars_len == 0 || gradient_len == 0 {
return result;
}
chars.iter().enumerate().fold(&mut result, |acc, (i, &c)| {
let index = if chars_len == 1 {
0
} else {
i * (gradient_len - 1) / (chars_len - 1)
};
let (r, g, b) = gradient[index];
write!(acc, "{}", c.to_string().truecolor(r, g, b)).expect("writing to string cannot fail");
acc
});
result
}