1use ecow::EcoString;
4use tinymist_derive::TypliteAttr;
5use typst_html::HtmlAttrs;
6
7use crate::Result;
8
9pub 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
87#[derive(TypliteAttr, Default)]
88pub struct VerbatimAttr {
89 pub block: bool,
90 pub src: EcoString,
91}
92
93pub trait TypliteAttrsParser {
94 fn parse(attrs: &HtmlAttrs) -> Result<Self>
95 where
96 Self: Sized;
97}
98
99pub trait TypliteAttrParser {
100 fn parse_attr(content: &EcoString) -> Result<Self>
101 where
102 Self: Sized;
103}
104
105impl TypliteAttrParser for usize {
106 fn parse_attr(content: &EcoString) -> Result<Self> {
107 Ok(content
108 .parse::<usize>()
109 .map_err(|_| format!("cannot parse {content} as usize"))?)
110 }
111}
112
113impl TypliteAttrParser for u32 {
114 fn parse_attr(content: &EcoString) -> Result<Self> {
115 Ok(content
116 .parse::<u32>()
117 .map_err(|_| format!("cannot parse {content} as u32"))?)
118 }
119}
120
121impl TypliteAttrParser for bool {
122 fn parse_attr(content: &EcoString) -> Result<Self> {
123 Ok(content
124 .parse::<bool>()
125 .map_err(|_| format!("cannot parse {content} as bool"))?)
126 }
127}
128
129impl TypliteAttrParser for EcoString {
130 fn parse_attr(content: &EcoString) -> Result<Self> {
131 Ok(content.clone())
132 }
133}
134
135impl<T> TypliteAttrParser for Option<T>
136where
137 T: TypliteAttrParser,
138{
139 fn parse_attr(content: &EcoString) -> Result<Self> {
140 if content.is_empty() {
141 Ok(None)
142 } else {
143 T::parse_attr(content).map(Some)
144 }
145 }
146}