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
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}