1use std::sync::atomic::{AtomicBool, Ordering};
2
3static COLOR_ENABLED: AtomicBool = AtomicBool::new(true);
4
5pub fn init(color: bool) {
7 COLOR_ENABLED.store(color, Ordering::Relaxed);
8}
9
10fn use_color() -> bool {
11 COLOR_ENABLED.load(Ordering::Relaxed)
12}
13
14pub fn success(msg: &str) -> String {
16 if use_color() {
17 format!("\x1b[38;5;83m\u{2714}\x1b[0m {msg}")
18 } else {
19 format!("[ok] {msg}")
20 }
21}
22
23pub fn fail(msg: &str) -> String {
25 if use_color() {
26 format!("\x1b[38;5;196m\u{2718}\x1b[0m {msg}")
27 } else {
28 format!("[error] {msg}")
29 }
30}
31
32pub fn step(msg: &str) -> String {
34 if use_color() {
35 format!("\x1b[38;5;45m\u{279c}\x1b[0m {msg}")
36 } else {
37 format!("[..] {msg}")
38 }
39}
40
41pub fn warn(msg: &str) -> String {
43 if use_color() {
44 format!("\x1b[38;5;208m\u{26a0}\x1b[0m {msg}")
45 } else {
46 format!("[warn] {msg}")
47 }
48}
49
50pub fn bold(s: &str) -> String {
52 if use_color() {
53 format!("\x1b[1m{s}\x1b[0m")
54 } else {
55 s.to_string()
56 }
57}
58
59pub fn dim(s: &str) -> String {
61 if use_color() {
62 format!("\x1b[2m{s}\x1b[0m")
63 } else {
64 s.to_string()
65 }
66}
67
68pub fn color(code: u8, s: &str) -> String {
70 if use_color() {
71 format!("\x1b[38;5;{code}m{s}\x1b[0m")
72 } else {
73 s.to_string()
74 }
75}
76
77pub fn human_size(bytes: u64) -> String {
79 if bytes < 1024 {
80 format!("{bytes} B")
81 } else if bytes < 1024 * 1024 {
82 format!("{:.1} KB", bytes as f64 / 1024.0)
83 } else {
84 format!("{:.1} MB", bytes as f64 / (1024.0 * 1024.0))
85 }
86}
87
88pub fn spinner(msg: &str) -> indicatif::ProgressBar {
90 use {
91 indicatif::{ProgressBar, ProgressStyle},
92 std::time::Duration,
93 };
94
95 let sp = ProgressBar::new_spinner();
96 sp.set_style(
97 ProgressStyle::default_spinner()
98 .tick_strings(&[
99 "✦ · · ",
100 " ✦ · ·",
101 "· ✦ · ",
102 " · ✦ ·",
103 "· · ✦ ",
104 " · · ✦",
105 "· · ✦ ",
106 " · ✦ ·",
107 "· ✦ · ",
108 " ✦ · ·",
109 "✦ · · ",
110 ])
111 .template(" {spinner:.cyan} {msg}")
112 .unwrap(),
113 );
114 sp.enable_steady_tick(Duration::from_millis(80));
115 sp.set_message(msg.to_string());
116 sp
117}
118
119pub fn human_duration(d: std::time::Duration) -> String {
121 let secs = d.as_secs_f64();
122 if secs < 0.1 {
123 format!("{:.0}ms", secs * 1000.0)
124 } else if secs < 60.0 {
125 format!("{secs:.1}s")
126 } else {
127 let mins = secs as u64 / 60;
128 let rem = secs as u64 % 60;
129 format!("{mins}m {rem}s")
130 }
131}