use std::{fmt::{Display, Debug}, time::Duration};
use chrono::{Timelike};
use colored_json::prelude::*;
pub const ON_CYAN: &str = "\x1b[48;5;6m\x1b[38;5;0m ";
pub const ON_WHITE: &str = "\x1b[48;5;15m\x1b[38;5;0m ";
pub const ON_YELLOW: &str = "\x1b[48;5;3m\x1b[38;5;0m ";
pub const ON_MAGENTA: &str = "\x1b[48;5;13m\x1b[38;5;0m ";
pub const ON_GREEN: &str = "\x1b[48;5;10m\x1b[38;5;0m ";
pub const ON_RED: &str = "\x1b[48;5;9m\x1b[38;5;0m ";
pub const ON_BLUE: &str = "\x1b[48;5;12m\x1b[38;5;0m ";
pub const ON_AMBER: &str = "\x1b[48;5;202m\x1b[38;5;0m ";
pub const ON_ORANGE: &str = "\x1b[48;5;208m\x1b[38;5;0m ";
pub const ON_PINK: &str = "\x1b[48;5;205m\x1b[38;5;0m ";
pub const ON_PURPLE: &str = "\x1b[48;5;92m\x1b[38;5;0m ";
pub const ON_BROWN: &str = "\x1b[48;5;94m\x1b[38;5;0m ";
pub const ON_GRAY: &str = "\x1b[48;5;242m\x1b[38;5;0m ";
pub const CYAN: &str = "\x1b[38;5;6m";
pub const WHITE: &str = "\x1b[38;5;15m";
pub const YELLOW: &str = "\x1b[38;5;3m";
pub const MAGENTA: &str = "\x1b[38;5;13m";
pub const GREEN: &str = "\x1b[38;5;10m";
pub const RED: &str = "\x1b[38;5;9m";
pub const BLUE: &str = "\x1b[38;5;12m";
pub const AMBER: &str = "\x1b[38;5;202m";
pub const ORANGE: &str = "\x1b[38;5;208m";
pub const PINK: &str = "\x1b[38;5;205m";
pub const PURPLE: &str = "\x1b[38;5;92m";
pub const BROWN: &str = "\x1b[38;5;94m";
pub const GRAY: &str = "\x1b[38;5;242m";
pub const DIM_GRAY: &str = "\x1b[38;5;238m";
pub const DARK_GRAY: &str = "\x1b[38;5;237m";
pub const RESET: &str = "\x1b[0m";
pub const BOLD: &str = "\x1b[1m";
pub const DIM: &str = "\x1b[2m";
pub const ITALIC: &str = "\x1b[3m";
#[macro_export]
macro_rules! substitute_args {
($text:expr, $args:expr) => {
{
let mut substituted = String::new();
let mut arg_index = 0;
let mut in_arg = false;
let mut arg = String::new();
for c in $text.chars() {
if c == '{' {
in_arg = true;
} else if c == '}' {
in_arg = false;
substituted.push_str(&format!("{}", $args[arg_index]));
arg_index += 1;
arg = String::new();
} else if in_arg {
arg.push(c);
} else {
substituted.push(c);
}
}
substituted
}
};
}
pub trait Printable {
fn print_with(&self, args: Vec<impl Display>);
fn print(&self);
fn format_with(&self, args: Vec<impl Display>) -> String;
fn format(&self) -> String;
}
pub trait Colorable {
fn color(&self, color: &str) -> String;
}
impl<T: Display> Colorable for T {
fn color(&self, color: &str) -> String {
let colored = parse_color_tags(&self.to_string());
colored
}
}
impl<T: Display> Printable for T {
fn print_with(&self, args: Vec<impl Display>) {
let colored = parse_color_tags(&self.to_string());
let substituted = substitute_args!(colored, args);
println!("{}", substituted);
}
fn print(&self) {
let colored = parse_color_tags(&self.to_string());
println!("{}", colored);
}
fn format_with(&self, args: Vec<impl Display>) -> String {
let colored = parse_color_tags(&self.to_string());
let substituted = substitute_args!(colored, args);
substituted
}
fn format(&self) -> String {
let colored = parse_color_tags(&self.to_string());
colored
}
}
pub trait PrettyJson {
fn json_pretty(&self) -> String;
}
impl PrettyJson for serde_json::Value {
fn json_pretty(&self) -> String {
let pretty = colored_json::to_colored_json_auto(self).unwrap_or_else(|_| "Error parsing json".to_string());
pretty
}
}
impl Printable for str {
fn print_with(&self, args: Vec<impl Display>) {
let colored = parse_color_tags(&self);
let substituted = substitute_args!(colored, args);
println!("{}", substituted);
}
fn print(&self) {
let colored = parse_color_tags(&self);
println!("{}", colored);
}
fn format_with(&self, args: Vec<impl Display>) -> String {
let colored = parse_color_tags(&self);
let substituted = substitute_args!(colored, args);
substituted
}
fn format(&self) -> String {
let colored = parse_color_tags(&self);
colored
}
}
pub trait TimePrintable {
fn to_string_hms(&self) -> String;
fn to_string_hm(&self) -> String;
fn to_string_ms(&self) -> String;
fn to_string_s(&self) -> String;
fn to_string_m(&self) -> String;
}
impl TimePrintable for chrono::NaiveTime {
fn to_string_hms(&self) -> String {
format!("{:02}:{:02}:{:02} {}", self.hour() % 12, self.minute(), self.second(), if self.hour() < 12 { "AM" } else { "PM" })
}
fn to_string_hm(&self) -> String {
format!("{:02}:{:02} {}", self.hour() % 12, self.minute(), if self.hour() < 12 { "AM" } else { "PM" })
}
fn to_string_ms(&self) -> String {
format!("{} hr {} min {} sec {} ms", self.hour(), self.minute(), self.second(), self.nanosecond() / 1_000_000)
}
fn to_string_s(&self) -> String {
format!("{} sec", self.hour() * 3600 + self.minute() * 60 + self.second())
}
fn to_string_m(&self) -> String {
format!("{} min", self.hour() * 60 + self.minute())
}
}
impl TimePrintable for std::time::Instant {
fn to_string_hms(&self) -> String {
let secs = self.elapsed().as_secs();
let mins = secs / 60;
let hours = mins / 60;
format!("{:02}:{:02}:{:02} {}", hours % 12, mins % 60, secs % 60, if hours < 12 { "AM" } else { "PM" })
}
fn to_string_hm(&self) -> String {
let secs = self.elapsed().as_secs();
let mins = secs / 60;
let hours = mins / 60;
format!("{:02}:{:02} {}", hours % 12, mins % 60, if hours < 12 { "AM" } else { "PM" })
}
fn to_string_ms(&self) -> String {
let secs = self.elapsed().as_secs();
let mins = secs / 60;
let hours = mins / 60;
format!("{} hr {} min {} sec {} ms", hours, mins % 60, secs % 60, self.elapsed().subsec_millis())
}
fn to_string_s(&self) -> String {
let secs = self.elapsed().as_secs();
let mins = secs / 60;
let hours = mins / 60;
format!("{:02}", secs % 60)
}
fn to_string_m(&self) -> String {
let secs = self.elapsed().as_secs();
let mins = secs / 60;
let hours = mins / 60;
format!("{:02}", mins % 60)
}
}
impl TimePrintable for Duration {
fn to_string_hms(&self) -> String {
let secs = self.as_secs();
format!("{}.{:02} seconds", secs, self.subsec_millis())
}
fn to_string_hm(&self) -> String {
let secs = self.as_secs();
let mins = secs / 60;
let hours = mins / 60;
format!("{}.{:02} minutes", mins, secs % 60)
}
fn to_string_ms(&self) -> String {
let secs = self.as_secs();
if secs > 60 {
let mins = secs / 60;
let hours = mins / 60;
format!("{}.{:02} MIN", mins, secs % 60)
} else if secs<1 {
format!("{}.{:02} MS", secs, self.subsec_millis())
} else {
format!("{}.{:02} SEC", secs, self.subsec_millis())
}
}
fn to_string_s(&self) -> String {
let secs = self.as_secs();
let mins = secs / 60;
let hours = mins / 60;
format!("{} sec", secs)
}
fn to_string_m(&self) -> String {
let secs = self.as_secs();
let mins = secs / 60;
let hours = mins / 60;
format!("{} min", mins)
}
}
fn parse_color_tags(text: &str) -> String {
let mut parsed = String::new();
let mut in_tag = false;
let mut tag = String::new();
for c in text.chars() {
if c == '[' {
in_tag = true;
} else if c == ']' {
in_tag = false;
parsed.push_str(&parse_tag(&tag));
tag.clear();
} else if in_tag {
tag.push(c);
} else {
parsed.push(c);
}
}
parsed
}
fn parse_tag(tag: &str) -> String {
match tag {
"red" => "\x1b[31m".to_string(),
"green" => "\x1b[32m".to_string(),
"yellow" => "\x1b[33m".to_string(),
"blue" => "\x1b[34m".to_string(),
"magenta" => "\x1b[35m".to_string(),
"cyan" => "\x1b[36m".to_string(),
"white" => "\x1b[37m".to_string(),
"black" => "\x1b[30m".to_string(),
"bold" => "\x1b[1m".to_string(),
"dim" => "\x1b[2m".to_string(),
"italic" => "\x1b[3m".to_string(),
"underline" => "\x1b[4m".to_string(),
"blink" => "\x1b[5m".to_string(),
"reverse" => "\x1b[7m".to_string(),
"hidden" => "\x1b[8m".to_string(),
"strikethrough" => "\x1b[9m".to_string(),
"dark_red" => "\x1b[31m".to_string(),
"dark_green" => "\x1b[32m".to_string(),
"dark_yellow" => "\x1b[33m".to_string(),
"dark_blue" => "\x1b[34m".to_string(),
"dark_magenta" => "\x1b[35m".to_string(),
"dark_cyan" => "\x1b[36m".to_string(),
"dark_white" => "\x1b[37m".to_string(),
"dark_black" => "\x1b[30m".to_string(),
"dark_gray" => "\x1b[2m".to_string(),
"dim_gray" => "\x1b[2m".to_string(),
"light_red" => "\x1b[91m".to_string(),
"light_green" => "\x1b[92m".to_string(),
"light_yellow" => "\x1b[93m".to_string(),
"light_blue" => "\x1b[94m".to_string(),
"light_magenta" => "\x1b[95m".to_string(),
"light_cyan" => "\x1b[96m".to_string(),
"light_white" => "\x1b[97m".to_string(),
"light_black" => "\x1b[90m".to_string(),
"light_gray" => "\x1b[37m".to_string(),
"reset" => "\x1b[0m".to_string(),
"purple" => "\x1b[35m".to_string(),
"orange" => "\x1b[33m".to_string(),
"grey" => "\x1b[90m".to_string(),
"pink" => "\x1b[95m".to_string(),
"light_purple" => "\x1b[95m".to_string(),
"vine" => "\x1b[32m".to_string(),
"light_vine" => "\x1b[92m".to_string(),
"dark_vine" => "\x1b[32m".to_string(),
"/" => "\x1b[0m".to_string(), "hline" => "\x1b[71m".to_string(),
"vline" => "\x1b[78m".to_string(),
"tlcorner" => "\x1b[6C".to_string(),
"trcorner" => "\x1b[6B".to_string(),
"blcorner" => "\x1b[6D".to_string(),
"brcorner" => "\x1b[6A".to_string(),
"cross" => "\x1b[6E".to_string(),
"tline" => "\x1b[77".to_string(),
"bline" => "\x1b[76".to_string(),
"lline" => "\x1b[74".to_string(),
"rline" => "\x1b[75".to_string(),
"tjunc" => "\x1b[6E".to_string(),
"bjunc" => "\x1b[6E".to_string(),
"ljunc" => "\x1b[6E".to_string(),
"rjunc" => "\x1b[6E".to_string(),
"curved_tl" => "\x1b[6C".to_string(),
"curved_tr" => "\x1b[6B".to_string(),
"curved_bl" => "\x1b[6D".to_string(),
"curved_br" => "\x1b[6A".to_string(),
"curved_tline" => "\x1b[77".to_string(),
"curved_bline" => "\x1b[76".to_string(),
"curved_lline" => "\x1b[74".to_string(),
"on_red" => "\x1b[41m".to_string(),
"on_orange" => "\x1b[43m".to_string(),
"on_purple" => "\x1b[45m".to_string(),
"on_pink" => "\x1b[45m".to_string(),
"on_vine" => "\x1b[42m".to_string(),
"on_green" => "\x1b[42m".to_string(),
"on_yellow" => "\x1b[43m".to_string(),
"on_blue" => "\x1b[44m".to_string(),
"on_magenta" => "\x1b[45m".to_string(),
"on_cyan" => "\x1b[46m".to_string(),
"on_white" => ON_WHITE.to_string(),
"on_black" => "\x1b[40m".to_string(),
"on_dark_red" => "\x1b[41m".to_string(),
"on_dark_green" => "\x1b[42m".to_string(),
"on_dark_yellow" => "\x1b[43m".to_string(),
"on_dark_blue" => "\x1b[44m".to_string(),
"on_dark_magenta" => "\x1b[45m".to_string(),
"on_dark_cyan" => "\x1b[46m".to_string(),
"on_dark_white" => "\x1b[47m".to_string(),
"on_dark_black" => "\x1b[40m".to_string(),
"on_dark_gray" => "\x1b[40m".to_string(),
"on_dim_gray" => "\x1b[40m".to_string(),
"on_light_red" => "\x1b[101m".to_string(),
"on_light_green" => "\x1b[102m".to_string(),
"on_light_yellow" => "\x1b[103m".to_string(),
"on_light_blue" => "\x1b[104m".to_string(),
"on_light_magenta" => "\x1b[105m".to_string(),
"on_light_cyan" => "\x1b[106m".to_string(),
"on_light_white" => "\x1b[107m".to_string(),
"on_light_black" => "\x1b[100m".to_string(),
"on_light_gray" => "\x1b[47m".to_string(),
_ => "".to_string(),
}
}
const COLORS: [&str; 16] = [
"red",
"green",
"yellow",
"blue",
"magenta",
"cyan",
"white",
"black",
"dark_red",
"dark_green",
"dark_yellow",
"dark_blue",
"dark_magenta",
"dark_cyan",
"dark_white",
"dark_black",
];
const STYLES: [&str; 9] = [
"bold",
"dim",
"italic",
"underline",
"blink",
"reverse",
"hidden",
"strikethrough",
"reset",
];
pub const ALL_COLORS_ANSII: [&str; 226] = [
"\x1b[38;5;0m", "\x1b[38;5;1m", "\x1b[38;5;2m", "\x1b[38;5;3m",
"\x1b[38;5;4m", "\x1b[38;5;5m", "\x1b[38;5;6m", "\x1b[38;5;7m",
"\x1b[38;5;8m", "\x1b[38;5;9m", "\x1b[38;5;10m", "\x1b[38;5;11m",
"\x1b[38;5;12m", "\x1b[38;5;13m", "\x1b[38;5;14m", "\x1b[38;5;15m",
"\x1b[38;5;16m", "\x1b[38;5;17m", "\x1b[38;5;18m", "\x1b[38;5;19m",
"\x1b[38;5;20m", "\x1b[38;5;21m", "\x1b[38;5;22m", "\x1b[38;5;23m",
"\x1b[38;5;24m", "\x1b[38;5;25m", "\x1b[38;5;26m", "\x1b[38;5;27m",
"\x1b[38;5;28m", "\x1b[38;5;29m", "\x1b[38;5;30m", "\x1b[38;5;31m",
"\x1b[38;5;32m", "\x1b[38;5;33m", "\x1b[38;5;34m", "\x1b[38;5;35m",
"\x1b[38;5;36m", "\x1b[38;5;37m", "\x1b[38;5;38m", "\x1b[38;5;39m",
"\x1b[38;5;40m", "\x1b[38;5;41m", "\x1b[38;5;42m", "\x1b[38;5;43m",
"\x1b[38;5;44m", "\x1b[38;5;45m", "\x1b[38;5;46m", "\x1b[38;5;47m",
"\x1b[38;5;48m", "\x1b[38;5;49m", "\x1b[38;5;50m", "\x1b[38;5;51m",
"\x1b[38;5;52m", "\x1b[38;5;53m", "\x1b[38;5;54m", "\x1b[38;5;55m",
"\x1b[38;5;56m", "\x1b[38;5;57m", "\x1b[38;5;58m", "\x1b[38;5;59m",
"\x1b[38;5;60m", "\x1b[38;5;61m", "\x1b[38;5;62m", "\x1b[38;5;63m",
"\x1b[38;5;64m", "\x1b[38;5;65m", "\x1b[38;5;66m", "\x1b[38;5;67m",
"\x1b[38;5;68m", "\x1b[38;5;69m", "\x1b[38;5;70m", "\x1b[38;5;71m",
"\x1b[38;5;72m", "\x1b[38;5;73m", "\x1b[38;5;74m", "\x1b[38;5;75m",
"\x1b[38;5;76m", "\x1b[38;5;77m", "\x1b[38;5;78m", "\x1b[38;5;79m",
"\x1b[38;5;80m", "\x1b[38;5;81m", "\x1b[38;5;82m", "\x1b[38;5;83m",
"\x1b[38;5;84m", "\x1b[38;5;85m", "\x1b[38;5;86m", "\x1b[38;5;87m",
"\x1b[38;5;88m", "\x1b[38;5;89m", "\x1b[38;5;90m", "\x1b[38;5;91m",
"\x1b[38;5;92m", "\x1b[38;5;93m", "\x1b[38;5;94m", "\x1b[38;5;95m",
"\x1b[38;5;96m", "\x1b[38;5;97m", "\x1b[38;5;98m", "\x1b[38;5;99m",
"\x1b[38;5;100m", "\x1b[38;5;101m", "\x1b[38;5;102m", "\x1b[38;5;103m",
"\x1b[38;5;104m", "\x1b[38;5;105m", "\x1b[38;5;106m", "\x1b[38;5;107m",
"\x1b[38;5;108m", "\x1b[38;5;109m", "\x1b[38;5;110m", "\x1b[38;5;111m",
"\x1b[38;5;112m", "\x1b[38;5;113m", "\x1b[38;5;114m", "\x1b[38;5;115m",
"\x1b[38;5;116m", "\x1b[38;5;117m", "\x1b[38;5;118m", "\x1b[38;5;119m",
"\x1b[38;5;120m", "\x1b[38;5;121m", "\x1b[38;5;122m", "\x1b[38;5;123m",
"\x1b[38;5;124m", "\x1b[38;5;125m", "\x1b[38;5;126m", "\x1b[38;5;127m",
"\x1b[38;5;128m", "\x1b[38;5;129m", "\x1b[38;5;130m", "\x1b[38;5;131m",
"\x1b[38;5;132m", "\x1b[38;5;133m", "\x1b[38;5;134m", "\x1b[38;5;135m",
"\x1b[38;5;136m", "\x1b[38;5;137m", "\x1b[38;5;138m", "\x1b[38;5;139m",
"\x1b[38;5;140m", "\x1b[38;5;141m", "\x1b[38;5;142m", "\x1b[38;5;143m",
"\x1b[38;5;144m", "\x1b[38;5;145m", "\x1b[38;5;146m", "\x1b[38;5;147m",
"\x1b[38;5;148m", "\x1b[38;5;149m", "\x1b[38;5;150m", "\x1b[38;5;151m",
"\x1b[38;5;152m", "\x1b[38;5;153m", "\x1b[38;5;154m", "\x1b[38;5;155m",
"\x1b[38;5;156m", "\x1b[38;5;157m", "\x1b[38;5;158m", "\x1b[38;5;159m",
"\x1b[38;5;160m", "\x1b[38;5;161m", "\x1b[38;5;162m", "\x1b[38;5;163m",
"\x1b[38;5;164m", "\x1b[38;5;165m", "\x1b[38;5;166m", "\x1b[38;5;167m",
"\x1b[38;5;168m", "\x1b[38;5;169m", "\x1b[38;5;170m", "\x1b[38;5;171m",
"\x1b[38;5;172m", "\x1b[38;5;173m", "\x1b[38;5;174m", "\x1b[38;5;175m",
"\x1b[38;5;176m", "\x1b[38;5;177m", "\x1b[38;5;178m", "\x1b[38;5;179m",
"\x1b[38;5;180m", "\x1b[38;5;181m", "\x1b[38;5;182m", "\x1b[38;5;183m",
"\x1b[38;5;184m", "\x1b[38;5;185m", "\x1b[38;5;186m", "\x1b[38;5;187m",
"\x1b[38;5;188m", "\x1b[38;5;189m", "\x1b[38;5;190m", "\x1b[38;5;191m",
"\x1b[38;5;192m", "\x1b[38;5;193m", "\x1b[38;5;194m", "\x1b[38;5;195m",
"\x1b[38;5;196m", "\x1b[38;5;197m", "\x1b[38;5;198m", "\x1b[38;5;199m",
"\x1b[38;5;200m", "\x1b[38;5;201m", "\x1b[38;5;202m", "\x1b[38;5;203m",
"\x1b[38;5;204m", "\x1b[38;5;205m", "\x1b[38;5;206m", "\x1b[38;5;207m",
"\x1b[38;5;208m", "\x1b[38;5;209m", "\x1b[38;5;210m", "\x1b[38;5;211m",
"\x1b[38;5;212m", "\x1b[38;5;213m", "\x1b[38;5;214m", "\x1b[38;5;215m",
"\x1b[38;5;216m", "\x1b[38;5;217m", "\x1b[38;5;218m", "\x1b[38;5;219m",
"\x1b[38;5;220m", "\x1b[38;5;221m", "\x1b[38;5;222m", "\x1b[38;5;223m",
"\x1b[38;5;224m", "\x1b[38;5;225m"
];