Shells in OCaml
1module Parameter = struct
2 type t =
3 | String of string
4 | Number of string
5 | Special of string
6 | Null (** Possible shell parameters *)
7end
8
9module type State = sig
10 type t
11 (** State for the shell and operating system that is carried from one
12 evaluation step to the next. *)
13
14 val cwd : t -> Fpath.t
15 (** The current working directory *)
16
17 val set_cwd : t -> Fpath.t -> t
18 (** Update the cwd *)
19
20 val expand : t -> [ `Tilde ] -> string
21 (** Expansions *)
22
23 val lookup : t -> param:string -> string option
24 (** Parameter lookup. [None] means [unset]. *)
25
26 val update :
27 ?export:bool ->
28 ?readonly:bool ->
29 t ->
30 param:string ->
31 string ->
32 (t, string) result
33 (** Update the state with a new parameter mapping and whether or not it should
34 exported to the environment (default false), if it is readonly (default
35 false). *)
36
37 val remove : param:string -> t -> bool * t
38 (** [remove ~param t] removes [param] from [t] if it exists. [bool] is [true]
39 if a removal took place. *)
40
41 val exports : t -> (string * string) list
42 (** All of the variables that must be exported to the environment *)
43
44 val readonly : t -> (string * string) list
45 (** All of the variables that must be exported to the environment *)
46
47 val pp_readonly : t Fmt.t
48 val pp_export : t Fmt.t
49 val dump : t Fmt.t
50end
51
52type redirect =
53 | Parent_redirect of
54 int * Eio_unix.Fd.t * Eio_unix.Private.Fork_action.blocking
55 | Child_redirect of
56 int * Eio_unix.Fd.t * Eio_unix.Private.Fork_action.blocking
57 | Close of Eio_unix.Fd.t
58
59let pp_redirect ppf = function
60 | Parent_redirect (i, fd, _) -> Fmt.pf ppf "%i <=p=> %a" i Eio_unix.Fd.pp fd
61 | Child_redirect (i, fd, _) -> Fmt.pf ppf "%i <=c=> %a" i Eio_unix.Fd.pp fd
62 | Close fd -> Fmt.pf ppf "close %a" Eio_unix.Fd.pp fd
63
64type exec_mode =
65 | Switched of Eio.Switch.t
66 | Async
67 (** How to execute a process. This mainly controls what happens at the end
68 of the running a script or some commands. When a process is
69 "switched", we use the same semantics as Eio, we sigkill the process
70 and cleanup. If the process is complete Async then we do not wait.
71 This allows us to exit before some of our child processes, which is a
72 requirement for implementing the semantics of a shell! *)
73
74module type Exec = sig
75 type t
76 (** An executor for commands *)
77
78 type process
79
80 val signal : process -> int -> unit
81 val pid : process -> int
82
83 val exec :
84 ?delay_reap:unit Eio.Promise.t ->
85 ?fork_actions:Eio_unix__.Fork_action.t list ->
86 ?fds:redirect list ->
87 ?stdin:_ Eio.Flow.source ->
88 ?stdout:_ Eio.Flow.sink ->
89 ?stderr:_ Eio.Flow.sink ->
90 ?env:(string * string) list ->
91 mode:exec_mode ->
92 pgid:int ->
93 cwd:Eio.Fs.dir_ty Eio.Path.t ->
94 executable:string ->
95 t ->
96 string list ->
97 (process, int * [ `Not_found ]) result
98 (** Run a command in a child process *)
99
100 val await : process -> unit Exit.t
101end
102
103module type Job = sig
104 type t
105 (** A job for job control *)
106
107 type process
108
109 val get_reaper : t -> unit Eio.Promise.t * unit Eio.Promise.u
110
111 val make :
112 int ->
113 [ `Built_in of unit Exit.t
114 | `Error of int
115 | `Exit of unit Exit.t
116 | `Process of process
117 | `Rdr of unit Exit.t ]
118 list ->
119 t
120
121 val get_id : t -> int
122 (** Get the ID of the job. *)
123
124 val set_id : int -> t -> t
125 (** Set the ID of the job. *)
126
127 val add_process : process -> t -> t
128 val add_built_in : unit Exit.t -> t -> t
129 val add_error : int -> t -> t
130 val add_rdr : unit Exit.t -> t -> t
131 val add_exit : unit Exit.t -> t -> t
132
133 val size : t -> int
134 (** Number of processes in this job *)
135
136 val await_exit : pipefail:bool -> interactive:bool -> t -> unit Exit.t
137 (** Given a job, [await_exit] will wait for the job to finish and return the
138 exit based on the various options passed in. *)
139end
140
141module type History = sig
142 type t
143 (** A history of commands *)
144
145 val empty : t
146 (** The empty history *)
147
148 type entry
149 (** A history entry, usually a command. *)
150
151 val make_entry : string -> entry
152 (** Construct an entry given a command. *)
153
154 val add : entry -> t -> t
155 (** Add an entry to the history. *)
156
157 val save : t -> _ Eio.Path.t -> unit
158 (** [save t path] should save history [t] to [path]. *)
159
160 val load : _ Eio.Path.t -> t
161 (** [load path] should try to read a history from [path]. *)
162
163 val history : command:string -> t -> t
164 (** [history ~command t] should return some subset of [t] (perhaps all of [t])
165 based on the current [command] to be used for history searching. *)
166
167 val commands : t -> string list
168 (** Converts your (perhaps richer) history to just a series of commands. *)
169
170 val pp : t Fmt.t
171 (** A pretty printer for the commands *)
172end