m2 0.0.0

Set of Unix tools to work with m2dirs
Documentation
use std::{
    fmt::{self, Display, Write},
    io::IsTerminal,
};

#[derive(Copy, Clone, Debug)]
pub enum Format {
    Reset,
    Bold,
    Faint,
    #[allow(dead_code)]
    Italic,
    #[allow(dead_code)]
    Underline,
    #[allow(dead_code)]
    Hex(&'static str),
    #[allow(dead_code)]
    None,
}

impl Display for Format {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        use Format::*;

        match self {
            Reset => write_escape_code(f, "0")?,
            Bold => write_escape_code(f, "1")?,
            Faint => write_escape_code(f, "2")?,
            Italic => write_escape_code(f, "3")?,
            Underline => write_escape_code(f, "4")?,
            Hex(h) => hex(f, h)?,
            None => {}
        }

        Ok(())
    }
}

#[allow(dead_code)]
pub fn hex<W: Write>(w: W, hex: &str) -> fmt::Result {
    if let Some((r, g, b)) = hex_to_ansi(hex) {
        write_escape_code(w, format!("38;2;{r};{g};{b}"))?;
    }
    Ok(())
}

fn hex_to_ansi(mut hex: &str) -> Option<(u32, u32, u32)> {
    if hex.starts_with('#') {
        hex = &hex[1..];
    }

    u32::from_str_radix(hex, 16)
        .ok()
        .map(|val| ((val >> 16) & 255, (val >> 8) & 255, val & 255))
}

fn write_escape_code<S: Display, W: Write>(mut w: W, code: S) -> fmt::Result {
    if std::env::var("NO_COLOR")
        .unwrap_or("".to_string())
        .is_empty()
        && std::io::stdout().is_terminal()
    {
        write!(w, "\x1b[{code}m")?;
    }
    Ok(())
}