pub mod meta;
pub mod palette;
pub mod syntax;
pub mod ui;
pub use crate::scheme::tinted8::structure::meta::SchemeMeta;
pub use crate::scheme::tinted8::structure::palette::Palette;
pub use crate::scheme::tinted8::structure::syntax::{Syntax, SyntaxKey};
pub use crate::scheme::tinted8::structure::ui::{Ui, UiKey};
use crate::scheme::tinted8::yaml::Tinted8Scheme as YamlTinted8Scheme;
use crate::tinted8::SUPPORTED_STYLING_SPEC_VERSION;
use crate::utils::slugify;
use crate::utils::titlecasify;
use crate::{SchemeSupports, SchemeVariant};
use semver::{Version, VersionReq};
use serde::{Deserialize, Deserializer, Serialize};
use std::fmt;
#[derive(Debug, Clone, Serialize)]
pub struct Scheme {
pub scheme: SchemeMeta,
pub palette: Palette,
pub syntax: Syntax,
pub ui: Ui,
pub variant: SchemeVariant,
}
impl fmt::Display for Scheme {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
writeln!(f, "scheme:")?;
writeln!(f, " system: \"{}\"", self.scheme.system)?;
writeln!(
f,
" supports: \n \"{}\"",
self.scheme.supports.styling_spec
)?;
writeln!(f, " name: \"{}\"", self.scheme.name)?;
writeln!(f, " author: \"{}\"", self.scheme.author)?;
writeln!(f, " theme-author: \"{}\"", self.scheme.theme_author)?;
writeln!(f, " slug: \"{}\"", self.scheme.slug)?;
if let Some(ref desc) = self.scheme.description {
writeln!(f, " description: \"{desc}\"")?;
}
#[allow(clippy::writeln_empty_string)]
writeln!(f, "")?;
writeln!(f, "variant: \"{}\"", self.variant)?;
if let Some(ref family) = self.scheme.family {
writeln!(f, "family: \"{family}\"")?;
}
if let Some(ref style) = self.scheme.style {
writeln!(f, "style: \"{style}\"")?;
}
#[allow(clippy::writeln_empty_string)]
writeln!(f, "")?;
writeln!(f, "palette:")?;
#[allow(clippy::writeln_empty_string)]
writeln!(f, "")?;
writeln!(f, "{}", self.palette)?;
writeln!(f, "syntax:")?;
writeln!(f, "{}", self.syntax)?;
writeln!(f, "ui:")?;
writeln!(f, "{}", self.ui)?;
Ok(())
}
}
impl<'de> Deserialize<'de> for Scheme {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let wrapper = YamlTinted8Scheme::deserialize(deserializer)?;
let (name, slug): (String, String) = match (
&wrapper.scheme.name,
&wrapper.scheme.slug,
&wrapper.scheme.family,
&wrapper.scheme.style,
) {
(Some(name), Some(slug), _, _) => (name.to_owned(), slug.to_owned()),
(Some(name), None, _, _) => (name.to_owned(), slugify(name)),
(None, Some(slug), _, _) => (titlecasify(slug), slug.to_owned()),
(None, None, Some(family), Some(style)) => {
let display_family = titlecasify(family);
let display_style = titlecasify(style);
let name = format!("{display_family} {display_style}");
(name.clone(), slugify(&name))
}
(None, None, Some(family), None) => {
let name = titlecasify(&family.clone());
(name, slugify(&family.clone()))
}
_ => {
return Err(serde::de::Error::custom(
"Either 'name', 'slug' or 'family' must exist in yaml scheme",
))
}
};
let palette =
Palette::try_from_basic(&wrapper.palette).map_err(serde::de::Error::custom)?;
let ui = Ui::try_from_basic(&wrapper.ui.unwrap_or_default(), &palette, &wrapper.variant)
.map_err(serde::de::Error::custom)?;
let syntax = Syntax::try_from_basic(
&wrapper.syntax.unwrap_or_default(),
&palette,
&wrapper.variant,
)
.map_err(serde::de::Error::custom)?;
let styling_spec = VersionReq::parse(&wrapper.scheme.supports.styling_spec)
.map_err(serde::de::Error::custom)?;
let styling_req =
Version::parse(SUPPORTED_STYLING_SPEC_VERSION).map_err(serde::de::Error::custom)?;
if !styling_spec.matches(&styling_req) {
return Err(serde::de::Error::custom(
format!("E002: Unsupported Tinted8 Styling Spec (requires {styling_req}, supported v{styling_spec})")
));
}
let styling_spec = styling_spec
.to_string()
.strip_prefix("^")
.unwrap_or(&styling_spec.to_string())
.to_string();
let scheme_meta = SchemeMeta {
name,
slug,
system: wrapper.scheme.system,
author: wrapper.scheme.author.clone(),
description: wrapper.scheme.description,
theme_author: wrapper.scheme.theme_author.unwrap_or(wrapper.scheme.author),
supports: SchemeSupports { styling_spec },
family: wrapper.scheme.family,
style: wrapper.scheme.style,
};
Ok(Self {
scheme: scheme_meta,
variant: wrapper.variant,
syntax,
ui,
palette,
})
}
}