tinycrossterm 0.1.0

Minimal, feature-gated, WASM-compatible subset of crossterm
Documentation
use std::fmt;
use std::io::Write;

use crate::Command;

/// Terminal colors.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Color {
    Reset,
    Black,
    DarkGrey,
    Red,
    DarkRed,
    Green,
    DarkGreen,
    Yellow,
    DarkYellow,
    Blue,
    DarkBlue,
    Magenta,
    DarkMagenta,
    Cyan,
    DarkCyan,
    White,
    Grey,
    Rgb { r: u8, g: u8, b: u8 },
    AnsiValue(u8),
}

impl Color {
    fn fg_ansi(self) -> ColorAnsi {
        match self {
            Color::Reset => ColorAnsi::Sgr(39),
            Color::Black => ColorAnsi::Sgr(30),
            Color::DarkGrey => ColorAnsi::Sgr(90),
            Color::Red => ColorAnsi::Sgr(31),
            Color::DarkRed => ColorAnsi::Sgr(91),
            Color::Green => ColorAnsi::Sgr(32),
            Color::DarkGreen => ColorAnsi::Sgr(92),
            Color::Yellow => ColorAnsi::Sgr(33),
            Color::DarkYellow => ColorAnsi::Sgr(93),
            Color::Blue => ColorAnsi::Sgr(34),
            Color::DarkBlue => ColorAnsi::Sgr(94),
            Color::Magenta => ColorAnsi::Sgr(35),
            Color::DarkMagenta => ColorAnsi::Sgr(95),
            Color::Cyan => ColorAnsi::Sgr(36),
            Color::DarkCyan => ColorAnsi::Sgr(96),
            Color::White => ColorAnsi::Sgr(37),
            Color::Grey => ColorAnsi::Sgr(97),
            Color::Rgb { r, g, b } => ColorAnsi::Rgb(38, r, g, b),
            Color::AnsiValue(n) => ColorAnsi::Ansi256(38, n),
        }
    }

    fn bg_ansi(self) -> ColorAnsi {
        match self {
            Color::Reset => ColorAnsi::Sgr(49),
            Color::Black => ColorAnsi::Sgr(40),
            Color::DarkGrey => ColorAnsi::Sgr(100),
            Color::Red => ColorAnsi::Sgr(41),
            Color::DarkRed => ColorAnsi::Sgr(101),
            Color::Green => ColorAnsi::Sgr(42),
            Color::DarkGreen => ColorAnsi::Sgr(102),
            Color::Yellow => ColorAnsi::Sgr(43),
            Color::DarkYellow => ColorAnsi::Sgr(103),
            Color::Blue => ColorAnsi::Sgr(44),
            Color::DarkBlue => ColorAnsi::Sgr(104),
            Color::Magenta => ColorAnsi::Sgr(45),
            Color::DarkMagenta => ColorAnsi::Sgr(105),
            Color::Cyan => ColorAnsi::Sgr(46),
            Color::DarkCyan => ColorAnsi::Sgr(106),
            Color::White => ColorAnsi::Sgr(47),
            Color::Grey => ColorAnsi::Sgr(107),
            Color::Rgb { r, g, b } => ColorAnsi::Rgb(48, r, g, b),
            Color::AnsiValue(n) => ColorAnsi::Ansi256(48, n),
        }
    }
}

enum ColorAnsi {
    Sgr(u8),
    Rgb(u8, u8, u8, u8),
    Ansi256(u8, u8),
}

impl ColorAnsi {
    fn write(self, w: &mut impl Write) -> std::io::Result<()> {
        match self {
            ColorAnsi::Sgr(code) => write!(w, "\x1b[{code}m"),
            ColorAnsi::Rgb(base, r, g, b) => write!(w, "\x1b[{base};2;{r};{g};{b}m"),
            ColorAnsi::Ansi256(base, n) => write!(w, "\x1b[{base};5;{n}m"),
        }
    }
}

/// Text attributes.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Attribute {
    Reset,
    Bold,
    Dim,
    Italic,
    Underlined,
    SlowBlink,
    RapidBlink,
    Reverse,
    Hidden,
    CrossedOut,
}

impl Attribute {
    fn sgr(self) -> u8 {
        match self {
            Attribute::Reset => 0,
            Attribute::Bold => 1,
            Attribute::Dim => 2,
            Attribute::Italic => 3,
            Attribute::Underlined => 4,
            Attribute::SlowBlink => 5,
            Attribute::RapidBlink => 6,
            Attribute::Reverse => 7,
            Attribute::Hidden => 8,
            Attribute::CrossedOut => 9,
        }
    }
}

/// Sets the foreground color.
#[derive(Debug, Clone, Copy)]
pub struct SetForegroundColor(pub Color);

impl Command for SetForegroundColor {
    fn write_ansi(&self, w: &mut impl Write) -> std::io::Result<()> {
        self.0.fg_ansi().write(w)
    }
}

/// Sets the background color.
#[derive(Debug, Clone, Copy)]
pub struct SetBackgroundColor(pub Color);

impl Command for SetBackgroundColor {
    fn write_ansi(&self, w: &mut impl Write) -> std::io::Result<()> {
        self.0.bg_ansi().write(w)
    }
}

/// Sets a text attribute.
#[derive(Debug, Clone, Copy)]
pub struct SetAttribute(pub Attribute);

impl Command for SetAttribute {
    fn write_ansi(&self, w: &mut impl Write) -> std::io::Result<()> {
        write!(w, "\x1b[{}m", self.0.sgr())
    }
}

/// Resets foreground and background colors to defaults.
#[derive(Debug, Clone, Copy)]
pub struct ResetColor;

impl Command for ResetColor {
    fn write_ansi(&self, w: &mut impl Write) -> std::io::Result<()> {
        w.write_all(b"\x1b[0m")
    }
}

/// Prints a value to the terminal.
#[derive(Debug, Clone)]
pub struct Print<T: fmt::Display>(pub T);

impl<T: fmt::Display> Command for Print<T> {
    fn write_ansi(&self, w: &mut impl Write) -> std::io::Result<()> {
        write!(w, "{}", self.0)
    }
}