rush_sync_server/ui/
color.rs

1// =====================================================
2// FILE: src/ui/color.rs - VOLLSTÄNDIG mit CLONE SUPPORT
3// =====================================================
4
5use crate::core::prelude::*;
6use log::Level;
7use once_cell::sync::Lazy;
8use std::collections::HashMap;
9use std::fmt;
10
11#[derive(Debug, Clone, Copy, PartialEq)] // ✅ CLONE ist bereits da
12pub struct AppColor(Color);
13
14// ✅ Zentrale Map für ALLE Farben & Kategorien
15static COLOR_MAP: Lazy<HashMap<&'static str, Color>> = Lazy::new(|| {
16    let mut map = HashMap::new();
17
18    // Standard-Farben
19    map.insert("black", Color::Black);
20    map.insert("red", Color::Red);
21    map.insert("green", Color::Green);
22    map.insert("yellow", Color::Yellow);
23    map.insert("blue", Color::Blue);
24    map.insert("magenta", Color::Magenta);
25    map.insert("cyan", Color::Cyan);
26    map.insert("gray", Color::Gray);
27    map.insert("darkgray", Color::DarkGray);
28    map.insert("lightred", Color::LightRed);
29    map.insert("lightgreen", Color::LightGreen);
30    map.insert("lightyellow", Color::LightYellow);
31    map.insert("lightblue", Color::LightBlue);
32    map.insert("lightmagenta", Color::LightMagenta);
33    map.insert("lightcyan", Color::LightCyan);
34    map.insert("white", Color::White);
35
36    // Kategorien
37    map.insert("error", Color::Red);
38    map.insert("warning", Color::Yellow);
39    map.insert("warn", Color::Yellow);
40    map.insert("info", Color::Green);
41    map.insert("debug", Color::Blue);
42    map.insert("trace", Color::White);
43    map.insert("lang", Color::Cyan);
44    map.insert("version", Color::LightBlue);
45    map.insert("startup", Color::Magenta);
46
47    map
48});
49
50impl AppColor {
51    pub fn new(color: Color) -> Self {
52        Self(color)
53    }
54
55    /// Universelle Umwandlung aus Kategorie oder Farbe
56    pub fn from_any<T: Into<String>>(source: T) -> Self {
57        let key = source.into().to_lowercase();
58        Self(*COLOR_MAP.get(key.as_str()).unwrap_or(&Color::Gray))
59    }
60
61    /// Aus explizitem Log-Level
62    pub fn from_log_level(level: Level) -> Self {
63        Self::from_any(level.to_string())
64    }
65
66    /// String-Validierung für Config (bleibt Result)
67    pub fn from_string(color_str: &str) -> crate::core::error::Result<Self> {
68        COLOR_MAP
69            .get(&color_str.to_lowercase().as_str())
70            .map(|&c| Self(c))
71            .ok_or_else(|| AppError::Validation(format!("Ungültige Farbe: {}", color_str)))
72    }
73
74    pub fn format_message(&self, level: &str, message: &str) -> String {
75        if level.is_empty() {
76            format!("\x1B[{}m{}\x1B[0m", self.to_ansi_code(), message)
77        } else {
78            format!(
79                "\x1B[{}m[{}] {}\x1B[0m",
80                self.to_ansi_code(),
81                level,
82                message
83            )
84        }
85    }
86
87    pub fn to_ansi_code(&self) -> u8 {
88        match self.0 {
89            Color::Black => 30,
90            Color::Red => 31,
91            Color::Green => 32,
92            Color::Yellow => 33,
93            Color::Blue => 34,
94            Color::Magenta => 35,
95            Color::Cyan => 36,
96            Color::Gray => 37,
97            Color::DarkGray => 90,
98            Color::LightRed => 91,
99            Color::LightGreen => 92,
100            Color::LightYellow => 93,
101            Color::LightBlue => 94,
102            Color::LightMagenta => 95,
103            Color::LightCyan => 96,
104            Color::White => 97,
105            _ => 37,
106        }
107    }
108
109    pub fn to_name(&self) -> &'static str {
110        COLOR_MAP
111            .iter()
112            .find(|(_, &v)| v == self.0)
113            .map(|(k, _)| *k)
114            .unwrap_or("gray")
115    }
116}
117
118impl fmt::Display for AppColor {
119    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
120        write!(f, "{}", self.to_name())
121    }
122}
123
124impl From<AppColor> for Color {
125    fn from(app_color: AppColor) -> Self {
126        app_color.0
127    }
128}
129
130impl From<&AppColor> for Color {
131    fn from(app_color: &AppColor) -> Self {
132        app_color.0
133    }
134}
135
136impl Default for AppColor {
137    fn default() -> Self {
138        Self(Color::Gray)
139    }
140}