about summary refs log tree commit diff
path: root/src/text_diff.rs
blob: bab8799b0568ce2a53b43165ccbf09b29d048c52 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
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);
            }
        }
    }
}