std.path
Paths, a type of their own: where a file is, read from a string in a
style — Posix (/a/b) or Windows (C:\a\b, \\server\share\a,
either slash read) — and written back in one. A path is its drive (on
Windows, C: or //server/share), whether it starts at the root, and
its segments; what is done with it is done with those, the same on every
platform. Only this module makes one, so it is always in that shape: no
empty segment, no ..
Reading one and writing one take the style as os, the system’s own
(native) unless it is given: parse s reads s as the system the
program runs on writes a path, parse (os := Windows) s as Windows
does. So a string from the program and one from outside, an argument or
a variable, are read the same way. native is not asked at run time: a
C program is built for one system, whose style it has. A string is
taken as a path where one is expected (readFile "src/main.hf", dir / "main.hf"), read so, by the coercion this module declares.
Style
data Style = Posix | WindowsHow a system writes a path: Posix (/a/b) or Windows
(C:\a\b, \\server\share\a, either slash read).
Path
data PathA path: its drive (Windows: C: or //server/share, with /s;
otherwise ""), whether it starts at the root, and its segments (no
"", no .; .. only where normal leaves one). Made only by
this module: by parse, from a string where a path is expected, and
by what is done with paths.
native
native : StyleThe style of the system the program runs on: Windows there,
Posix elsewhere — in a C program, the system it is built for; in
JavaScript, Node.js’s (Posix in a page).
styleOf
styleOf : String -> StyleThe style of a platform, named as Node.js names it (win32,
linux, …: process.platform).
>>> styleOf "darwin"Posixsep
sep : Style -> StringThe separator the style writes.
lower
lower : String -> StringThe ASCII letters of s, in lower case.
drive
drive : Path -> StringThe drive ("" where there is none; on Windows, C:, or
//server/share, with /s).
isAbsolute
isAbsolute : Path -> BoolWhether the path starts at the root (of its drive).
segments
segments : Path -> List StringThe segments, in order: no "", no ..
parse
parse : {os : Style := native} -> String -> Paths read as a path in the style os (the system’s, native,
unless it is given).
>>> segments (parse (os := Posix) "/a//b/./c/")["a", "b", "c"]>>> segments (parse (os := Posix) "C:\\a")["C:\\a"]>>> drive (parse (os := Windows) "c:\\x")"c:">>> segments (parse (os := Windows) "\\\\srv\\share\\x/y")["x", "y"]render
render : {os : Style := native} -> Path -> Stringp written in the style os (the system’s, native, unless it is
given): . for nothing.
>>> render (os := Windows) (parse (os := Windows) "//srv/share/a")"\\\\srv\\share\\a">>> render (os := Posix) (parse (os := Windows) "C:\\a\\b")"C:/a/b">>> render (os := Posix) (parse (os := Posix) "")"."instanceCoeStringPath
instance instanceCoeStringPath : Coe String PathA string where a path is expected: parse, in the system’s style.
>>> render (os := Posix) ("a//b.hf/" : Path)"a/b.hf">>> segments ("a/../b" : Path)["a", "..", "b"]>>> isAbsolute ("/" : Path)True>>> isAbsolute (parse (os := Windows) "C:x")FalseinstanceEqualityPath
instance instanceEqualityPath : Equality PathThe same drive, both absolute or neither, and the same segments, as
they are: case counts, and .. is not taken away (normal both
first, for that).
>>> ("a/b" : Path) == "a//b/"True>>> ("a/../b" : Path) == "b"FalseinstanceDebugPath
instance instanceDebugPath : Debug PathAs a program writes it: the string, in the system’s style, where
that reads back as the path; else as parse (os := Windows) reads
it.
>>> debug ("/a/b" : Path)"\"/a/b\"">>> debug (parse (os := Windows) "C:/a")"parse (os := Windows) \"C:\\\\a\""instanceShowPath
instance instanceShowPath : Show PathWritten in the system’s style, render.
>>> show ("a/b" : Path)"a/b"current
current : PathThe path of nothing, relative: the directory a path is from.
>>> current"."normal
normal : Path -> Pathp without its ..s, where they can go.
>>> normal "/a/./b/../../../c/""/c">>> normal "a/../../b""../b">>> render (os := Windows) (normal (parse (os := Windows) "C:/a\\..\\b"))"C:\\b"components
components : Path -> List StringThe segments of p, without the ..s that can go (not its drive,
nor whether it is absolute).
>>> components (parse (os := Windows) "a\\b/./c\\..\\d")["a", "b", "d"]join
join : Path -> Path -> Pathb from a: b itself if it is absolute (on a’s drive if it has
none), a and b one after the other otherwise; its ..s gone
where they can go. a / b is the same.
>>> join "src" "heff/load.hf""src/heff/load.hf">>> join "/a/b" "../c""/a/c">>> join "/a" "/b""/b">>> render (os := Windows) (join (parse (os := Windows) "C:\\a") (parse (os := Windows) "\\b"))"C:\\b"instanceDivisionPath
instance instanceDivisionPath : Division Patha / b is join a b: dir / "main.hf".
>>> ("src" : Path) / "heff" / "load.hf""src/heff/load.hf">>> render (os := Windows) (parse (os := Windows) "C:\\a" / "b/c.hf")"C:\\a\\b\\c.hf">>> render (os := Windows) (parse (os := Windows) "C:/work" / "notes.txt")"C:\\work\\notes.txt"joinAll
joinAll : List Path -> PathThe paths, each from the one before.
>>> joinAll ["a", "b", "c"]"a/b/c"dirname
dirname : Path -> PathThe directory p is in (the root’s is the root).
>>> dirname "/a/b/c.hf""/a/b">>> dirname "c.hf"".">>> dirname "/""/">>> render (os := Windows) (dirname (parse (os := Windows) "C:\\a"))"C:\\"basename
basename : Path -> StringThe last segment of p ("" for a root).
>>> basename "/a/b/c.hf/""c.hf">>> basename (parse (os := Windows) "C:\\a\\b.hf")"b.hf"extension
extension : Path -> StringThe extension of p’s last segment, with its . ("" if none: a
name starting with . has none by that .).
>>> extension "src/main.hf"".hf">>> extension "a.tar.gz"".gz">>> extension ".heff""">>> extension "Makefile"""stem
stem : Path -> Stringp’s last segment, without its extension.
>>> stem "src/heff/load.hf""load"relative
relative : {os : Style := native} -> Path -> Path -> Maybe PathHow to get to to from from, if there is a way: both are absolute
on one drive, or both relative from one place. The style os (the
system’s, unless it is given) says whether segments are the same in
any case (on Windows) or not.
>>> relative "/a/b/c" "/a/d"Just ("../../d")>>> relative "/a" "/a/b/c.hf"Just ("b/c.hf")>>> relative "/a" "/a"Just (".")>>> relative "/a" "b"Nothing>>> relative (os := Windows) (parse (os := Windows) "C:\\Src\\heff") (parse (os := Windows) "c:\\src\\lib") == Just (parse (os := Windows) "..\\lib")True>>> relative (os := Windows) (parse (os := Windows) "C:\\a") (parse (os := Windows) "D:\\a")NothingisUnder
isUnder : {os : Style := native} -> Path -> Path -> Boolp is dir or under it (in any case on Windows, as relative).
>>> isUnder "/a/b" "/a/b/c"True>>> isUnder "/a/b" "/a/bc"False>>> isUnder "/a/b" "/a/b"True>>> isUnder "src" "src/../lib/x.hf"False