1use std::sync::atomic::{AtomicBool, Ordering};
2
3static COLORS_ENABLED: AtomicBool = AtomicBool::new(true);
4
5pub fn configure(no_color: bool) {
6 let mut enabled = !no_color;
7
8 if std::env::var_os("NO_COLOR").is_some() {
9 enabled = false;
10 }
11
12 if let Ok(term) = std::env::var("TERM")
13 && term.eq_ignore_ascii_case("dumb")
14 {
15 enabled = false;
16 }
17
18 if std::env::var("CLICOLOR_FORCE").ok().as_deref() == Some("1") {
19 enabled = true;
20 }
21
22 COLORS_ENABLED.store(enabled, Ordering::Relaxed);
23}
24
25#[cfg(test)]
26pub fn set_color_enabled(enabled: bool) {
27 COLORS_ENABLED.store(enabled, Ordering::Relaxed);
28}
29
30fn style(code: &str, text: &str) -> String {
31 if text.is_empty() || !COLORS_ENABLED.load(Ordering::Relaxed) {
32 return text.to_string();
33 }
34
35 format!("\x1b[{code}m{text}\x1b[0m")
36}
37
38pub fn bold(text: &str) -> String {
39 style("1", text)
40}
41
42pub fn muted(text: &str) -> String {
43 style("2", text)
44}
45
46pub fn accent(text: &str) -> String {
47 style("36", text)
48}
49
50pub fn success(text: &str) -> String {
51 style("32", text)
52}
53
54pub fn failure(text: &str) -> String {
55 style("31", text)
56}
57
58pub fn warning(text: &str) -> String {
59 style("33", text)
60}
61
62pub fn info(text: &str) -> String {
63 style("96", text)
64}
65
66pub fn command(text: &str) -> String {
67 style("96", text)
68}
69
70pub fn number(text: &str) -> String {
71 style("96", text)
72}
73
74pub fn bullet(text: &str) -> String {
75 style("94", text)
76}