Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add LTerm.flush term when lTerm_read_line accepts user inputs (press Enter). #106

Open
arbipher opened this issue Apr 3, 2022 · 1 comment

Comments

@arbipher
Copy link

arbipher commented Apr 3, 2022

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.

@arbipher
Copy link
Author

arbipher commented Apr 3, 2022

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant