···4242 | Exit of int
4343 | Set of set
4444 | Wait of int
4545+ | Dot of string (* a.k.a source *)
45464647(* Change Directory *)
4748module Cd = struct
···130131 Cmd.v info term
131132end
132133134134+module Make_dot (T : sig
135135+ val name : string
136136+end) =
137137+struct
138138+ open Cmdliner
139139+140140+ let source_file =
141141+ let doc = "File to source." in
142142+ Arg.(required & pos 0 (some string) None & info [] ~docv:"FILE" ~doc)
143143+144144+ let t =
145145+ let make_dot n = Dot n in
146146+ let term = Term.(const make_dot $ source_file) in
147147+ let info =
148148+ let doc = "Execute commands in the current environment." in
149149+ Cmd.info T.name ~doc
150150+ in
151151+ Cmd.v info term
152152+end
153153+154154+module Source = Make_dot (struct
155155+ let name = "source"
156156+end)
157157+158158+module Dot = Make_dot (struct
159159+ let name = "dot"
160160+end)
161161+133162let of_args (w : string list) =
134163 let open Cmdliner in
135164 let exec_cmd cmd v =
···146175 | "exit" :: _ as cmd -> exec_cmd cmd Exit.t
147176 | "set" :: _ as cmd -> exec_cmd cmd Set.t
148177 | "wait" :: _ as cmd -> exec_cmd cmd Wait.t
178178+ | "source" :: _ as cmd -> exec_cmd cmd Source.t
179179+ | "." :: _ as cmd -> exec_cmd cmd Dot.t
149180 | _ -> None
+1
src/lib/built_ins.mli
···1919 | Exit of int
2020 | Set of set
2121 | Wait of int
2222+ | Dot of string
22232324val of_args : string list -> (t, string) result option
2425(** Parses a command-line to the built-ins, errors are returned if parsing. *)
+52-34
src/lib/eval.ml
···174174 | Ast.IoRedirect_IoHere _ ->
175175 Fmt.failwith "HERE documents not yet implemented!"
176176177177- let handle_built_in (ctx : ctx) = function
178178- | Built_ins.Cd { path } ->
179179- let cwd = S.cwd ctx.state in
180180- let+ state =
181181- match path with
182182- | Some p ->
183183- let fp = Fpath.append cwd (Fpath.v p) in
184184- Exit.zero @@ S.set_cwd ctx.state fp
185185- | None -> (
186186- match Eunix.find_env "HOME" with
187187- | None -> Exit.nonzero_msg ctx.state "HOME not set"
188188- | Some p -> Exit.zero (S.set_cwd ctx.state @@ Fpath.v p))
189189- in
190190- { ctx with state }
191191- | Pwd ->
192192- Fmt.pr "%a\n%!" Fpath.pp (S.cwd ctx.state);
193193- Exit.zero ctx
194194- | Exit n ->
195195- let should_exit =
196196- { Exit.default_should_exit with interactive = `Yes }
197197- in
198198- Exit.nonzero_msg ~should_exit ctx ~exit_code:n "exit"
199199- | Set { update; print_options } ->
200200- let v =
201201- Exit.zero
202202- { ctx with options = Built_ins.Options.update ctx.options update }
203203- in
204204- if print_options then Fmt.pr "%a%!" Built_ins.Options.pp ctx.options;
205205- v
206206- | Wait i -> (
207207- match Unix.waitpid [] i with
208208- | _, WEXITED 0 -> Exit.zero ctx
209209- | _, (WEXITED n | WSIGNALED n | WSTOPPED n) -> Exit.nonzero ctx n)
210210-211177 let cwd_of_ctx ctx = S.cwd ctx.state |> Fpath.to_string |> ( / ) ctx.fs
212178213179 let needs_glob_expansion : Ast.word_component -> bool = function
···615581 let ctx, cst = expand_cst ctx wc in
616582 word_glob_expand ctx cst)
617583 swc
584584+585585+ and handle_built_in (ctx : ctx) = function
586586+ | Built_ins.Cd { path } ->
587587+ let cwd = S.cwd ctx.state in
588588+ let+ state =
589589+ match path with
590590+ | Some p ->
591591+ let fp = Fpath.append cwd (Fpath.v p) in
592592+ Exit.zero @@ S.set_cwd ctx.state fp
593593+ | None -> (
594594+ match Eunix.find_env "HOME" with
595595+ | None -> Exit.nonzero_msg ctx.state "HOME not set"
596596+ | Some p -> Exit.zero (S.set_cwd ctx.state @@ Fpath.v p))
597597+ in
598598+ { ctx with state }
599599+ | Pwd ->
600600+ Fmt.pr "%a\n%!" Fpath.pp (S.cwd ctx.state);
601601+ Exit.zero ctx
602602+ | Exit n ->
603603+ let should_exit =
604604+ { Exit.default_should_exit with interactive = `Yes }
605605+ in
606606+ Exit.nonzero_msg ~should_exit ctx ~exit_code:n "exit"
607607+ | Set { update; print_options } ->
608608+ let v =
609609+ Exit.zero
610610+ { ctx with options = Built_ins.Options.update ctx.options update }
611611+ in
612612+ if print_options then Fmt.pr "%a%!" Built_ins.Options.pp ctx.options;
613613+ v
614614+ | Wait i -> (
615615+ match Unix.waitpid [] i with
616616+ | _, WEXITED 0 -> Exit.zero ctx
617617+ | _, (WEXITED n | WSIGNALED n | WSTOPPED n) -> Exit.nonzero ctx n)
618618+ | Dot file -> (
619619+ let resolve_program name =
620620+ if not (String.contains name '/') then
621621+ Sys.getenv_opt "PATH"
622622+ |> Option.value ~default:"/bin:/usr/bin"
623623+ |> String.split_on_char ':'
624624+ |> List.find_map (fun dir ->
625625+ let p = Filename.concat dir name in
626626+ if Sys.file_exists p then Some p else None)
627627+ else if Sys.file_exists name then Some name
628628+ else None
629629+ in
630630+ match resolve_program file with
631631+ | None -> Exit.nonzero ctx 127
632632+ | Some f ->
633633+ let program = Ast.of_file (ctx.fs / f) in
634634+ let ctx, _ = run (Exit.zero ctx) program in
635635+ ctx)
618636619637 and exec initial_ctx ((command, sep) : Ast.complete_command) =
620638 let rec loop : Eio.Switch.t -> ctx -> Ast.clist -> ctx Exit.t =