From 660b710caced45f0af887d17a81aae6fcea141e2 Mon Sep 17 00:00:00 2001 From: Mohammad Kanaan Date: Mon, 27 Jul 2026 12:53:58 +0300 Subject: [PATCH] feat: improve match_pattern to surface errors and avoid collecting everything at once feat: implement Match and Matches to hold more info and display it --- src/main.rs | 5 +++-- src/matches.rs | 33 +++++++++++++++++++++++++++++++++ src/parser.rs | 30 ++++++++++++++++++++++++++---- 3 files changed, 62 insertions(+), 6 deletions(-) create mode 100644 src/matches.rs diff --git a/src/main.rs b/src/main.rs index 4ee69c7..6087b71 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,4 +1,5 @@ use clap::Parser; +mod matches; mod parser; #[derive(Parser)] @@ -11,12 +12,12 @@ fn main() -> anyhow::Result<()> { let cli = Cli::parse(); let lines_iter = parser::read_lines(&cli.file_path)?; - let matches = parser::match_pattern(lines_iter, &cli.pattern); + let matches = parser::match_pattern(lines_iter, &cli.pattern, &cli.file_path); println!("Pattern: {}", cli.pattern); println!("File path: {}", cli.file_path); println!("---"); - println!("{:?}", matches); + println!("{}", matches?); Ok(()) } diff --git a/src/matches.rs b/src/matches.rs new file mode 100644 index 0000000..03fa838 --- /dev/null +++ b/src/matches.rs @@ -0,0 +1,33 @@ +use std::fmt::Display; + +pub struct Match { + pub file_name: String, + pub line_number: usize, + pub text: String, +} + +pub struct Matches { + pub items: Vec, + pub pattern: String, +} + +impl Display for Match { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}: line {}: {}", self.file_name, self.line_number, self.text) + } +} + +impl Display for Matches { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + writeln!(f, "Matches for pattern {}:", self.pattern); + + for (idx, item) in self.items.iter().enumerate() { + if idx > 0 { + writeln!(f)?; + } + + write!(f, "{}", item); + } + write!(f, "{}", "") + } +} diff --git a/src/parser.rs b/src/parser.rs index dfe7a6d..43d2df6 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -6,6 +6,8 @@ use std::{ use anyhow::Context; use regex::Regex; +use crate::matches::{self, Match, Matches}; + pub fn read_lines( file_path: &str, ) -> anyhow::Result>, anyhow::Error> { @@ -20,14 +22,34 @@ pub fn read_lines( Ok(reader.lines()) } +fn get_file_name_from_path(file_path: &str) -> String { + match file_path.rsplit('/').next() { + Some(name) => name.into(), + None => file_path.into(), + } +} + pub fn match_pattern( iter: impl Iterator>, pattern: &str, -) -> anyhow::Result, anyhow::Error> { + file_path: &str, +) -> anyhow::Result { let reg = Regex::new(pattern).with_context(|| format!("invalid regex: {:?}", pattern))?; - let lines = iter.collect::>>()?; + let mut matches = Vec::new(); - let matches = lines.into_iter().filter(|line| reg.is_match(line)).collect::>(); + for (idx, line) in iter.enumerate() { + let line = line?; - Ok(matches) + if reg.is_match(&line) { + let m = Match { + line_number: idx, + text: line, + file_name: get_file_name_from_path(file_path), + }; + + matches.push(m); + } + } + + Ok(Matches { items: matches, pattern: String::from(pattern) }) }