1use std::collections::HashMap;
2
3use crate::{
4 BANG_COMMENT, ROOT_KEY,
5 block::Block,
6 comment::{Comment, CommentType},
7 error::Error,
8 schema::Meta,
9 util,
10};
11
12#[derive(Debug, Clone)]
13pub struct Section {
14 pub key: String,
15 pub meta: Meta,
16 pub array_index: Option<usize>,
17 pub blocks: Vec<Block>,
18}
19
20impl Default for Section {
21 fn default() -> Self {
22 Section {
23 key: ROOT_KEY.to_string(),
24 meta: Meta::default(),
25 array_index: None,
26 blocks: Vec::new(),
27 }
28 }
29}
30
31impl Section {
32 pub fn is_root(&self) -> bool {
33 self.key == ROOT_KEY && !self.blocks.is_empty()
34 }
35 pub fn is_value(&self) -> bool {
36 self.key == ROOT_KEY && self.blocks.len() == 1 && self.blocks[0].is_value()
37 }
38
39 pub fn is_commented(&self) -> bool {
40 let mut commented = self.meta.config.commented;
41 for block in &self.blocks {
42 commented = commented && block.is_comented();
43 }
44 commented
45 }
46
47 pub fn is_none_skipped(&self) -> bool {
48 let mut skipped = self.meta.is_option_type() && self.meta.config.is_none_skipped();
49 for block in &self.blocks {
50 skipped = skipped && block.is_none_skipped();
51 }
52 skipped
53 }
54
55 pub fn assigned_to(&mut self, ident: impl AsRef<str>) {
56 if self.is_value() {
57 for block in &mut self.blocks {
58 block.key = ident.as_ref().to_string();
59 block.ident = ident.as_ref().to_string();
60 }
61 } else {
62 util::increase_key(&mut self.key, &ident);
63 for block in &mut self.blocks {
64 util::increase_key(&mut block.key, &ident);
65 }
66 }
67 }
68
69 pub fn reduce(sections: &mut Vec<Section>) {
70 let mut map: HashMap<String, &mut Section> = HashMap::new();
71 let mut dup = Vec::new();
72 for (i, section) in sections.iter_mut().enumerate() {
73 if let Some(s) = map.get_mut(§ion.key) {
74 s.blocks.append(&mut section.blocks);
75 dup.push(i);
76 } else {
77 map.insert(section.key.clone(), section);
78 }
79 }
80 for (i, index) in dup.iter().enumerate() {
81 sections.remove(index - i);
82 }
83 }
84
85 pub fn render(&self) -> Result<String, Error> {
86 if self.is_none_skipped() {
87 return Ok(String::new());
88 }
89 let comment = self.comment();
90 let text = comment.render()?;
91 let mut lines = Vec::new();
92 if !self.meta.config.is_comment_hidden() {
93 lines.push(text);
94 }
95 let (left, right) = if self.is_root() {
96 ("".to_string(), "".to_string())
97 } else if self.meta.is_array {
98 ("[[".to_string(), "]]".to_string())
99 } else {
100 ("[".to_string(), "]".to_string())
101 };
102 let bang = if self.is_commented() && (self.key != ROOT_KEY) {
103 BANG_COMMENT
104 } else {
105 ""
106 };
107 lines.push(format!("{bang}{}{}{}", left, self.key, right));
108 for block in &self.blocks {
109 let line = block.render()?;
110 if !line.is_empty() {
111 lines.push(line);
112 }
113 }
114 Ok(lines.join("\n"))
115 }
116
117 pub fn comment(&self) -> Comment {
118 let mut comment = self.meta.comment();
119 comment.comment_type = if self.is_root() {
120 CommentType::Root
121 } else {
122 CommentType::Section
123 };
124 comment
125 }
126}