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 "(no changes)".into(); } let Changeset { diffs, .. } = Changeset::new(first, second, "\n"); let mut output = String::new(); output.push_str("
"); 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(""); 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', ""); if i == 0 { output.push_str(&html_escape(text).replace('\n', ""); } Difference::Rem(ref text) => { output.push_str("
")); } 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', "
")); } } } output.push_str("\n"); 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', ""); } } } output.push_str("
")); } } output.push_str("\n