Shells in OCaml
1module Make (S : Types.State) (E : Types.Exec) = struct
2 module Eval = Eval.Make (S) (E)
3
4 let default_prompt s =
5 Fmt.str "%s > %!" (Fpath.normalize @@ S.cwd s |> Fpath.to_string)
6
7 let with_stdin_in_raw_mode fn =
8 let saved_tio = Unix.tcgetattr Unix.stdin in
9 let tio =
10 {
11 saved_tio with
12 (* input modes *)
13 c_ignpar = true;
14 c_istrip = false;
15 c_inlcr = false;
16 c_igncr = false;
17 c_ixon = false;
18 (* c_ixany = false; *)
19 (* c_iuclc = false; *)
20 c_ixoff = false;
21 (* output modes *)
22 c_opost = true;
23 (* control modes *)
24 c_isig = false;
25 c_icanon = false;
26 c_echo = false;
27 c_echoe = false;
28 c_echok = false;
29 c_echonl = false;
30 (* c_iexten = false; *)
31
32 (* special characters *)
33 c_vmin = 1;
34 c_vtime = 0;
35 }
36 in
37 Unix.tcsetattr Unix.stdin TCSADRAIN tio;
38 Fun.protect
39 ~finally:(fun () -> Unix.tcsetattr Unix.stdin TCSADRAIN saved_tio)
40 fn
41
42 let run ?(prompt = default_prompt) initial_ctx =
43 let rec loop (ctx : Eval.ctx) =
44 let p = prompt ctx.state in
45 match LNoise.linenoise p with
46 | None -> loop ctx
47 | Some c ->
48 let ast = Ast.of_string c in
49 let ctx', _ast =
50 with_stdin_in_raw_mode @@ fun () -> Eval.run ctx ast
51 in
52 loop ctx'
53 in
54 loop initial_ctx
55end