let ( / ) = Eio.Path.( / ) module Nlist = struct type 'a t = Singleton of 'a | Cons of 'a * 'a t let hd = function Singleton s -> s | Cons (s, _) -> s let rec length = function | Singleton _ -> 1 | Cons (_, rest) -> 1 + length rest let rec of_list = function | [] -> invalid_arg "Empty list" | [ x ] -> Singleton x | x :: xs -> Cons (x, of_list xs) let rec to_list = function | Singleton x -> [ x ] | Cons (x, xs) -> x :: to_list xs let rev vs = to_list vs |> List.rev |> of_list let cons v vs = Cons (v, vs) let rec map f = function | Singleton x -> Singleton (f x) | Cons (x, xs) -> Cons (f x, map f xs) let append v1 v2 = let rec loop = function | Singleton x -> Cons (x, v2) | Cons (x, xs) -> Cons (x, loop xs) in loop v1 let fold_left f acc v = to_list v |> List.fold_left f acc let ( @ ) = append let to_yojson f v : Yojson.Safe.t = let lst = to_list v in `List (List.map (fun i -> f i) lst) let pp elt ppf v = to_list v |> Fmt.(list elt) ppf let flatten v = to_list v |> List.flatten |> of_list end (* Nonempty, separated lists *) module Nslist = struct type ('v, 'sep) t = ('v * 'sep) Nlist.t [@@deriving to_yojson] let singleton sep i = Nlist.Singleton (i, sep) let cons sep i v = Nlist.cons (i, sep) v let append a b = Nlist.append a b let map f g (v : ('a, 'b) t) : ('c, 'd) t = Nlist.map (fun (a, b) -> (f a, g b)) v let fold_left f acc (vs : ('a, 'b) t) = Nlist.fold_left (fun acc (a, b) -> f acc a b) acc vs end let yojson_pp = Yojson.Safe.pretty_print ~std:true module String = struct include String let cut_prefix ~prefix s = match Astring.String.cut ~sep:prefix s with | Some ("", rest) -> Some rest | _ -> None let cut_suffix ~suffix s = match Astring.String.cut ~sep:suffix s with | Some (start, "") -> Some start | _ -> None end module Glob = struct let tests ~pattern s = List.filter Glob.(test (of_string pattern)) s let test ~pattern s = match tests ~pattern [ s ] with [ _ ] -> true | _ :: _ | [] -> false let glob_dir ~pattern dir = tests ~pattern (Eio.Path.read_dir dir) end