use std::fs;
use std::io::Write;
use colored::*;
use crate::types::GroupedMatches;
pub trait DiffFormatter {
fn print_preamble(&self, out: &mut dyn Write);
fn print_index(&self, groups: &Vec<GroupedMatches>, out: &mut dyn Write);
fn print_contents(&self, groups: &Vec<GroupedMatches>, out: &mut dyn Write);
}
pub struct DiffMarkdownFormatter;
pub struct DiffCliFormatter {
pub colored: bool,
pub align_tags: bool, }
impl DiffFormatter for DiffMarkdownFormatter {
fn print_preamble(&self, out: &mut dyn Write) {
writeln!(out, "# π¦ Cross-file Diff Report\n").unwrap();
}
fn print_index(&self, groups: &Vec<GroupedMatches>, out: &mut dyn Write) {
writeln!(out, "## π File Pairs\n").unwrap();
for g in groups {
writeln!(out, "- {} β {}", g.from_file, g.to_file).unwrap();
}
writeln!(out).unwrap();
}
fn print_contents(&self, groups: &Vec<GroupedMatches>, out: &mut dyn Write) {
writeln!(out, "## π Diff Contents\n").unwrap();
for g in groups {
writeln!(out, "### {} β {}\n", g.from_file, g.to_file).unwrap();
writeln!(out, "```python").unwrap();
if let Ok(src) = fs::read_to_string(&g.from_file) {
let lines: Vec<&str> = src.lines().collect();
let max_len = lines.iter().map(|l| l.len()).max().unwrap_or(0);
for (lineno, line) in lines.iter().enumerate() {
let mut tag = String::new();
for bwv in &g.blocks {
let m = &bwv.block;
let status = if bwv.is_addition { "[ADDED]" } else { "[MOVED]" };
if lineno >= m.from_range.0 && lineno < m.from_range.1 {
tag = format!(
" // {} ({}β{} β {}β{})",
status,
m.from_range.0, m.from_range.1,
m.to_file, m.to_range.0
);
break;
}
}
writeln!(out, "{:>4} {}", lineno + 1, line).unwrap();
if !tag.is_empty() {
writeln!(out, "{:>width$}{}", "", tag, width = 6 + max_len).unwrap();
}
}
}
writeln!(out, "```\n").unwrap();
}
}
}
impl DiffFormatter for DiffCliFormatter {
fn print_preamble(&self, out: &mut dyn Write) {
if self.colored {
writeln!(out, "{}\n", "π¦ Cross-file Diff Report".bright_magenta().bold()).unwrap();
} else {
writeln!(out, "π¦ Cross-file Diff Report\n").unwrap();
}
}
fn print_index(&self, groups: &Vec<GroupedMatches>, out: &mut dyn Write) {
writeln!(out, "π File Pairs").unwrap();
for g in groups {
if self.colored {
writeln!(
out,
"{} {} {}",
g.from_file.truecolor(0, 255, 255),
"β".bright_magenta(),
g.to_file.truecolor(0, 255, 255)
).unwrap();
} else {
writeln!(out, "- {} β {}", g.from_file, g.to_file).unwrap();
}
}
writeln!(out).unwrap();
}
fn print_contents(&self, groups: &Vec<GroupedMatches>, out: &mut dyn Write) {
for g in groups {
if self.colored {
writeln!(
out,
"{} {} {}",
g.from_file.truecolor(0, 255, 255),
"β".bright_magenta(),
g.to_file.truecolor(0, 255, 255)
).unwrap();
} else {
writeln!(out, "{} β {}", g.from_file, g.to_file).unwrap();
}
if let Ok(src) = fs::read_to_string(&g.from_file) {
let lines: Vec<&str> = src.lines().collect();
let max_len = lines.iter().map(|l| l.len()).max().unwrap_or(0);
for (lineno, line) in lines.iter().enumerate() {
let mut tag = String::new();
for bwv in &g.blocks {
let m = &bwv.block;
let status = if bwv.is_addition { "[ADDED]" } else { "[MOVED]" };
if lineno >= m.from_range.0 && lineno < m.from_range.1 {
tag = format!(
" {} ({}β{} β {}β{})",
status,
m.from_range.0, m.from_range.1,
m.to_file, m.to_range.0
);
break;
}
}
if self.align_tags {
if self.colored {
writeln!(
out,
"{:>4} {:<width$}{}",
lineno + 1,
line,
tag.bright_yellow(),
width = max_len + 1
).unwrap();
} else {
writeln!(
out,
"{:>4} {:<width$}{}",
lineno + 1,
line,
tag,
width = max_len + 1
).unwrap();
}
} else {
if self.colored {
writeln!(
out,
"{:>4} {}{}",
lineno + 1,
line,
tag.bright_yellow()
).unwrap();
} else {
writeln!(out, "{:>4} {}{}", lineno + 1, line, tag).unwrap();
}
}
}
}
writeln!(out).unwrap();
}
}
}