diff --git a/src/lib.rs b/src/lib.rs index d3cc698..4be0e0c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -585,39 +585,6 @@ impl<'t> Glob<'t> { Ok(Glob { tree, pattern }) } - /// Constructs a [`Glob`] from a glob expression with diagnostics. - /// - /// This function is the same as [`Glob::new`], but additionally returns detailed diagnostics - /// on both success and failure. - /// - /// See [`Glob::diagnose`]. - /// - /// # Examples - /// - /// ```rust - /// use tardar::DiagnosticResultExt as _; - /// use wax::Glob; - /// - /// let result = Glob::diagnosed("(?i)readme.{md,mkd,markdown}"); - /// for diagnostic in result.diagnostics() { - /// eprintln!("{}", diagnostic); - /// } - /// if let Some(glob) = result.ok_output() { /* ... */ } - /// ``` - /// - /// [`Glob`]: crate::Glob - /// [`Glob::diagnose`]: crate::Glob::diagnose - /// [`Glob::new`]: crate::Glob::new - #[cfg(feature = "miette")] - #[cfg_attr(docsrs, doc(cfg(feature = "miette")))] - pub fn diagnosed(expression: &'t str) -> DiagnosticResult<'t, Self> { - parse_and_diagnose(expression).and_then_diagnose(|tree| { - Glob::compile(tree.as_ref().tokens()) - .into_error_diagnostic() - .map_output(|pattern| Glob { tree, pattern }) - }) - } - /// Partitions a [`Glob`] into an invariant [`PathBuf`] prefix and variant [`Glob`] postfix. /// /// The invariant prefix contains no glob patterns nor other variant components and therefore @@ -703,157 +670,6 @@ impl<'t> Glob<'t> { } } - /// Gets an iterator over matching files in a directory tree. - /// - /// This function matches a [`Glob`] against a directory tree, returning each matching file as - /// a [`WalkEntry`]. [`Glob`]s are the only patterns that support this semantic operation; it - /// is not possible to match combinators over directory trees. - /// - /// As with [`Path::join`] and [`PathBuf::push`], the base directory can be escaped or - /// overridden by rooted [`Glob`]s. In many cases, the current working directory `.` is an - /// appropriate base directory and will be intuitively ignored if the [`Glob`] is rooted, such - /// as in `/mnt/media/**/*.mp4`. The [`has_root`] function can be used to check if a [`Glob`] - /// is rooted and the [`Walk::root`] function can be used to get the resulting root directory - /// of the traversal. - /// - /// The [root directory][`Walk::root`] is established via the [invariant - /// prefix][`Glob::partition`] of the [`Glob`]. **The prefix and any [semantic - /// literals][`Glob::has_semantic_literals`] in this prefix are interpreted semantically as a - /// path**, so components like `.` and `..` that precede variant patterns interact with the - /// base directory semantically. This means that expressions like `../**` escape the base - /// directory as expected on Unix and Windows, for example. - /// - /// This function uses the default [`WalkBehavior`]. To configure the behavior of the - /// traversal, see [`Glob::walk_with_behavior`]. - /// - /// Unlike functions in [`Pattern`], **this operation is semantic and interacts with the file - /// system**. - /// - /// # Examples - /// - /// ```rust,no_run - /// use wax::Glob; - /// - /// let glob = Glob::new("**/*.(?i){jpg,jpeg}").unwrap(); - /// for entry in glob.walk("./Pictures") { - /// let entry = entry.unwrap(); - /// println!("JPEG: {:?}", entry.path()); - /// } - /// ``` - /// - /// Glob expressions do not support general negations, but the [`not`] iterator adaptor can be - /// used when walking a directory tree to filter [`WalkEntry`]s using arbitary patterns. **This - /// should generally be preferred over functions like [`Iterator::filter`], because it avoids - /// unnecessary reads of directory trees when matching [exhaustive - /// negations][`Pattern::is_exhaustive`].** - /// - /// ```rust,no_run - /// use wax::walk::FileIterator; - /// use wax::Glob; - /// - /// let glob = Glob::new("**/*.(?i){jpg,jpeg,png}").unwrap(); - /// for entry in glob - /// .walk("./Pictures") - /// .not(["**/(i?){background,wallpaper}/**"]) - /// .unwrap() - /// { - /// let entry = entry.unwrap(); - /// println!("{:?}", entry.path()); - /// } - /// ``` - /// - /// [`Glob`]: crate::Glob - /// [`Glob::walk_with_behavior`]: crate::Glob::walk_with_behavior - /// [`has_root`]: crate::Glob::has_root - /// [`Iterator::filter`]: std::iter::Iterator::filter - /// [`not`]: crate::Walk::not - /// [`Path::join`]: std::path::Path::join - /// [`PathBuf::push`]: std::path::PathBuf::push - /// [`Pattern`]: crate::Pattern - /// [`Pattern::is_exhaustive`]: crate::Pattern::is_exhaustive - /// [`Walk::root`]: crate::Walk::root - /// [`WalkBehavior`]: crate::WalkBehavior - /// [`WalkEntry`]: crate::WalkEntry - //#[cfg(feature = "walk")] - //#[cfg_attr(docsrs, doc(cfg(feature = "walk")))] - //pub fn walk(&self, directory: impl AsRef) -> WalkGlob { - // self.walk_with_behavior(directory, WalkBehavior::default()) - //} - - /// Gets an iterator over matching files in a directory tree. - /// - /// This function is the same as [`Glob::walk`], but it additionally accepts a - /// [`WalkBehavior`]. This can be used to configure how the traversal interacts with symbolic - /// links, the maximum depth from the root, etc. - /// - /// Depth is relative to the [root directory][`Walk::root`] of the traversal, which is - /// determined by joining the given path and any [invariant prefix][`Glob::partition`] of the - /// [`Glob`]. - /// - /// See [`Glob::walk`] for more information. - /// - /// # Examples - /// - /// ```rust,no_run - /// use wax::walk::WalkBehavior; - /// use wax::Glob; - /// - /// let glob = Glob::new("**/*.(?i){jpg,jpeg}").unwrap(); - /// for entry in glob.walk_with_behavior("./Pictures", WalkBehavior::default()) { - /// let entry = entry.unwrap(); - /// println!("JPEG: {:?}", entry.path()); - /// } - /// ``` - /// - /// By default, symbolic links are read as normal files and their targets are ignored. To - /// follow symbolic links and traverse any directories that they reference, specify a - /// [`LinkBehavior`]. - /// - /// ```rust,no_run - /// use wax::walk::LinkBehavior; - /// use wax::Glob; - /// - /// let glob = Glob::new("**/*.txt").unwrap(); - /// for entry in glob.walk_with_behavior("/var/log", LinkBehavior::ReadTarget) { - /// let entry = entry.unwrap(); - /// println!("Log: {:?}", entry.path()); - /// } - /// ``` - /// - /// [`Glob`]: crate::Glob - /// [`Glob::partition`]: crate::Glob::partition - /// [`Glob::walk`]: crate::Glob::walk - /// [`LinkBehavior`]: crate::LinkBehavior - /// [`Walk::root`]: crate::Walk::root - /// [`WalkBehavior`]: crate::WalkBehavior - //#[cfg(feature = "walk")] - //#[cfg_attr(docsrs, doc(cfg(feature = "walk")))] - //pub fn walk_with_behavior( - // &self, - // directory: impl AsRef, - // behavior: impl Into, - //) -> WalkGlob { - // walk::walk(self, directory, behavior) - //} - - /// Gets **non-error** [`Diagnostic`]s. - /// - /// This function requires a receiving [`Glob`] and so does not report error-level - /// [`Diagnostic`]s. It can be used to get non-error diagnostics after constructing or - /// [partitioning][`Glob::partition`] a [`Glob`]. - /// - /// See [`Glob::diagnosed`]. - /// - /// [`Diagnostic`]: miette::Diagnostic - /// [`Glob`]: crate::Glob - /// [`Glob::diagnosed`]: crate::Glob::diagnosed - /// [`Glob::partition`]: crate::Glob::partition - #[cfg(feature = "miette")] - #[cfg_attr(docsrs, doc(cfg(feature = "miette")))] - pub fn diagnose(&self) -> impl Iterator> { - diagnostics::diagnose(self.tree.as_ref()) - } - /// Gets metadata for capturing sub-expressions. /// /// This function returns an iterator over capturing tokens, which describe the index and @@ -903,6 +719,60 @@ impl<'t> Glob<'t> { } } +/// APIs for diagnosing globs. +#[cfg(feature = "miette")] +#[cfg_attr(docsrs, doc(cfg(feature = "miette")))] +impl<'t> Glob<'t> { + /// Constructs a [`Glob`] from a glob expression with diagnostics. + /// + /// This function is the same as [`Glob::new`], but additionally returns detailed diagnostics + /// on both success and failure. + /// + /// See [`Glob::diagnose`]. + /// + /// # Examples + /// + /// ```rust + /// use tardar::DiagnosticResultExt as _; + /// use wax::Glob; + /// + /// let result = Glob::diagnosed("(?i)readme.{md,mkd,markdown}"); + /// for diagnostic in result.diagnostics() { + /// eprintln!("{}", diagnostic); + /// } + /// if let Some(glob) = result.ok_output() { /* ... */ } + /// ``` + /// + /// [`Glob`]: crate::Glob + /// [`Glob::diagnose`]: crate::Glob::diagnose + /// [`Glob::new`]: crate::Glob::new + #[cfg(feature = "miette")] + #[cfg_attr(docsrs, doc(cfg(feature = "miette")))] + pub fn diagnosed(expression: &'t str) -> DiagnosticResult<'t, Self> { + parse_and_diagnose(expression).and_then_diagnose(|tree| { + Glob::compile(tree.as_ref().tokens()) + .into_error_diagnostic() + .map_output(|pattern| Glob { tree, pattern }) + }) + } + + /// Gets **non-error** [`Diagnostic`]s. + /// + /// This function requires a receiving [`Glob`] and so does not report error-level + /// [`Diagnostic`]s. It can be used to get non-error diagnostics after constructing or + /// [partitioning][`Glob::partition`] a [`Glob`]. + /// + /// See [`Glob::diagnosed`]. + /// + /// [`Diagnostic`]: miette::Diagnostic + /// [`Glob`]: crate::Glob + /// [`Glob::diagnosed`]: crate::Glob::diagnosed + /// [`Glob::partition`]: crate::Glob::partition + pub fn diagnose(&self) -> impl Iterator> { + diagnostics::diagnose(self.tree.as_ref()) + } +} + impl Display for Glob<'_> { fn fmt(&self, f: &mut Formatter) -> fmt::Result { write!(f, "{}", self.tree.as_ref().expression()) diff --git a/src/walk/glob.rs b/src/walk/glob.rs index 6918ce4..13d0c39 100644 --- a/src/walk/glob.rs +++ b/src/walk/glob.rs @@ -10,6 +10,8 @@ use crate::walk::filter::{HierarchicalIterator, Separation}; use crate::walk::{EntryResidue, FileIterator, PathExt as _, TreeEntry, WalkBehavior, WalkError}; use crate::{BuildError, CandidatePath, Combine, Glob}; +/// APIs for matching globs against directory trees. +#[cfg_attr(docsrs, doc(cfg(feature = "walk")))] impl<'t> Glob<'t> { /// Gets an iterator over matching files in a directory tree. /// @@ -82,7 +84,6 @@ impl<'t> Glob<'t> { /// [`Walk::root`]: crate::Walk::root /// [`WalkBehavior`]: crate::WalkBehavior /// [`WalkEntry`]: crate::WalkEntry - #[cfg_attr(docsrs, doc(cfg(feature = "walk")))] pub fn walk(&self, directory: impl Into) -> impl FileIterator { self.walk_with_behavior(directory, WalkBehavior::default()) } @@ -133,7 +134,6 @@ impl<'t> Glob<'t> { /// [`LinkBehavior`]: crate::LinkBehavior /// [`Walk::root`]: crate::Walk::root /// [`WalkBehavior`]: crate::WalkBehavior - #[cfg_attr(docsrs, doc(cfg(feature = "walk")))] pub fn walk_with_behavior( &self, directory: impl Into, @@ -142,7 +142,6 @@ impl<'t> Glob<'t> { self.walker(directory).walk_with_behavior(behavior) } - #[cfg_attr(docsrs, doc(cfg(feature = "walk")))] pub fn walker(&self, directory: impl Into) -> GlobWalker { GlobWalker { anchor: self.anchor(directory),