lambda-term
lambda-term copied to clipboard
Add `LTerm.flush term` when `lTerm_read_line` accepts user inputs (press Enter).
I am working on my repl based on examples/repl.ml. A common scenario is e.g. Interpreter.eval
prints something to the stdout.
module Interpreter = struct
type state = { n : int }
let eval state s =
let out = "evaluated " ^ s in
let new_state = { n = state.n + 1 } in
Printf.printf "(side effect: \nwrite to stdout)\n";
flush stdout;
(new_state, out)
end
This will make the LTerm_read_line
behave strange (though reasonable). It will write the user input line again and line border if show_box
is set true e.g.
$ dune exec examples/repl.exe
In [1]: 11(side effect:
write to stdout)───────────────────────────────────────────────────────────────────────────────────────────────────┐
In [1]: 11
Out [2]: evaluated 11
The original example prints like this when my input is 1 1 (Enter)
.
$ dune exec examples/repl.exe
In [1]: 11
Out [2]: evaluated 11
My expected restult is
$ dune exec examples/repl.exe
In [1]: 11
(side effect:
write to stdout)
Out [2]: evaluated 11
The problem can be fixed by adding a flush in the main loop of the example
let rec loop term history state =
Lwt.catch (fun () ->
let rl = new read_line ~term ~history:(LTerm_history.contents history) ~state in
rl#run >|= fun command -> Some command)
(function
| Sys.Break -> return None
| exn -> Lwt.fail exn)
>>= function
| Some command ->
(* ADD HERE *)
(* flush the stdout when it got a user input *)
LTerm.flush term >>= fun () ->
let command_utf8= Zed_string.to_utf8 command in
let state, out = Interpreter.eval state command_utf8 in
LTerm.fprintls term (make_output state out)
>>= fun () ->
LTerm_history.add history command;
loop term history state
| None ->
loop term history state
...
My point to make the issue is I think it may be better to flush the stdout inside src/lterm_read_line.ml
when it accepts user input when pressing enter (or ^M). There are LTerm.flush term
in the code when handling other cases.
As a comparison, utop
which is based on lambda_term
doesn't have this problem, .e.g
utop # print_endline "\n42\n";;
42
- : unit = ()
To make utop err (I did it for debug my reply), printing sth after it reads user input before flush the buffer at line 827 of uTop_main.ml
e.g. ((fun () -> print_endline "suffix\n"; LTerm.flush term)
). Now utop also prints my input print_endline "\n42\n";;
again and then do the execution.
utop # print_endline "\n42\nsuffix
─( 12:22:07 )─< command 1 >─────────────────────────────────────────────────────────────────────────────────────────────────────────────{ counter: 0 }─
utop # print_endline "\n42\n";;
42
- : unit = ()
I could also guess the reason in the redraw logic of LTerm.read_line
on this input line is triggered when extra output is put here.