1use crate::{
2 BANG_COMMENT, COMMENT, Error, TomlValue,
3 comment::{Comment, CommentType},
4 schema::{Meta, VariantSchema},
5 util,
6 value::BlockValue,
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 is_comented(&self) -> bool {
32 self.value.is_none() && self.meta.config.commented
33 }
34
35 pub fn is_none_skipped(&self) -> bool {
36 self.meta.is_option_type() && self.meta.config.is_none_skipped() && self.value.is_none()
37 }
38
39 pub fn enum_is_expand(&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_expand(self.variants.len())
45 }
46
47 pub fn enum_is_fold(&self) -> bool {
48 if !self.is_enum() {
49 return false;
50 }
51 let style = self.meta.config.enum_style.unwrap_or_default();
52 style.can_fold(self.variants.len())
53 }
54
55 pub fn render(&self) -> Result<String, Error> {
56 if self.is_none_skipped() {
57 return Ok(String::new());
58 }
59 let mut block_value = self.meta.inner_default.clone().flatten();
60 let mut commented = self.meta.config.commented;
61 if let Some(value) = self.value.clone() {
62 block_value = value;
63 commented = false;
64 }
65 let raw_value;
66 if let Some(raw) = block_value.value {
67 raw_value = raw;
68 } else {
69 return Ok(String::new());
70 }
71 let tag = block_value.tag;
72 let text;
73 if self.enum_is_expand() {
74 text = self.render_enum_expand(commented, tag, raw_value)?;
75 } else if self.enum_is_fold() {
76 text = self.render_enum_fold(commented, tag, raw_value)?;
77 } else if self.is_enum() {
78 text = self.render_enum_single(commented, tag, raw_value)?;
79 } else {
80 text = self.render_single(commented, raw_value)?;
81 }
82 Ok(text)
83 }
84
85 fn render_enum_single(
86 &self,
87 commented: bool,
88 tag: String,
89 raw_value: TomlValue,
90 ) -> Result<String, Error> {
91 let mut lines = Vec::new();
92 for variant in &self.variants {
93 if variant.value.tag != tag {
94 continue;
95 }
96 let comment = util::comment_lines(&variant.docs);
97 if !self.meta.config.is_comment_hidden() {
98 lines.push(comment);
99 }
100 let line = if commented {
101 format!("{}{} = {}", BANG_COMMENT, self.ident, raw_value)
102 } else {
103 format!("{} = {}", self.ident, raw_value)
104 };
105 lines.push(line);
106 break;
107 }
108 lines.retain(|line| !line.trim().is_empty());
109 Ok(lines.join("\n"))
110 }
111
112 fn render_enum_expand(
113 &self,
114 commented: bool,
115 tag: String,
116 raw_value: TomlValue,
117 ) -> Result<String, Error> {
118 if !self.enum_is_expand() {
119 return Err(Error::EnumStyleError("not enum_expand style".to_string()));
120 }
121 let mut lines = Vec::new();
122 for variant in &self.variants {
123 let comment = util::comment_lines(&variant.docs);
124 if !self.meta.config.is_comment_hidden() {
125 lines.push(comment);
126 }
127 if variant.value.tag == tag {
128 let line = if commented {
129 format!("{}{} = {}", BANG_COMMENT, self.ident, raw_value)
130 } else {
131 format!("{} = {}", self.ident, raw_value)
132 };
133 lines.push(line);
134 } else if let Some(value) = &variant.value.raw {
135 let line = format!("{}{} = {}", BANG_COMMENT, self.ident, value);
136 lines.push(line)
137 }
138 }
139 lines.retain(|line| !line.trim().is_empty());
140 Ok(lines.join("\n"))
141 }
142
143 fn render_enum_fold(
144 &self,
145 commented: bool,
146 tag: String,
147 raw_value: TomlValue,
148 ) -> Result<String, Error> {
149 if !self.enum_is_fold() {
150 return Err(Error::EnumStyleError("not enum_fold style".to_string()));
151 }
152 let mut lines = Vec::new();
153 let comment = self.comment();
154 let text = comment.render()?;
155 if !self.meta.config.is_comment_hidden() {
156 lines.push(text);
157 }
158 let mut values = Vec::new();
159 for variant in &self.variants {
160 if variant.value.tag == tag {
161 let line = if commented {
162 format!("{}{} = {}", BANG_COMMENT, self.ident, raw_value)
163 } else {
164 format!("{} = {}", self.ident, raw_value)
165 };
166 lines.push(line);
167 }
168 if let Some(value) = &variant.value.raw {
169 values.push(format!("{value}"))
170 }
171 }
172 if values.len() > 1 {
173 lines.insert(
174 1,
175 format!("{} {} = {}", COMMENT, self.ident, values.join(" | ")),
176 );
177 }
178 lines.retain(|line| !line.trim().is_empty());
179 Ok(lines.join("\n"))
180 }
181
182 fn render_single(&self, commented: bool, raw_value: TomlValue) -> Result<String, Error> {
183 if self.is_enum() {
184 panic!()
185 }
186 let mut lines = Vec::new();
187 let comment = self.comment();
188 let text = comment.render()?;
189 if !self.meta.config.is_comment_hidden() {
190 lines.push(text);
191 }
192 let line = if commented {
193 format!("{}{} = {}", BANG_COMMENT, self.ident, raw_value)
194 } else {
195 format!("{} = {}", self.ident, raw_value)
196 };
197 lines.push(line);
198 lines.retain(|line| !line.trim().is_empty());
199 Ok(lines.join("\n"))
200 }
201
202 pub fn comment(&self) -> Comment {
203 let mut comment = self.meta.comment();
204 if self.variants.is_empty() {
205 comment.comment_type = CommentType::BlockField;
206 } else {
207 comment.comment_type = CommentType::BlockVariant;
208 }
209 comment
210 }
211}