1pub fn strip_trailing_whitespace(s: &str) -> String {
3 if s.is_empty() {
4 return "\n".to_string();
5 }
6 let mut res = String::with_capacity(s.len());
7 for line in s.lines() {
8 res.push_str(line.trim_end());
9 res.push('\n');
10 }
11 res
12}
13
14pub fn count_spaces_after_last_newline(s: &str, i: usize) -> usize {
15 debug_assert!(
17 s.is_char_boundary(i),
18 "Position i is not a valid UTF-8 boundary"
19 );
20
21 if let Some(pos) = s[..i].rfind('\n') {
23 let after_newline = &s[pos + 1..i];
25 after_newline.chars().take_while(|&c| c == ' ').count()
27 } else {
28 0
30 }
31}
32
33pub fn change_indent(text: &str, from_indent: usize, to_indent: usize) -> String {
53 if text.is_empty() || from_indent == 0 || from_indent == to_indent {
54 return text.to_string();
55 }
56
57 let mut result = String::with_capacity(text.len());
58 let mut first = true;
59
60 for line in text.lines() {
61 if !first {
62 result.push('\n');
63 }
64 first = false;
65
66 let trimmed = line.trim_start();
67 if trimmed.is_empty() {
68 continue;
70 } else {
71 let leading_spaces = line.len() - trimmed.len();
72 let indent_level = leading_spaces / from_indent;
73 let new_indent_size = to_indent * indent_level;
74
75 for _ in 0..new_indent_size {
77 result.push(' ');
78 }
79 result.push_str(trimmed);
80 }
81 }
82
83 result
84}
85
86pub fn indent_4_to_2(text: &str) -> String {
88 change_indent(text, 4, 2)
89}
90
91#[cfg(test)]
92mod tests {
93 use super::*;
94
95 #[test]
96 fn test_strip_trailing_whitespace() {
97 let s = strip_trailing_whitespace("");
98 assert_eq!(s, "\n");
99 let s = strip_trailing_whitespace(" ");
100 assert_eq!(s, "\n");
101 let s = strip_trailing_whitespace("\n");
102 assert_eq!(s, "\n");
103 let s = strip_trailing_whitespace(" \n - \n");
104 assert_eq!(s, "\n -\n");
105 let s = strip_trailing_whitespace(" \n - \n ");
106 assert_eq!(s, "\n -\n\n");
107 }
108
109 #[test]
110 fn test_change_indent_basic() {
111 let input = " line1\n line2\n line3";
112 let output = change_indent(input, 4, 2);
113 assert_eq!(output, " line1\n line2\n line3");
114 }
115
116 #[test]
117 fn test_change_indent_empty() {
118 assert_eq!(change_indent("", 4, 2), "");
119 assert_eq!(change_indent(" ", 4, 2), "");
120 }
121}