use std::{ fs::File, io::{BufRead, BufReader}, path::{Path, PathBuf}, }; use anyhow::Context; use regex::Regex; use crate::matches::{Match, Matches}; pub fn process_files( file_paths: &Vec, pattern: &str, ) -> anyhow::Result { 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> { match file_path.try_exists() { Ok(true) => {} Ok(false) => return Err(anyhow::anyhow!("File path needs to exist")), Err(e) => eprintln!("Error checking path: {e}"), } let path_string = file_path.to_string_lossy().to_string(); let file = File::open(file_path).with_context(|| format!("failed to open file: {path_string}"))?; 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, ) -> anyhow::Result { let reg = Regex::new(pattern).with_context(|| format!("invalid regex: {:?}", pattern))?; let mut matches = Vec::new(); for (idx, line) in iter.enumerate() { let line = line?; if reg.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 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); } }