Shells in OCaml

Vendor bruit directly

+698 -3
-3
.gitmodules
··· 1 - [submodule "vendor/bruit"] 2 - path = vendor/bruit 3 - url = https://tangled.org/patrick.sirref.org/bruit
+1
vendor/bruit/.gitignore
··· 1 + _build
+1
vendor/bruit/.ocamlformat
··· 1 + version=0.28.1
+5
vendor/bruit/README.md
··· 1 + bruit 2 + ----- 3 + 4 + An OCaml port of the excellent 5 + [linenoise](https://github.com/antirez/linenoise) library.
+32
vendor/bruit/bruit.opam
··· 1 + # This file is generated by dune, edit dune-project instead 2 + opam-version: "2.0" 3 + synopsis: "A short synopsis" 4 + description: "A longer description" 5 + maintainer: ["Maintainer Name <maintainer@example.com>"] 6 + authors: ["Author Name <author@example.com>"] 7 + license: "LICENSE" 8 + tags: ["add topics" "to describe" "your" "project"] 9 + homepage: "https://github.com/username/reponame" 10 + doc: "https://url/to/documentation" 11 + bug-reports: "https://github.com/username/reponame/issues" 12 + depends: [ 13 + "dune" {>= "3.20"} 14 + "ocaml" 15 + "odoc" {with-doc} 16 + ] 17 + build: [ 18 + ["dune" "subst"] {dev} 19 + [ 20 + "dune" 21 + "build" 22 + "-p" 23 + name 24 + "-j" 25 + jobs 26 + "@install" 27 + "@runtest" {with-test} 28 + "@doc" {with-doc} 29 + ] 30 + ] 31 + dev-repo: "git+https://github.com/username/reponame.git" 32 + x-maintenance-intent: ["(latest)"]
+26
vendor/bruit/dune-project
··· 1 + (lang dune 3.20) 2 + 3 + (name bruit) 4 + 5 + (generate_opam_files true) 6 + 7 + (source 8 + (github username/reponame)) 9 + 10 + (authors "Author Name <author@example.com>") 11 + 12 + (maintainers "Maintainer Name <maintainer@example.com>") 13 + 14 + (license LICENSE) 15 + 16 + (documentation https://url/to/documentation) 17 + 18 + (package 19 + (name bruit) 20 + (synopsis "A short synopsis") 21 + (description "A longer description") 22 + (depends ocaml) 23 + (tags 24 + ("add topics" "to describe" your project))) 25 + 26 + ; See the complete stanza docs at https://dune.readthedocs.io/en/stable/reference/dune-project/index.html
+3
vendor/bruit/example/dune
··· 1 + (executable 2 + (name main) 3 + (libraries bruit fmt.tty))
+27
vendor/bruit/example/main.ml
··· 1 + let h = ref [] 2 + 3 + let history prefix = 4 + if prefix <> "" then List.filter (fun s -> String.starts_with ~prefix s) !h 5 + else !h 6 + 7 + let complete s = 8 + match String.get s 0 with 9 + | 'h' -> [ "hello"; "hello there" ] 10 + | _ | (exception Invalid_argument _) -> [] 11 + 12 + let () = 13 + Fmt_tty.setup_std_outputs (); 14 + let rec loop sys_break = 15 + let prompt = 16 + if sys_break then "[\x1b[31m130\x1b[0m] \x1b[33m>>\x1b[0m " 17 + else "\x1b[33m>>\x1b[0m " 18 + in 19 + match Bruit.bruit ~history ~complete prompt with 20 + | String (Some s) -> 21 + Fmt.pr "%s\n%!" s; 22 + h := s :: !h; 23 + loop false 24 + | String None -> () 25 + | Ctrl_c -> loop true 26 + in 27 + loop false
+579
vendor/bruit/src/bruit.ml
··· 1 + (* See the end of the file for the original license of Linenoise. *) 2 + 3 + let max_line = 2048 4 + 5 + type key = 6 + | Enter 7 + | Ctrl_a 8 + | Ctrl_b 9 + | Ctrl_c 10 + | Ctrl_d 11 + | Ctrl_e 12 + | Ctrl_f 13 + | Ctrl_r 14 + | Ctrl_p 15 + | Ctrl_g 16 + | Backspace 17 + | Escape_sequence 18 + | Tab 19 + | Unknown of Uchar.t 20 + 21 + let key_of_char c = 22 + match Char.code c with 23 + | 1 -> Ctrl_a 24 + | 2 -> Ctrl_b 25 + | 3 -> Ctrl_c 26 + | 4 -> Ctrl_d 27 + | 5 -> Ctrl_e 28 + | 6 -> Ctrl_f 29 + | 7 -> Ctrl_g 30 + | 16 -> Ctrl_p 31 + | 18 -> Ctrl_r 32 + | 9 -> Tab 33 + | 13 -> Enter 34 + | 27 -> Escape_sequence 35 + | 127 -> Backspace 36 + | _ -> Unknown (Uchar.of_char c) 37 + 38 + module State = struct 39 + type completion = string -> string list 40 + 41 + type t = { 42 + ifd : Unix.file_descr; 43 + ofd : Unix.file_descr; 44 + buf : bytes; 45 + buf_len : int; 46 + prompt : bytes; 47 + plen : int; 48 + old_pos : int; 49 + pos : int; 50 + len : int; 51 + (* Update later *) 52 + cols : int; 53 + old_rows : int; 54 + old_row_pos : int; 55 + history_index : int; 56 + history : string list; 57 + saved_buf : string; 58 + read_buf : Bytes.t; 59 + in_completion : bool; 60 + completion_idx : int; 61 + complete : completion option; 62 + } 63 + 64 + let buf t = Bytes.sub t.buf 0 t.len 65 + 66 + 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 = 69 + { 70 + in_completion; 71 + ifd; 72 + ofd; 73 + buf; 74 + buf_len = Bytes.length buf; 75 + prompt; 76 + plen = Bytes.length prompt; 77 + old_pos; 78 + pos; 79 + len; 80 + cols = 0; 81 + old_row_pos = 1; 82 + history; 83 + old_rows = 0; 84 + history_index = -1; 85 + saved_buf = ""; 86 + complete; 87 + completion_idx; 88 + read_buf = Bytes.make 1 '\000' (* For reading a character *); 89 + } 90 + 91 + let override ?in_completion ?completion_idx ?complete ?ifd ?ofd ?buf ?buf_len 92 + ?prompt ?plen ?old_pos ?pos ?len ?cols ?old_rows ?old_row_pos 93 + ?history_index ?history ?saved_buf (t : t) = 94 + let () = 95 + match buf with 96 + | None -> () 97 + | Some buf -> Bytes.blit buf 0 t.buf 0 (Bytes.length buf) 98 + in 99 + { 100 + in_completion = Option.value ~default:t.in_completion in_completion; 101 + ifd = Option.value ~default:t.ifd ifd; 102 + ofd = Option.value ~default:t.ofd ofd; 103 + buf = t.buf; 104 + buf_len = Option.value ~default:t.buf_len buf_len; 105 + prompt = Option.value ~default:t.prompt prompt; 106 + plen = Option.value ~default:t.plen plen; 107 + old_pos = Option.value ~default:t.old_pos old_pos; 108 + pos = Option.value ~default:t.pos pos; 109 + len = Option.value ~default:t.len len; 110 + cols = Option.value ~default:t.cols cols; 111 + old_rows = Option.value ~default:t.old_rows old_rows; 112 + old_row_pos = Option.value ~default:t.old_row_pos old_row_pos; 113 + history_index = Option.value ~default:t.history_index history_index; 114 + complete = (match complete with Some f -> Some f | None -> t.complete); 115 + read_buf = t.read_buf; 116 + completion_idx = Option.value ~default:t.completion_idx completion_idx; 117 + history = Option.value ~default:t.history history; 118 + saved_buf = Option.value ~default:t.saved_buf saved_buf; 119 + } 120 + end 121 + 122 + let get_columns () = 123 + match Terminal.Size.get_columns () with Some n -> n | None -> 80 124 + 125 + let with_raw_mode (state : State.t) fn = 126 + let saved_tio = Unix.tcgetattr state.ifd in 127 + let tio : Unix.terminal_io = 128 + { 129 + saved_tio with 130 + c_brkint = false; 131 + c_icrnl = false; 132 + c_inpck = false; 133 + c_istrip = false; 134 + c_ixon = false; 135 + c_opost = false; 136 + c_csize = 8; 137 + c_echo = false; 138 + c_icanon = false; 139 + c_isig = false; 140 + c_vtime = 0; 141 + c_vmin = 1; 142 + } 143 + in 144 + Unix.tcsetattr state.ifd TCSAFLUSH tio; 145 + Fun.protect 146 + ~finally:(fun () -> Unix.tcsetattr state.ifd TCSADRAIN saved_tio) 147 + fn 148 + 149 + let write_bytes fd s = 150 + let len = Bytes.length s in 151 + let wrote = Unix.write fd s 0 len in 152 + assert (Int.equal len wrote) 153 + 154 + let write_uchar fd u = 155 + let b_len = Uchar.utf_8_byte_length u in 156 + let bs = Bytes.create b_len in 157 + let wrote = Bytes.set_utf_8_uchar bs 0 u in 158 + assert (Int.equal b_len wrote); 159 + write_bytes fd bs 160 + 161 + type edit = Editing of State.t | Finished of bytes option | Ctrl_c 162 + 163 + let read_char state = 164 + try 165 + let read = Unix.read state.State.ifd state.read_buf 0 1 in 166 + if read = 0 then `None else `Some (Bytes.unsafe_get state.read_buf 0) 167 + with Unix.Unix_error ((Unix.EWOULDBLOCK | Unix.EAGAIN), _, _) -> `Editing 168 + 169 + let edit_start ~stdin:_ ~stdout:_ state fn = 170 + with_raw_mode state @@ fun () -> 171 + let cols = get_columns () in 172 + (* Bytes.set state.buf 0 '\000'; *) 173 + let state = State.override ~cols ~buf_len:(state.buf_len - 1) state in 174 + write_bytes state.ofd state.prompt; 175 + fn state 176 + 177 + let utf8_display_width b len = 178 + let s = Bytes.to_string b in 179 + Terminal.guess_printed_width (String.sub s 0 len) 180 + 181 + let utf8_next_char_len s off = 182 + Bytes.get_utf_8_uchar s off 183 + |> Uchar.utf_decode_uchar |> Uchar.utf_8_byte_length 184 + 185 + let utf8_prev_char_len s off = 186 + let rec loop pos = 187 + if pos < 0 || pos < off - 4 then 188 + invalid_arg "UTF8 previous character length"; 189 + let decode = Bytes.get_utf_8_uchar s off in 190 + if Uchar.utf_decode_is_valid decode then 191 + Uchar.utf_decode_uchar decode |> Uchar.utf_8_byte_length 192 + else loop (pos - 1) 193 + in 194 + loop (off - 1) 195 + 196 + type refresh_flag = Rewrite 197 + 198 + let refresh_single_line ?(flags = []) ?prompt (state : State.t) = 199 + let prompt = match prompt with None -> state.prompt | Some p -> p in 200 + let pwidth = utf8_display_width prompt state.plen in 201 + let poscol = ref @@ utf8_display_width state.buf state.pos in 202 + let lencol = ref @@ utf8_display_width state.buf state.len in 203 + 204 + let rec loop (state : State.t) = 205 + if pwidth + !poscol >= state.cols then begin 206 + let clen = utf8_next_char_len state.buf 0 in 207 + let c_width = 208 + Uchar.utf_8_byte_length 209 + (Bytes.get_utf_8_uchar state.buf clen |> Uchar.utf_decode_uchar) 210 + in 211 + poscol := !poscol - c_width; 212 + lencol := !lencol - c_width; 213 + let state = 214 + State.override ~len:(state.len - clen) ~pos:(state.pos - clen) state 215 + in 216 + loop state 217 + end 218 + else state 219 + in 220 + let state = loop state in 221 + let ab = Buffer.create 0 in 222 + (* Clear line *) 223 + Buffer.add_char ab '\r'; 224 + 225 + (* Add prompt *) 226 + if List.mem Rewrite flags then begin 227 + Buffer.add_bytes ab prompt; 228 + Buffer.add_bytes ab (Bytes.sub state.buf 0 state.len) 229 + end; 230 + 231 + (* Erase to the right *) 232 + Buffer.add_string ab "\x1b[0K"; 233 + 234 + (* Cursor to the original position *) 235 + if List.mem Rewrite flags then begin 236 + Buffer.add_string ab (Format.sprintf "\r\x1b[%dC" (!poscol + pwidth)) 237 + end; 238 + write_bytes state.ofd (Buffer.to_bytes ab); 239 + state 240 + 241 + let refresh_line state = refresh_single_line ~flags:[ Rewrite ] state 242 + 243 + let refresh_line_with_completions (state : State.t) lcs = 244 + if state.completion_idx < List.length lcs then 245 + let saved_state = state in 246 + let saved_buf = Bytes.copy state.buf in 247 + let state = 248 + State.override 249 + ~len:(Bytes.length (List.nth lcs state.completion_idx)) 250 + ~pos:(Bytes.length (List.nth lcs state.completion_idx)) 251 + ~buf:(List.nth lcs state.completion_idx) 252 + state 253 + in 254 + let state : State.t = refresh_line state in 255 + State.override state ~len:saved_state.len ~pos:saved_state.pos 256 + ~buf:saved_buf 257 + else state 258 + 259 + let edit_insert (state : State.t) c = 260 + let clen = Uchar.utf_8_byte_length c in 261 + (* At the end of the line *) 262 + if Int.equal state.len state.pos then begin 263 + let _ : int = Bytes.set_utf_8_uchar state.buf state.pos c in 264 + let state = 265 + State.override ~pos:(state.pos + clen) ~len:(state.len + clen) state 266 + in 267 + if 268 + utf8_display_width state.prompt state.plen 269 + + utf8_display_width state.buf state.len 270 + < state.cols 271 + then begin 272 + write_uchar state.ofd c; 273 + state 274 + end 275 + else refresh_line state 276 + end 277 + else begin 278 + Bytes.blit state.buf state.pos state.buf (state.pos + clen) 279 + (state.len - state.pos); 280 + let _ : int = Bytes.set_utf_8_uchar state.buf state.pos c in 281 + let state = 282 + State.override ~len:(state.len + clen) ~pos:(state.pos + clen) state 283 + in 284 + refresh_line state 285 + end 286 + 287 + let edit_backspace (state : State.t) = 288 + let state = 289 + if state.pos > 0 && state.len > 0 then begin 290 + let clen = utf8_prev_char_len state.buf state.pos in 291 + let dst = state.pos - clen in 292 + let src = state.pos in 293 + let len = state.len - state.pos in 294 + Bytes.blit state.buf src state.buf dst len; 295 + State.override ~pos:(state.pos - clen) ~len:(state.len - clen) state 296 + end 297 + else state 298 + in 299 + refresh_line state 300 + 301 + let get_bytes state = Bytes.sub state.State.buf 0 state.len 302 + 303 + let complete_line (state : State.t) c cn = 304 + match cn (String.of_bytes (get_bytes state)) with 305 + | [] -> (State.override ~in_completion:false state, `Char c) 306 + | xs -> 307 + let state, c = 308 + match key_of_char c with 309 + | Tab -> 310 + if not state.in_completion then 311 + ( State.override ~in_completion:true ~completion_idx:0 state, 312 + `Edit_more ) 313 + else 314 + ( State.override 315 + ~completion_idx: 316 + ((state.completion_idx + 1) mod (List.length xs + 1)) 317 + state, 318 + `Edit_more ) 319 + | _ -> 320 + let state = 321 + if state.completion_idx < List.length xs then begin 322 + let to_write = List.nth xs state.completion_idx in 323 + let to_write_len = String.length to_write in 324 + Bytes.blit_string to_write 0 state.buf 0 to_write_len; 325 + State.override ~len:to_write_len ~pos:to_write_len state 326 + end 327 + else state 328 + in 329 + (State.override ~in_completion:false state, `Char c) 330 + in 331 + if state.in_completion && state.completion_idx < List.length xs then begin 332 + (refresh_line_with_completions state (List.map Bytes.of_string xs), c) 333 + end 334 + else begin 335 + (refresh_line state, c) 336 + end 337 + 338 + let move_left (state : State.t) = 339 + let s = 340 + if state.pos > 0 then 341 + State.override 342 + ~pos:(state.pos - utf8_prev_char_len state.buf state.pos) 343 + state 344 + else state 345 + in 346 + refresh_line s 347 + 348 + let move_right (state : State.t) = 349 + let s = 350 + if state.pos > 0 then 351 + State.override 352 + ~pos:(state.pos + utf8_next_char_len state.buf state.pos) 353 + state 354 + else state 355 + in 356 + refresh_line s 357 + 358 + let reverse_incr_search ~history (state : State.t) = 359 + let has_match = ref true in 360 + let search_buf = Buffer.create 16 in 361 + let search_pos = ref 0 in 362 + let search_dir = ref (-1) in 363 + let h = history "" in 364 + let history_len = List.length h in 365 + let saved_buf = Bytes.copy state.buf in 366 + let exception Completed of State.t in 367 + let rec loop state : State.t = 368 + let prompt = 369 + if !has_match then 370 + Fmt.str "(reverse-i-search)`%s': " (Buffer.contents search_buf) 371 + else 372 + Fmt.str "(failed-reverse-i-search)`%s': " (Buffer.contents search_buf) 373 + in 374 + let new_char = ref false in 375 + let state = State.override ~pos:0 state in 376 + let state = 377 + refresh_single_line ~flags:[ Rewrite ] ~prompt:(String.to_bytes prompt) 378 + state 379 + in 380 + let state = 381 + match read_char state with 382 + | `Editing -> loop state 383 + | `None -> loop state 384 + | `Some c -> ( 385 + match key_of_char c with 386 + | Backspace -> 387 + if Buffer.length search_buf > 0 then begin 388 + (* Pretty wasteful... *) 389 + let s = Buffer.contents search_buf in 390 + Buffer.clear search_buf; 391 + Buffer.add_substring search_buf s 0 (String.length s - 1); 392 + search_pos := 0 393 + end; 394 + state 395 + | Ctrl_p -> 396 + search_dir := -1; 397 + if !search_pos >= history_len then search_pos := history_len - 1; 398 + state 399 + | Ctrl_r -> 400 + search_dir := 1; 401 + if !search_pos < 0 then search_pos := 0; 402 + state 403 + | Ctrl_g -> 404 + let l = Bytes.length saved_buf in 405 + Bytes.blit saved_buf 0 state.buf 0 l; 406 + let state = refresh_line (State.override ~pos:l ~len:l state) in 407 + raise (Completed state) 408 + | Enter -> 409 + let state = State.override ~pos:state.len state in 410 + raise (Completed state) 411 + | _ -> 412 + if Char.compare c ' ' > 0 then begin 413 + new_char := true; 414 + Buffer.add_char search_buf c; 415 + search_pos := 0; 416 + state 417 + end 418 + else 419 + State.override ~pos:state.len state |> refresh_line |> fun s -> 420 + raise (Completed s)) 421 + in 422 + has_match := false; 423 + let state = 424 + if Buffer.length search_buf > 0 then begin 425 + let rec inner_loop () = 426 + if !search_pos >= 0 && !search_pos < history_len then begin 427 + let entry = List.nth h !search_pos in 428 + match 429 + ( Astring.String.cut ~sep:(Buffer.contents search_buf) entry, 430 + !new_char 431 + || not 432 + @@ String.equal entry (Bytes.to_string (State.buf state)) ) 433 + with 434 + | Some (_l, _r), true -> 435 + has_match := true; 436 + Bytes.blit_string entry 0 state.buf 0 (String.length entry); 437 + let state = State.override ~len:(String.length entry) state in 438 + state 439 + | _ -> 440 + search_pos := !search_pos + !search_dir; 441 + inner_loop () 442 + end 443 + else state 444 + in 445 + inner_loop () 446 + end 447 + else state 448 + in 449 + loop state 450 + in 451 + try loop state with Completed state -> state 452 + 453 + let edit_history dir fn (state : State.t) = 454 + let saved_state = state in 455 + let current_buf = Bytes.sub_string state.buf 0 state.len in 456 + let state = 457 + match (dir, state.history_index) with 458 + | `Prev, -1 -> 459 + State.override ~history:(fn current_buf) ~history_index:0 460 + ~saved_buf:current_buf state 461 + | `Prev, m -> 462 + let max_history = List.length state.history in 463 + if m < max_history - 1 then 464 + State.override ~history_index:(state.history_index + 1) state 465 + else state 466 + | `Next, m when m >= 0 -> 467 + State.override ~history_index:(state.history_index - 1) state 468 + | _ -> state 469 + in 470 + match (state.history, state.history_index) with 471 + | [], _ -> saved_state 472 + | _, -1 -> 473 + let len = String.length state.saved_buf in 474 + State.override ~buf:(Bytes.of_string state.saved_buf) ~pos:len ~len state 475 + |> refresh_line 476 + | _ -> 477 + let max_history = List.length state.history in 478 + let idx = min max_history state.history_index in 479 + let s = List.nth state.history idx in 480 + let s_len = String.length s in 481 + State.override ~buf:(Bytes.of_string s) ~pos:s_len ~len:s_len state 482 + |> refresh_line 483 + 484 + let edit_feed ~history state = 485 + match read_char state with 486 + | `Editing -> Editing state 487 + | `None -> Finished None 488 + | `Some c -> ( 489 + let uc = Uchar.of_char c in 490 + let state, c = 491 + if state.in_completion || key_of_char c = Tab then 492 + match state.complete with 493 + | None -> (state, `Char c) 494 + | Some cn -> complete_line state c cn 495 + else (state, `Char c) 496 + in 497 + match c with 498 + | `Edit_more -> Editing state 499 + | `Char c -> ( 500 + match key_of_char c with 501 + | Enter -> Finished (Some (Bytes.sub state.buf 0 state.len)) 502 + | Ctrl_d -> 503 + if Int.equal state.len 0 then Finished None else Editing state 504 + | Ctrl_c -> Ctrl_c 505 + | Ctrl_b -> Editing (move_left state) 506 + | Ctrl_f -> Editing (move_right state) 507 + | Ctrl_r -> Editing (reverse_incr_search ~history state) 508 + | Backspace -> Editing (edit_backspace state) 509 + | Tab -> Editing state 510 + | Escape_sequence -> ( 511 + let c1 = 512 + read_char state |> function `Some c -> c | _ -> assert false 513 + in 514 + let c2 = 515 + read_char state |> function `Some c -> c | _ -> assert false 516 + in 517 + match (c1, c2) with 518 + | '[', 'A' -> Editing (edit_history `Prev history state) 519 + | '[', 'B' -> Editing (edit_history `Next history state) 520 + | '[', 'C' -> Editing (move_right state) 521 + | '[', 'D' -> Editing (move_left state) 522 + | _ -> Editing state) 523 + | Unknown _ | _ -> 524 + let state = edit_insert state uc in 525 + Editing state)) 526 + 527 + type result = String of string option | Ctrl_c 528 + 529 + let blocking_edit ?complete ~history ~stdin ~stdout buf ~prompt = 530 + let state = State.make ?complete ~prompt buf in 531 + let res = 532 + edit_start ~stdin ~stdout state @@ fun state -> 533 + let rec loop = function 534 + | Editing state -> loop (edit_feed ~history state) 535 + | Finished s -> String (Option.map Bytes.to_string s) 536 + | Ctrl_c -> Ctrl_c 537 + in 538 + loop (edit_feed ~history state) 539 + in 540 + res 541 + 542 + type history = string -> string list 543 + 544 + let bruit ?complete ?(history = fun _ -> []) prompt = 545 + let prompt = Bytes.of_string prompt in 546 + let buf = Bytes.make max_line '\000' in 547 + if not (Unix.isatty Unix.stdin) then failwith "Stdin is not a tty" 548 + else 549 + blocking_edit ?complete ~history ~stdin:Unix.stdin ~stdout:Unix.stdout buf 550 + ~prompt 551 + 552 + (* 553 + * Copyright (c) 2010-2023, Salvatore Sanfilippo <antirez at gmail dot com> 554 + * Copyright (c) 2010-2013, Pieter Noordhuis <pcnoordhuis at gmail dot com> 555 + * 556 + * All rights reserved. 557 + * 558 + * Redistribution and use in source and binary forms, with or without 559 + * modification, are permitted provided that the following conditions are 560 + * met: 561 + * 562 + * * Redistributions of source code must retain the above copyright 563 + * notice, this list of conditions and the following disclaimer. 564 + * 565 + * * Redistributions in binary form must reproduce the above copyright 566 + * notice, this list of conditions and the following disclaimer in the 567 + * documentation and/or other materials provided with the distribution. 568 + * 569 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 570 + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 571 + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 572 + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 573 + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 574 + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 575 + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 576 + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 577 + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 578 + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 579 + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *)
+18
vendor/bruit/src/bruit.mli
··· 1 + (** {! Bruit} is a port of the C library 2 + {{:https://github.com/antirez/linenoise} Linenoise} to OCaml. It is not as 3 + feature complete as the library, contributions are very welcome. 4 + 5 + The main entry point to the library is {! bruit}. *) 6 + 7 + type history = string -> string list 8 + (** The history callback that provides the user with the current line and 9 + expects a list of history items to scroll through using the arrow keys. *) 10 + 11 + type result = String of string option | Ctrl_c 12 + 13 + val bruit : 14 + ?complete:(string -> string list) -> ?history:history -> string -> result 15 + (** [bruit ?complete prompt] reads from [stdin] and returns the read string if 16 + any, and on [ctrl+c] returns {! Ctrl_c}. 17 + 18 + @param complete Used for completions, defaults to [None]. *)
+4
vendor/bruit/src/dune
··· 1 + (library 2 + (public_name bruit) 3 + (libraries terminal unix fmt astring) 4 + (name bruit))
+2
vendor/bruit/test/dune
··· 1 + (test 2 + (name test_bruit))
vendor/bruit/test/test_bruit.ml

This is a binary file and will not be displayed.