1use crate::util::shorten;
4use console::{pad_str, style, Alignment, StyledObject};
5use std::sync::LazyLock;
6use std::{
7 fmt::Display,
8 io::{stdout, IsTerminal},
9};
10use term_size::dimensions as terminal_dimensions;
11
12pub static PAD_OUTPUT: LazyLock<bool> = LazyLock::new(|| stdout().is_terminal());
14
15pub const LABEL_WIDTH: usize = 12;
17
18#[derive(Default)]
20pub enum OutputLabel<'a> {
21 Error(&'a str),
23 Warning(&'a str),
25 Info(&'a str),
27 Success(&'a str),
29 Custom(StyledObject<&'a str>),
31 #[default]
33 None,
34}
35
36pub fn println_label<M: AsRef<str> + Display>(label: OutputLabel, message: M) {
38 match label {
39 OutputLabel::Error(_) => {
40 eprintln!("{}", pretty_output(label, message));
41 }
42 _ => {
43 println!("{}", pretty_output(label, message));
44 }
45 }
46}
47
48pub fn pretty_output<M: AsRef<str> + Display>(out_label: OutputLabel, message: M) -> String {
54 let (label, label_is_empty) = match out_label {
55 OutputLabel::Error(error) => (style(error).bold().red(), false),
56 OutputLabel::Warning(warn) => (style(warn).bold().yellow(), false),
57 OutputLabel::Info(info) => (style(info).bold().cyan(), false),
58 OutputLabel::Success(success) => (style(success).bold().green(), false),
59 OutputLabel::Custom(custom) => (custom, false),
60 OutputLabel::None => (style(""), true),
61 };
62
63 if *PAD_OUTPUT {
65 let (term_width, _) = terminal_dimensions().unwrap_or((80, 80));
66
67 let message = shorten(message.to_string(), term_width - LABEL_WIDTH - 1);
68
69 format!(
70 "{} {}",
71 pad_str(
72 label.to_string().as_str(),
73 LABEL_WIDTH,
74 Alignment::Right,
75 None
76 ),
77 message
78 )
79 } else {
80 if label_is_empty {
82 format!("\t{message}")
83 } else {
84 format!("{label} {message}")
85 }
86 }
87}