diff --git a/crates/text-edit/src/lib.rs b/crates/text-edit/src/lib.rs index 9bb4271b65..4705d18187 100644 --- a/crates/text-edit/src/lib.rs +++ b/crates/text-edit/src/lib.rs @@ -176,6 +176,7 @@ impl TextEditBuilder { pub fn finish(self) -> TextEdit { let mut indels = self.indels; assert_disjoint_or_equal(&mut indels); + indels = coalesce_indels(indels); TextEdit { indels } } pub fn invalidates_offset(&self, offset: TextSize) -> bool { @@ -205,6 +206,21 @@ where indels.clone().zip(indels.skip(1)).all(|(l, r)| l.delete.end() <= r.delete.start() || l == r) } +fn coalesce_indels(indels: Vec) -> Vec { + indels + .into_iter() + .coalesce(|mut a, b| { + if a.delete.end() == b.delete.start() { + a.insert.push_str(&b.insert); + a.delete = TextRange::new(a.delete.start(), b.delete.end()); + Ok(a) + } else { + Err((a, b)) + } + }) + .collect_vec() +} + #[cfg(test)] mod tests { use super::{TextEdit, TextEditBuilder, TextRange}; @@ -261,4 +277,40 @@ mod tests { let edit2 = TextEdit::delete(range(9, 13)); assert!(edit1.union(edit2).is_err()); } + + #[test] + fn test_coalesce_disjoint() { + let mut builder = TextEditBuilder::default(); + builder.replace(range(1, 3), "aa".into()); + builder.replace(range(5, 7), "bb".into()); + let edit = builder.finish(); + + assert_eq!(edit.indels.len(), 2); + } + + #[test] + fn test_coalesce_adjacent() { + let mut builder = TextEditBuilder::default(); + builder.replace(range(1, 3), "aa".into()); + builder.replace(range(3, 5), "bb".into()); + + let edit = builder.finish(); + assert_eq!(edit.indels.len(), 1); + assert_eq!(edit.indels[0].insert, "aabb"); + assert_eq!(edit.indels[0].delete, range(1, 5)); + } + + #[test] + fn test_coalesce_adjacent_series() { + let mut builder = TextEditBuilder::default(); + builder.replace(range(1, 3), "au".into()); + builder.replace(range(3, 5), "www".into()); + builder.replace(range(5, 8), "".into()); + builder.replace(range(8, 9), "ub".into()); + + let edit = builder.finish(); + assert_eq!(edit.indels.len(), 1); + assert_eq!(edit.indels[0].insert, "auwwwub"); + assert_eq!(edit.indels[0].delete, range(1, 9)); + } }