use std::fmt; use std::fs::read; use std::process::exit; use console::{style, Style}; use similar::{ChangeTag, TextDiff}; struct Line(Option); 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), } } } fn main() { let args: Vec<_> = std::env::args_os().collect(); if args.len() != 3 { eprintln!("usage: terminal-inline [old] [new]"); exit(1); } let old = read(&args[1]).unwrap(); let new = read(&args[2]).unwrap(); let diff = TextDiff::from_lines(&old, &new); for (idx, group) in diff.grouped_ops(3).iter().enumerate() { if idx > 0 { println!("{:-^1$}", "-", 80); } 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()), }; print!( "{}{} |{}", style(Line(change.old_index())).dim(), style(Line(change.new_index())).dim(), s.apply_to(sign).bold(), ); for (emphasized, value) in change.iter_strings_lossy() { if emphasized { print!("{}", s.apply_to(value).underlined().on_black()); } else { print!("{}", s.apply_to(value)); } } if change.missing_newline() { println!(); } } } } }