Skip to content

Commit

Permalink
Merge pull request #1 from kqito/update-matching-logic
Browse files Browse the repository at this point in the history
Improved the matching system
  • Loading branch information
kqito committed Jan 1, 2025
2 parents eb407d9 + d1a5ad7 commit 1be3457
Show file tree
Hide file tree
Showing 14 changed files with 518 additions and 257 deletions.
102 changes: 102 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ regex = "1.10.4"
thiserror = "1.0.61"
argh = "0.1.10"
atty = "0.2.14"
walkdir = "2"

[dev-dependencies]
pretty_assertions = "1.4.0"
Expand Down
37 changes: 33 additions & 4 deletions src/args.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
use std::io::{self, Read};

use anyhow::Result;
use argh::FromArgs;

#[derive(FromArgs, PartialEq, Debug)]
Expand All @@ -16,8 +19,34 @@ pub struct Args {
/// Omit duplicate paths
pub unique: Option<bool>,

#[argh(switch)]
/// no-validate
/// Skip validation of the file
pub no_validate: Option<bool>,
#[argh(option, short = 'c')]
/// current_dir
/// Set the current directory
/// Default: "."
/// Example: /path/to/dir
pub current_dir: Option<String>,

#[argh(option, short = 'i')]
/// ignore
/// Ignore pattern
pub ignore: Vec<String>,
}

pub fn get_input() -> Result<Option<String>> {
let mut pipeline_input = String::new();
let is_piped = atty::isnt(atty::Stream::Stdin);

if is_piped {
if io::stdin().read_to_string(&mut pipeline_input).is_err() {
return Err(anyhow::anyhow!("Failed to read from stdin"));
}
}

let content = if pipeline_input == "" {
Ok(None)
} else {
Ok(Some(pipeline_input))
};

content
}
124 changes: 124 additions & 0 deletions src/grep/finder.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
use regex::Regex;
use std::fmt::Debug;
use walkdir::{DirEntry, WalkDir};

#[derive(Debug, Clone)]
pub struct IOFinder {
pub current_dir: String,
pub ignore_pattern: Vec<String>,
}

#[derive(Debug, Clone)]
pub enum ResourceType {
Directory,
File,
}

#[derive(Debug, Clone)]
pub struct Resource {
pub path: String,
pub resource_type: ResourceType,
}

#[derive(Debug, Clone)]
pub struct Stats {
pub resources: Vec<Resource>,
}

pub trait Finder: FinderClone + Debug {
fn current_dir(&mut self, current_dir: &str);
fn ignore(&mut self, ignore: Vec<String>);
fn find(&mut self) -> Stats;
}

pub trait FinderClone {
fn clone_box(&self) -> Box<dyn Finder>;
}

impl<T> FinderClone for T
where
T: 'static + Finder + Clone,
{
fn clone_box(&self) -> Box<dyn Finder> {
Box::new(self.clone())
}
}

impl Clone for Box<dyn Finder> {
fn clone(&self) -> Box<dyn Finder> {
self.clone_box()
}
}

impl IOFinder {
pub fn new() -> Self {
Self {
current_dir: ".".to_string(),
ignore_pattern: vec![],
}
}

fn is_ignored(&self, entry: &DirEntry) -> bool {
let path = entry.path();
let path_str = path.to_str().unwrap();

for pattern in &self.ignore_pattern {
if path_str.contains(pattern) {
return true;
}
}

false
}
}

impl Finder for IOFinder {
fn current_dir(&mut self, current_dir: &str) {
self.current_dir = current_dir.to_string();
}

fn ignore(&mut self, ignore: Vec<String>) {
self.ignore_pattern = ignore;
}

fn find(&mut self) -> Stats {
let mut resources: Vec<Resource> = Vec::new();
let walker = WalkDir::new(&self.current_dir).into_iter();

for entry in walker.filter_entry(|e| !self.is_ignored(e)) {
if let Ok(entry) = entry {
resources.push(Resource {
path: entry.path().to_str().unwrap().to_string(),
resource_type: if entry.file_type().is_dir() {
ResourceType::Directory
} else {
ResourceType::File
},
});
}
}

Stats { resources }
}
}

impl Stats {
pub fn as_regex(&self) -> Regex {
let mut matches: Vec<String> = self
.resources
.iter()
.map(|r| {
let path = r.path.replace("/", r"\/");
match r.resource_type {
ResourceType::Directory => format!(r"{}", path),
// Support for line and column numbers
ResourceType::File => format!(r"{}(:\d+:\d+)?", path),
}
})
.collect();
matches.sort_by(|a, b| b.len().cmp(&a.len()));

let pattern = matches.join("|");
Regex::new(&pattern).unwrap()
}
}
37 changes: 22 additions & 15 deletions src/grep/mod.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
mod finder;
pub mod params;
mod tests;

use std::path::Path;

use params::GrepParams;
use regex::Regex;

use crate::output::{pretty_print, Status};

#[derive(Debug, PartialEq)]
pub enum GrepItemType {
Expand All @@ -23,12 +23,25 @@ pub struct GrepItem {
/// Extract path in string message with regex
pub fn grep(params: &GrepParams) -> Vec<GrepItem> {
let mut items: Vec<GrepItem> = Vec::new();
let regex = Regex::new(r"([a-zA-Z0-9_\-./]+(\.[a-zA-Z0-9_\-]+)+)").unwrap();
let mut finder = params.finder.clone();
finder.current_dir(&params.current_dir);
finder.ignore(params.ignore_pattern.clone());
let find_list = finder.find();

if params.debug {
pretty_print(&format!("Finder: {:#?}", &find_list), Status::Info);
pretty_print(
&format!("Finder Regex: {:#?}", &find_list.as_regex()),
Status::Info,
);
}

// Iterate over all matches in the content
for cap in find_list.as_regex().captures_iter(&params.content) {
let matched = cap[0].to_string();
let parts: Vec<&str> = matched.split(':').collect();

// Iterate over all matches in the message
for cap in regex.captures_iter(&params.content) {
let path = cap[0].to_string();
let parts: Vec<&str> = path.split(':').collect();
let path = parts.get(0).unwrap().to_string();
let line: Option<usize> = match parts.get(1) {
Some(line) => match line.parse::<usize>() {
Ok(line) => Some(line),
Expand All @@ -50,12 +63,6 @@ pub fn grep(params: &GrepParams) -> Vec<GrepItem> {
false => GrepItemType::RelativePath,
};

if params.validate {
if !Path::new(&path).exists() {
continue;
}
}

items.push(GrepItem {
path,
line,
Expand All @@ -64,7 +71,7 @@ pub fn grep(params: &GrepParams) -> Vec<GrepItem> {
});
}

// debup by item.path
// dedup by item.path
items.sort_by(|a, b| {
a.path
.partial_cmp(&b.path)
Expand Down
Loading

0 comments on commit 1be3457

Please sign in to comment.