difference/
merge.rs

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
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
use Difference;

// merges the changes from two strings, given a common substring
pub fn merge(orig: &str, edit: &str, common: &str, split: &str) -> Vec<Difference> {
    let mut ret = Vec::new();

    let mut l = orig.split(split).peekable();
    let mut r = edit.split(split).peekable();
    let mut c = common.split(split).peekable();

    // Turn empty strings into [], not [""]
    if orig == "" {
        l.next();
    }
    if edit == "" {
        r.next();
    }
    if common == "" {
        c.next();
    }

    while l.peek().is_some() || r.peek().is_some() {
        let mut same = Vec::new();
        while l.peek().is_some() && l.peek() == c.peek() && r.peek() == c.peek() {
            same.push(l.next().unwrap());
            r.next();
            c.next();
        }
        if !same.is_empty() {
            let joined = same.join(split);
            if split != "" || joined != "" {
                ret.push(Difference::Same(joined));
            }
        }

        let mut rem = Vec::new();
        while l.peek().is_some() && l.peek() != c.peek() {
            rem.push(l.next().unwrap());
        }
        if !rem.is_empty() {
            ret.push(Difference::Rem(rem.join(split)));
        }

        let mut add = Vec::new();
        while r.peek().is_some() && r.peek() != c.peek() {
            add.push(r.next().unwrap());
        }
        if !add.is_empty() {
            ret.push(Difference::Add(add.join(split)));
        }
    }

    ret
}


#[test]
fn test_merge() {
    assert_eq!(
        merge("testa", "tost", "tst", ""),
        vec![
            Difference::Same("t".to_string()),
            Difference::Rem("e".to_string()),
            Difference::Add("o".to_string()),
            Difference::Same("st".to_string()),
            Difference::Rem("a".to_string()),
        ]
    );

    assert_eq!(
        merge("", "a", "", ""),
        vec![Difference::Add("a".to_string())]
    );

    assert_eq!(
        merge("a\nb", "a\n\nb", "a\nb", "\n"),
        vec![
            Difference::Same("a".to_string()),
            Difference::Add("".to_string()),
            Difference::Same("b".to_string()),
        ]
    );

    assert_eq!(
        merge("a\n", "c\n", "\n", "\n"),
        vec![
            Difference::Rem("a".to_string()),
            Difference::Add("c".to_string()),
            Difference::Same("".to_string()),
        ]
    );
}