Skip to main content

ephemeris_documents/yaml/source/
leaf.rs

1//! A value that is not a mapping.
2
3use std::fmt;
4
5use super::text::{Origin, Reindent, Text};
6
7/// The raw text of a value, from the end of the owning key through the end
8/// of its last line. The tail holds what follows the value on that line,
9/// such as a comment. `decoded` is the scalar the text spells, when it is one.
10#[derive(Debug, Clone, PartialEq, Eq)]
11pub(crate) struct Leaf {
12    value: Text,
13    tail: Text,
14    decoded: Option<String>,
15}
16
17impl Leaf {
18    pub(super) const fn new(value: Text, tail: Text, decoded: Option<String>) -> Self {
19        Self {
20            value,
21            tail,
22            decoded,
23        }
24    }
25
26    /// Text that is kept as a whole and has no scalar value.
27    pub(super) fn raw(text: Text) -> Self {
28        Self::new(text, Text::default(), None)
29    }
30
31    /// The scalar the text spells.
32    pub(crate) fn decoded(&self) -> Option<&str> {
33        self.decoded.as_deref()
34    }
35
36    /// End the last line with a line break, adding one when it is missing.
37    pub(super) fn terminate(&mut self) {
38        if self.tail.is_empty() {
39            self.value.terminate();
40        } else {
41            self.tail.terminate();
42        }
43    }
44
45    /// Move the lines after the first by `shift`.
46    pub(super) fn reindent(&mut self, shift: Reindent) {
47        self.value.reindent(shift, Origin::MidLine);
48    }
49
50    /// The comment on the key line, with the whitespace before it. For a
51    /// multi-line value this is the one after the block scalar indicator.
52    pub(super) fn comment(&self) -> Option<&str> {
53        let line = match self.value.as_str().split_once('\n') {
54            Some((first, _)) => first,
55            None => self.tail.as_str(),
56        };
57        Text::comment_in(line)
58    }
59
60    /// Put `comment` on the key line unless it has one. After a multi-line
61    /// value, the key line is the one with the block scalar indicator.
62    pub(super) fn keep_comment(&mut self, comment: &str) {
63        if self.comment().is_some() {
64            return;
65        }
66        match self.value.as_str().split_once('\n') {
67            Some((first, rest)) => {
68                self.value = Text::from(format!("{}{comment}\n{rest}", first.trim_end()));
69            }
70            None => self.tail = Text::from(format!("{comment}\n")),
71        }
72    }
73
74    /// The value and the tail as one text.
75    pub(super) fn into_text(self) -> Text {
76        let Self {
77            mut value, tail, ..
78        } = self;
79        value.append(&tail);
80        value
81    }
82}
83
84impl fmt::Display for Leaf {
85    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
86        write!(f, "{}{}", self.value, self.tail)
87    }
88}