about summary refs log blame commit diff
path: root/src/display/color.rs
blob: afe0039998b8ed528caec5b9b870a40a88023ee4 (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
















                                                         








                                                                  
                             
                                                                   


                          
                                                                   




                                     
                                                                   


                          
                                                                   



                          





                                














                                         
                                                                            


































                                                                              



























































                                                                      
use serde::de::{self, Unexpected, Visitor};
use std::fmt;
use std::marker::PhantomData;
use termion::color;

#[derive(Debug)]
pub struct Color(Box<dyn color::Color>);

unsafe impl Sync for Color {}
unsafe impl Send for Color {}

impl Color {
    pub fn new<C: color::Color + 'static>(c: C) -> Self {
        Color(Box::new(c))
    }
}

impl PartialEq for Color {
    fn eq(&self, other: &Self) -> bool {
        format!("{}{}", color::Fg(self), color::Bg(self))
            == format!("{}{}", color::Fg(other), color::Bg(other))
    }
}

impl Eq for Color {}

impl color::Color for Color {
    fn write_fg(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        self.0.write_fg(f)
    }

    fn write_bg(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        self.0.write_bg(f)
    }
}

impl<'a> color::Color for &'a Color {
    fn write_fg(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        self.0.write_fg(f)
    }

    fn write_bg(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        self.0.write_bg(f)
    }
}

impl Default for Color {
    fn default() -> Self {
        Color::new(color::Reset)
    }
}

pub struct ColorVisitor {
    marker: PhantomData<fn() -> Color>,
}

impl ColorVisitor {
    fn new() -> Self {
        ColorVisitor {
            marker: PhantomData,
        }
    }
}

impl<'de> Visitor<'de> for ColorVisitor {
    type Value = Color;

    fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
        formatter.write_str("A color")
    }

    fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
    where
        E: de::Error,
    {
        match v.to_lowercase().as_ref() {
            "black" => Ok(Color(Box::new(color::Black))),
            "blue" => Ok(Color(Box::new(color::Blue))),
            "cyan" => Ok(Color(Box::new(color::Cyan))),
            "green" => Ok(Color(Box::new(color::Green))),
            "light black" | "light_black" => {
                Ok(Color(Box::new(color::LightBlack)))
            }
            "light blue" | "light_blue" => {
                Ok(Color(Box::new(color::LightBlue)))
            }
            "light cyan" | "light_cyan" => {
                Ok(Color(Box::new(color::LightCyan)))
            }
            "light green" | "light_green" => {
                Ok(Color(Box::new(color::LightGreen)))
            }
            "light magenta" | "light_magenta" => {
                Ok(Color(Box::new(color::LightMagenta)))
            }
            "light red" | "light_red" => Ok(Color(Box::new(color::LightRed))),
            "light white" | "light_white" => {
                Ok(Color(Box::new(color::LightWhite)))
            }
            "light yellow" | "light_yellow" => {
                Ok(Color(Box::new(color::LightYellow)))
            }
            "magenta" => Ok(Color(Box::new(color::Magenta))),
            "red" => Ok(Color(Box::new(color::Red))),
            "white" => Ok(Color(Box::new(color::White))),
            "yellow" => Ok(Color(Box::new(color::Yellow))),
            _ => Err(de::Error::invalid_value(
                Unexpected::Str(v),
                &"a valid color",
            )),
        }
    }

    fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
    where
        A: de::MapAccess<'de>,
    {
        let mut red = None;
        let mut green = None;
        let mut blue = None;
        while let Some((k, v)) = map.next_entry()? {
            match k {
                "red" => {
                    red = Some(v);
                }
                "green" => {
                    green = Some(v);
                }
                "blue" => {
                    blue = Some(v);
                }
                _ => {
                    return Err(de::Error::unknown_field(
                        k,
                        &["red", "green", "blue"],
                    ));
                }
            }
        }

        match (red, green, blue) {
            (Some(r), Some(g), Some(b)) => {
                Ok(Color(Box::new(color::Rgb(r, g, b))))
            }
            (None, _, _) => Err(de::Error::missing_field("red")),
            (_, None, _) => Err(de::Error::missing_field("green")),
            (_, _, None) => Err(de::Error::missing_field("blue")),
        }
    }

    fn visit_u8<E: de::Error>(self, v: u8) -> Result<Self::Value, E> {
        Ok(Color(Box::new(color::AnsiValue(v))))
    }
}

impl<'de> serde::Deserialize<'de> for Color {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: serde::Deserializer<'de>,
    {
        deserializer.deserialize_any(ColorVisitor::new())
    }
}