use core::convert::TryInto;
use core::fmt::{self, Display, Formatter, Write};
use owo_colors::OwoColorize;
pub struct Table {
pub inner: [RichScalar; 256],
pub requires_rich: bool,
}
#[derive(Debug, Clone, Copy)]
#[repr(transparent)]
pub struct Scalar(pub u32);
#[derive(Debug, Clone, Copy)]
pub struct RichScalar {
pub scalar: Scalar,
pub reversed: bool,
pub bold: bool,
pub dimmed: bool,
}
impl Display for Scalar {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
f.write_char(self.0.try_into().or(Err(fmt::Error))?)
}
}
impl RichScalar {
pub const fn new(scalar: u32) -> Self {
Self {
scalar: Scalar(scalar),
reversed: false,
bold: false,
dimmed: false,
}
}
pub const fn reversed(self, reversed: bool) -> Self {
Self { reversed, ..self }
}
pub const fn bold(self, bold: bool) -> Self {
Self { bold, ..self }
}
pub const fn dimmed(self, dimmed: bool) -> Self {
Self { dimmed, ..self }
}
}
macro_rules! reversed {
($self:ident, $scalar:ident, $($inner:tt)*) => {
if $self.reversed {
let $scalar = $scalar.reversed();
$($inner)*
} else {
$($inner)*
}
};
}
macro_rules! bold {
($self:ident, $scalar:ident, $($inner:tt)*) => {
if $self.bold {
let $scalar = $scalar.bold();
$($inner)*
} else {
$($inner)*
}
};
}
macro_rules! dimmed {
($self:ident, $scalar:ident, $($inner:tt)*) => {
if $self.dimmed {
let $scalar = $scalar.dimmed();
$($inner)*
} else {
$($inner)*
}
};
}
impl Display for RichScalar {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
let scalar = self.scalar;
reversed!(
self,
scalar,
bold!(
self,
scalar,
dimmed!(self, scalar, Display::fmt(&scalar, f))
)
)
}
}
pub const DEFAULT: Table = {
let mut result = [RichScalar::new(0); 256];
let mut byte = 0;
while byte < 0x100 {
result[byte] = match (byte, printable(byte as u8), picture(byte as u8)) {
(0x00, _, Some(x)) => RichScalar::new(x).dimmed(true),
(_, Some(x), _) => RichScalar::new(x).bold(true),
(x, _, _) => RichScalar::new(CP437[x] as u32).dimmed(true),
};
byte += 1;
}
Table {
inner: result,
requires_rich: false,
}
};
pub const CLASSIC: Table = {
let mut result = [RichScalar::new('.' as u32); 256];
let mut byte = 0;
while byte < 0x100 {
if let Some(x) = printable(byte as u8) {
result[byte] = RichScalar::new(x);
}
byte += 1;
}
Table {
inner: result,
requires_rich: false,
}
};
pub const REVERSE: Table = {
let mut result = [RichScalar::new(0); 256];
let mut byte = 0;
while byte < 0x100 {
let low = byte as u8 & 0x7F;
result[byte] = match (printable(low), picture(low)) {
(Some(x), _) => RichScalar::new(x).reversed(byte > 0x7F),
(_, Some(x)) => RichScalar::new(x).reversed(byte > 0x7F),
_ => result[byte], };
byte += 1;
}
Table {
inner: result,
requires_rich: true,
}
};
const fn printable(byte: u8) -> Option<u32> {
match byte {
x if 0x20 <= x && x < 0x7F => Some(x as u32),
_ => None,
}
}
const fn picture(byte: u8) -> Option<u32> {
match byte {
x if x < 0x20 => Some('␀' as u32 + x as u32),
0x7F => Some('␡' as u32),
_ => None,
}
}
#[rustfmt::skip]
const CP437: [char; 256] = [
'\0','☺','☻','♥','♦','♣','♠','•','◘','○','◙','♂','♀','♪','♫','☼',
'►','◄','↕','‼','¶','§','▬','↨','↑','↓','→','←','∟','↔','▲','▼',
' ','!','"','#','$','%','&','\'','(',')','*','+',',','-','.','/',
'0','1','2','3','4','5','6','7','8','9',':',';','<','=','>','?',
'@','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O',
'P','Q','R','S','T','U','V','W','X','Y','Z','[','\\',']','^','_',
'`','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o',
'p','q','r','s','t','u','v','w','x','y','z','{','|','}','~','⌂',
'Ç','ü','é','â','ä','à','å','ç','ê','ë','è','ï','î','ì','Ä','Å',
'É','æ','Æ','ô','ö','ò','û','ù','ÿ','Ö','Ü','¢','£','¥','₧','ƒ',
'á','í','ó','ú','ñ','Ñ','ª','º','¿','⌐','¬','½','¼','¡','«','»',
'░','▒','▓','│','┤','╡','╢','╖','╕','╣','║','╗','╝','╜','╛','┐',
'└','┴','┬','├','─','┼','╞','╟','╚','╔','╩','╦','╠','═','╬','╧',
'╨','╤','╥','╙','╘','╒','╓','╫','╪','┘','┌','█','▄','▌','▐','▀',
'α','ß','Γ','π','Σ','σ','µ','τ','Φ','Θ','Ω','δ','∞','φ','ε','∩',
'≡','±','≥','≤','⌠','⌡','÷','≈','°','∙','·','√','ⁿ','²','■',' ',
];