1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
//! `collage` is a template engine for Rust, designed for writing HTML and similar markup languages.
//!
//! Rendering is performed by the [`markup!`] macro and custom structs and enums can be rendered by implementing the
//! [`Render`] trait.
extern crate alloc;
use String;
pub use html_escape;
/// Parses an alternative markup syntax into a [`FnOnce`](`&mut` [`String`]) function.
///
/// # Syntax
///
/// Instead of writing elements with angle brackets, they are written with curly braces.
///
/// ```
/// use collage::Render;
/// let markup = collage::markup! {
/// h1 { "Lorem ipsum" }
/// p { "Quae occaecati corrupti perferendis officia eos quidem" }
/// };
/// assert_eq!(
/// "<h1>Lorem ipsum</h1><p>Quae occaecati corrupti perferendis officia eos quidem</p>",
/// markup.render()
/// );
/// ```
///
/// [Void elements](https://developer.mozilla.org/en-US/docs/Glossary/Void_element) are closed using a semicolon.
///
/// ```
/// use collage::Render;
/// let markup = collage::markup! {
/// meta charset="utf-8";
/// link rel="stylesheet" href="/style.css";
/// };
/// assert_eq!(
/// r#"<meta charset="utf-8"><link rel="stylesheet" href="/style.css">"#,
/// markup.render()
/// );
/// ```
///
/// # Interpolation
///
/// Many Rust literals can be used plainly.
///
/// ```
/// use collage::Render;
/// let markup = collage::markup! {
/// "text" ' ' b"bytes" ' ' 'c' ' ' 42 ' ' 3.14 ' ' true
/// };
/// assert_eq!("text bytes c 42 3.14 true", markup.render());
/// ```
///
/// Rust code can be inserted by surrounding it with parenthesis.
///
/// ```
/// use collage::Render;
/// let (x, y) = (10, 30);
/// let markup = collage::markup! { p { "x: " (x) ", y: " (y) } };
/// assert_eq!("<p>x: 10, y: 30</p>", markup.render());
/// ```
///
/// It works the same for attribute values.
///
/// ```
/// use collage::Render;
/// let val = "my_div";
/// let markup = collage::markup! { div "id"=(val) {} };
/// assert_eq!(r#"<div id="my_div"></div>"#, markup.render());
/// ```
///
/// # Control flow
///
/// `if` statements can be used to conditionally render content.
///
/// ```
/// use collage::Render;
/// let markup = collage::markup! { div { (if true { "shown" } else { "hidden" }) } };
/// assert_eq!("<div>shown</div>", markup.render());
/// ```
///
/// This is especially useful for conditionally rendering attributes.
///
/// ```
/// use collage::Render;
/// let markup = collage::markup! {
/// div (if true { "hidden" }) (if false { "autofocus" }) {}
/// };
/// assert_eq!("<div hidden></div>", markup.render());
/// ```
///
/// `match` can be used as expected. If this macro is used again in the match arm bodies, not all cases have to be covered. Instead nothing will be rendered if there is no match.
///
/// ```
/// use collage::Render;
/// let role = "user";
/// let markup = collage::markup! {
/// (match role {
/// "admin" => collage::markup! { p { "foo" } },
/// "user" => collage::markup! { p { "bar" } },
/// })
/// };
/// assert_eq!("<p>bar</p>", markup.render());
/// ```
///
/// `for` combined with additional macro use can be used to rendering content in a loop.
///
/// ```
/// use collage::Render;
/// let markup = collage::markup! {
/// ul { (for item in ["one", "two", "three"] { markup! { li { (item) } } }) }
/// };
/// assert_eq!("<ul><li>one</li><li>two</li><li>three</li></ul>", markup.render());
/// ```
pub use markup;
/// This is mostly used automatically by the [`markup!`] macro to render partial content. It can be used when manual
/// control is required.
///
/// The [`markup!`] macro wraps the resulting Rust tokens in the following code, while this macro parses the tokens
/// verbatim.
///
/// ```ignore
/// quote::quote! {{
/// extern crate alloc;
/// extern crate collage;
/// &|__collage_buffer: &mut alloc::string::String| {
/// __collage_buffer.reserve(...);
/// // Macro content is inserted here
/// }
/// }}
/// ```
///
/// # Example
///
/// ```
/// use collage::Render;
/// let markup = collage::markup! { form { (collage::markup_part! { input; }) } };
/// assert_eq!("<form><input></form>", markup.render());
/// ```
pub use markup_part;
/// The [`markup!`] macro will render interpolated content by wrapping it in this trait's [`Render::render_to`]
/// function.
///
/// Implementing this trait for types will allow them them to be used directly in the [`markup!`] macro.
///
/// # Example
///
/// ```
/// let markup = collage::markup! { (42) };
/// // Is equivalent to
/// let markup = {
/// extern crate alloc;
/// extern crate collage;
/// &|__collage_buffer: &mut alloc::string::String| {
/// __collage_buffer.reserve(4usize);
/// collage::Render::render_to(&42, __collage_buffer);
/// }
/// };
/// ```
impl_render_itoa!
impl_render_ryu!
/// The literal `<!DOCTYPE html>` element.
///
/// # Examples
///
/// ```
/// use collage::Render;
/// let markup = collage::markup! { (collage::doctype) };
/// assert_eq!("<!DOCTYPE html>", markup.render());
/// ```