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 }
36}
37
38#[derive(TypliteAttr, Default)]
39pub struct IdocAttr {
40 pub src: EcoString,
41 pub mode: EcoString,
42}
43
44#[derive(TypliteAttr, Default)]
45pub struct HeadingAttr {
46 pub level: usize,
47}
48
49#[derive(TypliteAttr, Default)]
50pub struct ImageAttr {
51 pub src: EcoString,
52 pub alt: EcoString,
53}
54
55#[derive(TypliteAttr, Default)]
56pub struct FigureAttr {
57 pub caption: EcoString,
58}
59
60#[derive(TypliteAttr, Default)]
61pub struct LinkAttr {
62 pub dest: EcoString,
63}
64
65#[derive(TypliteAttr, Default)]
66pub struct RawAttr {
67 pub lang: EcoString,
68 pub block: bool,
69 pub text: EcoString,
70}
71
72#[derive(TypliteAttr, Default)]
73pub struct ListItemAttr {
74 pub value: Option<u32>,
75}
76
77#[derive(TypliteAttr, Default)]
78pub struct AlertsAttr {
79 pub class: EcoString,
80}
81
82pub trait TypliteAttrsParser {
83 fn parse(attrs: &HtmlAttrs) -> Result<Self>
84 where
85 Self: Sized;
86}
87
88pub trait TypliteAttrParser {
89 fn parse_attr(content: &EcoString) -> Result<Self>
90 where
91 Self: Sized;
92}
93
94impl TypliteAttrParser for usize {
95 fn parse_attr(content: &EcoString) -> Result<Self> {
96 Ok(content
97 .parse::<usize>()
98 .map_err(|_| format!("cannot parse {content} as usize"))?)
99 }
100}
101
102impl TypliteAttrParser for u32 {
103 fn parse_attr(content: &EcoString) -> Result<Self> {
104 Ok(content
105 .parse::<u32>()
106 .map_err(|_| format!("cannot parse {content} as u32"))?)
107 }
108}
109
110impl TypliteAttrParser for bool {
111 fn parse_attr(content: &EcoString) -> Result<Self> {
112 Ok(content
113 .parse::<bool>()
114 .map_err(|_| format!("cannot parse {content} as bool"))?)
115 }
116}
117
118impl TypliteAttrParser for EcoString {
119 fn parse_attr(content: &EcoString) -> Result<Self> {
120 Ok(content.clone())
121 }
122}
123
124impl<T> TypliteAttrParser for Option<T>
125where
126 T: TypliteAttrParser,
127{
128 fn parse_attr(content: &EcoString) -> Result<Self> {
129 if content.is_empty() {
130 Ok(None)
131 } else {
132 T::parse_attr(content).map(Some)
133 }
134 }
135}