use std::time::Duration;
use serde::Serialize;
use crate::report_helpers;
#[derive(Debug, Serialize)]
pub struct LanguageReport {
pub name: String,
pub files: usize,
pub blank: usize,
pub comment: usize,
pub code: usize,
}
pub struct VerboseStats {
pub total_files: usize,
pub unique_files: usize,
pub duplicate_files: usize,
pub binary_files: usize,
pub elapsed: Duration,
}
const COL_LANG: usize = 20;
const COL_FILES: usize = 8;
const COL_NUM: usize = 12;
const SEP_WIDTH: usize = 1 + COL_LANG + 1 + COL_FILES + 1 + COL_NUM + 1 + COL_NUM + 1 + COL_NUM;
pub fn print_report(mut reports: Vec<LanguageReport>, verbose: Option<VerboseStats>) {
reports.sort_by(|a, b| b.code.cmp(&a.code));
if let Some(stats) = &verbose {
let secs = stats.elapsed.as_secs_f64();
let files_per_sec = if secs > 0.0 {
stats.unique_files as f64 / secs
} else {
0.0
};
let total_lines: usize = reports.iter().map(|r| r.blank + r.comment + r.code).sum();
let lines_per_sec = if secs > 0.0 {
total_lines as f64 / secs
} else {
0.0
};
println!("{:>8} text files.", stats.total_files);
println!("{:>8} unique files.", stats.unique_files);
println!("{:>8} files ignored (duplicates).", stats.duplicate_files);
println!("{:>8} files ignored (binary).", stats.binary_files);
println!(
"T={:.2} s ({:.1} files/s, {:.1} lines/s)",
secs, files_per_sec, lines_per_sec
);
println!();
}
let separator = report_helpers::separator(SEP_WIDTH);
println!("{separator}");
println!(
" {:<COL_LANG$} {:>COL_FILES$} {:>COL_NUM$} {:>COL_NUM$} {:>COL_NUM$}",
"Language", "Files", "Blank", "Comment", "Code"
);
println!("{separator}");
let mut total_files = 0usize;
let mut total_blank = 0usize;
let mut total_comment = 0usize;
let mut total_code = 0usize;
for r in &reports {
println!(
" {:<COL_LANG$} {:>COL_FILES$} {:>COL_NUM$} {:>COL_NUM$} {:>COL_NUM$}",
r.name, r.files, r.blank, r.comment, r.code
);
total_files += r.files;
total_blank += r.blank;
total_comment += r.comment;
total_code += r.code;
}
println!("{separator}");
println!(
" {:<COL_LANG$} {:>COL_FILES$} {:>COL_NUM$} {:>COL_NUM$} {:>COL_NUM$}",
"SUM:", total_files, total_blank, total_comment, total_code
);
println!("{separator}");
}
#[derive(Serialize)]
struct JsonOutput {
languages: Vec<LanguageReport>,
totals: JsonTotals,
}
#[derive(Serialize)]
struct JsonTotals {
files: usize,
blank: usize,
comment: usize,
code: usize,
}
pub fn print_json(mut reports: Vec<LanguageReport>) {
reports.sort_by(|a, b| b.code.cmp(&a.code));
let totals = JsonTotals {
files: reports.iter().map(|r| r.files).sum(),
blank: reports.iter().map(|r| r.blank).sum(),
comment: reports.iter().map(|r| r.comment).sum(),
code: reports.iter().map(|r| r.code).sum(),
};
let output = JsonOutput {
languages: reports,
totals,
};
report_helpers::print_json_stdout(&output).unwrap();
}
#[derive(Debug, Serialize)]
pub struct AuthorReport {
pub name: String,
pub email: String,
pub files: usize,
pub blank: usize,
pub comment: usize,
pub code: usize,
}
pub fn print_author_report(mut reports: Vec<AuthorReport>) {
reports.sort_by(|a, b| b.code.cmp(&a.code));
let col_author = reports
.iter()
.map(|r| report_helpers::display_width(r.name.as_str()))
.max()
.unwrap_or(0)
.max(report_helpers::display_width("Author"));
let sep_width = 1 + col_author + 1 + COL_FILES + 1 + COL_NUM + 1 + COL_NUM + 1 + COL_NUM;
let separator = report_helpers::separator(sep_width);
println!("{separator}");
println!(
" {} {:>COL_FILES$} {:>COL_NUM$} {:>COL_NUM$} {:>COL_NUM$}",
report_helpers::pad_to("Author", col_author),
"Files",
"Blank",
"Comment",
"Code"
);
println!("{separator}");
let mut total_files = 0usize;
let mut total_blank = 0usize;
let mut total_comment = 0usize;
let mut total_code = 0usize;
for r in &reports {
println!(
" {} {:>COL_FILES$} {:>COL_NUM$} {:>COL_NUM$} {:>COL_NUM$}",
report_helpers::pad_to(&r.name, col_author),
r.files,
r.blank,
r.comment,
r.code
);
total_files += r.files;
total_blank += r.blank;
total_comment += r.comment;
total_code += r.code;
}
println!("{separator}");
println!(
" {} {:>COL_FILES$} {:>COL_NUM$} {:>COL_NUM$} {:>COL_NUM$}",
report_helpers::pad_to("SUM:", col_author),
total_files,
total_blank,
total_comment,
total_code
);
println!("{separator}");
}
pub fn print_author_json(mut reports: Vec<AuthorReport>) {
reports.sort_by(|a, b| b.code.cmp(&a.code));
#[derive(Serialize)]
struct JsonOutput {
authors: Vec<AuthorReport>,
totals: JsonTotals,
}
let totals = JsonTotals {
files: reports.iter().map(|r| r.files).sum(),
blank: reports.iter().map(|r| r.blank).sum(),
comment: reports.iter().map(|r| r.comment).sum(),
code: reports.iter().map(|r| r.code).sum(),
};
report_helpers::print_json_stdout(&JsonOutput {
authors: reports,
totals,
})
.unwrap();
}
#[cfg(test)]
#[path = "report_test.rs"]
mod tests;