typlite/
attributes.rs

1//! Attributes for HTML elements and parsing
2
3use ecow::EcoString;
4use tinymist_derive::TypliteAttr;
5use typst_html::HtmlAttrs;
6
7use crate::Result;
8
9/// Tag attributes defined for HTML elements.
10pub mod md_attr {
11    use typst_html::HtmlAttr;
12
13    macro_rules! attrs {
14        ($($attr:ident -> $name:ident)*) => {
15            $(#[allow(non_upper_case_globals)]
16            pub const $attr: HtmlAttr = HtmlAttr::constant(
17                stringify!($name)
18            );)*
19        }
20    }
21
22    attrs! {
23        media -> media
24        src -> src
25        alt -> alt
26        level -> level
27        dest -> dest
28        lang -> lang
29        block -> block
30        text -> text
31        mode -> mode
32        value -> value
33        caption -> caption
34        class -> class
35        id -> id
36    }
37}
38
39#[derive(TypliteAttr, Default)]
40pub struct IdocAttr {
41    pub src: EcoString,
42    pub mode: EcoString,
43}
44
45#[derive(TypliteAttr, Default)]
46pub struct HeadingAttr {
47    pub id: EcoString,
48    pub level: usize,
49}
50
51#[derive(TypliteAttr, Default)]
52pub struct ImageAttr {
53    pub id: EcoString,
54    pub src: EcoString,
55    pub alt: EcoString,
56}
57
58#[derive(TypliteAttr, Default)]
59pub struct FigureAttr {
60    pub id: EcoString,
61    pub caption: EcoString,
62}
63
64#[derive(TypliteAttr, Default)]
65pub struct LinkAttr {
66    pub dest: EcoString,
67}
68
69#[derive(TypliteAttr, Default)]
70pub struct RawAttr {
71    pub id: EcoString,
72    pub lang: EcoString,
73    pub block: bool,
74    pub text: EcoString,
75}
76
77#[derive(TypliteAttr, Default)]
78pub struct ListItemAttr {
79    pub value: Option<u32>,
80}
81
82#[derive(TypliteAttr, Default)]
83pub struct AlertsAttr {
84    pub class: EcoString,
85}
86
87pub trait TypliteAttrsParser {
88    fn parse(attrs: &HtmlAttrs) -> Result<Self>
89    where
90        Self: Sized;
91}
92
93pub trait TypliteAttrParser {
94    fn parse_attr(content: &EcoString) -> Result<Self>
95    where
96        Self: Sized;
97}
98
99impl TypliteAttrParser for usize {
100    fn parse_attr(content: &EcoString) -> Result<Self> {
101        Ok(content
102            .parse::<usize>()
103            .map_err(|_| format!("cannot parse {content} as usize"))?)
104    }
105}
106
107impl TypliteAttrParser for u32 {
108    fn parse_attr(content: &EcoString) -> Result<Self> {
109        Ok(content
110            .parse::<u32>()
111            .map_err(|_| format!("cannot parse {content} as u32"))?)
112    }
113}
114
115impl TypliteAttrParser for bool {
116    fn parse_attr(content: &EcoString) -> Result<Self> {
117        Ok(content
118            .parse::<bool>()
119            .map_err(|_| format!("cannot parse {content} as bool"))?)
120    }
121}
122
123impl TypliteAttrParser for EcoString {
124    fn parse_attr(content: &EcoString) -> Result<Self> {
125        Ok(content.clone())
126    }
127}
128
129impl<T> TypliteAttrParser for Option<T>
130where
131    T: TypliteAttrParser,
132{
133    fn parse_attr(content: &EcoString) -> Result<Self> {
134        if content.is_empty() {
135            Ok(None)
136        } else {
137            T::parse_attr(content).map(Some)
138        }
139    }
140}