toml_input/
block.rs

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}