use ecow::EcoString;
use crate::diag::{bail, HintedStrResult, SourceResult};
use crate::engine::Engine;
use crate::foundations::{
cast, elem, Args, Array, Construct, Content, Datetime, Fields, OneOrMultiple, Smart,
StyleChain, Styles, Value,
};
#[elem(Construct)]
pub struct DocumentElem {
#[ghost]
pub title: Option<Content>,
#[ghost]
pub author: OneOrMultiple<EcoString>,
#[ghost]
pub description: Option<Content>,
#[ghost]
pub keywords: OneOrMultiple<EcoString>,
#[ghost]
pub date: Smart<Option<Datetime>>,
}
impl Construct for DocumentElem {
fn construct(_: &mut Engine, args: &mut Args) -> SourceResult<Content> {
bail!(args.span, "can only be used in set rules")
}
}
#[derive(Debug, Default, Clone, PartialEq, Hash)]
pub struct Author(Vec<EcoString>);
cast! {
Author,
self => self.0.into_value(),
v: EcoString => Self(vec![v]),
v: Array => Self(v.into_iter().map(Value::cast).collect::<HintedStrResult<_>>()?),
}
#[derive(Debug, Default, Clone, PartialEq, Hash)]
pub struct Keywords(Vec<EcoString>);
cast! {
Keywords,
self => self.0.into_value(),
v: EcoString => Self(vec![v]),
v: Array => Self(v.into_iter().map(Value::cast).collect::<HintedStrResult<_>>()?),
}
#[derive(Debug, Default, Clone, PartialEq, Hash)]
pub struct DocumentInfo {
pub title: Option<EcoString>,
pub author: Vec<EcoString>,
pub description: Option<EcoString>,
pub keywords: Vec<EcoString>,
pub date: Smart<Option<Datetime>>,
}
impl DocumentInfo {
pub fn populate(&mut self, styles: &Styles) {
let chain = StyleChain::new(styles);
let has = |field| styles.has::<DocumentElem>(field as _);
if has(<DocumentElem as Fields>::Enum::Title) {
self.title =
DocumentElem::title_in(chain).map(|content| content.plain_text());
}
if has(<DocumentElem as Fields>::Enum::Author) {
self.author = DocumentElem::author_in(chain).0;
}
if has(<DocumentElem as Fields>::Enum::Description) {
self.description =
DocumentElem::description_in(chain).map(|content| content.plain_text());
}
if has(<DocumentElem as Fields>::Enum::Keywords) {
self.keywords = DocumentElem::keywords_in(chain).0;
}
if has(<DocumentElem as Fields>::Enum::Date) {
self.date = DocumentElem::date_in(chain);
}
}
}