2

I would like to implement a REPL in another language than Erlang, and am really intrigued by this feature of the interactive erl (Eshell) prompt:

1> spawn(fun() -> timer:sleep(5000), io:format("~p~n", ["later"]) end).
<0.34.0>
2> i can ty

So what I did here is spawn some background process that eventually writes to the terminal. In the meantime I've typed i can ty just as five seconds have passed by and "later" gets inserted right above 2>, resulting in:

1> spawn(fun() -> timer:sleep(5000), io:format("~p~n", ["later"]) end).
<0.34.0>
"later"      
2> i can type...

In other languages, such as Bash or Node.js, this would rather have resulted in something like:

2> i can ty"later"
pe...

How does Erlang do that? I've tried googling around and even had a quick look at its source code, but could not find out how this gets accomplished. I assume it must involve some terminal control sequences?

Felix Rabe
  • 4,206
  • 4
  • 25
  • 34
  • This is not an easy question, and to be honest you might not find answer here. If you are really interested you might hit erlang mailig list, where all the cool-cats hang out: `erlang-questions@erlang.org` – mpm Oct 05 '14 at 00:20
  • Writing to stdout is done by a process. Messages sent to it could be intercepted by the shell. –  Oct 05 '14 at 00:25

1 Answers1

4

Erlang shell is more complex than in other languages, because it has to work with distributed systems with many processes. Fred Hebert wrote article about Erlang shell called "As bad as anything else".

Basically, when you call io:format, it sends a message to its group leader. In "Learn you some Erlang/Building OTP applications" (again by Fred) there is a note about group leaders and io protocol.

As @rightfold mentioned in his comment in his comment, io_protocol involves sending messages. It means, that they are written to the console sequentially. In other languages, if you have more processes writing at the same time, you can have parts of the messages interleaved, but not in Erlang. The protocol also involves waiting for reply. For example, check io:execute_request on github.

user_drv is responsible for writing the message to actual tty and it uses ncurses to put it, where it wants, so it can insert the message before the command you started to write, which leaves clean history.

tkowal
  • 9,129
  • 1
  • 27
  • 51