enum FormatOpt {
FgColour(ColourOpt),
BgColour(ColourOpt),
Bold,
Dim,
Underline,
Blink,
Inverse,
Hidden,
Reset,
NoEndReset,
}
pub enum ColourOpt {
Red,
Green,
Yellow,
Blue,
Magenta,
Cyan,
White,
Black,
BrightRed,
BrightGreen,
BrightYellow,
BrightBlue,
BrightMagenta,
BrightCyan,
BrightWhite,
BrightBlack,
}
impl ColourOpt {
fn fg(&self) -> &str {
match self {
ColourOpt::Red => "31",
ColourOpt::Green => "32",
ColourOpt::Yellow => "33",
ColourOpt::Blue => "34",
ColourOpt::Magenta => "35",
ColourOpt::Cyan => "36",
ColourOpt::White => "37",
ColourOpt::Black => "30",
ColourOpt::BrightRed => "91",
ColourOpt::BrightGreen => "92",
ColourOpt::BrightYellow => "93",
ColourOpt::BrightBlue => "94",
ColourOpt::BrightMagenta => "95",
ColourOpt::BrightCyan => "96",
ColourOpt::BrightWhite => "97",
ColourOpt::BrightBlack => "90",
}
}
fn bg(&self) -> &str {
match self {
ColourOpt::Red => "41",
ColourOpt::Green => "42",
ColourOpt::Yellow => "43",
ColourOpt::Blue => "44",
ColourOpt::Magenta => "45",
ColourOpt::Cyan => "46",
ColourOpt::White => "47",
ColourOpt::Black => "40",
ColourOpt::BrightRed => "101",
ColourOpt::BrightGreen => "102",
ColourOpt::BrightYellow => "103",
ColourOpt::BrightBlue => "104",
ColourOpt::BrightMagenta => "105",
ColourOpt::BrightCyan => "106",
ColourOpt::BrightWhite => "107",
ColourOpt::BrightBlack => "100",
}
}
}
enum ResetFlag {
True,
False,
Final,
}
pub struct Format {
opts: Vec<FormatOpt>,
str: String,
}
impl Format {
pub fn new(str: &str) -> Format {
Format {
opts: Vec::new(),
str: str.to_string(),
}
}
fn add_opt(&mut self, opt: FormatOpt) -> &mut Self {
self.opts.push(opt);
self
}
pub fn fg(&mut self, colour: ColourOpt) -> &mut Self {
self.add_opt(FormatOpt::FgColour(colour))
}
pub fn bg(&mut self, colour: ColourOpt) -> &mut Self {
self.add_opt(FormatOpt::BgColour(colour))
}
pub fn colour(&mut self, fg: ColourOpt, bg: ColourOpt) -> &mut Self {
self.fg(fg).bg(bg)
}
pub fn bold(&mut self) -> &mut Self {
self.add_opt(FormatOpt::Bold)
}
pub fn dim(&mut self) -> &mut Self {
self.add_opt(FormatOpt::Dim)
}
pub fn underline(&mut self) -> &mut Self {
self.add_opt(FormatOpt::Underline)
}
pub fn blink(&mut self) -> &mut Self {
self.add_opt(FormatOpt::Blink)
}
pub fn inverse(&mut self) -> &mut Self {
self.add_opt(FormatOpt::Inverse)
}
pub fn hidden(&mut self) -> &mut Self {
self.add_opt(FormatOpt::Hidden)
}
pub fn reset(&mut self) -> &mut Self {
self.add_opt(FormatOpt::Reset)
}
pub fn no_end_reset(&mut self) -> &mut Self {
self.add_opt(FormatOpt::NoEndReset)
}
pub fn fmt(&self) -> String {
format_str(&self.str, &self.opts)
}
pub fn print(&self) {
println!("{}", self.fmt())
}
}
fn format_str(msg: &str, opts: &[FormatOpt]) -> String {
if opts.is_empty() {
return msg.to_string();
}
let len = opts.len();
let mut fmt_str = String::new();
let mut reset_flag = ResetFlag::True;
fmt_str.push_str("\x1b[");
for (i, opt) in opts.iter().enumerate() {
if i == len - 1 {
match opt {
FormatOpt::FgColour(colour) => {
fmt_str.push_str(&format!("{}m", colour.fg()));
}
FormatOpt::BgColour(colour) => {
fmt_str.push_str(&format!("{}m", colour.bg()));
}
FormatOpt::Bold => {
fmt_str.push_str("1m");
}
FormatOpt::Dim => {
fmt_str.push_str("2m");
}
FormatOpt::Underline => {
fmt_str.push_str("4m");
}
FormatOpt::Blink => {
fmt_str.push_str("5m");
}
FormatOpt::Inverse => {
fmt_str.push_str("7m");
}
FormatOpt::Hidden => {
fmt_str.push_str("8m");
}
FormatOpt::Reset => {
fmt_str.push_str("0m");
}
FormatOpt::NoEndReset => {
reset_flag = ResetFlag::Final;
}
}
} else {
match opt {
FormatOpt::FgColour(colour) => {
fmt_str.push_str(&format!("{};", colour.fg()));
}
FormatOpt::BgColour(colour) => {
fmt_str.push_str(&format!("{};", colour.bg()));
}
FormatOpt::Bold => {
fmt_str.push_str("1;");
}
FormatOpt::Dim => {
fmt_str.push_str("2;");
}
FormatOpt::Underline => {
fmt_str.push_str("4;");
}
FormatOpt::Blink => {
fmt_str.push_str("5;");
}
FormatOpt::Inverse => {
fmt_str.push_str("7;");
}
FormatOpt::Hidden => {
fmt_str.push_str("8;");
}
FormatOpt::Reset => {
fmt_str.push_str("0;");
}
FormatOpt::NoEndReset => {
reset_flag = ResetFlag::False;
}
}
}
}
match reset_flag {
ResetFlag::True => {
fmt_str.push_str(msg);
fmt_str.push_str("\x1b[0m");
}
ResetFlag::Final => {
fmt_str.replace_range(fmt_str.len() - 1..fmt_str.len(), "m");
fmt_str.push_str(msg);
}
ResetFlag::False => {
fmt_str.push_str(msg);
}
}
fmt_str
}