1use crate::{
2 comment::{Comment, CommentType},
3 schema::{Meta, VariantSchema},
4 util,
5 value::BlockValue,
6 Error, TomlValue, BANG_COMMENT, COMMENT,
7};
8
9#[derive(Debug, Clone, Default)]
10pub struct Block {
11 pub key: String,
12 pub ident: String,
13 pub meta: Meta,
14 pub value: Option<BlockValue>,
15 pub variants: Vec<VariantSchema>,
16}
17
18impl Block {
19 pub fn is_enum(&self) -> bool {
20 !self.variants.is_empty()
21 }
22
23 pub fn is_value(&self) -> bool {
24 self.ident.is_empty()
25 }
26
27 pub fn is_field(&self) -> bool {
28 !self.is_value()
29 }
30
31 pub fn enum_is_expand(&self) -> bool {
32 if !self.is_enum() {
33 return false;
34 }
35 let style = self.meta.config.enum_style.unwrap_or_default();
36 style.can_expand(self.variants.len())
37 }
38
39 pub fn enum_is_fold(&self) -> bool {
40 if !self.is_enum() {
41 return false;
42 }
43 let style = self.meta.config.enum_style.unwrap_or_default();
44 style.can_fold(self.variants.len())
45 }
46
47 pub fn render(&self) -> Result<String, Error> {
48 let mut block_value = self.meta.inner_default.clone().flatten();
49 let mut commented = self.meta.config.block_comment;
50 if let Some(value) = self.value.clone() {
51 block_value = value;
52 commented = false;
53 }
54 let raw_value;
55 if let Some(raw) = block_value.value {
56 raw_value = raw;
57 } else {
58 return Ok(String::new());
59 }
60 let tag = block_value.tag;
61 let text;
62 if self.enum_is_expand() {
63 text = self.render_enum_expand(commented, tag, raw_value)?;
64 } else if self.enum_is_fold() {
65 text = self.render_enum_fold(commented, tag, raw_value)?;
66 } else if self.is_enum() {
67 text = self.render_enum_single(commented, tag, raw_value)?;
68 } else {
69 text = self.render_single(commented, raw_value)?;
70 }
71 Ok(text)
72 }
73
74 fn render_enum_single(
75 &self,
76 commented: bool,
77 tag: String,
78 raw_value: TomlValue,
79 ) -> Result<String, Error> {
80 let mut lines = Vec::new();
81 for variant in &self.variants {
82 let comment = util::comment_lines(&variant.docs);
83 if variant.value.tag == tag {
84 let line = if commented {
85 format!("{}{} = {}", BANG_COMMENT, self.ident, raw_value)
86 } else {
87 format!("{} = {}", self.ident, raw_value)
88 };
89 lines.push(comment);
90 lines.push(line);
91 break;
92 }
93 }
94 Ok(lines.join("\n"))
95 }
96
97 fn render_enum_expand(
98 &self,
99 commented: bool,
100 tag: String,
101 raw_value: TomlValue,
102 ) -> Result<String, Error> {
103 if !self.enum_is_expand() {
104 panic!()
105 }
106 let mut lines = Vec::new();
107 for variant in &self.variants {
108 let comment = util::comment_lines(&variant.docs);
109 if variant.value.tag == tag {
110 let line = if commented {
111 format!("{}{} = {}", BANG_COMMENT, self.ident, raw_value)
112 } else {
113 format!("{} = {}", self.ident, raw_value)
114 };
115 if comment.len() > 0 {
116 lines.push(comment);
117 }
118 lines.push(line);
119 } else if let Some(value) = &variant.value.raw {
120 if comment.len() > 0 {
121 lines.push(comment);
122 }
123 let line = format!("{}{} = {}", BANG_COMMENT, self.ident, value);
124 lines.push(line)
125 }
126 }
127 Ok(lines.join("\n"))
128 }
129
130 fn render_enum_fold(
131 &self,
132 commented: bool,
133 tag: String,
134 raw_value: TomlValue,
135 ) -> Result<String, Error> {
136 if !self.enum_is_fold() {
137 panic!()
138 }
139 let mut lines = Vec::new();
140 let mut values = Vec::new();
141 for variant in &self.variants {
142 let comment = util::comment_lines(&variant.docs);
143 if variant.value.tag == tag {
144 let line = if commented {
145 format!("{}{} = {}", BANG_COMMENT, self.ident, raw_value)
146 } else {
147 format!("{} = {}", self.ident, raw_value)
148 };
149 lines.push(comment);
150 lines.push(line);
151 }
152 if let Some(value) = &variant.value.raw {
153 values.push(format!("{value}"))
154 }
155 }
156 if values.len() > 1 {
157 lines.insert(
158 0,
159 format!("{} {} = {}", COMMENT, self.ident, values.join(" | ")),
160 );
161 }
162 Ok(lines.join("\n"))
163 }
164
165 fn render_single(&self, commented: bool, raw_value: TomlValue) -> Result<String, Error> {
166 if self.is_enum() {
167 panic!()
168 }
169 let mut lines = Vec::new();
170 let comment = self.comment();
171 let text = comment.render()?;
172 if !text.is_empty() {
173 lines.push(text);
174 }
175 let line = if commented {
176 format!("{}{} = {}", BANG_COMMENT, self.ident, raw_value)
177 } else {
178 format!("{} = {}", self.ident, raw_value)
179 };
180 lines.push(line);
181 Ok(lines.join("\n"))
182 }
183
184 pub fn comment(&self) -> Comment {
185 let mut comment = self.meta.comment();
186 if self.variants.is_empty() {
187 comment.comment_type = CommentType::BlockField;
188 } else {
189 comment.comment_type = CommentType::BlockVariant;
190 }
191 comment
192 }
193}