mabel_eno/elements/
section.rs

1use std::cell::Cell;
2use std::ops::{Range, RangeInclusive};
3use std::rc::Rc;
4
5use crate::elements::{CommentImpl, DocumentInternals, ElementImpl};
6use crate::queries::{
7    EmbedQuery, EmbedQueryImpl, EmbedQueryParent, FieldQuery, FieldQueryImpl, FieldQueryParent,
8    FlagQuery, FlagQueryImpl, FlagQueryParent, Matches, SectionElements, SectionQuery,
9    SectionQueryImpl, SectionQueryParent,
10};
11use crate::{Element, Embed, Error, Field, Flag, Printer};
12
13#[derive(Debug)]
14pub struct Section {
15    document_internals: Rc<DocumentInternals>,
16    elements: Vec<Box<dyn SectionElement>>,
17    key_range: Range<usize>,
18    line_begin_index: usize,
19    pub line_number: u32,
20    operator_range: Range<usize>,
21    touched: Cell<bool>,
22}
23
24pub trait SectionElement: std::fmt::Debug + Element + ElementImpl {
25    fn as_element(&self) -> &dyn Element;
26
27    // TODO: Expose through an additional private trait
28    fn as_mut_embed(&mut self) -> Option<&mut Embed> {
29        None
30    }
31    fn as_mut_field(&mut self) -> Option<&mut Field> {
32        None
33    }
34    fn as_mut_flag(&mut self) -> Option<&mut Flag> {
35        None
36    }
37    fn as_mut_section(&mut self) -> Option<&mut Section> {
38        None
39    }
40
41    fn key(&self) -> &str;
42}
43
44pub trait SectionImpl {
45    fn get_elements(&self) -> &[Box<dyn SectionElement>];
46    fn get_elements_mut(&mut self) -> &mut Vec<Box<dyn SectionElement>>;
47    fn get_elements_ref(&self) -> &Vec<Box<dyn SectionElement>>;
48    #[allow(clippy::new_ret_no_self)]
49    fn new(
50        document_internals: Rc<DocumentInternals>,
51        elements: Vec<Box<dyn SectionElement>>,
52        key_range: Range<usize>,
53        line_begin_index: usize,
54        line_number: u32,
55        operator_range: Range<usize>,
56    ) -> Section;
57}
58
59impl Section {
60    pub fn elements(&self) -> &[Box<dyn SectionElement>] {
61        for element in &self.elements {
62            element.touch();
63        }
64        self.elements.as_slice()
65    }
66
67    pub fn embed(&self, key: &str) -> Result<EmbedQuery, Error> {
68        let element_option = match self.elements.single_embed_with_key(key) {
69            Matches::None => None,
70            Matches::One(embed) => Some(embed),
71            Matches::Multiple(_first, second) => {
72                return Err(Error::new(
73                    "Only a single embed was expected".to_string(),
74                    second.line_number,
75                ))
76            }
77            Matches::WrongType(element) => {
78                return Err(Error::new(
79                    "An embed was expected".to_string(),
80                    element.line_number(),
81                ))
82            }
83        };
84
85        // TODO: Revisit whether Some(key.to_string()) ever makes sense (as in: does the key need to be an option? Isn't it always present maybe?)
86        Ok(EmbedQuery::new(
87            element_option,
88            Some(key.to_string()),
89            EmbedQueryParent::Section(self),
90        ))
91    }
92
93    pub fn field(&self, key: &str) -> Result<FieldQuery, Error> {
94        let element_option = match self.elements.single_field_with_key(key) {
95            Matches::None => None,
96            Matches::One(field) => Some(field),
97            Matches::Multiple(_first, second) => {
98                return Err(Error::new(
99                    "Only a single field was expected".to_string(),
100                    second.line_number,
101                ))
102            }
103            Matches::WrongType(element) => {
104                return Err(Error::new(
105                    "A field was expected".to_string(),
106                    element.line_number(),
107                ))
108            }
109        };
110
111        Ok(FieldQuery::new(
112            element_option,
113            Some(key.to_string()),
114            FieldQueryParent::Section(self),
115        ))
116    }
117
118    pub fn flag(&self, key: &str) -> Result<FlagQuery, Error> {
119        let element_option = match self.elements.single_flag_with_key(key) {
120            Matches::None => None,
121            Matches::One(flag) => Some(flag),
122            Matches::Multiple(_first, second) => {
123                return Err(Error::new(
124                    "Only a single flag was expected".to_string(),
125                    second.line_number,
126                ))
127            }
128            Matches::WrongType(element) => {
129                return Err(Error::new(
130                    "A flag was expected".to_string(),
131                    element.line_number(),
132                ))
133            }
134        };
135
136        Ok(FlagQuery::new(
137            element_option,
138            Some(key.to_string()),
139            FlagQueryParent::Section(self),
140        ))
141    }
142
143    pub fn len(&self) -> usize {
144        self.elements.len()
145    }
146
147    pub fn is_empty(&self) -> bool {
148        self.elements.is_empty()
149    }
150
151    pub fn optional_embed(&self, key: &str) -> Result<Option<&Embed>, Error> {
152        match self.elements.single_embed_with_key(key) {
153            Matches::None => Ok(None),
154            Matches::One(embed) => {
155                embed.touch();
156                Ok(Some(embed))
157            }
158            Matches::Multiple(_first, second) => Err(Error::new(
159                "Only a single embed was expected".to_string(),
160                second.line_number,
161            )),
162            Matches::WrongType(element) => Err(Error::new(
163                "A embed was expected".to_string(),
164                element.line_number(),
165            )),
166        }
167    }
168
169    pub fn optional_field(&self, key: &str) -> Result<Option<&Field>, Error> {
170        match self.elements.single_field_with_key(key) {
171            Matches::None => Ok(None),
172            Matches::One(field) => {
173                field.touch();
174                Ok(Some(field))
175            }
176            Matches::Multiple(_first, second) => Err(Error::new(
177                "Only a single field was expected".to_string(),
178                second.line_number,
179            )),
180            Matches::WrongType(element) => Err(Error::new(
181                "A field was expected".to_string(),
182                element.line_number(),
183            )),
184        }
185    }
186
187    pub fn optional_flag(&self, key: &str) -> Result<Option<&Flag>, Error> {
188        match self.elements.single_flag_with_key(key) {
189            Matches::None => Ok(None),
190            Matches::One(flag) => {
191                flag.touch();
192                Ok(Some(flag))
193            }
194            Matches::Multiple(_first, second) => Err(Error::new(
195                "Only a single flag was expected".to_string(),
196                second.line_number,
197            )),
198            Matches::WrongType(element) => Err(Error::new(
199                "A flag was expected".to_string(),
200                element.line_number(),
201            )),
202        }
203    }
204
205    pub fn optional_section(&self, key: &str) -> Result<Option<&Section>, Error> {
206        match self.elements.single_section_with_key(key) {
207            Matches::None => Ok(None),
208            Matches::One(section) => {
209                section.touch();
210                Ok(Some(section))
211            }
212            Matches::Multiple(_first, second) => Err(Error::new(
213                "Only a single section was expected".to_string(),
214                second.line_number,
215            )),
216            Matches::WrongType(element) => Err(Error::new(
217                "A section was expected".to_string(),
218                element.line_number(),
219            )),
220        }
221    }
222
223    pub fn required_embed(&self, key: &str) -> Result<&Embed, Error> {
224        match self.elements.single_embed_with_key(key) {
225            Matches::None => Err(Error::new("Not found".to_string(), self.line_number)),
226            Matches::One(embed) => {
227                embed.touch();
228                Ok(embed)
229            }
230            Matches::Multiple(_first, second) => Err(Error::new(
231                format!("Only a single embed with key {} was expected", key),
232                second.line_number,
233            )),
234            Matches::WrongType(element) => Err(Error::new(
235                "A embed was expected".to_string(),
236                element.line_number(),
237            )),
238        }
239    }
240
241    pub fn required_field(&self, key: &str) -> Result<&Field, Error> {
242        match self.elements.single_field_with_key(key) {
243            Matches::None => Err(Error::new("Not found".to_string(), self.line_number)),
244            Matches::One(field) => {
245                field.touch();
246                Ok(field)
247            }
248            Matches::Multiple(_first, second) => Err(Error::new(
249                format!("Only a single field with key {} was expected", key),
250                second.line_number,
251            )),
252            Matches::WrongType(element) => Err(Error::new(
253                "A field was expected".to_string(),
254                element.line_number(),
255            )),
256        }
257    }
258
259    pub fn required_flag(&self, key: &str) -> Result<&Flag, Error> {
260        match self.elements.single_flag_with_key(key) {
261            Matches::None => Err(Error::new("Not found".to_string(), self.line_number)),
262            Matches::One(flag) => {
263                flag.touch();
264                Ok(flag)
265            }
266            Matches::Multiple(_first, second) => Err(Error::new(
267                format!("Only a single flag with key {} was expected", key),
268                second.line_number,
269            )),
270            Matches::WrongType(element) => Err(Error::new(
271                "A flag was expected".to_string(),
272                element.line_number(),
273            )),
274        }
275    }
276
277    pub fn required_section(&self, key: &str) -> Result<&Section, Error> {
278        match self.elements.single_section_with_key(key) {
279            Matches::None => Err(Error::new("Not found".to_string(), self.line_number)),
280            Matches::One(section) => {
281                section.touch();
282                Ok(section)
283            }
284            Matches::Multiple(_first, second) => Err(Error::new(
285                format!("Only a single section with key {} was expected", key),
286                second.line_number,
287            )),
288            Matches::WrongType(element) => Err(Error::new(
289                "A section was expected".to_string(),
290                element.line_number(),
291            )),
292        }
293    }
294
295    pub fn section(&self, key: &str) -> Result<SectionQuery, Error> {
296        let element_option = match self.elements.single_section_with_key(key) {
297            Matches::None => None,
298            Matches::One(section) => Some(section),
299            Matches::Multiple(_first, second) => {
300                return Err(Error::new(
301                    "Only a single section was expected".to_string(),
302                    second.line_number,
303                ))
304            }
305            Matches::WrongType(element) => {
306                return Err(Error::new(
307                    "A section was expected".to_string(),
308                    element.line_number(),
309                ))
310            }
311        };
312
313        Ok(SectionQuery::new(
314            element_option,
315            Some(key.to_string()),
316            SectionQueryParent::Section(self),
317        ))
318    }
319
320    pub fn untouched_elements(&self) -> Vec<&dyn Element> {
321        self.elements.untouched()
322    }
323}
324
325impl Element for Section {
326    fn as_section(&self) -> Option<&Section> {
327        Some(self)
328    }
329
330    fn is_section(&self) -> bool {
331        true
332    }
333
334    fn line_number(&self) -> u32 {
335        self.line_number
336    }
337
338    fn snippet(&self) -> String {
339        self.snippet_with_options(&*self.document_internals.default_printer, true)
340    }
341
342    fn snippet_with_options(&self, printer: &dyn Printer, gutter: bool) -> String {
343        let mut out = String::new();
344
345        if gutter {
346            out.push_str(&printer.gutter(self.line_number));
347        }
348
349        out.push_str(
350            &self.document_internals.content[self.line_begin_index..self.operator_range.start],
351        );
352        out.push_str(
353            &printer.operator(&self.document_internals.content[self.operator_range.clone()]),
354        );
355        out.push_str(
356            &self.document_internals.content[self.operator_range.end..self.key_range.start],
357        );
358        out.push_str(&printer.key(&self.document_internals.content[self.key_range.clone()]));
359
360        let mut line_number = self.line_number + 1;
361
362        for element in &self.elements {
363            out.push('\n');
364
365            let element_line_range = element.line_range();
366
367            while line_number < *element_line_range.start() {
368                if let Some(comment) = self
369                    .document_internals
370                    .comments
371                    .borrow()
372                    .iter()
373                    .find(|comment| comment.line_number == line_number)
374                {
375                    out.push_str(&comment.snippet_with_options(printer, gutter));
376                } else if gutter {
377                    out.push_str(&printer.gutter(line_number));
378                }
379
380                out.push('\n');
381
382                line_number += 1;
383            }
384
385            out.push_str(&element.snippet_with_options(printer, gutter));
386
387            line_number = *element_line_range.end() + 1;
388        }
389
390        out
391    }
392
393    fn touch(&self) {
394        self.touched.set(true);
395    }
396}
397
398impl ElementImpl for Section {
399    fn line_range(&self) -> RangeInclusive<u32> {
400        match self.elements.last() {
401            Some(element) => self.line_number..=*element.line_range().end(),
402            None => self.line_number..=self.line_number,
403        }
404    }
405
406    fn touched(&self) -> bool {
407        self.touched.get()
408    }
409}
410
411impl SectionElement for Section {
412    fn as_element(&self) -> &dyn Element {
413        self
414    }
415
416    fn as_mut_section(&mut self) -> Option<&mut Section> {
417        Some(self)
418    }
419
420    fn key(&self) -> &str {
421        &self.document_internals.content[self.key_range.clone()]
422    }
423}
424
425impl SectionImpl for Section {
426    fn get_elements(&self) -> &[Box<dyn SectionElement>] {
427        self.elements.as_slice()
428    }
429
430    fn get_elements_mut(&mut self) -> &mut Vec<Box<dyn SectionElement>> {
431        &mut self.elements
432    }
433
434    fn get_elements_ref(&self) -> &Vec<Box<dyn SectionElement>> {
435        &self.elements
436    }
437
438    fn new(
439        document_internals: Rc<DocumentInternals>,
440        elements: Vec<Box<dyn SectionElement>>,
441        key_range: Range<usize>,
442        line_begin_index: usize,
443        line_number: u32,
444        operator_range: Range<usize>,
445    ) -> Section {
446        Section {
447            document_internals,
448            elements,
449            key_range,
450            line_begin_index,
451            line_number,
452            operator_range,
453            touched: Cell::new(false),
454        }
455    }
456}