1use crate::parser::{Child, Element};
2use std::borrow::Cow;
3
4fn serialise_term(text: &str) -> Cow<str> {
5 if text.is_empty() {
6 return "\"\"".into();
7 }
8
9 let mut text: Cow<str> = text.into();
10
11 if text.contains('`') {
13 text = text.replace('`', "'").into();
14 }
15
16 let first_char = text.chars().next().unwrap();
17 let mut needs_to_be_quoted = first_char == '\'' || first_char == '"';
18
19 let mut has_dbl_quote = false;
20 let mut has_sgl_quote = false;
21 for x in text.chars() {
22 if x == ' ' {
23 needs_to_be_quoted = true;
24 } else if x == '\'' {
25 has_sgl_quote = true;
26 } else if x == '"' {
27 has_dbl_quote = true;
28 }
29 }
30
31 if !needs_to_be_quoted {
32 return text;
33 }
34
35 let quote_char = {
36 if has_dbl_quote && has_sgl_quote {
37 '`'
38 } else if has_dbl_quote {
39 '\''
40 } else {
41 '"'
42 }
43 };
44
45 format!("{}{}{}", quote_char, text, quote_char).into()
46}
47
48pub fn serialize_to_string(element: &Element) -> String {
50 let mut buf = String::new();
51 process(&mut buf, element, 0);
52 buf
53}
54
55fn process(buf: &mut String, element: &Element, indent_level: usize) {
56 for _ in 0..indent_level {
58 buf.push_str(" ")
59 }
60 buf.push('<');
61 buf.push_str(element.tag);
62
63 for x in &element.attr {
64 let x = serialise_term(x);
65 buf.push(' ');
66 buf.push_str(&x);
67 }
68
69 buf.push('\n');
70
71 for child in element.children.iter() {
72 match child {
73 Child::Line(child) => {
74 for _ in 0..(indent_level + 1) {
75 buf.push_str(" ")
76 }
77
78 let mut is_first = true;
79 for x in child {
80 let x = serialise_term(x);
81 if is_first {
82 is_first = false;
83 } else {
84 buf.push(' ')
85 }
86 buf.push_str(&x);
87 }
88
89 buf.push('\n');
90 }
91 Child::Element(child) => {
92 process(buf, child, indent_level + 1);
93 buf.push('\n');
94 }
95 }
96 }
97
98 for _ in 0..indent_level {
100 buf.push_str(" ")
101 }
102 buf.push('>');
103}