Shells in OCaml
3
fork

Configure Feed

Select the types of activity you want to include in your feed.

Add the dot built-in

Has been added both as a `.` and as the word `source`.

+100 -35
+31
src/lib/built_ins.ml
··· 42 42 | Exit of int 43 43 | Set of set 44 44 | Wait of int 45 + | Dot of string (* a.k.a source *) 45 46 46 47 (* Change Directory *) 47 48 module Cd = struct ··· 130 131 Cmd.v info term 131 132 end 132 133 134 + module Make_dot (T : sig 135 + val name : string 136 + end) = 137 + struct 138 + open Cmdliner 139 + 140 + let source_file = 141 + let doc = "File to source." in 142 + Arg.(required & pos 0 (some string) None & info [] ~docv:"FILE" ~doc) 143 + 144 + let t = 145 + let make_dot n = Dot n in 146 + let term = Term.(const make_dot $ source_file) in 147 + let info = 148 + let doc = "Execute commands in the current environment." in 149 + Cmd.info T.name ~doc 150 + in 151 + Cmd.v info term 152 + end 153 + 154 + module Source = Make_dot (struct 155 + let name = "source" 156 + end) 157 + 158 + module Dot = Make_dot (struct 159 + let name = "dot" 160 + end) 161 + 133 162 let of_args (w : string list) = 134 163 let open Cmdliner in 135 164 let exec_cmd cmd v = ··· 146 175 | "exit" :: _ as cmd -> exec_cmd cmd Exit.t 147 176 | "set" :: _ as cmd -> exec_cmd cmd Set.t 148 177 | "wait" :: _ as cmd -> exec_cmd cmd Wait.t 178 + | "source" :: _ as cmd -> exec_cmd cmd Source.t 179 + | "." :: _ as cmd -> exec_cmd cmd Dot.t 149 180 | _ -> None
+1
src/lib/built_ins.mli
··· 19 19 | Exit of int 20 20 | Set of set 21 21 | Wait of int 22 + | Dot of string 22 23 23 24 val of_args : string list -> (t, string) result option 24 25 (** Parses a command-line to the built-ins, errors are returned if parsing. *)
+52 -34
src/lib/eval.ml
··· 174 174 | Ast.IoRedirect_IoHere _ -> 175 175 Fmt.failwith "HERE documents not yet implemented!" 176 176 177 - let handle_built_in (ctx : ctx) = function 178 - | Built_ins.Cd { path } -> 179 - let cwd = S.cwd ctx.state in 180 - let+ state = 181 - match path with 182 - | Some p -> 183 - let fp = Fpath.append cwd (Fpath.v p) in 184 - Exit.zero @@ S.set_cwd ctx.state fp 185 - | None -> ( 186 - match Eunix.find_env "HOME" with 187 - | None -> Exit.nonzero_msg ctx.state "HOME not set" 188 - | Some p -> Exit.zero (S.set_cwd ctx.state @@ Fpath.v p)) 189 - in 190 - { ctx with state } 191 - | Pwd -> 192 - Fmt.pr "%a\n%!" Fpath.pp (S.cwd ctx.state); 193 - Exit.zero ctx 194 - | Exit n -> 195 - let should_exit = 196 - { Exit.default_should_exit with interactive = `Yes } 197 - in 198 - Exit.nonzero_msg ~should_exit ctx ~exit_code:n "exit" 199 - | Set { update; print_options } -> 200 - let v = 201 - Exit.zero 202 - { ctx with options = Built_ins.Options.update ctx.options update } 203 - in 204 - if print_options then Fmt.pr "%a%!" Built_ins.Options.pp ctx.options; 205 - v 206 - | Wait i -> ( 207 - match Unix.waitpid [] i with 208 - | _, WEXITED 0 -> Exit.zero ctx 209 - | _, (WEXITED n | WSIGNALED n | WSTOPPED n) -> Exit.nonzero ctx n) 210 - 211 177 let cwd_of_ctx ctx = S.cwd ctx.state |> Fpath.to_string |> ( / ) ctx.fs 212 178 213 179 let needs_glob_expansion : Ast.word_component -> bool = function ··· 615 581 let ctx, cst = expand_cst ctx wc in 616 582 word_glob_expand ctx cst) 617 583 swc 584 + 585 + and handle_built_in (ctx : ctx) = function 586 + | Built_ins.Cd { path } -> 587 + let cwd = S.cwd ctx.state in 588 + let+ state = 589 + match path with 590 + | Some p -> 591 + let fp = Fpath.append cwd (Fpath.v p) in 592 + Exit.zero @@ S.set_cwd ctx.state fp 593 + | None -> ( 594 + match Eunix.find_env "HOME" with 595 + | None -> Exit.nonzero_msg ctx.state "HOME not set" 596 + | Some p -> Exit.zero (S.set_cwd ctx.state @@ Fpath.v p)) 597 + in 598 + { ctx with state } 599 + | Pwd -> 600 + Fmt.pr "%a\n%!" Fpath.pp (S.cwd ctx.state); 601 + Exit.zero ctx 602 + | Exit n -> 603 + let should_exit = 604 + { Exit.default_should_exit with interactive = `Yes } 605 + in 606 + Exit.nonzero_msg ~should_exit ctx ~exit_code:n "exit" 607 + | Set { update; print_options } -> 608 + let v = 609 + Exit.zero 610 + { ctx with options = Built_ins.Options.update ctx.options update } 611 + in 612 + if print_options then Fmt.pr "%a%!" Built_ins.Options.pp ctx.options; 613 + v 614 + | Wait i -> ( 615 + match Unix.waitpid [] i with 616 + | _, WEXITED 0 -> Exit.zero ctx 617 + | _, (WEXITED n | WSIGNALED n | WSTOPPED n) -> Exit.nonzero ctx n) 618 + | Dot file -> ( 619 + let resolve_program name = 620 + if not (String.contains name '/') then 621 + Sys.getenv_opt "PATH" 622 + |> Option.value ~default:"/bin:/usr/bin" 623 + |> String.split_on_char ':' 624 + |> List.find_map (fun dir -> 625 + let p = Filename.concat dir name in 626 + if Sys.file_exists p then Some p else None) 627 + else if Sys.file_exists name then Some name 628 + else None 629 + in 630 + match resolve_program file with 631 + | None -> Exit.nonzero ctx 127 632 + | Some f -> 633 + let program = Ast.of_file (ctx.fs / f) in 634 + let ctx, _ = run (Exit.zero ctx) program in 635 + ctx) 618 636 619 637 and exec initial_ctx ((command, sep) : Ast.complete_command) = 620 638 let rec loop : Eio.Switch.t -> ctx -> Ast.clist -> ctx Exit.t =
+16 -1
test/built_ins.t
··· 37 37 > sleep 1 && 38 38 > echo hello > hello.txt 39 39 > ) & 40 - > wait $! 40 + > wait \$! 41 41 > cat hello.txt 42 42 > EOF 43 43 44 44 $ sh test_good.sh 45 45 hello 46 46 47 + 3. Dot 48 + 49 + $ cat > test.sh << EOF 50 + > foo=hello bar=world 51 + > EOF 52 + 53 + $ cat > run.sh << EOF 54 + > . ./test.sh 55 + > echo \$foo \$bar 56 + > EOF 57 + 58 + $ sh run.sh 59 + hello world 60 + $ msh run.sh 61 + hello world