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
|
use difference::Changeset;
use difference::Difference;
use sputnik::html_escape;
use std::cmp;
use std::fmt::Write as FmtWrite;
pub fn diff(first: &str, second: &str) -> String {
if first == second {
return "<em>(no changes)</em>".into();
}
let Changeset { diffs, .. } = Changeset::new(&first, &second, "\n");
let mut output = String::new();
output.push_str("<pre>");
for i in 0..diffs.len() {
match diffs[i] {
Difference::Same(ref text) => {
let text = html_escape(text);
let lines: Vec<_> = text.split('\n').collect();
if i == 0 {
output.push_str(&lines[lines.len().saturating_sub(3)..].join("\n"));
} else if i == diffs.len() - 1 {
output.push_str(&lines[..cmp::min(3, lines.len())].join("\n"));
} else {
output.push_str(&text);
}
}
Difference::Add(ref text) => {
output.push_str("<div class=addition>");
if i == 0 {
output.push_str(&html_escape(text).replace("\n", "<br>"));
} else {
match diffs.get(i - 1) {
Some(Difference::Rem(ref rem)) => {
word_diff(&mut output, rem, text, "ins");
}
_ => {
output.push_str(&html_escape(text).replace("\n", "<br>"));
}
}
}
output.push_str("\n</div>");
}
Difference::Rem(ref text) => {
output.push_str("<div class=deletion>");
match diffs.get(i + 1) {
Some(Difference::Add(ref add)) => {
word_diff(&mut output, add, text, "del");
}
_ => {
output.push_str(&html_escape(text).replace("\n", "<br>"));
}
}
output.push_str("\n</div>");
}
}
}
output.push_str("</pre>");
output
}
fn word_diff(out: &mut String, text1: &str, text2: &str, tagname: &str) {
let Changeset { diffs, .. } = Changeset::new(text1, text2, " ");
for c in diffs {
match c {
Difference::Same(ref z) => {
out.push_str(&html_escape(z).replace("\n", "<br>"));
out.push(' ');
}
Difference::Add(ref z) => {
write!(
out,
"<{0}>{1}</{0}> ",
tagname,
html_escape(z).replace("\n", "<br>")
)
.expect("write error");
}
_ => {}
}
}
}
|