roxy_cli 0.1.2

A command-line static site generator
use std::str::FromStr;

use serde::Deserialize;

use crate::DEFAULT_THEME;

pub(crate) trait Merge {
    fn merge(self, other: Self) -> Self;
}

fn merge_opts<M: Merge>(a: Option<M>, b: Option<M>) -> Option<M> {
    match (a, b) {
        (Some(a), Some(b)) => Some(a.merge(b)),
        (None, Some(b)) => Some(b),
        (Some(a), None) => Some(a),
        _ => None,
    }
}

#[derive(Debug)]
pub(crate) struct Config {
    pub roxy: RoxyConfig,
    pub syntect: SyntectConfig
}

impl From<ConfigDeserializer> for Config {
    fn from(value: ConfigDeserializer) -> Self {
        Self {
            roxy: value.roxy.map_or_else(Default::default, From::from),
            syntect: value.syntect.map_or_else(Default::default, From::from)
        }
    }
}

#[derive(Debug)]
pub(crate) struct RoxyConfig {
    pub slug_word_limit: usize
}

impl From<RoxyConfigDeserializer> for RoxyConfig {
    fn from(value: RoxyConfigDeserializer) -> Self {
        Self {
            slug_word_limit: value.slug_word_limit.unwrap_or(24usize)
        }
    }
}

impl Default for RoxyConfig {
    fn default() -> Self {
        Self {
            slug_word_limit: 24usize
        }
    }
}

#[derive(Debug)]
pub(crate) struct SyntectConfig {
    pub theme: String,
    pub theme_dir: Option<String>
}

impl From<SyntectConfigDeserializer> for SyntectConfig {
    fn from(value: SyntectConfigDeserializer) -> Self {
        Self {
            theme: value.theme.unwrap_or(DEFAULT_THEME.into()),
            theme_dir: value.theme_dir
        }
    }
}

impl Default for SyntectConfig {
    fn default() -> Self {
        Self {
            theme: DEFAULT_THEME.into(),
            theme_dir: None
        }
    }
}

#[derive(Debug, Default, Deserialize)]
pub(crate) struct ConfigDeserializer {
    pub roxy: Option<RoxyConfigDeserializer>,
    pub syntect: Option<SyntectConfigDeserializer>,
}

impl FromStr for ConfigDeserializer {
    type Err = toml::de::Error;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        toml::from_str(s)
    }
}

impl Merge for ConfigDeserializer {
    fn merge(self, other: Self) -> Self {
        Self {
            roxy: merge_opts(self.roxy, other.roxy),
            syntect: merge_opts(self.syntect, other.syntect),
        }
    }
}
#[derive(Debug, Deserialize)]
pub(crate) struct RoxyConfigDeserializer {
    pub slug_word_limit: Option<usize>,
}

impl Default for RoxyConfigDeserializer {
    fn default() -> Self {
        Self {
            slug_word_limit: Some(8usize),
        }
    }
}

impl Merge for RoxyConfigDeserializer {
    fn merge(self, other: Self) -> Self {
        Self {
            slug_word_limit: self.slug_word_limit.or(other.slug_word_limit),
        }
    }
}

#[derive(Debug, Default, Deserialize)]
pub(crate) struct SyntectConfigDeserializer {
    pub theme: Option<String>,
    pub theme_dir: Option<String>,
}

impl Merge for SyntectConfigDeserializer {
    fn merge(self, other: SyntectConfigDeserializer) -> Self {
        Self {
            theme: self.theme.or(other.theme),
            theme_dir: self.theme_dir.or(other.theme_dir),
        }
    }
}