diff --git a/src/builder.rs b/src/builder.rs index 6351a40..3b6778e 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -25,6 +25,8 @@ pub struct SearchBuilder { hidden: bool, /// Filters Vector, defaults to empty vec filters: Vec, + /// When set to false, will not apply filters to directories and will exclude them from results. + dirs: bool, } impl SearchBuilder { @@ -42,6 +44,7 @@ impl SearchBuilder { self.ignore_case, self.hidden, self.filters.clone(), + self.dirs, ) } @@ -201,7 +204,7 @@ impl SearchBuilder { /// use rust_search::SearchBuilder; /// /// let search: Vec = SearchBuilder::default() - /// .with_hidden() + /// .hidden() /// .build() /// .collect(); /// ``` @@ -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 = SearchBuilder::default() + /// .dirs(false) + /// .build() + /// .collect(); + /// ``` + pub fn dirs(mut self, value: bool) -> Self { + self.dirs = value; + self + } } impl Default for SearchBuilder { @@ -249,6 +269,7 @@ impl Default for SearchBuilder { ignore_case: false, hidden: false, filters: vec![], + dirs: true, } } } diff --git a/src/filter.rs b/src/filter.rs index 2f8c308..30864b8 100644 --- a/src/filter.rs +++ b/src/filter.rs @@ -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() { @@ -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; } diff --git a/src/search.rs b/src/search.rs index 89a235c..5b2c029 100644 --- a/src/search.rs +++ b/src/search.rs @@ -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); @@ -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 = search.collect(); /// ``` @@ -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, @@ -71,6 +73,7 @@ impl Search { ignore_case: bool, with_hidden: bool, filters: Vec, + dirs: bool, ) -> Self { let regex_search_input = utils::build_regex_search_input(search_input, file_ext, strict, ignore_case); @@ -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 { @@ -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