pub fn replace_range(original: &str, range: std::ops::Range<usize>, replacement: &str) -> String {
let mut out =
String::with_capacity(original.len() + replacement.len() - (range.end - range.start));
out.push_str(&original[..range.start]);
out.push_str(replacement);
out.push_str(&original[range.end..]);
out
}
pub fn insert_at(original: &str, offset: usize, new_content: &str) -> String {
let mut out = String::with_capacity(original.len() + new_content.len());
out.push_str(&original[..offset]);
out.push_str(new_content);
out.push_str(&original[offset..]);
out
}
pub fn indent_block(block: &str, column: usize) -> String {
let pad = " ".repeat(column);
let mut out = String::with_capacity(block.len() + column * 4);
for (i, line) in block.split_inclusive('\n').enumerate() {
let trimmed = line.trim_start_matches([' ', '\t']);
if trimmed.is_empty() || trimmed == "\n" {
out.push_str(trimmed);
continue;
}
if i == 0 {
out.push_str(trimmed);
} else {
out.push_str(&pad);
out.push_str(trimmed);
}
}
out
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn replace_range_replaces_inner_bytes() {
let s = "abcXYZdef";
let out = replace_range(s, 3..6, "...");
assert_eq!(out, "abc...def");
}
#[test]
fn replace_range_at_start() {
let s = "abcdef";
let out = replace_range(s, 0..3, "ZZZ");
assert_eq!(out, "ZZZdef");
}
#[test]
fn replace_range_at_end() {
let s = "abcdef";
let out = replace_range(s, 3..6, "ZZZ");
assert_eq!(out, "abcZZZ");
}
#[test]
fn replace_range_with_longer_replacement() {
let s = "abc.def";
let out = replace_range(s, 3..4, "XYZ");
assert_eq!(out, "abcXYZdef");
}
#[test]
fn replace_range_with_shorter_replacement() {
let s = "abcXYZdef";
let out = replace_range(s, 3..6, "_");
assert_eq!(out, "abc_def");
}
#[test]
fn insert_at_pushes_offset_content_right() {
let s = "abdef";
let out = insert_at(s, 2, "c");
assert_eq!(out, "abcdef");
}
#[test]
fn insert_at_start_and_end() {
assert_eq!(insert_at("def", 0, "abc"), "abcdef");
assert_eq!(insert_at("abc", 3, "def"), "abcdef");
}
#[test]
fn indent_block_pads_subsequent_lines_only() {
let block = "key:\n child: value\n";
let out = indent_block(block, 4);
assert_eq!(out, "key:\n child: value\n");
}
#[test]
fn indent_block_preserves_blank_lines() {
let block = "a:\n\nb:\n";
let out = indent_block(block, 2);
assert_eq!(out, "a:\n\n b:\n");
}
#[test]
fn indent_block_replaces_existing_leading_whitespace() {
let block = "key:\n already_indented: x\n";
let out = indent_block(block, 2);
assert_eq!(
out, "key:\n already_indented: x\n",
"existing leading ws should be replaced, not appended"
);
}
}