Skip to main content

ephemeris_documents/yaml/source/
opaque.rs

1//! A mapping that is kept as raw text until an edit needs it.
2
3use std::fmt;
4
5use super::mapping::Mapping;
6use super::text::{Origin, Reindent, Text};
7
8/// The raw text of a mapping the tree does not split into entries.
9///
10/// A flow mapping also carries its block rewrite. The text prints until an
11/// edit changes the rewrite, and then the rewrite prints instead.
12#[derive(Debug, Clone, PartialEq, Eq)]
13pub(crate) struct Opaque {
14    text: Text,
15    rewrite: Option<Rewrite>,
16}
17
18#[derive(Debug, Clone, PartialEq, Eq)]
19struct Rewrite {
20    original: Mapping,
21    edited: Mapping,
22}
23
24impl Opaque {
25    /// Text the tree cannot edit.
26    pub(super) const fn raw(text: Text) -> Self {
27        Self {
28            text,
29            rewrite: None,
30        }
31    }
32
33    /// Text that an edit replaces with `block`.
34    pub(super) fn flow(text: Text, block: Mapping) -> Self {
35        Self {
36            text,
37            rewrite: Some(Rewrite {
38                original: block.clone(),
39                edited: block,
40            }),
41        }
42    }
43
44    /// The block rewrite, when the text has one.
45    pub(super) fn mapping(&self) -> Option<&Mapping> {
46        self.rewrite.as_ref().map(|rewrite| &rewrite.edited)
47    }
48
49    pub(super) fn mapping_mut(&mut self) -> Option<&mut Mapping> {
50        self.rewrite.as_mut().map(|rewrite| &mut rewrite.edited)
51    }
52
53    /// Whether edits cannot enter this text.
54    pub(super) const fn is_unsupported(&self) -> bool {
55        self.rewrite.is_none()
56    }
57
58    /// The comment on the key line, with the whitespace before it.
59    pub(super) fn comment(&self) -> Option<&str> {
60        self.mapping()?.comment()
61    }
62
63    /// End the last line with a line break, adding one when it is missing.
64    pub(super) fn terminate(&mut self) {
65        self.text.terminate();
66        if let Some(rewrite) = &mut self.rewrite {
67            rewrite.original.terminate();
68            rewrite.edited.terminate();
69        }
70    }
71
72    /// Move the lines after the first by `shift`.
73    pub(super) fn reindent(&mut self, shift: Reindent) {
74        self.text.reindent(shift, Origin::MidLine);
75    }
76}
77
78impl fmt::Display for Opaque {
79    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
80        match &self.rewrite {
81            Some(rewrite) if rewrite.edited != rewrite.original => rewrite.edited.fmt(f),
82            Some(_) | None => self.text.fmt(f),
83        }
84    }
85}