use std::{
collections::{BTreeMap, HashSet},
path::{Path, PathBuf},
};
use console::style;
use super::ReporterOutput;
use crate::{parser::InjectAction, processor::InjectStatus};
pub struct Output {}
impl Output {}
#[derive(Default)]
struct CalculateData<'a> {
actions: usize,
errors: BTreeMap<&'a PathBuf, &'a String>,
inject_count: usize,
inject_files: HashSet<&'a PathBuf>,
not_found: BTreeMap<&'a PathBuf, HashSet<&'a String>>,
not_found_count: usize,
equal: usize,
}
impl ReporterOutput for Output {
fn start(&mut self) {}
fn end(&mut self) {}
fn report(&self, root_folder: &Path, result: &BTreeMap<PathBuf, InjectStatus>) {
let mut data = CalculateData::default();
for (file, status) in result {
match status {
InjectStatus::Injected(summary) => {
data.actions += summary.actions.len();
for action in &summary.actions {
match action {
InjectAction::Equal { snippet_id: _ } => data.equal += 1,
InjectAction::Injected {
snippet_id: _,
content: _,
} => {
data.inject_files.insert(file);
data.inject_count += 1;
}
InjectAction::NotFound { snippet_id } => {
data.not_found
.entry(file)
.or_insert_with(|| HashSet::from([snippet_id]))
.insert(snippet_id);
data.not_found_count += 1;
}
}
}
}
InjectStatus::None => (),
InjectStatus::Error(err) => {
data.errors.insert(file, err);
}
};
}
println!("==============================");
println!("{}", style(" Snipgrep ").green().bold());
println!("==============================");
println!();
println!("{}", style("Overall Summary:").bold());
println!("Folder : {}", root_folder.display());
println!("Total Files Processed : {}", result.len());
println!("Total Actions Taken : {}", data.actions);
println!();
println!("{}", style("Detailed Summary by Action Type:").bold());
println!("{}", style(format!("Equal : {}", data.equal)).cyan());
println!(
"{}",
style(format!("Injected : {}", style(data.inject_count))).green()
);
if !data.not_found.is_empty() {
println!(
"{}",
style(format!("Not Found : {}", data.not_found_count)).yellow()
);
}
if !data.errors.is_empty() {
println!(
"{}",
style(format!("Error : {}", data.errors.len())).red()
);
}
if !data.not_found.is_empty() {
println!();
println!("{}", style("Not Found:").bold());
let mut entries: Vec<_> = data.not_found.iter().collect();
entries.sort_by(|(file1, _), (file2, _)| file1.cmp(file2));
for (file, snippet_ids) in entries {
let path_view = std::fs::canonicalize(root_folder)
.map(|absolute_path| file.strip_prefix(absolute_path).unwrap_or(file))
.unwrap_or(file);
let mut sorted_snippet_ids: Vec<_> = snippet_ids.iter().copied().collect();
sorted_snippet_ids.sort();
for snippet_id in sorted_snippet_ids {
println!(" - {}, snippet id: {}", path_view.display(), snippet_id);
}
}
}
if !data.errors.is_empty() {
println!();
println!("{}", style("Errors:").bold());
for (file, error_msg) in data.errors {
let path_view = std::fs::canonicalize(root_folder)
.map(|absolute_path| file.strip_prefix(absolute_path).unwrap_or(file))
.unwrap_or(file);
println!(" - {} : {error_msg}", path_view.display());
}
}
if !data.inject_files.is_empty() {
println!();
println!("Injected In Files:");
for file in data.inject_files {
let path_view = std::fs::canonicalize(root_folder)
.map(|absolute_path| file.strip_prefix(absolute_path).unwrap_or(file))
.unwrap_or(file);
println!(" - {}", path_view.display());
}
}
}
}