use std::path::PathBuf; use clap::Args; use crate::project::ProjectItem; use self::entry::SearchEntry; pub mod entry; type EntryIter = std::vec::IntoIter; #[derive(Debug, Default, Clone, Args)] pub struct Search { /// Directory to search. /// /// Directories are searched recursively based on `--max-depth`. pub paths: Vec, #[command(flatten)] pub filter: Filters, } #[derive(Debug, Default, Clone, Args)] pub struct Filters { /// Match all child directories #[arg(long, short, conflicts_with_all = ["pattern", "git"])] pub all: bool, /// Max depth to recurse. /// /// Setting to 0 will only use the supplied directory. #[arg(short = 'd', long, default_value = "1")] pub max_depth: Option, /// Recurse into hidden directories. /// /// Traverse into hidden directories while searching. A directory is considered hidden /// if its name starts with a `.` sign (dot). If `--max-depth` is 0, this has no effect. #[arg(long)] pub hidden: bool, /// Match directories containing item named #[arg(long, short)] pub pattern: Option, /// Match git repositories #[cfg(feature = "git")] #[arg(long, short, default_value_t = true)] pub git: bool, } impl IntoIterator for Search { type Item = ProjectItem; type IntoIter = SearchIter; fn into_iter(self) -> Self::IntoIter { SearchIter { iter: self.paths.into_iter(), config: self.filter, curr: None, } } } pub struct SearchIter { iter: EntryIter, config: Filters, curr: Option, } impl std::fmt::Debug for SearchIter { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct("Projects") .field("paths_iter", &self.iter) .finish_non_exhaustive() } } impl Iterator for SearchIter { type Item = ProjectItem; #[tracing::instrument] fn next(&mut self) -> Option { match self.curr.as_mut().and_then(|c| c.next()) { Some(proj) => Some(proj), None => { self.curr = Some(SearchEntry::new(self.iter.next()?, &self.config)); self.next() } } } }