use crate::config::Config;
use crate::core_types::FileInfo;
use crate::errors::{io_error_with_path, AppError};
use anyhow::{Context, Result};
use log::debug;
use rayon::prelude::*;
use std::fs; use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
mod content_filters;
mod content_reader;
mod counter;
use content_filters::{remove_comments, remove_empty_lines};
use content_reader::read_file_content; use counter::calculate_counts;
pub fn process_batch(
files: &mut [FileInfo], config: &Config,
stop_signal: Arc<AtomicBool>,
) -> Result<()> {
if files.is_empty() {
debug!("No files in this batch to process.");
return Ok(());
}
debug!("Starting parallel processing for {} files.", files.len());
files
.par_iter_mut()
.try_for_each(|file_info| -> Result<()> {
if !stop_signal.load(Ordering::Relaxed) {
return Err(AppError::Interrupted.into());
}
debug!(
"Processing file: {} (Binary: {})",
file_info.absolute_path.display(),
file_info.is_binary
);
let original_content_str: String;
let original_content_bytes: Vec<u8>;
if file_info.is_binary {
original_content_bytes = fs::read(&file_info.absolute_path)
.map_err(|e| io_error_with_path(e, &file_info.absolute_path))
.with_context(|| {
format!(
"Failed to read binary file content: {}",
file_info.absolute_path.display()
)
})?;
original_content_str = String::from_utf8_lossy(&original_content_bytes).to_string();
debug!(
"Read {} bytes from binary file {}",
original_content_bytes.len(),
file_info.relative_path.display()
);
} else {
original_content_str = read_file_content(&file_info.absolute_path)?;
original_content_bytes = original_content_str.as_bytes().to_vec(); debug!(
"Read {} bytes from text file {}",
original_content_bytes.len(),
file_info.relative_path.display()
);
}
if config.counts {
if file_info.is_binary {
file_info.counts = Some(crate::core_types::FileCounts {
lines: 0, characters: original_content_bytes.len(),
words: 0,
});
} else {
file_info.counts = Some(calculate_counts(&original_content_str));
}
debug!(
"Calculated counts for {}: {:?}",
file_info.relative_path.display(),
file_info.counts
);
}
let mut processed_content = original_content_str;
if !file_info.is_binary {
if config.remove_comments {
processed_content = remove_comments(&processed_content);
debug!(
"Applied comment removal to {}",
file_info.relative_path.display()
);
}
if config.remove_empty_lines {
processed_content = remove_empty_lines(&processed_content);
debug!(
"Applied empty line removal to {}",
file_info.relative_path.display()
);
}
} else {
debug!(
"Skipping content filters for binary file {}",
file_info.relative_path.display()
);
}
file_info.processed_content = Some(processed_content);
Ok(())
})?;
debug!("Finished processing batch of {} files.", files.len());
Ok(())
}