Shells in OCaml
3
fork

Configure Feed

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

Hints in interactive mode

+80 -16
+3 -1
src/lib/eunix.ml
··· 13 13 14 14 let get_user_and_host () = 15 15 Eio_unix.run_in_systhread ~label:"get_user_and_host" @@ fun () -> 16 - let name = Unix.getlogin () in 16 + let name = 17 + try Unix.getlogin () with Unix.Unix_error (Unix.ENOENT, _, _) -> "root" 18 + in 17 19 let host = Unix.gethostname () in 18 20 Fmt.str "%s@%s" name host 19 21
+11 -1
src/lib/interactive.ml
··· 98 98 |> Option.map Ast.word_components_to_string); 99 99 let p = prompt ctx in 100 100 Fmt.pr "%s\r%!" p; 101 + let hint command = 102 + if String.length command < 2 then None 103 + else 104 + match H.history ~command !h |> H.commands with 105 + | [] -> None 106 + | x :: _ -> ( 107 + match Astring.String.cut ~sep:command x with 108 + | Some ("", rest) -> Some (rest, `Fg (`Hi `Magenta)) 109 + | _ -> None) 110 + in 101 111 match 102 - Bruit.bruit 112 + Bruit.bruit ~hint 103 113 ~history:(fun command -> H.history ~command !h |> H.commands) 104 114 ~complete "% " 105 115 with
+13
test/debootstrap/Dockerfile
··· 1 + FROM ocaml/opam:debian-13-ocaml-5.3@sha256:3f0e61f92c78a39cd5161d75975809d44fc12fa7e6ae0fbced236aa1a2ae45e9 AS builder 2 + 3 + WORKDIR /home/opam/src 4 + 5 + COPY --chown=opam merry.opam . 6 + RUN opam pin . -yn 7 + RUN opam install . --deps-only --with-test 8 + COPY --chown=opam . . 9 + RUN opam exec -- dune build --profile=release 10 + 11 + FROM debian:13 12 + COPY --from=builder /home/opam/src/_build/default/src/bin/main.exe /bin/msh 13 + ENTRYPOINT [ "msh" ]
+44 -13
vendor/bruit/src/bruit.ml
··· 1 1 (* See the end of the file for the original license of Linenoise. *) 2 - 2 + let () = Fmt.set_style_renderer Format.str_formatter `Ansi_tty 3 3 let max_line = 2048 4 + 5 + type hint = string -> (string * Fmt.style) option 4 6 5 7 type key = 6 8 | Enter ··· 59 61 in_completion : bool; 60 62 completion_idx : int; 61 63 complete : completion option; 64 + hint : hint; 62 65 } 63 66 64 67 let buf t = Bytes.sub t.buf 0 t.len 65 68 66 69 let make ?(in_completion = false) ?(completion_idx = 0) ?complete 67 - ?(old_pos = 0) ?(pos = 0) ?(len = 0) ?(history = []) ?(ifd = Unix.stdin) 68 - ?(ofd = Unix.stdout) ~prompt buf = 70 + ?(old_pos = 0) ?(pos = 0) ?(len = 0) ?(history = []) 71 + ?(hint = fun _ -> None) ?(ifd = Unix.stdin) ?(ofd = Unix.stdout) ~prompt 72 + buf = 69 73 { 70 74 in_completion; 71 75 ifd; ··· 86 90 complete; 87 91 completion_idx; 88 92 read_buf = Bytes.make 1 '\000' (* For reading a character *); 93 + hint; 89 94 } 90 95 91 96 let override ?in_completion ?completion_idx ?complete ?ifd ?ofd ?buf ?buf_len ··· 116 121 completion_idx = Option.value ~default:t.completion_idx completion_idx; 117 122 history = Option.value ~default:t.history history; 118 123 saved_buf = Option.value ~default:t.saved_buf saved_buf; 124 + hint = t.hint; 119 125 } 120 126 end 121 127 ··· 195 201 196 202 type refresh_flag = Rewrite 197 203 204 + let refresh_with_hints ~pwidth ~ab (state : State.t) = 205 + let buf_width = utf8_display_width state.buf state.len in 206 + if pwidth + buf_width < state.cols then begin 207 + match state.hint (State.buf state |> Bytes.to_string) with 208 + | None -> () 209 + | Some (hint, style) -> 210 + let () = 211 + Format.fprintf Format.str_formatter "%a" 212 + Fmt.(styled style string) 213 + hint 214 + in 215 + Buffer.add_string ab (Format.flush_str_formatter ()) 216 + end 217 + 198 218 let refresh_single_line ?(flags = []) ?prompt (state : State.t) = 199 219 let prompt = match prompt with None -> state.prompt | Some p -> p in 200 220 let pwidth = utf8_display_width prompt state.plen in ··· 227 247 Buffer.add_bytes ab prompt; 228 248 Buffer.add_bytes ab (Bytes.sub state.buf 0 state.len) 229 249 end; 250 + 251 + refresh_with_hints ~pwidth:state.len ~ab state; 230 252 231 253 (* Erase to the right *) 232 254 Buffer.add_string ab "\x1b[0K"; ··· 270 292 < state.cols 271 293 then begin 272 294 write_uchar state.ofd c; 273 - state 295 + refresh_line state 274 296 end 275 297 else refresh_line state 276 298 end ··· 298 320 in 299 321 refresh_line state 300 322 301 - let get_bytes state = Bytes.sub state.State.buf 0 state.len 302 - 303 323 let complete_line (state : State.t) c cn = 304 - match cn (String.of_bytes (get_bytes state)) with 324 + match cn (String.of_bytes (State.buf state)) with 305 325 | [] -> (State.override ~in_completion:false state, `Char c) 306 326 | xs -> 307 327 let state, c = ··· 345 365 in 346 366 refresh_line s 347 367 368 + let complete_with_hint (state : State.t) = 369 + let buf = State.buf state |> Bytes.to_string in 370 + match state.hint buf with 371 + | None -> state 372 + | Some (h, _) -> 373 + let new_buf = buf ^ h in 374 + let end_buf = String.length new_buf in 375 + Bytes.blit_string new_buf 0 state.buf 0 end_buf; 376 + State.override ~pos:end_buf ~len:end_buf state 377 + 348 378 let move_right (state : State.t) = 349 379 let s = 350 - if state.pos > 0 then 380 + if state.pos < state.len then 351 381 State.override 352 382 ~pos:(state.pos + utf8_next_char_len state.buf state.pos) 353 383 state 384 + else if state.pos = state.len then complete_with_hint state 354 385 else state 355 386 in 356 387 refresh_line s ··· 526 557 527 558 type result = String of string option | Ctrl_c 528 559 529 - let blocking_edit ?complete ~history ~stdin ~stdout buf ~prompt = 530 - let state = State.make ?complete ~prompt buf in 560 + let blocking_edit ?complete ~history ~hint ~stdin ~stdout buf ~prompt = 561 + let state = State.make ?complete ~hint ~prompt buf in 531 562 let res = 532 563 edit_start ~stdin ~stdout state @@ fun state -> 533 564 let rec loop = function ··· 541 572 542 573 type history = string -> string list 543 574 544 - let bruit ?complete ?(history = fun _ -> []) prompt = 575 + let bruit ?complete ?(history = fun _ -> []) ?(hint = fun _ -> None) prompt = 545 576 let prompt = Bytes.of_string prompt in 546 577 let buf = Bytes.make max_line '\000' in 547 578 if not (Unix.isatty Unix.stdin) then failwith "Stdin is not a tty" 548 579 else 549 - blocking_edit ?complete ~history ~stdin:Unix.stdin ~stdout:Unix.stdout buf 550 - ~prompt 580 + blocking_edit ?complete ~history ~hint ~stdin:Unix.stdin ~stdout:Unix.stdout 581 + buf ~prompt 551 582 552 583 (* 553 584 * Copyright (c) 2010-2023, Salvatore Sanfilippo <antirez at gmail dot com>
+9 -1
vendor/bruit/src/bruit.mli
··· 8 8 (** The history callback that provides the user with the current line and 9 9 expects a list of history items to scroll through using the arrow keys. *) 10 10 11 + type hint = string -> (string * Fmt.style) option 12 + (** The hint callback takes the current input and a user can return, optionally, 13 + extra information to fill in on the current line. *) 14 + 11 15 type result = String of string option | Ctrl_c 12 16 13 17 val bruit : 14 - ?complete:(string -> string list) -> ?history:history -> string -> result 18 + ?complete:(string -> string list) -> 19 + ?history:history -> 20 + ?hint:hint -> 21 + string -> 22 + result 15 23 (** [bruit ?complete prompt] reads from [stdin] and returns the read string if 16 24 any, and on [ctrl+c] returns {! Ctrl_c}. 17 25