-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(color): implement colorful logging
- Loading branch information
Showing
21 changed files
with
618 additions
and
160 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,177 @@ | ||
use std::fmt::Display; | ||
|
||
#[derive(Debug, Clone, Copy)] | ||
pub enum Color { | ||
Reset, | ||
Black, | ||
Red, | ||
Green, | ||
Yellow, | ||
Blue, | ||
Magenta, | ||
Cyan, | ||
White, | ||
BrightBlack, | ||
BrightRed, | ||
BrightGreen, | ||
BrightYellow, | ||
BrightBlue, | ||
BrightMagenta, | ||
BrightCyan, | ||
BrightWhite, | ||
} | ||
|
||
impl Color { | ||
pub fn to_ansi_code(self, is_bg: bool) -> &'static str { | ||
match self { | ||
Color::Reset => "\x1B[0m", | ||
Color::Black => { | ||
if is_bg { | ||
"\x1B[40m" | ||
} else { | ||
"\x1B[30m" | ||
} | ||
} | ||
Color::Red => { | ||
if is_bg { | ||
"\x1B[41m" | ||
} else { | ||
"\x1B[31m" | ||
} | ||
} | ||
Color::Green => { | ||
if is_bg { | ||
"\x1B[42m" | ||
} else { | ||
"\x1B[32m" | ||
} | ||
} | ||
Color::Yellow => { | ||
if is_bg { | ||
"\x1B[43m" | ||
} else { | ||
"\x1B[33m" | ||
} | ||
} | ||
Color::Blue => { | ||
if is_bg { | ||
"\x1B[44m" | ||
} else { | ||
"\x1B[34m" | ||
} | ||
} | ||
Color::Magenta => { | ||
if is_bg { | ||
"\x1B[45m" | ||
} else { | ||
"\x1B[35m" | ||
} | ||
} | ||
Color::Cyan => { | ||
if is_bg { | ||
"\x1B[46m" | ||
} else { | ||
"\x1B[36m" | ||
} | ||
} | ||
Color::White => { | ||
if is_bg { | ||
"\x1B[47m" | ||
} else { | ||
"\x1B[37m" | ||
} | ||
} | ||
Color::BrightBlack => { | ||
if is_bg { | ||
"\x1B[100m" | ||
} else { | ||
"\x1B[90m" | ||
} | ||
} | ||
Color::BrightRed => { | ||
if is_bg { | ||
"\x1B[101m" | ||
} else { | ||
"\x1B[91m" | ||
} | ||
} | ||
Color::BrightGreen => { | ||
if is_bg { | ||
"\x1B[102m" | ||
} else { | ||
"\x1B[92m" | ||
} | ||
} | ||
Color::BrightYellow => { | ||
if is_bg { | ||
"\x1B[103m" | ||
} else { | ||
"\x1B[93m" | ||
} | ||
} | ||
Color::BrightBlue => { | ||
if is_bg { | ||
"\x1B[104m" | ||
} else { | ||
"\x1B[94m" | ||
} | ||
} | ||
Color::BrightMagenta => { | ||
if is_bg { | ||
"\x1B[105m" | ||
} else { | ||
"\x1B[95m" | ||
} | ||
} | ||
Color::BrightCyan => { | ||
if is_bg { | ||
"\x1B[106m" | ||
} else { | ||
"\x1B[96m" | ||
} | ||
} | ||
Color::BrightWhite => { | ||
if is_bg { | ||
"\x1B[107m" | ||
} else { | ||
"\x1B[97m" | ||
} | ||
} | ||
} | ||
} | ||
} | ||
|
||
pub trait ColorExt { | ||
fn color(self, color: Color) -> String; | ||
fn bg_color(self, color: Color) -> String; | ||
fn bold(self) -> String; | ||
} | ||
|
||
impl<T: Display> ColorExt for T { | ||
fn color(self, color: Color) -> String { | ||
format!( | ||
"{}{}{}", | ||
color.to_ansi_code(false), | ||
self, | ||
Color::Reset.to_ansi_code(false) | ||
) | ||
} | ||
|
||
fn bg_color(self, color: Color) -> String { | ||
format!( | ||
"{}{}{}", | ||
color.to_ansi_code(true), | ||
self, | ||
Color::Reset.to_ansi_code(true) | ||
) | ||
} | ||
|
||
fn bold(self) -> String { | ||
format!( | ||
"{}\x1B[1m{}{}", | ||
Color::Reset.to_ansi_code(false), | ||
self, | ||
Color::Reset.to_ansi_code(false) | ||
) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,141 @@ | ||
use libc::{ioctl, winsize, STDOUT_FILENO, TIOCGWINSZ}; | ||
use std::mem; | ||
|
||
pub struct Grid { | ||
cols: usize, | ||
col_widths: Vec<Option<usize>>, | ||
col_ratios: Vec<f64>, | ||
rows: Vec<Vec<String>>, | ||
separator: String, | ||
} | ||
|
||
impl Grid { | ||
pub fn builder(cols: usize) -> GridBuilder { | ||
GridBuilder { | ||
cols, | ||
col_widths: vec![None; cols], | ||
col_ratios: vec![1.0; cols], | ||
separator: String::new(), | ||
} | ||
} | ||
|
||
fn get_terminal_width() -> usize { | ||
let mut w: winsize = unsafe { mem::zeroed() }; | ||
|
||
if unsafe { ioctl(STDOUT_FILENO, TIOCGWINSZ, &mut w) } == 0 { | ||
if w.ws_col > 0 { | ||
w.ws_col as usize | ||
} else { | ||
80 | ||
} | ||
} else { | ||
80 | ||
} | ||
} | ||
|
||
fn calculate_column_widths(&mut self) { | ||
let mut total_fixed_width = 0; | ||
let mut total_ratio = 0.0; | ||
|
||
for (i, &width) in self.col_widths.iter().enumerate() { | ||
if let Some(w) = width { | ||
total_fixed_width += w; | ||
} else { | ||
total_ratio += self.col_ratios[i]; | ||
} | ||
} | ||
|
||
let terminal_width = Grid::get_terminal_width(); | ||
|
||
if total_fixed_width >= terminal_width { | ||
panic!("Total fixed column widths exceed the terminal width"); | ||
} | ||
|
||
let remaining_width = terminal_width.saturating_sub(total_fixed_width); | ||
|
||
for (i, width) in self.col_widths.iter_mut().enumerate() { | ||
if width.is_none() { | ||
let ratio = self.col_ratios[i]; | ||
*width = Some((remaining_width as f64 * (ratio / total_ratio)).round() as usize); | ||
} | ||
} | ||
} | ||
|
||
pub fn row(&mut self, row: Vec<String>) -> &mut Self { | ||
if row.len() != self.cols { | ||
panic!("Row length must match the number of columns."); | ||
} | ||
self.rows.push(row); | ||
self | ||
} | ||
|
||
fn truncate_row(row: &[String], widths: &[usize]) -> Vec<String> { | ||
row.iter() | ||
.enumerate() | ||
.map(|(i, col)| { | ||
let max_width = widths[i]; | ||
if col.len() > max_width { | ||
format!("{}...", &col[..max_width.saturating_sub(3)]) | ||
} else { | ||
col.clone() | ||
} | ||
}) | ||
.collect() | ||
} | ||
|
||
pub fn print(mut self) { | ||
self.calculate_column_widths(); | ||
|
||
let column_widths: Vec<usize> = self.col_widths.iter().map(|w| w.unwrap_or(0)).collect(); | ||
|
||
for row in &self.rows { | ||
let truncated_row = Grid::truncate_row(row, &column_widths); | ||
for (i, col) in truncated_row.iter().enumerate() { | ||
let width = column_widths[i]; | ||
print!("{:width$} ", col, width = width); | ||
if i < self.cols - 1 { | ||
print!("{}", self.separator) | ||
} | ||
} | ||
println!(); | ||
} | ||
} | ||
} | ||
|
||
pub struct GridBuilder { | ||
cols: usize, | ||
col_widths: Vec<Option<usize>>, | ||
col_ratios: Vec<f64>, | ||
separator: String, | ||
} | ||
|
||
impl GridBuilder { | ||
pub fn set_width(mut self, col: usize, width: usize) -> Self { | ||
if col < self.cols { | ||
self.col_widths[col] = Some(width); | ||
} | ||
self | ||
} | ||
|
||
pub fn set_ratio(mut self, col: usize, ratio: f64) -> Self { | ||
if col < self.cols { | ||
self.col_ratios[col] = ratio; | ||
} | ||
self | ||
} | ||
|
||
pub fn set_separator(mut self, separator: String) -> Self { | ||
self.separator = separator; | ||
self | ||
} | ||
|
||
pub fn build(self) -> Grid { | ||
Grid { | ||
cols: self.cols, | ||
col_widths: self.col_widths, | ||
col_ratios: self.col_ratios, | ||
rows: Vec::new(), | ||
separator: self.separator, | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
#[macro_export] | ||
macro_rules! warn { | ||
($($arg:tt)*) => { | ||
println!("{} {}", "[WARN]".color(Color::BrightYellow).bold(), format!($($arg)*)) | ||
}; | ||
} | ||
|
||
#[macro_export] | ||
macro_rules! info { | ||
($($arg:tt)*) => { | ||
println!("{} {}", "[INFO]".color(Color::BrightBlue).bold(), format!($($arg)*)) | ||
}; | ||
} | ||
|
||
#[macro_export] | ||
macro_rules! error { | ||
($($arg:tt)*) => { | ||
eprintln!("{} {}", "[ERROR]".color(Color::BrightRed).bold(), format!($($arg)*)) | ||
}; | ||
} | ||
|
||
#[macro_export] | ||
macro_rules! success { | ||
($($arg:tt)*) => { | ||
println!("{} {}", "[SUCCESS]".color(Color::BrightGreen).bold(), format!($($arg)*)) | ||
}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,6 @@ | ||
pub mod color; | ||
pub mod config; | ||
pub mod constant; | ||
pub mod grid; | ||
pub mod log; | ||
pub mod util; |
Oops, something went wrong.