Skip to content

Commit

Permalink
Merge pull request #2 from kqito/fix-compiled-too-big
Browse files Browse the repository at this point in the history
Improve grep system
  • Loading branch information
kqito authored Jan 3, 2025
2 parents ad2f86b + e59d96f commit 924ee9b
Show file tree
Hide file tree
Showing 9 changed files with 202 additions and 140 deletions.
52 changes: 52 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 @@ -21,6 +21,7 @@ thiserror = "1.0.61"
argh = "0.1.10"
atty = "0.2.14"
walkdir = "2"
rayon = "1.10.0"

[dev-dependencies]
pretty_assertions = "1.4.0"
Expand Down
1 change: 0 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,6 @@ Positional Arguments:

Options:
-d, --debug help
-u, --unique unique Omit duplicate paths
--help display usage information
```

Expand Down
11 changes: 6 additions & 5 deletions src/args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,6 @@ pub struct Args {
/// help
pub debug: Option<bool>,

#[argh(switch, short = 'u')]
/// unique
/// Omit duplicate paths
pub unique: Option<bool>,

#[argh(option, short = 'c')]
/// current_dir
/// Set the current directory
Expand All @@ -30,6 +25,12 @@ pub struct Args {
/// ignore
/// Ignore pattern
pub ignore: Vec<String>,

#[argh(option, short = 't')]
/// filetype
/// Filter by type: file (f), directory (d/dir), symlink (l)
/// Default: file (f)
pub filetype: Vec<String>,
}

pub fn get_input() -> Result<Option<String>> {
Expand Down
57 changes: 28 additions & 29 deletions src/grep/finder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,30 +2,26 @@ use regex::Regex;
use std::fmt::Debug;
use walkdir::{DirEntry, WalkDir};

use super::params::Filetype;

#[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,
pub filetype: Filetype,
}

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

pub trait Finder: FinderClone + Debug {
pub trait Finder: FinderClone + Debug + Sync + Send {
fn current_dir(&mut self, current_dir: &str);
fn ignore(&mut self, ignore: Vec<String>);
fn find(&mut self) -> Stats;
Expand Down Expand Up @@ -87,12 +83,20 @@ impl Finder for IOFinder {

for entry in walker.filter_entry(|e| !self.is_ignored(e)) {
if let Ok(entry) = entry {
let path_str = entry.path().to_str().unwrap();
// omit "./" prefix
let path = if path_str.starts_with("./") {
path_str[2..].to_string()
} else {
path_str.to_string()
};

resources.push(Resource {
path: entry.path().to_str().unwrap().to_string(),
resource_type: if entry.file_type().is_dir() {
ResourceType::Directory
path,
filetype: if entry.file_type().is_dir() {
Filetype::Directory
} else {
ResourceType::File
Filetype::File
},
});
}
Expand All @@ -102,23 +106,18 @@ impl Finder for IOFinder {
}
}

impl Stats {
impl Resource {
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()
match self.filetype {
Filetype::Directory => {
let path = self.path.replace("/", r"\/");
Regex::new(&format!(r"{}", path)).unwrap()
}
// Support for line and column numbers
Filetype::File => {
let path = self.path.replace("/", r"\/");
Regex::new(&format!(r"{}(:\d+:\d+)?", path)).unwrap()
}
}
}
}
101 changes: 57 additions & 44 deletions src/grep/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,13 @@ mod finder;
pub mod params;
mod tests;

use params::GrepParams;

use crate::output::{pretty_print, Status};
use params::{Filetype, GrepParams};
use rayon::prelude::*;
use std::{
fmt::Debug,
sync::{Arc, RwLock},
};

#[derive(Debug, PartialEq)]
pub enum GrepItemType {
Expand All @@ -18,68 +22,77 @@ pub struct GrepItem {
pub line: Option<usize>,
pub column: Option<usize>,
pub item_type: GrepItemType,
pub filetype: Filetype,
}

/// Extract path in string message with regex
pub fn grep(params: &GrepParams) -> Vec<GrepItem> {
let mut items: Vec<GrepItem> = Vec::new();
let mut finder = params.finder.clone();
finder.current_dir(&params.current_dir);
finder.ignore(params.ignore_pattern.clone());
let find_list = finder.find();
let finder = Arc::new(RwLock::new(params.finder.clone()));
let mut finder_lock = finder.write().unwrap();
finder_lock.current_dir(&params.current_dir);
finder_lock.ignore(params.ignore_pattern.clone());
let find_list = finder_lock.find();
drop(finder_lock);

if params.debug {
pretty_print(&format!("Content: {:#?}", &params.content), Status::Info);
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();
let items: Vec<_> = find_list
.resources
.par_iter()
.filter_map(|r| {
// Improve performance by checking if it matches without using regular expressions
if !params.content.contains(&r.path) {
return None;
}

if params.debug {
pretty_print(&format!("Matched: {}", &r.path), Status::Info);
}

let path = parts.get(0).unwrap().to_string();
let line: Option<usize> = match parts.get(1) {
Some(line) => match line.parse::<usize>() {
let numbers = match r.as_regex().find(&params.content) {
Some(numbers) => numbers,
None => return None,
};
let line = match numbers.as_str().parse::<usize>() {
Ok(line) => Some(line),
Err(_) => None,
},
None => None,
};

let column: Option<usize> = match parts.get(2) {
Some(column) => match column.parse::<usize>() {
};
let column = match numbers.as_str().parse::<usize>() {
Ok(column) => Some(column),
Err(_) => None,
},
None => None,
};

let item_type = match path.starts_with('/') {
true => GrepItemType::AbsolutePath,
false => GrepItemType::RelativePath,
};
};
let item_type = match &r.path.starts_with('/') {
true => GrepItemType::AbsolutePath,
false => GrepItemType::RelativePath,
};

items.push(GrepItem {
path,
line,
column,
item_type,
});
}
Some(GrepItem {
path: r.path.clone(),
line,
column,
item_type,
filetype: r.filetype.clone(),
})
})
.collect();

let mut unique_items: Vec<GrepItem> = items.into_iter().collect();
// dedup by item.path
items.sort_by(|a, b| {
unique_items.sort_by(|a, b| {
a.path
.partial_cmp(&b.path)
.unwrap_or(std::cmp::Ordering::Equal)
});
if params.unique {
items.dedup_by(|a, b| a.path == b.path);
}
unique_items.dedup_by(|a, b| a.path == b.path);

// filetypeでのフィルタリング
unique_items.retain(|item| match item.filetype {
Filetype::File => params.filetype.contains(&Filetype::File),
Filetype::Directory => params.filetype.contains(&Filetype::Directory),
});

items
unique_items
}
Loading

0 comments on commit 924ee9b

Please sign in to comment.