label_logger/
log.rs

1//! The actual implementation of the logger core
2
3use console::{Alignment, StyledObject, pad_str, style};
4use std::sync::LazyLock;
5use std::{
6	fmt::Display,
7	io::{IsTerminal, stdout},
8};
9
10/// Checks if the output is piped and simplify the output for better debugging
11pub static PAD_OUTPUT: LazyLock<bool> = LazyLock::new(|| stdout().is_terminal());
12
13/// The maximum length of a log label
14pub const LABEL_WIDTH: usize = 12;
15
16/// The enum of possible output labels
17#[derive(Default)]
18pub enum OutputLabel<'a> {
19	/// Outputs `Error` in red
20	Error(&'a str),
21	/// Outputs `Warning` in yellow
22	Warning(&'a str),
23	/// Outputs the provided label in blue
24	Info(&'a str),
25	/// Outputs the provided label in green
26	Success(&'a str),
27	/// Outputs the provided label in the provided color
28	Custom(StyledObject<&'a str>),
29	/// Outputs a blank space with no label
30	#[default]
31	None,
32}
33
34/// Print a message with the specified label
35pub fn println_label<M: AsRef<str> + Display>(label: OutputLabel, message: M) {
36	match label {
37		OutputLabel::Error(_) => {
38			eprintln!("{}", pretty_output(label, message));
39		}
40		_ => {
41			println!("{}", pretty_output(label, message));
42		}
43	}
44}
45
46/// Pretty a message with a given label and a given message color
47///
48/// # Panics
49/// We panic if we can't determine the width of the stdout `TTY`.
50/// But it is only used in a part where we check that we are connected a real `TTY`
51pub fn pretty_output<M: AsRef<str> + Display>(out_label: OutputLabel, message: M) -> String {
52	let (label, label_is_empty) = match out_label {
53		OutputLabel::Error(error) => (style(error).bold().red(), false),
54		OutputLabel::Warning(warn) => (style(warn).bold().yellow(), false),
55		OutputLabel::Info(info) => (style(info).bold().cyan(), false),
56		OutputLabel::Success(success) => (style(success).bold().green(), false),
57		OutputLabel::Custom(custom) => (custom, false),
58		OutputLabel::None => (style(""), true),
59	};
60
61	// Pad output if the stdout is a tty
62	if *PAD_OUTPUT {
63		format!(
64			"{} {}",
65			pad_str(
66				label.to_string().as_str(),
67				LABEL_WIDTH,
68				Alignment::Right,
69				None
70			),
71			message
72		)
73	} else {
74		// Special case for piped output, none label adds a tabulation at the start
75		if label_is_empty {
76			format!("\t{message}")
77		} else {
78			format!("{label} {message}")
79		}
80	}
81}