Can the Erlang shell support Ctrl+D by default?

Can the Erlang shell support Ctrl+D to exit the shell gracefully? Currently there are two common ways to exit the shell: either q(). (graceful shutdown) or Ctrl+C twice (killing the process). There’s also init:stop() which is equivalent to q() but I never use it.

The problem is, it is much more cumbersome to type q().<enter> (5 keypresses, not counting the Shift key to get parentheses on European keyboards). Ctrl+D is just one keypress (not counting Ctrl).

Furthermore, and perhaps the most annoying factor, is that killing the shell will not gracefully exit so things like shell history and other shutdown procedures do not happen. Try it yourself:

$ erl -kernel shell_history enabled
Erlang/OTP 29 [erts-17.0.5] [source] [64-bit] [smp:12:12] [ds:12:12:10] [async-threads:1] [jit]

Eshell V17.0.5 (press Ctrl+G to abort, type help(). for help)
1> foo.
foo
2>
BREAK: (a)bort (A)bort with dump (c)ontinue (p)roc info (i)nfo
       (l)oaded (v)ersion (k)ill (D)b-tables (d)istribution
^C⏎

Then start a shell again, and observe foo. not being in the history.

If Ctrl+D were supported, this would be similar to many other shells (Python, Postgres etc.) and would make sense for new users and could quickly become muscle memory for old users.

2 Likes

Can the Erlang shell support THE USER’S END-OF-FILE key,
which might not be Ctrl-D. My end-of-file character has been Ctrl-Z
since 1979, and I’m sick of programs that think Ctrl-D was handed
down on Sinai as the only possible end-of-file character.

Even better. I’m curious, where do you configure that shortcut normally? Do other shells, e.g. Python etc., pick it up correctly mostly?

1 Like

On Unix, a text-mode program with stdin from a tty and not switching the tty to raw mode, so still in cooked mode, should just see EOF and not ^D or whatever the stty eof setting says.

If it switches to raw mode, which an interactive REPL might well do, then yes it will see ^D or ^Z or whatever the user typed. I think users expect their initial stty eof setting to be respected.

This should be set in your $SHELL’s configuration file (.bashrc, .login, etc) if you want to override the OS defaults.

1 Like

Ctrl+g, q

Keyboard control characters have been configurable in UNIX (and POSIX-compatibles) since V7. The stty(1) command was present5 in V6, but did not allow rebinding control characters to control functions.

ok@DESKTOP-7VKF5CM:~$ stty -a
speed 38400 baud; rows 30; columns 120; line = 0;
intr = ^C; quit = ^; erase = ^?; kill = ^U; eof = ^Z; eol = ; eol2 = ; swtch = ; start = ^Q;
stop = ^S; susp = ^X; rprnt = ^R; werase = ^W; lnext = ^V; discard = ^O; min = 1; time = 0;
-parenb -parodd -cmspar cs8 -hupcl -cstopb cread -clocal -crtscts
-ignbrk -brkint -ignpar -parmrk -inpck -istrip -inlcr -igncr icrnl ixon -ixoff -iuclc -ixany -imaxbel -iutf8
opost -olcuc -ocrnl onlcr -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0
isig icanon iexten echo echoe echok -echonl -noflsh -xcase -tostop -echoprt echoctl echoke -flusho -extproc

intr = interrupt (ask running program to pay attention, for interactive languages may return to interaction level or may enter a new interaction level, default action is drop dead)
quit = forcibly kill the running program
erase = delete previous character on current line, might be BS or DEL
werase = delete previous word on current line
kill = delete all previous characters on current line
rprint = retype current line (linux sometimes messes up)
stop = pause output
start = resume output
discard = discard output
susp = suspend current job NOW
dsusp = (delayed) suspend current job when it reads to this point
lnext = take next character literally even when it is a control character
eof = ship the current record to the reading program now, without any line terminator.
When the current record is empty, this is reported as a length 0 record by read(2) and
this is taken as end of file.

Originally UNIX used printing chaaracters for erase and kill, which made changing them particularly useful.

You would set them using

% stty eof ^Z susp ^X

Some of the stty options apply to all uses of the terminal.
Some (notably the editing characters) apply only in ‘cooked’ mode.
Some (the interrupt characters) apply in ‘cooked’ and ‘rare’ modes but not ‘raw’ mode.
Strictly speaking cooked/rare/raw modes don’t exist any longer. The options have been distributed across several POSIX calls. See termios(7) for details. These characters are the “special characters” specified in the c_cc field of struct termios.

Note that here I’m talking about what the terminal does when you read(2) from and write(2) to it.
Programs that use the “readline” or “editline” libraries to provide history and/or completion do whatever those (configurable!) libraries do. bash users were accustomed to using the features provided by the terminal, so bash respects the user’s special character assignments by default. Some programs are much less well-behaved. If a program offers emacs-like keybindings, Ctrl-D signifies “delete the character to the right of the cursor”, so treating it as end-of-file would definitely count as user-hostile.

If I want readline facilities with a program that doesn’t otherwise provide them, I know where to find rlwrap(1). If a program does provide readline facilities, I want it to be better than using rlwrap, otherwise what’s the point?

Ah, the fun of termcap files and stty, lots of work to be done before you could use your hardware. Now this is all I ever need:

^Jstty sane^J

Termcap came after stty. User-settable special characters have nothing to do with termcap. There were hundreds of termcap entries already defined, so the work to be done was small to nearly nonexistent (setting the $TERM environment variable). I used termcap for decades and don’t believe I ever needed to write a termcap entry.

The thing is, if you are frequently switching between (Linux under WSL2 or Cygwin) and (command.com or PowerShell), it is REALLY nice to be able to use the same eof character everwhere. There are enough problems in life without having to remember whether to use ^D, ^Z, or ^Y (oh wait, that one was EMAS, dead these many years).

1 Like

Yes, understood, I was just saying the days of dealing with the intricacies of terminals, and serial communications, are well in my past now. I haven’t needed to set $TERM to anything other than xterm-256color in decades.

Well my experience was certainly different, but I was installing and supporting a multi-user application with a fullscreen TUI using line draw characters (i.e. ┣) and serial mice. Servers had dozens of serial ports for terminals, mice, modems, printers, and the console ports of managed devices. I carried a serial data analyzer around and solved integration problems every day. Customers would ignore our supported hardware list as their vendors would claim compatibility. So yeah, I wrote a ton of termcap/terminfo and printcap files. It’s all a fading memory now, but enough to recognize the importance of good terminal emulation.