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
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
// SPDX-FileCopyrightText: 2022 Kevin Amado <kamadorueda@gmail.com>
//
// SPDX-License-Identifier: GPL-3.0-only
use crate::mem::own;
use crate::mem::own_ll;
#[derive(Clone, Debug, Eq, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
/// `''parts''`.
pub struct IndentedString {
pub parts: Box<[crate::Part]>,
pub span: Box<crate::Span>,
}
impl std::convert::From<*mut crate::ffi::any> for IndentedString {
fn from(ptr: *mut crate::ffi::any) -> Self {
let crate::ffi::IndentedString { parts, span } = own(ptr);
let mut parts: Box<[crate::Part]> =
own_ll::<crate::ffi::Part, crate::Part>(parts);
strip_indentation(&mut parts);
Self { parts, span: Box::new(crate::Span::from(span)) }
}
}
fn strip_indentation(parts: &mut [crate::Part]) {
let mut at_start_of_line = true;
let mut min_indent: usize = usize::MAX;
let mut cur_indent: usize = 0;
// Compute the min indentation
for part in &*parts {
if let crate::Part::Raw(crate::PartRaw { content, .. }) = part {
for char in content.chars() {
if at_start_of_line {
match char {
' ' => {
cur_indent += 1;
},
'\n' => {
cur_indent = 0;
},
_ => {
at_start_of_line = false;
if cur_indent < min_indent {
min_indent = cur_indent;
}
},
}
} else if char == '\n' {
at_start_of_line = true;
cur_indent = 0;
}
}
}
}
// Trim spaces from each line
let mut cur_dropped: usize = 0;
let parts_count = parts.len();
for part in parts.iter_mut() {
match part {
crate::Part::Raw(crate::PartRaw { content, .. }) => {
*content = content
.chars()
.filter(|char| {
if at_start_of_line {
match char {
' ' => {
cur_dropped += 1;
cur_dropped > min_indent
},
'\n' => {
cur_dropped = 0;
true
},
_ => {
at_start_of_line = false;
cur_dropped = 0;
true
},
}
} else {
if *char == '\n' {
at_start_of_line = true;
}
true
}
})
.collect::<String>()
.into_boxed_str();
if parts_count == 1 {
if let Some(last_new_line) = content.rfind('\n') {
if content[last_new_line + 1..]
.chars()
.all(|char| char == ' ')
{
*content = content[0..last_new_line + 1]
.to_string()
.into_boxed_str();
}
}
}
},
_ => {
at_start_of_line = false;
cur_dropped = 0;
},
}
}
}