···13131414let get_user_and_host () =
1515 Eio_unix.run_in_systhread ~label:"get_user_and_host" @@ fun () ->
1616- let name = Unix.getlogin () in
1616+ let name =
1717+ try Unix.getlogin () with Unix.Unix_error (Unix.ENOENT, _, _) -> "root"
1818+ in
1719 let host = Unix.gethostname () in
1820 Fmt.str "%s@%s" name host
1921
+11-1
src/lib/interactive.ml
···9898 |> Option.map Ast.word_components_to_string);
9999 let p = prompt ctx in
100100 Fmt.pr "%s\r%!" p;
101101+ let hint command =
102102+ if String.length command < 2 then None
103103+ else
104104+ match H.history ~command !h |> H.commands with
105105+ | [] -> None
106106+ | x :: _ -> (
107107+ match Astring.String.cut ~sep:command x with
108108+ | Some ("", rest) -> Some (rest, `Fg (`Hi `Magenta))
109109+ | _ -> None)
110110+ in
101111 match
102102- Bruit.bruit
112112+ Bruit.bruit ~hint
103113 ~history:(fun command -> H.history ~command !h |> H.commands)
104114 ~complete "% "
105115 with
···11(* See the end of the file for the original license of Linenoise. *)
22-22+let () = Fmt.set_style_renderer Format.str_formatter `Ansi_tty
33let max_line = 2048
44+55+type hint = string -> (string * Fmt.style) option
4657type key =
68 | Enter
···5961 in_completion : bool;
6062 completion_idx : int;
6163 complete : completion option;
6464+ hint : hint;
6265 }
63666467 let buf t = Bytes.sub t.buf 0 t.len
65686669 let make ?(in_completion = false) ?(completion_idx = 0) ?complete
6767- ?(old_pos = 0) ?(pos = 0) ?(len = 0) ?(history = []) ?(ifd = Unix.stdin)
6868- ?(ofd = Unix.stdout) ~prompt buf =
7070+ ?(old_pos = 0) ?(pos = 0) ?(len = 0) ?(history = [])
7171+ ?(hint = fun _ -> None) ?(ifd = Unix.stdin) ?(ofd = Unix.stdout) ~prompt
7272+ buf =
6973 {
7074 in_completion;
7175 ifd;
···8690 complete;
8791 completion_idx;
8892 read_buf = Bytes.make 1 '\000' (* For reading a character *);
9393+ hint;
8994 }
90959196 let override ?in_completion ?completion_idx ?complete ?ifd ?ofd ?buf ?buf_len
···116121 completion_idx = Option.value ~default:t.completion_idx completion_idx;
117122 history = Option.value ~default:t.history history;
118123 saved_buf = Option.value ~default:t.saved_buf saved_buf;
124124+ hint = t.hint;
119125 }
120126end
121127···195201196202type refresh_flag = Rewrite
197203204204+let refresh_with_hints ~pwidth ~ab (state : State.t) =
205205+ let buf_width = utf8_display_width state.buf state.len in
206206+ if pwidth + buf_width < state.cols then begin
207207+ match state.hint (State.buf state |> Bytes.to_string) with
208208+ | None -> ()
209209+ | Some (hint, style) ->
210210+ let () =
211211+ Format.fprintf Format.str_formatter "%a"
212212+ Fmt.(styled style string)
213213+ hint
214214+ in
215215+ Buffer.add_string ab (Format.flush_str_formatter ())
216216+ end
217217+198218let refresh_single_line ?(flags = []) ?prompt (state : State.t) =
199219 let prompt = match prompt with None -> state.prompt | Some p -> p in
200220 let pwidth = utf8_display_width prompt state.plen in
···227247 Buffer.add_bytes ab prompt;
228248 Buffer.add_bytes ab (Bytes.sub state.buf 0 state.len)
229249 end;
250250+251251+ refresh_with_hints ~pwidth:state.len ~ab state;
230252231253 (* Erase to the right *)
232254 Buffer.add_string ab "\x1b[0K";
···270292 < state.cols
271293 then begin
272294 write_uchar state.ofd c;
273273- state
295295+ refresh_line state
274296 end
275297 else refresh_line state
276298 end
···298320 in
299321 refresh_line state
300322301301-let get_bytes state = Bytes.sub state.State.buf 0 state.len
302302-303323let complete_line (state : State.t) c cn =
304304- match cn (String.of_bytes (get_bytes state)) with
324324+ match cn (String.of_bytes (State.buf state)) with
305325 | [] -> (State.override ~in_completion:false state, `Char c)
306326 | xs ->
307327 let state, c =
···345365 in
346366 refresh_line s
347367368368+let complete_with_hint (state : State.t) =
369369+ let buf = State.buf state |> Bytes.to_string in
370370+ match state.hint buf with
371371+ | None -> state
372372+ | Some (h, _) ->
373373+ let new_buf = buf ^ h in
374374+ let end_buf = String.length new_buf in
375375+ Bytes.blit_string new_buf 0 state.buf 0 end_buf;
376376+ State.override ~pos:end_buf ~len:end_buf state
377377+348378let move_right (state : State.t) =
349379 let s =
350350- if state.pos > 0 then
380380+ if state.pos < state.len then
351381 State.override
352382 ~pos:(state.pos + utf8_next_char_len state.buf state.pos)
353383 state
384384+ else if state.pos = state.len then complete_with_hint state
354385 else state
355386 in
356387 refresh_line s
···526557527558type result = String of string option | Ctrl_c
528559529529-let blocking_edit ?complete ~history ~stdin ~stdout buf ~prompt =
530530- let state = State.make ?complete ~prompt buf in
560560+let blocking_edit ?complete ~history ~hint ~stdin ~stdout buf ~prompt =
561561+ let state = State.make ?complete ~hint ~prompt buf in
531562 let res =
532563 edit_start ~stdin ~stdout state @@ fun state ->
533564 let rec loop = function
···541572542573type history = string -> string list
543574544544-let bruit ?complete ?(history = fun _ -> []) prompt =
575575+let bruit ?complete ?(history = fun _ -> []) ?(hint = fun _ -> None) prompt =
545576 let prompt = Bytes.of_string prompt in
546577 let buf = Bytes.make max_line '\000' in
547578 if not (Unix.isatty Unix.stdin) then failwith "Stdin is not a tty"
548579 else
549549- blocking_edit ?complete ~history ~stdin:Unix.stdin ~stdout:Unix.stdout buf
550550- ~prompt
580580+ blocking_edit ?complete ~history ~hint ~stdin:Unix.stdin ~stdout:Unix.stdout
581581+ buf ~prompt
551582552583(*
553584 * Copyright (c) 2010-2023, Salvatore Sanfilippo <antirez at gmail dot com>
+9-1
vendor/bruit/src/bruit.mli
···88(** The history callback that provides the user with the current line and
99 expects a list of history items to scroll through using the arrow keys. *)
10101111+type hint = string -> (string * Fmt.style) option
1212+(** The hint callback takes the current input and a user can return, optionally,
1313+ extra information to fill in on the current line. *)
1414+1115type result = String of string option | Ctrl_c
12161317val bruit :
1414- ?complete:(string -> string list) -> ?history:history -> string -> result
1818+ ?complete:(string -> string list) ->
1919+ ?history:history ->
2020+ ?hint:hint ->
2121+ string ->
2222+ result
1523(** [bruit ?complete prompt] reads from [stdin] and returns the read string if
1624 any, and on [ctrl+c] returns {! Ctrl_c}.
1725