use std::path::Path;
pub(crate) fn get_code_stats(
root_path: &Path,
ignored_paths: &[&str],
included_paths: Option<Vec<impl AsRef<str>>>,
config: &tokei::Config,
) -> Vec<LanguageCodeStats> {
let mut ls = tokei::Languages::new();
if let Some(included_paths) = included_paths {
let target_paths = included_paths
.iter()
.map(|s| {
let mut p = root_path.to_path_buf();
p.push(s.as_ref());
p
})
.collect::<Vec<_>>();
ls.get_statistics(target_paths.as_slice(), ignored_paths, config);
} else {
ls.get_statistics(&[root_path], ignored_paths, config);
}
let mut res = Vec::with_capacity(ls.len());
for (lang_type, stats) in ls {
res.push(LanguageCodeStats::new(lang_type.to_string(), stats));
}
res
}
pub trait CodeStats {
fn language(&self) -> &str;
fn files(&self) -> usize;
fn lines(&self) -> usize;
fn blanks(&self) -> usize;
fn code(&self) -> usize;
fn comments(&self) -> usize;
fn comments_to_code(&self) -> f64 {
self.comments() as f64 / self.code() as f64
}
#[must_use]
fn summary(&self) -> Self;
}
#[derive(Debug, Clone)]
pub struct LanguageCodeStats {
language: String,
stats: tokei::Language,
}
impl LanguageCodeStats {
#[must_use]
pub fn new(language_name: String, stats: tokei::Language) -> Self {
Self {
language: language_name,
stats,
}
}
#[must_use]
pub fn inaccurate(&self) -> bool {
self.stats.inaccurate
}
#[must_use]
pub fn children(&self) -> Vec<LanguageBlob> {
let mut b = Vec::with_capacity(self.stats.children.len());
for (lang_type, reports) in &self.stats.children {
let mut stats = tokei::CodeStats::new();
for r in reports {
stats += r.stats.clone();
}
b.push(LanguageBlob::new(
lang_type.to_string(),
reports.len(),
stats,
));
}
b
}
}
impl CodeStats for LanguageCodeStats {
fn language(&self) -> &str {
&self.language
}
fn files(&self) -> usize {
self.stats.reports.len()
}
fn lines(&self) -> usize {
self.stats.lines()
}
fn blanks(&self) -> usize {
self.stats.blanks
}
fn code(&self) -> usize {
self.stats.code
}
fn comments(&self) -> usize {
self.stats.comments
}
fn summary(&self) -> LanguageCodeStats {
Self::new(self.language.clone(), self.stats.summarise())
}
}
#[derive(Debug, Clone)]
pub struct LanguageBlob {
language: String,
files: usize,
stats: tokei::CodeStats,
}
impl LanguageBlob {
#[must_use]
pub fn new(
language: String,
files: usize,
stats: tokei::CodeStats,
) -> Self {
Self {
language,
files,
stats,
}
}
#[must_use]
pub fn blobs(&self) -> Vec<LanguageBlob> {
let mut b = Vec::with_capacity(self.stats.blobs.len());
for (lang_type, stats) in &self.stats.blobs {
b.push(LanguageBlob::new(
lang_type.to_string(),
self.files,
stats.clone(),
));
}
b
}
}
impl CodeStats for LanguageBlob {
fn language(&self) -> &str {
&self.language
}
fn files(&self) -> usize {
self.files
}
fn lines(&self) -> usize {
self.stats.lines()
}
fn blanks(&self) -> usize {
self.stats.blanks
}
fn code(&self) -> usize {
self.stats.code
}
fn comments(&self) -> usize {
self.stats.comments
}
fn summary(&self) -> LanguageBlob {
Self::new(self.language.clone(), self.files, self.stats.summarise())
}
}