Skip to main content

varpulis_cli/
output.rs

1//! CLI output helpers for consistent formatting, colors, and progress indicators.
2//!
3//! Respects the `NO_COLOR` environment variable (<https://no-color.org/>).
4
5use std::env;
6
7use indicatif::{ProgressBar, ProgressStyle};
8use owo_colors::OwoColorize;
9
10/// Whether color output is enabled (respects NO_COLOR env var).
11pub fn color_enabled() -> bool {
12    env::var("NO_COLOR").is_err()
13}
14
15/// Create a progress bar for known total (preload mode).
16pub fn create_progress_bar(total: u64) -> ProgressBar {
17    let pb = ProgressBar::new(total);
18    pb.set_style(
19        ProgressStyle::with_template(
20            "[{elapsed_precise}] {bar:40.cyan/blue} {pos}/{len} ({per_sec}) [{eta}]",
21        )
22        .unwrap()
23        .progress_chars("##-"),
24    );
25    pb
26}
27
28/// Create a spinner for unknown total (streaming mode).
29pub fn create_spinner(msg: &str) -> ProgressBar {
30    let pb = ProgressBar::new_spinner();
31    pb.set_style(
32        ProgressStyle::with_template("{spinner} {msg} [{elapsed_precise}]")
33            .unwrap()
34            .tick_chars("⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏"),
35    );
36    pb.set_message(msg.to_string());
37    pb.enable_steady_tick(std::time::Duration::from_millis(120));
38    pb
39}
40
41/// Print a success message in green.
42pub fn success(msg: &str) {
43    if color_enabled() {
44        println!("{}", msg.green().bold());
45    } else {
46        println!("{msg}");
47    }
48}
49
50/// Print an error message in red.
51pub fn error(msg: &str) {
52    if color_enabled() {
53        eprintln!("{}", msg.red().bold());
54    } else {
55        eprintln!("{msg}");
56    }
57}
58
59/// Print a warning message in yellow.
60pub fn warning(msg: &str) {
61    if color_enabled() {
62        eprintln!("{}", msg.yellow());
63    } else {
64        eprintln!("{msg}");
65    }
66}
67
68/// Print a header/banner.
69pub fn header(msg: &str) {
70    if color_enabled() {
71        println!("{}", msg.bold());
72        println!("{}", "=".repeat(msg.len()).dimmed());
73    } else {
74        println!("{msg}");
75        println!("{}", "=".repeat(msg.len()));
76    }
77}