aboutsummaryrefslogtreecommitdiff
path: root/src/diff.rs
diff options
context:
space:
mode:
authorMartin Fischer <martin@push-f.com>2021-06-23 14:12:02 +0200
committerMartin Fischer <martin@push-f.com>2021-06-23 14:36:17 +0200
commit3ed32ef268b54965c97b13efdf24a1539c4ec1c1 (patch)
treea0f80b097339693763a0bce2896c083c1000c6cc /src/diff.rs
parent086e0e30e47f796a12809036dfc787490904a8ae (diff)
refactor: split up main.rs into multiple modules
Diffstat (limited to 'src/diff.rs')
-rw-r--r--src/diff.rs86
1 files changed, 86 insertions, 0 deletions
diff --git a/src/diff.rs b/src/diff.rs
new file mode 100644
index 0000000..382c7db
--- /dev/null
+++ b/src/diff.rs
@@ -0,0 +1,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");
+ }
+ _ => {}
+ }
+ }
+}