1use std::io::Write;
13use std::sync::atomic::{AtomicBool, AtomicU8, Ordering};
14
15use owo_colors::{OwoColorize, Stream};
16
17static QUIET: AtomicBool = AtomicBool::new(false);
18static VERBOSE: AtomicU8 = AtomicU8::new(0);
19
20pub fn set_quiet(quiet: bool) {
22 QUIET.store(quiet, Ordering::Relaxed);
23}
24
25pub fn is_quiet() -> bool {
26 QUIET.load(Ordering::Relaxed)
27}
28
29pub fn set_verbose(count: u8) {
31 VERBOSE.store(count, Ordering::Relaxed);
32}
33
34pub fn is_verbose() -> bool {
38 VERBOSE.load(Ordering::Relaxed) > 0
39}
40
41fn write_stderr(line: &str) {
42 let _ = writeln!(std::io::stderr(), "{line}");
43}
44
45pub fn step(msg: &str) {
47 if is_quiet() {
48 return;
49 }
50 let glyph = "→".if_supports_color(Stream::Stderr, |t| t.dimmed());
51 write_stderr(&format!("{glyph} {msg}"));
52}
53
54pub fn ok(msg: &str) {
56 if is_quiet() {
57 return;
58 }
59 let mark = "✔".if_supports_color(Stream::Stderr, |t| t.green());
60 let body = msg.if_supports_color(Stream::Stderr, |t| t.green());
61 write_stderr(&format!("{mark} {body}"));
62}
63
64pub fn warn(msg: &str) {
66 let mark = "!".if_supports_color(Stream::Stderr, |t| t.yellow());
67 let body = msg.if_supports_color(Stream::Stderr, |t| t.yellow());
68 write_stderr(&format!("{mark} {body}"));
69}
70
71#[allow(dead_code)]
75pub fn hint(lines: &[&str]) {
76 if lines.is_empty() {
77 return;
78 }
79 let head = "Hint:".if_supports_color(Stream::Stderr, |t| t.cyan().bold().to_string());
80 let mut err = std::io::stderr();
81 let _ = writeln!(err, "\n{head} {}", lines[0]);
82 for l in &lines[1..] {
83 let _ = writeln!(err, " {l}");
84 }
85}
86
87pub fn error(msg: &str) {
92 let head = "Error:".if_supports_color(Stream::Stderr, |t| t.red().bold().to_string());
93 write_stderr(&format!("\n{head} {msg}"));
94}