| 135212de Andy McCall ↶ |
1 |
|
| 2 |
|
| 3 |
|
| 4 |
|
| 5 |
use console::{style, StyledObject, Term}; |
| 6 |
use indicatif::{ProgressBar, ProgressStyle}; |
| 7 |
use std::sync::atomic::{AtomicBool, Ordering}; |
| 8 |
use std::time::Duration; |
| 9 |
|
| 10 |
static PLAIN: AtomicBool = AtomicBool::new(false); |
| 11 |
static INIT: std::sync::Once = std::sync::Once::new(); |
| 12 |
|
| 13 |
|
| 14 |
pub fn init(plain_flag: bool) { |
| 15 |
INIT.call_once(|| { |
| 16 |
let no_color = std::env::var_os("NO_COLOR").is_some(); |
| 17 |
let tty = Term::stdout().features().is_attended(); |
| 18 |
let plain = plain_flag || no_color || !tty; |
| 19 |
PLAIN.store(plain, Ordering::Relaxed); |
| 20 |
console::set_colors_enabled(!plain); |
| 21 |
}); |
| 22 |
} |
| 23 |
|
| 24 |
pub fn plain() -> bool { |
| 25 |
PLAIN.load(Ordering::Relaxed) |
| 26 |
} |
| 27 |
|
| 28 |
fn s<T: std::fmt::Display>(v: T) -> StyledObject<T> { |
| 29 |
style(v) |
| 30 |
} |
| 31 |
|
| 32 |
|
| 33 |
pub fn id<T: std::fmt::Display>(v: T) -> String { |
| 34 |
s(v).cyan().bold().to_string() |
| 35 |
} |
| 36 |
|
| 37 |
pub fn hash<T: std::fmt::Display>(v: T) -> String { |
| 38 |
s(v).dim().to_string() |
| 39 |
} |
| 40 |
pub fn path<T: std::fmt::Display>(v: T) -> String { |
| 41 |
s(v).bold().to_string() |
| 42 |
} |
| 43 |
pub fn ok<T: std::fmt::Display>(v: T) -> String { |
| 44 |
s(v).green().to_string() |
| 45 |
} |
| 46 |
pub fn warn<T: std::fmt::Display>(v: T) -> String { |
| 47 |
s(v).yellow().to_string() |
| 48 |
} |
| 49 |
pub fn err<T: std::fmt::Display>(v: T) -> String { |
| 50 |
s(v).red().bold().to_string() |
| 51 |
} |
| 52 |
pub fn dim<T: std::fmt::Display>(v: T) -> String { |
| 53 |
s(v).dim().to_string() |
| 54 |
} |
| 55 |
pub fn heading<T: std::fmt::Display>(v: T) -> String { |
| 56 |
s(v).bold().underlined().to_string() |
| 57 |
} |
| 58 |
|
| 59 |
pub fn tag(t: &str) -> String { |
| 60 |
match t { |
| 61 |
"A" => s(t).green().bold().to_string(), |
| 62 |
"M" | "X" => s(t).yellow().bold().to_string(), |
| 63 |
"D" | "C!" => s(t).red().bold().to_string(), |
| 64 |
"R" => s(t).cyan().bold().to_string(), |
| 65 |
other => other.to_string(), |
| 66 |
} |
| 67 |
} |
| 68 |
|
| 69 |
|
| 70 |
|
| 71 |
pub struct Spinner { |
| 72 |
bar: Option<ProgressBar>, |
| 73 |
} |
| 74 |
|
| 75 |
pub fn spinner(msg: &str) -> Spinner { |
| 76 |
if plain() { |
| 77 |
return Spinner { bar: None }; |
| 78 |
} |
| 79 |
let bar = ProgressBar::new_spinner(); |
| 80 |
bar.set_style(ProgressStyle::with_template("{spinner:.cyan} {msg}").unwrap().tick_strings(&["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏", "✔"])); |
| 81 |
bar.set_message(msg.to_string()); |
| 82 |
bar.enable_steady_tick(Duration::from_millis(80)); |
| 83 |
Spinner { bar: Some(bar) } |
| 84 |
} |
| 85 |
|
| 86 |
impl Spinner { |
| 87 |
|
| 88 |
pub fn done(self, msg: &str) { |
| 89 |
match &self.bar { |
| 90 |
Some(b) => b.finish_with_message(msg.to_string()), |
| 91 |
None => println!("{msg}"), |
| 92 |
} |
| 93 |
} |
| 94 |
|
| 95 |
pub fn clear(self) { |
| 96 |
if let Some(b) = &self.bar { |
| 97 |
b.finish_and_clear(); |
| 98 |
} |
| 99 |
} |
| 100 |
} |