1use console::style;
5use core::fmt;
6use once_cell::sync::Lazy;
7use std::time::Instant;
8
9static INTERNAL_CI: Lazy<bool> = Lazy::new(|| std::env::var("DUVET_INTERNAL_CI").is_ok());
10
11#[macro_export]
12macro_rules! progress {
13 ($progress:ident, $fmt:literal $($tt:tt)*) => {
14 $progress.finish(format_args!($fmt $($tt)*));
15 };
16 ($fmt:literal $($tt:tt)*) => {
17 $crate::progress::Progress::new(format_args!($fmt $($tt)*))
18 };
19}
20
21pub struct Progress {
22 start_time: Instant,
23}
24
25impl Progress {
26 pub fn new<T: fmt::Display>(v: T) -> Self {
27 let start_time = Instant::now();
28 let v = v.to_string();
29 if let Some((status, info)) = v.split_once(' ') {
30 let status = style(status).cyan().bold();
31 eprintln!("{status:>12} {info}")
32 } else {
33 eprintln!("{v}");
34 }
35 Self { start_time }
36 }
37
38 pub fn finish<T: fmt::Display>(self, v: T) {
39 let total = self.total_time();
40 let total = style(&total).dim();
41
42 let v = v.to_string();
43 if let Some((status, info)) = v.split_once(' ') {
44 let status = style(status).green().bold();
45 eprintln!("{status:>12} {info} {total}")
46 } else {
47 eprintln!("{v} {total}");
48 }
49 }
50
51 fn total_time(&self) -> String {
52 if *INTERNAL_CI {
53 return String::new();
54 }
55
56 let total = self.start_time.elapsed();
57
58 if total.as_secs() > 0 {
59 format!("{:.2}s", total.as_secs_f32())
60 } else if total.as_millis() > 0 {
61 format!("{}ms", total.as_millis())
62 } else if total.as_micros() > 0 {
63 format!("{}µs", total.as_micros())
64 } else {
65 format!("{total:?}")
66 }
67 }
68}