···11type 'a t = 'a Fs.dir * Fs.path
2233+(* Like [Filename.is_relative] but always using "/" as the separator. *)
44+let is_relative = function
55+ | "" -> true
66+ | x -> x.[0] <> '/'
77+88+(* Like [Filename.concat] but always using "/" as the separator. *)
99+let concat a b =
1010+ let l = String.length a in
1111+ if l = 0 || a.[l - 1] = '/' then a ^ b
1212+ else a ^ "/" ^ b
1313+314let ( / ) (dir, p1) p2 =
415 match p1, p2 with
55- | p1, "" -> (dir, Filename.concat p1 p2)
66- | _, p2 when not (Filename.is_relative p2) -> (dir, p2)
1616+ | p1, "" -> (dir, concat p1 p2)
1717+ | _, p2 when not (is_relative p2) -> (dir, p2)
718 | ".", p2 -> (dir, p2)
88- | p1, p2 -> (dir, Filename.concat p1 p2)
1919+ | p1, p2 -> (dir, concat p1 p2)
9201021let pp f (Resource.T (t, ops), p) =
1122 let module X = (val (Resource.get ops Fs.Pi.Dir)) in
+26
vendor/opam/eio/tests/fs.md
···985985+seek from end: 9
986986- : unit = ()
987987```
988988+989989+# Extending paths
990990+991991+```ocaml
992992+# run @@ fun env ->
993993+ let base = fst env#cwd in
994994+ List.iter (fun (a, b) -> traceln "%S / %S = %S" a b (snd ((base, a) / b))) [
995995+ "foo", "bar";
996996+ "foo/", "bar";
997997+ "foo", "/bar";
998998+ "foo", "";
999999+ "foo/", "";
10001000+ "", "";
10011001+ "", "bar";
10021002+ "/", "";
10031003+ ]
10041004++"foo" / "bar" = "foo/bar"
10051005++"foo/" / "bar" = "foo/bar"
10061006++"foo" / "/bar" = "/bar"
10071007++"foo" / "" = "foo/"
10081008++"foo/" / "" = "foo/"
10091009++"" / "" = ""
10101010++"" / "bar" = "bar"
10111011++"/" / "" = "/"
10121012+- : unit = ()
10131013+```