Shells in OCaml
at main 84 lines 2.2 kB view raw
1let ( / ) = Eio.Path.( / ) 2 3module Nlist = struct 4 type 'a t = Singleton of 'a | Cons of 'a * 'a t 5 6 let hd = function Singleton s -> s | Cons (s, _) -> s 7 8 let rec length = function 9 | Singleton _ -> 1 10 | Cons (_, rest) -> 1 + length rest 11 12 let rec of_list = function 13 | [] -> invalid_arg "Empty list" 14 | [ x ] -> Singleton x 15 | x :: xs -> Cons (x, of_list xs) 16 17 let rec to_list = function 18 | Singleton x -> [ x ] 19 | Cons (x, xs) -> x :: to_list xs 20 21 let rev vs = to_list vs |> List.rev |> of_list 22 let cons v vs = Cons (v, vs) 23 24 let rec map f = function 25 | Singleton x -> Singleton (f x) 26 | Cons (x, xs) -> Cons (f x, map f xs) 27 28 let append v1 v2 = 29 let rec loop = function 30 | Singleton x -> Cons (x, v2) 31 | Cons (x, xs) -> Cons (x, loop xs) 32 in 33 loop v1 34 35 let fold_left f acc v = to_list v |> List.fold_left f acc 36 let ( @ ) = append 37 38 let to_yojson f v : Yojson.Safe.t = 39 let lst = to_list v in 40 `List (List.map (fun i -> f i) lst) 41 42 let pp elt ppf v = to_list v |> Fmt.(list elt) ppf 43 let flatten v = to_list v |> List.flatten |> of_list 44end 45 46(* Nonempty, separated lists *) 47module Nslist = struct 48 type ('v, 'sep) t = ('v * 'sep) Nlist.t [@@deriving to_yojson] 49 50 let singleton sep i = Nlist.Singleton (i, sep) 51 let cons sep i v = Nlist.cons (i, sep) v 52 let append a b = Nlist.append a b 53 54 let map f g (v : ('a, 'b) t) : ('c, 'd) t = 55 Nlist.map (fun (a, b) -> (f a, g b)) v 56 57 let fold_left f acc (vs : ('a, 'b) t) = 58 Nlist.fold_left (fun acc (a, b) -> f acc a b) acc vs 59end 60 61let yojson_pp = Yojson.Safe.pretty_print ~std:true 62 63module String = struct 64 include String 65 66 let cut_prefix ~prefix s = 67 match Astring.String.cut ~sep:prefix s with 68 | Some ("", rest) -> Some rest 69 | _ -> None 70 71 let cut_suffix ~suffix s = 72 match Astring.String.cut ~sep:suffix s with 73 | Some (start, "") -> Some start 74 | _ -> None 75end 76 77module Glob = struct 78 let tests ~pattern s = List.filter Glob.(test (of_string pattern)) s 79 80 let test ~pattern s = 81 match tests ~pattern [ s ] with [ _ ] -> true | _ :: _ | [] -> false 82 83 let glob_dir ~pattern dir = tests ~pattern (Eio.Path.read_dir dir) 84end