1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
use super::*;
#[derive(Default)]
pub(crate) struct Ctx {
pub(crate) config: Config,
pub(crate) just_spaced: bool,
pub(crate) consec_new_line: i32,
}
/// you may push into your own buffer using this to ensure you push considering context
///
/// you may then push said buffer the final result.
impl Ctx {
pub(crate) fn from_config(config: Config) -> Self {
Self {
config,
..Default::default()
}
}
/// Trim spaces for Space nodes if they contain a linebreak.
/// avoids:
/// - putting two consecutive spaces.
/// - putting more than two consecutive newlines.
#[instrument(skip_all)]
pub(crate) fn push_in(&mut self, s: &str, res: &mut String) {
let s = if s.contains('\n') {
s.trim_end_matches(' ')
} else {
s
};
for c in s.chars() {
match c {
' ' => {
if self.just_spaced {
debug!("IGNORED space");
} else {
debug!("PUSHED SPACE");
self.just_spaced = true;
res.push(' ');
}
}
'\n' => {
if self.consec_new_line <= 1 {
debug!("PUSHED NEWLINE");
self.consec_new_line += 1;
res.push('\n')
} else {
debug!("IGNORED newline");
}
}
_ => {
// debug!("PUSHED {c}");
res.push(c);
self.lost_context();
}
}
}
}
/// makes the context aware it missed info,
/// should be called when pushing directly in result.
pub(crate) fn push_raw_in(&mut self, s: &str, result: &mut String) {
debug!("PUSH_RAW: {s:?}");
result.push_str(s);
self.lost_context()
}
/// adds an indentation for each line the input except the first to match the current level of identation.
pub(crate) fn push_raw_indent(&mut self, s: &str, result: &mut String) {
debug!("push::raw::indent");
let mut is_first = true;
for s in s.lines() {
let s = s.trim_end();
if is_first {
is_first = false;
self.push_raw_in(s, result);
continue;
}
self.push_raw_in("\n", result);
self.push_raw_in(&self.get_indent(), result);
self.push_raw_in(s, result)
}
}
/// must be called when you cannot keep track of what you pushed
/// so that context doesn't refuse your next pushes for no reasons.
pub(crate) fn lost_context(&mut self) {
self.just_spaced = false;
self.consec_new_line = 0;
}
/// returns an indent using config to get it's length.
pub(crate) fn get_indent(&self) -> String {
" ".repeat(self.config.ident_space)
}
}