use colored::*;
use similar::{ChangeTag, TextDiff};
pub fn show_diff(old: &str, new: &str, old_label: &str, new_label: &str, use_color: bool) {
let diff = TextDiff::from_lines(old, new);
if use_color {
println!("{}", format!("--- {}", old_label).red());
println!("{}", format!("+++ {}", new_label).green());
} else {
println!("--- {}", old_label);
println!("+++ {}", new_label);
}
for (idx, group) in diff.grouped_ops(3).iter().enumerate() {
if idx > 0 {
println!("...");
}
for op in group {
for change in diff.iter_changes(op) {
let sign = match change.tag() {
ChangeTag::Delete => "-",
ChangeTag::Insert => "+",
ChangeTag::Equal => " ",
};
if use_color {
match change.tag() {
ChangeTag::Delete => print!("{}", format!("{}{}", sign, change).red()),
ChangeTag::Insert => print!("{}", format!("{}{}", sign, change).green()),
ChangeTag::Equal => print!("{}{}", sign, change),
}
} else {
print!("{}{}", sign, change);
}
}
}
}
}
pub fn show_simple_diff(old: &str, new: &str, use_color: bool) {
let diff = TextDiff::from_lines(old, new);
let mut changes = 0;
for op in diff.ops() {
for change in diff.iter_changes(op) {
match change.tag() {
ChangeTag::Delete => {
if use_color {
print!("{}", format!("- {}", change.value()).red());
} else {
print!("- {}", change.value());
}
changes += 1;
}
ChangeTag::Insert => {
if use_color {
print!("{}", format!("+ {}", change.value()).green());
} else {
print!("+ {}", change.value());
}
changes += 1;
}
ChangeTag::Equal => {}
}
}
}
if changes == 0 {
println!("No differences found.");
}
}
pub fn diff_stats(old: &str, new: &str) -> DiffStats {
let diff = TextDiff::from_lines(old, new);
let mut stats = DiffStats::default();
for op in diff.ops() {
for change in diff.iter_changes(op) {
match change.tag() {
ChangeTag::Delete => {
stats.deletions += 1;
stats.lines_removed += 1;
}
ChangeTag::Insert => {
stats.insertions += 1;
stats.lines_added += 1;
}
ChangeTag::Equal => {}
}
}
}
stats
}
#[derive(Debug, Default)]
pub struct DiffStats {
pub insertions: usize,
pub deletions: usize,
pub lines_added: usize,
pub lines_removed: usize,
}
impl DiffStats {
pub fn display(&self, use_color: bool) {
if use_color {
println!(
"{} insertions({}), {} deletions({})",
self.insertions,
"+".green(),
self.deletions,
"-".red()
);
} else {
println!(
"{} insertions(+), {} deletions(-)",
self.insertions, self.deletions
);
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_diff_stats() {
let old = "line1\nline2\nline3\n";
let new = "line1\nline2 modified\nline4\n";
let stats = diff_stats(old, new);
assert!(stats.insertions > 0 || stats.deletions > 0);
}
#[test]
fn test_no_diff() {
let text = "same\ncontent\n";
let stats = diff_stats(text, text);
assert_eq!(stats.insertions, 0);
assert_eq!(stats.deletions, 0);
}
}