istat 0.6.0

A lightweight and batteries-included status_command for i3 and sway
Documentation
use hex_color::HexColor;
use serde_derive::{Deserialize, Serialize};

use crate::error::Result;

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ColorPair {
    pub fg: HexColor,
    pub bg: HexColor,
}

impl ColorPair {
    pub const fn new(fg: HexColor, bg: HexColor) -> ColorPair {
        ColorPair { fg, bg }
    }
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PowerlineSeparator {
    value: String,
    #[serde(default)]
    scale: Option<u32>,
}

impl PowerlineSeparator {
    pub fn to_span(&self) -> String {
        match self.scale {
            None => self.value.clone(),
            Some(pct) => format!(r#"<span size="{}%">{}</span>"#, pct, self.value),
        }
    }
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Theme {
    #[serde(default = "Theme::default_bg")]
    pub bg: HexColor,
    #[serde(default = "Theme::default_fg")]
    pub fg: HexColor,
    #[serde(default = "Theme::default_dim")]
    pub dim: HexColor,

    #[serde(default = "Theme::default_red")]
    pub red: HexColor,
    #[serde(default = "Theme::default_orange")]
    pub orange: HexColor,
    #[serde(default = "Theme::default_yellow")]
    pub yellow: HexColor,
    #[serde(default = "Theme::default_green")]
    pub green: HexColor,
    #[serde(default = "Theme::default_purple")]
    pub purple: HexColor,
    #[serde(default = "Theme::default_blue")]
    pub blue: HexColor,

    /// The foreground for an urgent item. Defaults to `theme.fg`.
    #[serde(default = "Theme::default_bg")]
    pub urgent_fg: HexColor,
    /// The background for an urgent item. Defaults to `theme.red`.
    #[serde(default = "Theme::default_red")]
    pub urgent_bg: HexColor,

    #[serde(default = "Theme::default_powerline")]
    pub powerline: Vec<ColorPair>,
    #[serde(default)]
    pub powerline_enable: bool,
    #[serde(default = "Theme::default_powerline_separator")]
    pub powerline_separator: PowerlineSeparator,
}

impl Default for Theme {
    fn default() -> Self {
        Self {
            bg: Self::default_bg(),
            fg: Self::default_fg(),
            dim: Self::default_dim(),

            red: Self::default_red(),
            orange: Self::default_orange(),
            yellow: Self::default_yellow(),
            green: Self::default_green(),
            purple: Self::default_purple(),
            blue: Self::default_blue(),

            urgent_fg: Self::default_bg(),
            urgent_bg: Self::default_red(),

            powerline: Self::default_powerline(),
            powerline_enable: false,
            powerline_separator: Self::default_powerline_separator(),
        }
    }
}

impl Theme {
    pub fn validate(&self) -> Result<()> {
        if self.powerline.len() <= 1 {
            bail!("theme.powerline must contain at least two values");
        }

        Ok(())
    }

    const DEFAULT_POWERLINE: &[ColorPair] = &[
        ColorPair::new(HexColor::rgb(216, 222, 233), HexColor::rgb(59, 66, 82)),
        ColorPair::new(HexColor::rgb(229, 233, 240), HexColor::rgb(67, 76, 94)),
        ColorPair::new(HexColor::rgb(236, 239, 244), HexColor::rgb(76, 86, 106)),
        ColorPair::new(HexColor::rgb(229, 233, 240), HexColor::rgb(67, 76, 94)),
    ];

    const fn default_bg() -> HexColor {
        HexColor::rgb(46, 52, 64)
    }

    const fn default_fg() -> HexColor {
        HexColor::rgb(216, 222, 233)
    }

    const fn default_dim() -> HexColor {
        HexColor::rgb(76, 86, 106)
    }

    const fn default_blue() -> HexColor {
        HexColor::rgb(143, 188, 187)
    }

    const fn default_red() -> HexColor {
        HexColor::rgb(191, 97, 106)
    }

    const fn default_orange() -> HexColor {
        HexColor::rgb(208, 135, 112)
    }

    const fn default_yellow() -> HexColor {
        HexColor::rgb(235, 203, 139)
    }

    const fn default_green() -> HexColor {
        HexColor::rgb(163, 190, 140)
    }

    const fn default_purple() -> HexColor {
        HexColor::rgb(180, 142, 173)
    }

    fn default_powerline() -> Vec<ColorPair> {
        Self::DEFAULT_POWERLINE.to_vec()
    }

    fn default_powerline_separator() -> PowerlineSeparator {
        PowerlineSeparator {
            value: "".into(),
            scale: None,
        }
    }
}