use std::{ fs::File, io::{BufRead, BufReader}, path::{Path, PathBuf}, }; use anyhow::Context; use regex::{Regex, RegexBuilder}; use crate::{ cli::CliOptions, matches::{Match, Matches}, }; pub fn process_files( file_paths: &Vec, pattern: &str, cli_options: &CliOptions, ) -> anyhow::Result { let reg = RegexBuilder::new(pattern) .case_insensitive(cli_options.ignore_case) .build() .with_context(|| format!("invalid regex: {:?}", pattern))?; let mut matches = Matches { items: vec![], pattern: String::from(pattern) }; for file_path in file_paths { let lines_iter = read_lines(file_path)?; let mut _matches = match_pattern(lines_iter, pattern, file_path, ®)?; matches.append(&mut _matches); } // let lines_iter = read_lines(file_path)?; // let matches = match_pattern(lines_iter, pattern, file_path)?; Ok(matches) } pub fn read_lines( file_path: &Path, ) -> anyhow::Result>, anyhow::Error> { let file = File::open(file_path) .with_context(|| format!("failed to open file: {}", file_path.display()))?; let reader = BufReader::new(file); Ok(reader.lines()) } fn get_file_name_from_path(file_path: &Path) -> String { match file_path.file_name() { Some(name) => name.to_string_lossy().to_string(), None => String::from("unknown"), } } pub fn match_pattern( iter: impl Iterator>, pattern: &str, file_path: &Path, regex: &Regex, ) -> anyhow::Result { let mut matches = Vec::new(); for (idx, line) in iter.enumerate() { let line = line?; if regex.is_match(&line) { let m = Match { line_number: idx + 1, text: line, file_name: get_file_name_from_path(file_path), }; matches.push(m); } } Ok(Matches { items: matches, pattern: String::from(pattern) }) } #[cfg(test)] mod tests { use super::*; #[test] fn test_get_file_name_from_path() { let path = Path::new("/path/to/file.txt"); let file_name = get_file_name_from_path(path); assert_eq!(file_name, "file.txt"); let path = Path::new("file.txt"); let file_name = get_file_name_from_path(path); assert_eq!(file_name, "file.txt"); } #[test] fn matches_lines_and_tracks_line_numbers() { let input: Vec> = vec![Ok("hola".into()), Ok("no".into()), Ok("hola again".into())]; let reg = Regex::new("hola").unwrap(); let result = match_pattern(input.into_iter(), r"^hola", Path::new("/tmp/test.txt"), ®).unwrap(); assert_eq!(result.items.len(), 2); assert_eq!(result.items[0].text, "hola"); assert_eq!(result.items[0].line_number, 1); assert_eq!(result.items[0].file_name, "test.txt"); assert_eq!(result.items[1].text, "hola again"); assert_eq!(result.items[1].line_number, 3); } }