about summary refs log tree commit diff
path: root/src/text_diff.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/text_diff.rs')
-rw-r--r--src/text_diff.rs52
1 files changed, 52 insertions, 0 deletions
diff --git a/src/text_diff.rs b/src/text_diff.rs
new file mode 100644
index 0000000..bab8799
--- /dev/null
+++ b/src/text_diff.rs
@@ -0,0 +1,52 @@
+use difference::{Changeset, Difference};
+use serde::{Deserialize, Serialize};
+
+#[derive(Serialize, Deserialize, Debug)]
+pub enum TextChange {
+    Inserted { at: usize, new_content: String },
+    Deleted { at: usize, upto: usize },
+}
+
+impl TextChange {
+    pub fn diff(old: &str, new: &str) -> Vec<Self> {
+        let change_set = Changeset::new(old, new, "");
+
+        let mut changes = Vec::new();
+        let mut at: usize = 0;
+
+        for diff in change_set.diffs.iter() {
+            match diff {
+                Difference::Add(new_content) => {
+                    let change = TextChange::Inserted {
+                        at,
+                        new_content: new_content.to_owned(),
+                    };
+                    at += new_content.len();
+                    changes.push(change);
+                }
+                Difference::Rem(removed_content) => {
+                    changes.push(TextChange::Deleted {
+                        at,
+                        upto: removed_content.len(),
+                    });
+                }
+                Difference::Same(same_content) => {
+                    at += same_content.len();
+                }
+            }
+        }
+
+        changes
+    }
+
+    pub fn apply(&self, buffer: &mut String) {
+        match self {
+            TextChange::Deleted { at, upto } => {
+                buffer.replace_range(at..upto, "");
+            }
+            TextChange::Inserted { at, new_content } => {
+                buffer.insert_str(*at, new_content);
+            }
+        }
+    }
+}