std.glob
Glob patterns, as a shell writes them: src/**/*.hf, read once
(compile), then matched against a path (matches) or expanded from
a directory into the paths there that match (glob). A pattern is
cut at each / into segments, matched one by one against a path’s
(std.path’s segments); a pattern starting with / matches an
absolute path, any other a relative one. In a segment:
- a rune stands for itself;
\before a rune, that rune (\*,\[,\\); *: any run of runes, none too, in the segment (never past a/, as Go’sfilepath.Match), a.first in a name too;?: one rune;[abc],[a-z0-9]: one rune of the class;[^...]or[!...]: one not of it (a]first in it is one of it, as a-first or last is;\escapes in it too);**, a segment of its own: any number of segments, none too.
Runes are compared as they are: case counts.
import coimport exceptionimport std.filesystemimport std.glob as Globimport std.path
-- | the heff sources under a directory, at any depthsources : {e : HFunctor} -> {{disk : filesystem <: e}} -> {{ex : exception FileError <: e}} -> Path -> Co e (List Path)sources dir = case Glob.compile "**/*.hf" of Left why -> pure Nil Right g -> Glob.glob dir gGlob
data GlobA pattern read: whether it starts with /, and its segments.
compile
compile : String -> Either String GlobA pattern read, or why it cannot be: a [ with no ], a \ at
the end, a range backwards, a ** with more in its segment. An
empty segment, or ., is none (a//./b is a/b).
>>> either (\why -> why) (\g -> "read") (compile "src/**/*.hf")"read">>> either (\why -> why) (\g -> "read") (compile "[ab")"a `[` with no `]`">>> either (\why -> why) (\g -> "read") (compile "a\\")"a `\\` at the end">>> either (\why -> why) (\g -> "read") (compile "[z-a]")"a range of a class backwards">>> either (\why -> why) (\g -> "read") (compile "src/a**")"a `**` with more in its segment: `**` is a segment of its own"matches
matches : Glob -> Path -> BoolWhether the pattern matches a path, segment by segment: both
absolute, or neither, and each segment of the pattern matching one
of the path’s — a **, any number of them.
>>> either (\why -> False) (\g -> matches g "main.hf") (compile "*.hf")True>>> either (\why -> False) (\g -> matches g "src/main.hf") (compile "*.hf")False>>> either (\why -> False) (\g -> matches g ".profile") (compile "*")True>>> either (\why -> Nil) (\g -> List.map (\p -> matches g p) ["src/a.hf", "src/x/y/b.hf", "a.hf", "src/x/y"]) (compile "src/**/*.hf")[True, True, False, False]>>> either (\why -> Nil) (\g -> List.map (\p -> matches g p) ["a/b", "a", "b"]) (compile "**")[True, True, True]>>> either (\why -> Nil) (\g -> List.map (\p -> matches g p) ["a/x/b/y/c", "a/b/c", "a/c", "a/b/x"]) (compile "a/**/b/**/c")[True, True, False, False]>>> either (\why -> Nil) (\g -> List.map (\p -> matches g p) ["abc", "a\u{e9}c", "ac", "abbc"]) (compile "a?c")[True, True, False, False]>>> either (\why -> Nil) (\g -> List.map (\p -> matches g p) ["xb", "xd", "x-", "x]"]) (compile "x[]a-c-]")[True, False, True, True]>>> either (\why -> Nil) (\g -> List.map (\p -> matches g p) ["b", "d", "!"]) (compile "[!a-c]")[False, True, True]>>> either (\why -> Nil) (\g -> List.map (\p -> matches g p) ["a*b", "axb"]) (compile "a\\*b")[True, False]>>> either (\why -> Nil) (\g -> List.map (\p -> matches g p) ["aaaab", "aaaa"]) (compile "*a*a*b")[True, False]>>> either (\why -> Nil) (\g -> List.map (\p -> matches g p) ["/usr/bin", "usr/bin"]) (compile "/usr/*")[True, False]glob
glob : {e : HFunctor} -> {{ev : filesystem <: e}} -> {{ex : exception FileError <: e}} -> Path -> Glob -> Co e (List Path)The paths the pattern matches from root — a relative pattern
from it, an absolute one from the root — each root and the
segments after it, sorted, name by name, as walk visits them.
Only the directories the pattern reaches are read: a segment with
no *, ? nor class is gone on to, not looked for, and a **
walks below where it is, links not followed (elsewhere a link is
followed, as Go’s filepath.Glob follows one). A directory not
there, or not a directory, has no paths that match; what else
cannot be read is thrown.