]> git.lizzy.rs Git - rust.git/blobdiff - crates/text_edit/src/lib.rs
test: add unit test for TextEdit::apply()
[rust.git] / crates / text_edit / src / lib.rs
index c4000d80522f68750e97c87e900334bfa10f638d..f478e4dcf576c4a82d3c54adc657b87ffd4a0f0a 100644 (file)
@@ -3,7 +3,6 @@
 //! `rust-analyzer` never mutates text itself and only sends diffs to clients,
 //! so `TextEdit` is the ultimate representation of the work done by
 //! rust-analyzer.
-use std::collections::HashSet;
 
 pub use text_size::{TextRange, TextSize};
 
@@ -116,20 +115,16 @@ pub fn apply(&self, text: &mut String) {
     }
 
     pub fn union(&mut self, other: TextEdit) -> Result<(), TextEdit> {
-        dbg!(&self, &other);
         // FIXME: can be done without allocating intermediate vector
         let mut all = self.iter().chain(other.iter()).collect::<Vec<_>>();
-        if !check_disjoint_or_equal(&mut all) {
+        if !check_disjoint_and_sort(&mut all) {
             return Err(other);
         }
 
-        // remove duplicates
-        // FIXME: maybe make indels a HashSet instead to get rid of this?
-        let our_indels = self.indels.clone();
-        let our_indels = our_indels.iter().collect::<HashSet<_>>();
-        let other_indels = other.indels.into_iter().filter(|i| !our_indels.contains(i));
-
-        self.indels.extend(other_indels);
+        self.indels.extend(other.indels);
+        check_disjoint_and_sort(&mut self.indels);
+        // Only dedup deletions and replacements, keep all insertions
+        self.indels.dedup_by(|a, b| a == b && !a.delete.is_empty());
         Ok(())
     }
 
@@ -196,10 +191,11 @@ fn indel(&mut self, indel: Indel) {
     }
 }
 
-fn assert_disjoint_or_equal(indels: &mut [impl std::borrow::Borrow<Indel>]) {
-    assert!(check_disjoint_or_equal(indels));
+fn assert_disjoint_or_equal(indels: &mut [Indel]) {
+    assert!(check_disjoint_and_sort(indels));
 }
-fn check_disjoint_or_equal(indels: &mut [impl std::borrow::Borrow<Indel>]) -> bool {
+// FIXME: Remove the impl Bound here, it shouldn't be needed
+fn check_disjoint_and_sort(indels: &mut [impl std::borrow::Borrow<Indel>]) -> bool {
     indels.sort_by_key(|indel| (indel.borrow().delete.start(), indel.borrow().delete.end()));
     indels.iter().zip(indels.iter().skip(1)).all(|(l, r)| {
         let l = l.borrow();
@@ -207,3 +203,17 @@ fn check_disjoint_or_equal(indels: &mut [impl std::borrow::Borrow<Indel>]) -> bo
         l.delete.end() <= r.delete.start() || l == r
     })
 }
+
+#[test]
+fn test_apply() {
+    let mut text = "_11h1_2222_xx3333_4444_6666".to_string();
+    let mut builder = TextEditBuilder::default();
+    builder.replace(TextRange::new(3.into(), 4.into()), "1".to_string());
+    builder.delete(TextRange::new(11.into(), 13.into()));
+    builder.insert(22.into(), "_5555".to_string());
+
+    let text_edit = builder.finish();
+    text_edit.apply(&mut text);
+
+    assert_eq!(text, "_1111_2222_3333_4444_5555_6666")
+}
\ No newline at end of file