use std::fmt::Debug;
use color::AsBackground;
pub trait Style: Sized + Clone {
fn prefix(&self) -> String;
fn and(self, other: impl Style) -> GeneralStyle {
GeneralStyle::new(self.prefix() + &other.prefix()).into()
}
}
pub trait ColorStyle: Style {}
pub trait TextStyle: Style {}
pub trait BorderPattern {
fn get_top_left(&self) -> char;
fn get_top_right(&self) -> char;
fn get_bottom_left(&self) -> char;
fn get_bottom_right(&self) -> char;
fn get_top(&self) -> char;
fn get_bottom(&self) -> char;
fn get_left(&self) -> char;
fn get_right(&self) -> char;
}
#[derive(Clone, Debug)]
pub struct TChar {
pub char: char,
pub control: String,
}
impl TChar {
pub fn new(c: char, ctrl: String) -> Self {
TChar {
char: c,
control: ctrl,
}
}
}
#[derive(Debug, Clone)]
pub struct TString {
pub chars: Vec<TChar>,
}
impl TString {
pub fn new() -> Self {
TString { chars: Vec::new() }
}
pub fn from_str(s: &str, style: impl Into<GeneralStyle>) -> Self {
let mut chars = Vec::new();
let style = style.into().clone();
for c in s.chars() {
chars.push(TChar::new(c, style.prefix()));
}
TString { chars }
}
pub fn make_string(&self) -> String {
self.chars
.iter()
.map(|c| format!("{}{}", c.control, c.char))
.collect()
}
pub fn styled(&self, style: impl Into<GeneralStyle>) -> TString {
let style = style.into().clone();
let chars = self
.chars
.iter()
.map(move |c| {
let mut new_c = c.clone();
new_c.control = style.prefix() + &new_c.control;
new_c
})
.collect();
TString { chars }
}
pub fn len(&self) -> usize {
self.chars.len()
}
}
#[derive(Debug, Clone)]
pub struct GeneralStyle {
pub prefix: String,
}
impl GeneralStyle {
pub fn new(prefix: String) -> Self {
GeneralStyle { prefix }
}
}
impl GeneralStyle {
pub fn from_style<T: Style>(style: T) -> Self {
GeneralStyle::new(style.prefix())
}
}
impl Style for GeneralStyle {
fn prefix(&self) -> String {
self.prefix.clone()
}
}
#[derive(Debug, Clone)]
pub struct NoStyle;
impl Style for NoStyle {
fn prefix(&self) -> String {
String::new()
}
}
impl TextStyle for NoStyle {}
impl ColorStyle for NoStyle {}
impl From<NoStyle> for GeneralStyle {
fn from(_: NoStyle) -> Self {
GeneralStyle::new(String::new())
}
}
#[derive(Debug, Clone)]
pub struct RgbColor(pub u8, pub u8, pub u8);
impl Style for RgbColor {
fn prefix(&self) -> String {
format!("\x1b[38;2;{};{};{}m", self.0, self.1, self.2)
}
}
impl From<RgbColor> for GeneralStyle {
fn from(color: RgbColor) -> Self {
GeneralStyle::new(color.prefix())
}
}
impl ColorStyle for RgbColor {}
impl Style for AsBackground<RgbColor> {
fn prefix(&self) -> String {
format!("\x1b[48;2;{};{};{}m", self.0 .0, self.0 .1, self.0 .2)
}
}
impl From<AsBackground<RgbColor>> for GeneralStyle {
fn from(color: AsBackground<RgbColor>) -> Self {
GeneralStyle::new(color.prefix())
}
}
impl ColorStyle for AsBackground<RgbColor> {}
#[macro_export]
macro_rules! tstr {
($s:expr) => {
TString::from_str($s)
};
($s:expr, $($args:tt)*) => {
TString::from_str(format!($s, $($args)*))
}
}
macro_rules! impl_style {
($name:ty, $prefix:expr) => {
impl Style for $name {
fn prefix(&self) -> String {
$prefix.to_string()
}
}
impl ColorStyle for $name {}
impl From<$name> for GeneralStyle {
fn from(_: $name) -> Self {
GeneralStyle::new($prefix.to_string())
}
}
};
}
macro_rules! new_style {
($name:ident, $prefix:expr) => {
#[doc = " A style that can be applied to text in a terminal."]
#[derive(Debug, Clone)]
pub struct $name;
impl Style for $name {
fn prefix(&self) -> String {
$prefix.to_string()
}
}
impl From<$name> for GeneralStyle {
fn from(_: $name) -> Self {
GeneralStyle::new($prefix.to_string())
}
}
};
(color, $name:ident, $prefix:expr) => {
new_style!($name, $prefix);
impl ColorStyle for $name {}
};
(text, $name:ident, $prefix:expr) => {
new_style!($name, $prefix);
impl TextStyle for $name {}
};
}
pub mod color {
use super::*;
#[derive(Debug, Clone)]
pub struct AsBackground<T: ColorStyle>(pub T);
new_style!(color, Black, "\x1b[30m");
new_style!(color, Red, "\x1b[31m");
new_style!(color, Green, "\x1b[32m");
new_style!(color, Yellow, "\x1b[33m");
new_style!(color, Blue, "\x1b[34m");
new_style!(color, Magenta, "\x1b[35m");
new_style!(color, Cyan, "\x1b[36m");
new_style!(color, White, "\x1b[37m");
new_style!(color, Grey, "\x1b[38m");
new_style!(color, LightBlack, "\x1b[90m");
new_style!(color, LightRed, "\x1b[91m");
new_style!(color, LightGreen, "\x1b[92m");
new_style!(color, LightYellow, "\x1b[93m");
new_style!(color, LightBlue, "\x1b[94m");
new_style!(color, LightMagenta, "\x1b[95m");
new_style!(color, LightCyan, "\x1b[96m");
new_style!(color, LightWhite, "\x1b[97m");
impl_style!(AsBackground<Black>, "\x1b[40m");
impl_style!(AsBackground<Red>, "\x1b[41m");
impl_style!(AsBackground<Green>, "\x1b[42m");
impl_style!(AsBackground<Yellow>, "\x1b[43m");
impl_style!(AsBackground<Blue>, "\x1b[44m");
impl_style!(AsBackground<Magenta>, "\x1b[45m");
impl_style!(AsBackground<Cyan>, "\x1b[46m");
impl_style!(AsBackground<White>, "\x1b[47m");
impl_style!(AsBackground<Grey>, "\x1b[48m");
impl_style!(AsBackground<LightBlack>, "\x1b[100m");
impl_style!(AsBackground<LightRed>, "\x1b[101m");
impl_style!(AsBackground<LightGreen>, "\x1b[102m");
impl_style!(AsBackground<LightYellow>, "\x1b[103m");
impl_style!(AsBackground<LightBlue>, "\x1b[104m");
impl_style!(AsBackground<LightMagenta>, "\x1b[105m");
impl_style!(AsBackground<LightCyan>, "\x1b[106m");
impl_style!(AsBackground<LightWhite>, "\x1b[107m");
new_style!(text, Bold, "\x1b[1m");
new_style!(text, Italic, "\x1b[3m");
new_style!(text, Underline, "\x1b[4m");
new_style!(text, Blink, "\x1b[5m");
new_style!(text, Reverse, "\x1b[7m");
new_style!(text, Hidden, "\x1b[8m");
new_style!(text, Strikethrough, "\x1b[9m");
new_style!(text, Reset, "\x1b[0m");
}
#[derive(Debug, Clone)]
pub struct GeneralBorderPattern {
pub top_left: char,
pub top_right: char,
pub bottom_left: char,
pub bottom_right: char,
pub top: char,
pub bottom: char,
pub left: char,
pub right: char,
}
impl BorderPattern for GeneralBorderPattern {
fn get_top_left(&self) -> char {
self.top_left
}
fn get_top_right(&self) -> char {
self.top_right
}
fn get_bottom_left(&self) -> char {
self.bottom_left
}
fn get_bottom_right(&self) -> char {
self.bottom_right
}
fn get_top(&self) -> char {
self.top
}
fn get_bottom(&self) -> char {
self.bottom
}
fn get_left(&self) -> char {
self.left
}
fn get_right(&self) -> char {
self.right
}
}
macro_rules! border_pattern {
($name:ident, $top_left:expr, $top_right:expr, $bottom_left:expr, $bottom_right:expr, $top:expr, $bottom:expr, $left:expr, $right:expr) => {
pub struct $name;
impl BorderPattern for $name {
fn get_top_left(&self) -> char {
$top_left
}
fn get_top_right(&self) -> char {
$top_right
}
fn get_bottom_left(&self) -> char {
$bottom_left
}
fn get_bottom_right(&self) -> char {
$bottom_right
}
fn get_top(&self) -> char {
$top
}
fn get_bottom(&self) -> char {
$bottom
}
fn get_left(&self) -> char {
$left
}
fn get_right(&self) -> char {
$right
}
}
impl From<$name> for GeneralBorderPattern {
fn from(border: $name) -> Self {
GeneralBorderPattern {
top_left: border.get_top_left(),
top_right: border.get_top_right(),
bottom_left: border.get_bottom_left(),
bottom_right: border.get_bottom_right(),
top: border.get_top(),
bottom: border.get_bottom(),
left: border.get_left(),
right: border.get_right(),
}
}
}
};
}
pub mod pattern {
use super::*;
#[rustfmt::skip] border_pattern!(NoBorder, ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ');
#[rustfmt::skip] border_pattern!(DefaultBorder, '┐', '┌', '┘', '└', '─', '─', '│', '│');
#[rustfmt::skip] border_pattern!(DoubleBorder, '╗', '╔', '╝', '╚', '═', '═', '║', '║');
#[rustfmt::skip] border_pattern!(DottedBorder, '.', '.', '.', '.', '.', '.', '.', '.');
#[rustfmt::skip] border_pattern!(DashedBorder, '┐', '┌', '┘', '└', '-', '-', '∣', '∣');
#[rustfmt::skip] border_pattern!(SolidBorder, '█', '█', '█', '█', '█', '█', '█', '█');
#[rustfmt::skip] border_pattern!(SlashBorder, '/', '/', '/', '/', '/', '/', '/', '/');
#[rustfmt::skip] border_pattern!(BackSlashBorder, '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\');
#[rustfmt::skip] border_pattern!(TripleDottedBorder, '⠏', '⠹', '⠧', '⠼', '⠉', '⠤', '⠇', '⠸');
}