use ecow::EcoString;
use crate::diag::{HintedStrResult, SourceResult, bail};
use crate::engine::Engine;
use crate::foundations::{
Args, Array, Construct, Content, Datetime, OneOrMultiple, Smart, StyleChain, Styles,
Value, cast, elem,
};
use crate::text::{Locale, TextElem};
#[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>>,
pub locale: Smart<Locale>,
}
impl DocumentInfo {
pub fn populate(&mut self, styles: &Styles) {
let chain = StyleChain::new(styles);
if styles.has(DocumentElem::title) {
self.title = chain
.get_ref(DocumentElem::title)
.as_ref()
.map(|content| content.plain_text());
}
if styles.has(DocumentElem::author) {
self.author = chain.get_cloned(DocumentElem::author).0;
}
if styles.has(DocumentElem::description) {
self.description = chain
.get_ref(DocumentElem::description)
.as_ref()
.map(|content| content.plain_text());
}
if styles.has(DocumentElem::keywords) {
self.keywords = chain.get_cloned(DocumentElem::keywords).0;
}
if styles.has(DocumentElem::date) {
self.date = chain.get(DocumentElem::date);
}
}
pub fn populate_locale(&mut self, styles: &Styles) {
if self.locale.is_custom() {
return;
}
let chain = StyleChain::new(styles);
let mut locale: Option<Locale> = None;
if styles.has(TextElem::lang) {
locale.get_or_insert_default().lang = chain.get(TextElem::lang);
}
if styles.has(TextElem::region) {
locale.get_or_insert_default().region = chain.get(TextElem::region);
}
self.locale = Smart::from(locale);
}
}