agent_tui_common/common/
color.rs1use std::io::IsTerminal;
4use std::sync::OnceLock;
5
6static NO_COLOR: OnceLock<bool> = OnceLock::new();
7
8pub fn init(no_color_flag: bool) {
9 let _ = NO_COLOR.set(
10 no_color_flag || std::env::var("NO_COLOR").is_ok() || !std::io::stdout().is_terminal(),
11 );
12}
13
14pub fn is_disabled() -> bool {
15 *NO_COLOR.get().unwrap_or(&false)
16}
17
18mod codes {
19 pub const RESET: &str = "\x1b[0m";
20 pub const GREEN: &str = "\x1b[32m";
21 pub const RED: &str = "\x1b[31m";
22 pub const YELLOW: &str = "\x1b[33m";
23 pub const CYAN: &str = "\x1b[36m";
24 pub const DIM: &str = "\x1b[90m";
25 pub const BOLD: &str = "\x1b[1m";
26}
27
28pub struct Colors;
29
30fn wrap_with_ansi(text: &str, prefixes: &[&str]) -> String {
31 let prefix_len: usize = prefixes.iter().map(|prefix| prefix.len()).sum();
32 let mut out = String::with_capacity(prefix_len + text.len() + codes::RESET.len());
33 for prefix in prefixes {
34 out.push_str(prefix);
35 }
36 out.push_str(text);
37 out.push_str(codes::RESET);
38 out
39}
40
41impl Colors {
42 pub fn success(text: &str) -> String {
43 if is_disabled() {
44 text.to_string()
45 } else {
46 wrap_with_ansi(text, &[codes::GREEN])
47 }
48 }
49
50 pub fn error(text: &str) -> String {
51 if is_disabled() {
52 text.to_string()
53 } else {
54 wrap_with_ansi(text, &[codes::RED])
55 }
56 }
57
58 pub fn info(text: &str) -> String {
59 if is_disabled() {
60 text.to_string()
61 } else {
62 wrap_with_ansi(text, &[codes::CYAN])
63 }
64 }
65
66 pub fn warning(text: &str) -> String {
67 if is_disabled() {
68 text.to_string()
69 } else {
70 wrap_with_ansi(text, &[codes::YELLOW])
71 }
72 }
73
74 pub fn dim(text: &str) -> String {
75 if is_disabled() {
76 text.to_string()
77 } else {
78 wrap_with_ansi(text, &[codes::DIM])
79 }
80 }
81
82 pub fn bold(text: &str) -> String {
83 if is_disabled() {
84 text.to_string()
85 } else {
86 wrap_with_ansi(text, &[codes::BOLD])
87 }
88 }
89
90 pub fn session_id(text: &str) -> String {
91 if is_disabled() {
92 text.to_string()
93 } else {
94 wrap_with_ansi(text, &[codes::BOLD, codes::CYAN])
95 }
96 }
97}
98
99#[cfg(test)]
100#[path = "color_tests.rs"]
101mod tests;