use std::collections::HashMap;
use ansi_term::Style;
use serde::{Deserialize, Serialize};
use crate::{
error::{Error, Result},
log::Highlight,
};
#[derive(Default, Debug, Clone, PartialEq, Deserialize, Serialize)]
pub struct ConfigColorMap(pub HashMap<String, ConfigColor>);
#[derive(Default, Debug, Clone, PartialEq, Deserialize, Serialize)]
pub struct ConfigColor {
pub color: Option<Color>,
pub background: Option<Color>,
pub bold: Option<bool>,
pub underline: Option<bool>,
pub italic: Option<bool>,
pub inverse: Option<bool>,
}
#[derive(Default, Debug, Clone, PartialEq, Deserialize, Serialize)]
pub struct ColorValue {
pub color: String,
pub rgb: Option<String>,
}
macro_rules! map {
() => {
HashMap::new()
};
($($key:expr => $value:expr),+ $(,)?) => {{
let mut map = HashMap::new();
$( map.insert($key, $value); )*
map
}};
}
impl ConfigColorMap {
pub fn get(&self, key: &str) -> Option<&ConfigColor> {
self.0.get(key)
}
pub fn default_highlights() -> HashMap<Highlight, Style> {
use ansi_term::Color::*;
map![
Highlight::Important => Red.bold(),
Highlight::Special => Cyan.normal(),
Highlight::Repo => Cyan.normal(),
Highlight::Origin => Green.normal(),
Highlight::Remote => Green.normal(),
Highlight::Username => Green.normal(),
Highlight::Path => Cyan.normal(),
Highlight::Protocol => Cyan.normal(),
Highlight::Url => Purple.normal(),
Highlight::Commit => Green.normal(),
Highlight::Date => Style::new(),
Highlight::Author => Style::new(),
Highlight::CommitMsg => Cyan.normal(),
Highlight::Warning => Yellow.normal()
]
}
pub fn parse_highlights(&self) -> Result<HashMap<Highlight, Style>> {
let mut map = Self::default_highlights();
for (k, v) in &self.0 {
match k.as_str() {
"important" => {
map.insert(Highlight::Important, v.parse()?);
}
"special" => {
map.insert(Highlight::Special, v.parse()?);
}
"repo" => {
map.insert(Highlight::Repo, v.parse()?);
}
"origin" => {
map.insert(Highlight::Origin, v.parse()?);
}
"remote" => {
map.insert(Highlight::Remote, v.parse()?);
}
"username" => {
map.insert(Highlight::Username, v.parse()?);
}
"path" => {
map.insert(Highlight::Path, v.parse()?);
}
"protocol" => {
map.insert(Highlight::Protocol, v.parse()?);
}
"url" => {
map.insert(Highlight::Url, v.parse()?);
}
"commit" => {
map.insert(Highlight::Commit, v.parse()?);
}
"date" => {
map.insert(Highlight::Date, v.parse()?);
}
"author" => {
map.insert(Highlight::Author, v.parse()?);
}
"commit_msg" => {
map.insert(Highlight::CommitMsg, v.parse()?);
}
"warning" => {
map.insert(Highlight::Warning, v.parse()?);
}
_ => {
return Err(Error::deserialization(format!(
"could not validate color config: '{}' is not a valid highlight. Expected one of {}",
k,
concat!(
"important, special, repo, origin, remote, username, path, protocol, ",
"url, commit, date, author, commit_msg, warning."
),
)))
}
}
}
Ok(map)
}
}
impl ConfigColor {
pub fn parse(&self) -> Result<ansi_term::Style> {
let mut color = Style::new();
if let Some(fg) = &self.color {
color = color.fg(Result::from(fg)?);
}
if let Some(bg) = &self.background {
color = color.on(Result::from(bg)?);
}
if let Some(true) = self.bold {
color = color.bold();
}
if let Some(true) = self.underline {
color = color.underline();
}
if let Some(true) = self.italic {
color = color.italic();
}
if let Some(true) = self.inverse {
color = color.reverse();
}
Ok(color)
}
}
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
#[serde(untagged)]
pub enum Color {
Fixed(u8),
RGB { r: u8, g: u8, b: u8 },
Named(String),
}
impl From<&Color> for Result<ansi_term::Color> {
fn from(value: &Color) -> Self {
use Color::*;
match value {
Named(s) => match s.to_lowercase().as_str() {
"black" => Ok(ansi_term::Color::Black),
"red" => Ok(ansi_term::Color::Red),
"green" => Ok(ansi_term::Color::Green),
"yellow" => Ok(ansi_term::Color::Yellow),
"blue" => Ok(ansi_term::Color::Blue),
"purple" => Ok(ansi_term::Color::Purple),
"cyan" => Ok(ansi_term::Color::Cyan),
"white" => Ok(ansi_term::Color::White),
_ => Err(Error::deserialization(format!(
"could not parse color: '{}' is not a valid color name. Expected one of: {}",
s, "black, red, green, yellow, blue, purple, cyan, white"
))),
},
Fixed(value) => Ok(ansi_term::Color::Fixed(*value)),
RGB { r, g, b } => Ok(ansi_term::Color::RGB(*r, *g, *b)),
}
}
}