use crate::detect;
use crate::theme;
fn style_fg(text: &str, color: ratatui::style::Color) -> String {
if !detect::should_style() {
return text.to_string();
}
let code = color_to_ansi_fg(color);
format!("{code}{text}\x1b[0m")
}
fn style_bold(text: &str, color: ratatui::style::Color) -> String {
if !detect::should_style() {
return text.to_string();
}
let code = color_to_ansi_fg(color);
format!("\x1b[1m{code}{text}\x1b[0m")
}
fn style_dim(text: &str) -> String {
if !detect::should_style() {
return text.to_string();
}
format!("\x1b[2m{text}\x1b[0m")
}
fn color_to_ansi_fg(color: ratatui::style::Color) -> String {
use ratatui::style::Color;
match color {
Color::Rgb(r, g, b) => format!("\x1b[38;2;{r};{g};{b}m"),
Color::Black => "\x1b[30m".into(),
Color::Red => "\x1b[31m".into(),
Color::Green => "\x1b[32m".into(),
Color::Yellow => "\x1b[33m".into(),
Color::Blue => "\x1b[34m".into(),
Color::Magenta => "\x1b[35m".into(),
Color::Cyan => "\x1b[36m".into(),
Color::White => "\x1b[37m".into(),
Color::DarkGray => "\x1b[90m".into(),
Color::LightRed => "\x1b[91m".into(),
Color::LightGreen => "\x1b[92m".into(),
Color::LightYellow => "\x1b[93m".into(),
Color::LightBlue => "\x1b[94m".into(),
Color::LightMagenta => "\x1b[95m".into(),
Color::LightCyan => "\x1b[96m".into(),
Color::Gray => "\x1b[37m".into(),
Color::Indexed(n) => format!("\x1b[38;5;{n}m"),
Color::Reset => String::new(),
}
}
pub fn format_success(message: &str) -> String {
format!("✅ {}", style_fg(message, theme::COLOR_SUCCESS.resolve()))
}
pub fn format_error(message: &str) -> String {
format!("❌ {}", style_bold(message, theme::COLOR_ERROR.resolve()))
}
pub fn format_warning(message: &str) -> String {
format!("⚠️ {}", style_fg(message, theme::COLOR_WARNING.resolve()))
}
pub fn format_info(message: &str) -> String {
format!("ℹ️ {}", style_fg(message, theme::COLOR_PRIMARY.resolve()))
}
pub fn format_command(command: &str) -> String {
format!("▶ {}", style_bold(command, theme::COLOR_SECONDARY.resolve()))
}
pub fn format_progress(message: &str) -> String {
format!("⏳ {}", style_fg(message, theme::COLOR_WARNING.resolve()))
}
pub fn format_prompt(message: &str) -> String {
format!("? {}", style_bold(message, theme::COLOR_PRIMARY.resolve()))
}
pub fn format_verbose(message: &str) -> String {
style_dim(message)
}
pub fn format_list_item(message: &str) -> String {
format!(" • {message}")
}
pub fn format_section_header(header: &str) -> String {
let bar = "━".repeat(74usize.saturating_sub(header.len() + 1));
format!(
"\n━━━ {} {}",
style_bold(header, theme::COLOR_PRIMARY.resolve()),
style_dim(&bar)
)
}
pub fn format_count(message: &str) -> String {
format!("📊 {}", style_fg(message, theme::COLOR_ACCENT.resolve()))
}
pub fn format_location(message: &str) -> String {
format!("📁 {}", style_fg(message, theme::COLOR_SECONDARY.resolve()))
}
pub fn format_list_header(header: &str) -> String {
style_bold(header, theme::COLOR_FG.resolve())
}
pub fn format_search(message: &str) -> String {
format!("🔍 {}", style_fg(message, theme::COLOR_PRIMARY.resolve()))
}
pub fn success(message: &str) {
eprintln!("{}", format_success(message));
}
pub fn error(message: &str) {
eprintln!("{}", format_error(message));
}
pub fn warning(message: &str) {
eprintln!("{}", format_warning(message));
}
pub fn info(message: &str) {
eprintln!("{}", format_info(message));
}
pub fn progress(message: &str) {
eprintln!("{}", format_progress(message));
}
pub fn verbose(message: &str) {
eprintln!("{}", format_verbose(message));
}
pub fn section(header: &str) {
eprintln!("{}", format_section_header(header));
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn format_success_contains_emoji() {
let s = format_success("all good");
assert!(s.contains('✅'));
assert!(s.contains("all good"));
}
#[test]
fn format_error_contains_emoji() {
let s = format_error("it broke");
assert!(s.contains('❌'));
assert!(s.contains("it broke"));
}
#[test]
fn format_list_item_is_indented() {
let s = format_list_item("entry");
assert!(s.starts_with(" •"));
}
#[test]
fn format_section_header_has_rule() {
let s = format_section_header("Test");
assert!(s.contains('━'));
assert!(s.contains("Test"));
}
#[test]
fn color_to_ansi_fg_basic_colors() {
use ratatui::style::Color;
assert_eq!(color_to_ansi_fg(Color::Red), "\x1b[31m");
assert_eq!(color_to_ansi_fg(Color::Green), "\x1b[32m");
assert!(color_to_ansi_fg(Color::Rgb(255, 0, 0)).contains("255"));
}
}