use std::{ ops::{Deref, DerefMut}, path::{Path, PathBuf}, }; use ignore::{DirEntry, WalkBuilder}; use tracing::{debug, error}; use crate::{parser::Parser, project::Project}; pub struct SearchBuilder { walk_builder: WalkBuilder, projects: Vec, parsers: Vec>, } impl SearchBuilder { pub fn new>(path: P) -> Self { Self { walk_builder: WalkBuilder::new(&path), projects: Default::default(), parsers: Default::default(), } } pub fn project>(&mut self, path: P) { self.projects.push(path.as_ref().to_path_buf()) } pub fn parser(&mut self, parser: impl Parser + 'static) { self.parsers.push(Box::new(parser)) } pub fn build(mut self) -> impl Iterator { self.walk_builder .standard_filters(true) .build() .inspect(|res| { if let Err(err) = res { error!(%err, "Ignoring errored path"); } }) .flatten() .map(DirEntry::into_path) .chain(self.projects.into_iter()) .map(move |p| self.parsers.parse(p)) .inspect(|res| { if let Err(err) = res { debug!(%err, "Failed to match"); } }) .flatten() } } impl Deref for SearchBuilder { type Target = WalkBuilder; fn deref(&self) -> &Self::Target { &self.walk_builder } } impl DerefMut for SearchBuilder { fn deref_mut(&mut self) -> &mut Self::Target { &mut self.walk_builder } }