5 | import public Data.FilePath.Body
6 | import public Data.List1
7 | import public Data.Maybe
8 | import public Data.String
16 | export infixl 5 </>
, />
19 | record DriveLetter where
20 | constructor MkDriveLetter
22 | 0 prf : isAlpha letter === True
25 | fromChar : (c : Char) -> {auto 0 prf : isAlpha c === True} -> DriveLetter
26 | fromChar c = MkDriveLetter c prf
28 | namespace DriveLetter
30 | parse : Char -> Maybe DriveLetter
31 | parse c with (isAlpha c) proof prf
32 | parse c | True = Just $
MkDriveLetter c prf
33 | parse c | False = Nothing
36 | Show DriveLetter where
37 | showPrec p (MkDriveLetter c _) = showCon p "MkDriveLetter" $
showArg c ++ " _"
40 | Interpolation DriveLetter where
41 | interpolate (MkDriveLetter c _) = singleton c
44 | Eq DriveLetter where
45 | MkDriveLetter c _ == MkDriveLetter d _ = c == d
48 | data AbsType = Unix | Disk DriveLetter | UNC Body Body
52 | showPrec p Unix = "Unix"
53 | showPrec p (Disk d) = showCon p "Disk" $
showArg d
54 | showPrec p (UNC sv sh) = showCon p "UNC" $
showArg sv ++ showArg sh
57 | Interpolation AbsType where
58 | interpolate Unix = "/"
59 | interpolate (Disk d) = "\{d}:\\"
60 | interpolate (UNC sv sh) = "\\\\\{sv}\\\{sh}\\"
65 | Disk d == Disk d' = d == d'
66 | UNC sv sh == UNC sv' sh' = sv == sv' && sh == sh'
72 | data PathType = Rel | Abs
78 | data Path : PathType -> Type where
80 | PAbs : AbsType -> SnocList Body -> Path Abs
83 | PRel : SnocList Body -> Path Rel
88 | (</>) : Path t -> Path Rel -> Path t
89 | (</>) (PAbs at sx) (PRel sy) = PAbs at (sx ++ sy)
90 | (</>) (PRel sx) (PRel sy) = PRel (sx ++ sy)
94 | (/>) : Path t -> Body -> Path t
95 | fp /> s = fp </> PRel [< s]
100 | split : Path t -> Maybe (Path t, Body)
101 | split (PAbs at (sx :< x)) = Just (PAbs at sx, x)
102 | split (PRel (sx :< x)) = Just (PRel sx, x)
103 | split (PAbs _ [<]) = Nothing
104 | split (PRel [<]) = Nothing
110 | (<.>) : Path t -> Body -> Path t
111 | PAbs at (sx :< x) <.> s = PAbs at (sx :< (x <.> s))
112 | PRel (sx :< x) <.> s = PRel (sx :< (x <.> s))
113 | PRel [<] <.> s = PRel [< preDot s]
114 | PAbs at [<] <.> s = PAbs at [< preDot s]
119 | root = PAbs Unix [<]
123 | disk : DriveLetter -> Path Abs
124 | disk d = PAbs (Disk d) [<]
128 | network : Body -> Body -> Path Abs
129 | network sv sh = PAbs (UNC sv sh) [<]
133 | isAbsolute : Path t -> Bool
134 | isAbsolute (PAbs _ _) = True
135 | isAbsolute (PRel _) = False
139 | basename : Path t -> Maybe Body
140 | basename = map snd . split
144 | parentDir : Path t -> Maybe (Path t)
145 | parentDir = map fst . split
149 | parentDirs : Path t -> List (Path t)
150 | parentDirs fp = case parentDir fp of
152 | Just p => p :: parentDirs (assert_smaller fp p)
156 | splitFileName : Path t -> Maybe (Path t, Body)
157 | splitFileName p = do
159 | (base,ext) <- split b
160 | pure (p2 /> base, ext)
165 | stemAndExt : Path t -> Maybe (Body, Body)
166 | stemAndExt p = split p >>= split . snd
170 | fileStem : Path t -> Maybe Body
171 | fileStem p = map fst (stemAndExt p) <|> map snd (split p)
175 | extension : Path t -> Maybe Body
176 | extension = map snd . stemAndExt
178 | normAbs : SnocList Body -> SnocList Body
180 | normAbs (sx :< "..") = case normAbs sx of
183 | normAbs (sx :< x) = normAbs sx :< x
185 | normRel : SnocList Body -> SnocList Body
187 | normRel (sx :< "..") = case normRel sx of
189 | (sx2 :< "..") => sx2 :< ".." :< ".."
191 | normRel (sx :< x) = normRel sx :< x
199 | normalize : Path t -> Path t
200 | normalize (PAbs at sx) = PAbs at (normAbs sx)
201 | normalize (PRel sx) = PRel (normRel sx)
205 | isHidden : Path b -> Bool
206 | isHidden (PAbs _ $
_ :< x) = isHidden x
207 | isHidden (PRel $
_ :< x) = isHidden x
214 | mapToList : (a -> b) -> SnocList a -> List b -> List b
215 | mapToList f [<] xs = xs
216 | mapToList f (sx :< x) xs = mapToList f sx (f x :: xs)
219 | Show (Path t) where
220 | showPrec p (PAbs at sx) = showCon p "PAbs" $
showArg at ++ showArg sx
221 | showPrec p (PRel sx) = showCon p "PRel" $
showArg sx
224 | Interpolation (Path t) where
225 | interpolate (PAbs at sx) =
227 | . (interpolate at ::)
228 | . intersperse (singleton Sep)
229 | $
mapToList interpolate (normAbs sx) []
230 | interpolate (PRel [<]) = "."
231 | interpolate (PRel sx) =
233 | . intersperse (singleton Sep)
234 | $
mapToList interpolate (normRel sx) []
238 | heq : Path t1 -> Path t2 -> Bool
239 | heq (PAbs at sx) (PAbs at' sy) = at == at' && sx == sy
240 | heq (PRel sx) (PRel sy) = sx == sy
246 | hcomp : Path t1 -> Path t2 -> Ordering
247 | hcomp (PAbs at sx) (PAbs at' sy) = compare sx sy
248 | hcomp (PRel sx) (PRel sy) = compare sx sy
249 | hcomp (PAbs _ _) (PRel _) = LT
250 | hcomp (PRel _) (PAbs _ _) = GT
252 | public export %inline
253 | Eq (Path t) where (==) = heq
256 | Ord (Path t) where compare = hcomp
259 | Semigroup (Path Rel) where (<+>) = (</>)
262 | Monoid (Path Rel) where neutral = PRel [<]
270 | record FilePath where
272 | {0 pathType : PathType}
273 | path : Path pathType
275 | public export %inline
277 | FP p1 == FP p2 = heq p1 p2
281 | compare (FP p1) (FP p2) = hcomp p1 p2
284 | Show FilePath where show (FP p) = show p
287 | Interpolation FilePath where interpolate (FP p) = interpolate p
294 | FromString FilePath where
295 | fromString s = case trim s of
296 | "" => FP $
PRel Lin
297 | "." => FP $
PRel Lin
298 | st => case map trim $
split (\c => c == '/' || c == '\\') st of
299 | "" ::: "" :: sv :: sh :: ps => case (parse sv, parse sh) of
300 | (Just sv', Just sh') => FP $
PAbs (UNC sv' sh') $
[<] <>< mapMaybe parse ps
301 | _ => FP $
PAbs Unix $
[<] <>< mapMaybe parse (sv :: sh :: ps)
302 | p ::: ps => case strM p of
303 | StrNil => FP $
PAbs Unix $
[<] <>< mapMaybe parse ps
304 | StrCons c ":" => case parse c of
305 | Just d => FP $
PAbs (Disk d) $
[<] <>< mapMaybe parse ps
306 | Nothing => FP $
PRel $
[<] <>< mapMaybe parse (p :: ps)
307 | _ => FP $
PRel $
[<] <>< mapMaybe parse (p :: ps)
313 | (/>) : FilePath -> (b : Body) -> FilePath
314 | FP fp /> b = FP $
fp /> b
318 | (</>) : FilePath -> Path Rel -> FilePath
319 | FP fp </> p = FP $
fp </> p
324 | split : FilePath -> Maybe (FilePath, Body)
325 | split (FP p) = map (\(fp,s) => (FP fp, s)) $
split p
331 | (<.>) : FilePath -> (b : Body) -> FilePath
332 | FP fp <.> s = FP $
fp <.> s
337 | root = FP $
PAbs Unix [<]
341 | isAbsolute : FilePath -> Bool
342 | isAbsolute (FP p) = isAbsolute p
346 | basename : FilePath -> Maybe Body
347 | basename = map snd . split
351 | parentDir : FilePath -> Maybe FilePath
352 | parentDir = map fst . split
356 | parentDirs : FilePath -> List FilePath
357 | parentDirs (FP p) = map (\p' => FP p') $
parentDirs p
361 | splitFileName : FilePath -> Maybe (FilePath, Body)
362 | splitFileName (FP p) = mapFst FP <$> splitFileName p
367 | stemAndExt : FilePath -> Maybe (Body, Body)
368 | stemAndExt (FP p) = stemAndExt p
372 | fileStem : FilePath -> Maybe Body
373 | fileStem (FP p) = fileStem p
377 | extension : FilePath -> Maybe Body
378 | extension (FP p) = extension p
382 | isHidden : FilePath -> Bool
383 | isHidden (FP p) = isHidden p
391 | data IsAbs : FilePath -> Type where
392 | ItIsAbs : IsAbs (FP $
PAbs at sx)
394 | public export %inline
395 | toAbs : (fp : FilePath) -> {auto 0 prf : IsAbs fp} -> Path Abs
396 | toAbs (FP (PAbs at sx)) = PAbs at sx
400 | data IsRel : FilePath -> Type where
401 | ItIsRel : IsRel (FP $
PRel sx)
403 | public export %inline
404 | toRel : (fp : FilePath) -> {auto 0 prf : IsRel fp} -> Path Rel
405 | toRel (FP (PRel sx)) = PRel sx
413 | parse : String -> Maybe (Path Abs)
416 | in parseUNC cs <|> parseDisk cs <|> parseUnix cs
418 | parseBody : List Char -> Maybe (SnocList Body)
420 | let ps := split (\c => c == '/' || c == '\\') t
421 | in (Lin <><) <$> traverse fromChars (forget ps)
423 | parseUNCBody : List Char -> Maybe (Path Abs)
424 | parseUNCBody t = case split (\c => c == '/' || c == '\\') t of
425 | [] ::: _ => Nothing
426 | _ ::: [] :: _ => Nothing
427 | sv ::: sh :: ps => Just $
PAbs (UNC !(fromChars sv) !(fromChars sh)) ((Lin <><) !(traverse fromChars ps))
430 | parseUnix : List Char -> Maybe (Path Abs)
431 | parseUnix ('/' :: t) = PAbs Unix <$> parseBody t
432 | parseUnix ('\\' :: t) = PAbs Unix <$> parseBody t
433 | parseUnix _ = Nothing
435 | parseDisk : List Char -> Maybe (Path Abs)
436 | parseDisk (d :: ':' :: '/' :: t) = [| PAbs (Disk <$> parse d) (parseBody t) |]
437 | parseDisk (d :: ':' :: '\\' :: t) = [| PAbs (Disk <$> parse d) (parseBody t) |]
438 | parseDisk _ = Nothing
440 | parseUNC : List Char -> Maybe (Path Abs)
441 | parseUNC ('/' :: '/' :: t) = parseUNCBody t
442 | parseUNC ('\\' :: '\\' :: t) = parseUNCBody t
443 | parseUNC _ = Nothing
448 | -> {auto 0 prf : IsJust (AbsPath.parse s)}
450 | fromString s = fromJust (parse s)
458 | parse : String -> Maybe (Path Rel)
459 | parse "." = Just (PRel [<])
461 | let ps := split (\c => c == '/' || c == '\\') (unpack s)
462 | in PRel . (Lin <><) <$> traverse fromChars (forget ps)
467 | -> {auto 0 prf : IsJust (RelPath.parse s)}
469 | fromString s = fromJust (parse s)
476 | parse : String -> Maybe FilePath
477 | parse str = FP <$> AbsPath.parse str
478 | <|> FP <$> RelPath.parse str
488 | "abdlkjf/sdf/bb/sdfljlsjdfsdfjl/kklsdj2320398we/_jkw0r/u23__0294owe/jwjf.txt"
492 | testAbsUnix : Path Abs
494 | "/bdlkjf/sdf/bb/sdfljlsjdfsdfjl/kklsdj2320398we/_jkw0r/u23__0294owe/jwjf.txt"
498 | testAbsDisk : Path Abs
500 | "C:\\bdlkjf\\sdf\\bb\\sdfljlsjdfsdfjl\\kklsdj2320398we\\_jkw0r\\u23__0294owe\\jwjf.txt"
504 | testAbsUNC : Path Abs
506 | "\\\\localhost\\share\\dfljlsjdfsdfjl\\kklsdj2320398we\\_jkw0r\\u23__0294owe\\jwjf.txt"