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
use crate::{
html::attributes::AttributeValue, mt_dom::AttValue, Attribute, Element,
Node,
};
use std::fmt;
pub trait Render {
fn render(&self, buffer: &mut dyn fmt::Write) -> fmt::Result {
self.render_with_indent(buffer, 0)
}
fn render_with_indent(
&self,
buffer: &mut dyn fmt::Write,
indent: usize,
) -> fmt::Result;
}
impl<MSG> Render for Node<MSG> {
fn render_with_indent(
&self,
buffer: &mut dyn fmt::Write,
indent: usize,
) -> fmt::Result {
match self {
Node::Element(element) => {
element.render_with_indent(buffer, indent)
}
Node::Text(text) => write!(buffer, "{}", text),
}
}
}
impl<MSG> Render for Element<MSG> {
fn render_with_indent(
&self,
buffer: &mut dyn fmt::Write,
indent: usize,
) -> fmt::Result {
write!(buffer, "<{}", self.tag())?;
for attr in self.get_attributes() {
write!(buffer, " ")?;
attr.render_with_indent(buffer, indent)?;
}
write!(buffer, ">")?;
let children = self.get_children();
let first_child = children.get(0);
let is_first_child_text_node =
first_child.map(|node| node.is_text()).unwrap_or(false);
let is_lone_child_text_node =
children.len() == 1 && is_first_child_text_node;
if is_lone_child_text_node {
first_child.unwrap().render_with_indent(buffer, indent)?;
} else {
for child in self.get_children() {
write!(buffer, "\n{}", " ".repeat(indent + 1))?;
child.render_with_indent(buffer, indent + 1)?;
}
}
if !is_lone_child_text_node && !children.is_empty() {
write!(buffer, "\n{}", " ".repeat(indent))?;
}
write!(buffer, "</{}>", self.tag())?;
Ok(())
}
}
impl<MSG> Render for Attribute<MSG> {
fn render_with_indent(
&self,
buffer: &mut dyn fmt::Write,
indent: usize,
) -> fmt::Result {
write!(buffer, "{}=\"", self.name())?;
for (i, att_value) in self.value().iter().enumerate() {
match att_value {
AttValue::Plain(plain) => {
if i > 0 && !plain.is_style() {
write!(buffer, " ")?;
}
plain.render_with_indent(buffer, indent)?;
}
_ => (),
}
}
write!(buffer, "\"")?;
Ok(())
}
}
impl Render for AttributeValue {
fn render_with_indent(
&self,
buffer: &mut dyn fmt::Write,
_index: usize,
) -> fmt::Result {
match self {
AttributeValue::Simple(simple) => {
write!(buffer, "{}", simple.to_string())?;
}
AttributeValue::Style(styles_att) => {
for s_att in styles_att {
write!(buffer, "{};", s_att)?;
}
}
_ => (),
}
Ok(())
}
}