use std::fmt::{self, Write};
use console::{Style, style};
use similar::{ChangeTag, TextDiff};
#[derive(Debug)]
struct Line(Option<usize>);
impl fmt::Display for Line {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self.0 {
None => write!(f, " "),
Some(idx) => write!(f, "{:>4}", idx + 1),
}
}
}
pub(crate) fn diff(old: &str, new: &str) -> String {
let diff = TextDiff::from_lines(old, new);
let mut output = String::new();
for (idx, group) in diff.grouped_ops(3).iter().enumerate() {
if idx > 0 {
writeln!(&mut output, "{0:─^1$}┼{0:─^2$}", "─", 9, 120).unwrap();
}
for op in group {
for change in diff.iter_inline_changes(op) {
let (sign, s) = match change.tag() {
ChangeTag::Delete => ("-", Style::new().red()),
ChangeTag::Insert => ("+", Style::new().green()),
ChangeTag::Equal => (" ", Style::new().dim()),
};
write!(
&mut output,
"{}{} │{}",
style(Line(change.old_index())).dim(),
style(Line(change.new_index())).dim(),
s.apply_to(sign).bold(),
)
.unwrap();
for (emphasized, value) in change.iter_strings_lossy() {
if emphasized {
write!(&mut output, "{}", s.apply_to(value).underlined().on_black())
.unwrap();
} else {
write!(&mut output, "{}", s.apply_to(value)).unwrap();
}
}
if change.missing_newline() {
writeln!(&mut output).unwrap();
}
}
}
}
output
}