nmbrs_workload/edit/
splice.rs1pub fn replace_range(original: &str, range: std::ops::Range<usize>, replacement: &str) -> String {
28 let mut out =
29 String::with_capacity(original.len() + replacement.len() - (range.end - range.start));
30 out.push_str(&original[..range.start]);
31 out.push_str(replacement);
32 out.push_str(&original[range.end..]);
33 out
34}
35
36pub fn insert_at(original: &str, offset: usize, new_content: &str) -> String {
41 let mut out = String::with_capacity(original.len() + new_content.len());
42 out.push_str(&original[..offset]);
43 out.push_str(new_content);
44 out.push_str(&original[offset..]);
45 out
46}
47
48pub fn indent_block(block: &str, column: usize) -> String {
59 let pad = " ".repeat(column);
60 let mut out = String::with_capacity(block.len() + column * 4);
61 for (i, line) in block.split_inclusive('\n').enumerate() {
62 let trimmed = line.trim_start_matches([' ', '\t']);
63 if trimmed.is_empty() || trimmed == "\n" {
64 out.push_str(trimmed);
65 continue;
66 }
67 if i == 0 {
74 out.push_str(trimmed);
75 } else {
76 out.push_str(&pad);
77 out.push_str(trimmed);
78 }
79 }
80 out
81}
82
83#[cfg(test)]
84mod tests {
85 use super::*;
86
87 #[test]
88 fn replace_range_replaces_inner_bytes() {
89 let s = "abcXYZdef";
90 let out = replace_range(s, 3..6, "...");
91 assert_eq!(out, "abc...def");
92 }
93
94 #[test]
95 fn replace_range_at_start() {
96 let s = "abcdef";
97 let out = replace_range(s, 0..3, "ZZZ");
98 assert_eq!(out, "ZZZdef");
99 }
100
101 #[test]
102 fn replace_range_at_end() {
103 let s = "abcdef";
104 let out = replace_range(s, 3..6, "ZZZ");
105 assert_eq!(out, "abcZZZ");
106 }
107
108 #[test]
109 fn replace_range_with_longer_replacement() {
110 let s = "abc.def";
111 let out = replace_range(s, 3..4, "XYZ");
112 assert_eq!(out, "abcXYZdef");
113 }
114
115 #[test]
116 fn replace_range_with_shorter_replacement() {
117 let s = "abcXYZdef";
118 let out = replace_range(s, 3..6, "_");
119 assert_eq!(out, "abc_def");
120 }
121
122 #[test]
123 fn insert_at_pushes_offset_content_right() {
124 let s = "abdef";
125 let out = insert_at(s, 2, "c");
126 assert_eq!(out, "abcdef");
127 }
128
129 #[test]
130 fn insert_at_start_and_end() {
131 assert_eq!(insert_at("def", 0, "abc"), "abcdef");
132 assert_eq!(insert_at("abc", 3, "def"), "abcdef");
133 }
134
135 #[test]
136 fn indent_block_pads_subsequent_lines_only() {
137 let block = "key:\n child: value\n";
138 let out = indent_block(block, 4);
139 assert_eq!(out, "key:\n child: value\n");
142 }
143
144 #[test]
145 fn indent_block_preserves_blank_lines() {
146 let block = "a:\n\nb:\n";
147 let out = indent_block(block, 2);
148 assert_eq!(out, "a:\n\n b:\n");
149 }
150
151 #[test]
152 fn indent_block_replaces_existing_leading_whitespace() {
153 let block = "key:\n already_indented: x\n";
154 let out = indent_block(block, 2);
155 assert_eq!(
156 out, "key:\n already_indented: x\n",
157 "existing leading ws should be replaced, not appended"
158 );
159 }
160}