Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add flag to exclude directories from filtering #35

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 22 additions & 1 deletion src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ pub struct SearchBuilder {
hidden: bool,
/// Filters Vector, defaults to empty vec
filters: Vec<FilterType>,
/// When set to false, will not apply filters to directories and will exclude them from results.
dirs: bool,
}

impl SearchBuilder {
Expand All @@ -42,6 +44,7 @@ impl SearchBuilder {
self.ignore_case,
self.hidden,
self.filters.clone(),
self.dirs,
)
}

Expand Down Expand Up @@ -201,7 +204,7 @@ impl SearchBuilder {
/// use rust_search::SearchBuilder;
///
/// let search: Vec<String> = SearchBuilder::default()
/// .with_hidden()
/// .hidden()
/// .build()
/// .collect();
/// ```
Expand Down Expand Up @@ -233,6 +236,23 @@ impl SearchBuilder {
);
self
}

/// Choose whether to apply filters to directories and include matches in search results. Defaults to true.
/// ### Arguments
/// * `value`
/// ### Examples
/// ```rust
/// use rust_search::SearchBuilder;
///
/// let search: Vec<String> = SearchBuilder::default()
/// .dirs(false)
/// .build()
/// .collect();
/// ```
pub fn dirs(mut self, value: bool) -> Self {
self.dirs = value;
self
}
}

impl Default for SearchBuilder {
Expand All @@ -249,6 +269,7 @@ impl Default for SearchBuilder {
ignore_case: false,
hidden: false,
filters: vec![],
dirs: true,
}
}
}
9 changes: 7 additions & 2 deletions src/filter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,11 @@ pub enum FilterType {
}

impl FilterType {
pub fn apply(&self, dir: &DirEntry) -> bool {
pub fn apply(&self, dir: &DirEntry, filter_dirs: bool) -> bool {
if let Ok(m) = dir.metadata() {
if !filter_dirs && m.file_type().is_dir() {
return true;
}
match self {
Self::Created(cmp, time) => {
if let Ok(created) = m.created() {
Expand Down Expand Up @@ -94,7 +97,9 @@ pub trait FilterExt {
fn file_size_greater(self, size: FileSize) -> Self;
/// custom filter that exposes the [`DirEntry`] directly
/// ```rust
/// builder.custom_filter(|dir| dir.metadata().unwrap().is_file())
/// # use rust_search::FilterExt;
/// # let builder = rust_search::SearchBuilder::default();
/// builder.custom_filter(|dir| dir.metadata().unwrap().is_file());
/// ```
fn custom_filter(self, f: FilterFn) -> Self;
}
Expand Down
25 changes: 19 additions & 6 deletions src/search.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@ use regex::Regex;
///
/// ## Iterate on the results
///
/// ```
/// ```ignore
/// use rust_search::Search;
///
/// let search = Search::new("src", None, Some(".rs"), Some(1));
/// let search = Search::new("src", None, None, Some(".rs"), Some(1), None, false, false, false, vec![], true);
///
/// for path in search {
/// println!("{:?}", path);
Expand All @@ -28,10 +28,10 @@ use regex::Regex;
///
/// ## Collect results into a vector
///
/// ```
/// ```ignore
/// use rust_search::Search;
///
/// let search = Search::new("src", None, Some(".rs"), Some(1));
/// let search = Search::new("src", None, None, Some(".rs"), Some(1), None, false, false, false, vec![], true);
///
/// let paths_vec: Vec<String> = search.collect();
/// ```
Expand All @@ -51,14 +51,16 @@ impl Search {
/// Search for files in a given arguments
/// ### Arguments
/// * `search_location` - The location to search in
/// * `more_locations` - Additional locations to search in
/// * `search_input` - The search input, defaults to any word
/// * `file_ext` - The file extension to search for, defaults to any file extension
/// * `depth` - The depth to search to, defaults to no limit
/// * `limit` - The limit of results to return, defaults to no limit
/// * `strict` - Whether to search for the exact word or not
/// * `ignore_case` - Whether to ignore case or not
/// * `hidden` - Whether to search hidden files or not
/// * `with_hidden` - Whether to search hidden files or not
/// * `filters` - Vector of filters to search by `DirEntry` data
/// * `dirs` - Whether to apply filters to directories and include them in results.
#[allow(clippy::too_many_arguments)]
pub(crate) fn new(
search_location: impl AsRef<Path>,
Expand All @@ -71,6 +73,7 @@ impl Search {
ignore_case: bool,
with_hidden: bool,
filters: Vec<FilterType>,
dirs: bool,
) -> Self {
let regex_search_input =
utils::build_regex_search_input(search_input, file_ext, strict, ignore_case);
Expand All @@ -85,7 +88,7 @@ impl Search {

// filters getting applied to walker
// only if all filters are true then the walker will return the file
walker.filter_entry(move |dir| filters.iter().all(|f| f.apply(dir)));
walker.filter_entry(move |entry| filters.iter().all(|f| f.apply(entry, dirs)));

if let Some(locations) = more_locations {
for location in locations {
Expand All @@ -101,6 +104,16 @@ impl Search {

Box::new(move |path_entry| {
if let Ok(entry) = path_entry {
if !dirs {
// if dirs is false and entry is a directory,
// proceed with the search without sending its path or incrementing the counter
if let Ok(m) = entry.metadata() {
if m.file_type().is_dir() {
return WalkState::Continue;
}
}
}

let path = entry.path();
if let Some(file_name) = path.file_name() {
// Lossy means that if the file name is not valid UTF-8
Expand Down