forked from
patrick.sirref.org/merry
Shells in OCaml
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