use std::str::FromStr;
use smallvec::SmallVec;
use crate::diag::bail;
use crate::foundations::{Array, Content, Packed, Smart, Styles, cast, elem, scope};
use crate::introspection::{Locatable, Tagged};
use crate::layout::{Alignment, Em, HAlignment, Length, VAlignment};
use crate::model::{ListItemLike, ListLike, Numbering, NumberingPattern};
#[elem(scope, title = "Numbered List", Locatable, Tagged)]
pub struct EnumElem {
#[default(true)]
pub tight: bool,
#[default(Numbering::Pattern(NumberingPattern::from_str("1.").unwrap()))]
pub numbering: Numbering,
pub start: Smart<u64>,
#[default(false)]
pub full: bool,
#[default(false)]
pub reversed: bool,
pub indent: Length,
#[default(Em::new(0.5).into())]
pub body_indent: Length,
pub spacing: Smart<Length>,
#[default(HAlignment::End + VAlignment::Top)]
pub number_align: Alignment,
#[variadic]
pub children: Vec<Packed<EnumItem>>,
#[internal]
#[fold]
#[ghost]
pub parents: SmallVec<[u64; 4]>,
}
#[scope]
impl EnumElem {
#[elem]
type EnumItem;
}
#[elem(name = "item", title = "Numbered List Item", Tagged)]
pub struct EnumItem {
#[positional]
pub number: Smart<u64>,
#[required]
pub body: Content,
}
cast! {
EnumItem,
array: Array => {
let mut iter = array.into_iter();
let (number, body) = match (iter.next(), iter.next(), iter.next()) {
(Some(a), Some(b), None) => (a.cast()?, b.cast()?),
_ => bail!("array must contain exactly two entries"),
};
Self::new(body).with_number(number)
},
v: Content => v.unpack::<Self>().unwrap_or_else(Self::new),
}
impl ListLike for EnumElem {
type Item = EnumItem;
fn create(children: Vec<Packed<Self::Item>>, tight: bool) -> Self {
Self::new(children).with_tight(tight)
}
}
impl ListItemLike for EnumItem {
fn styled(mut item: Packed<Self>, styles: Styles) -> Packed<Self> {
item.body.style_in_place(styles);
item
}
}