willghatch / racket-rash

The Reckless Racket Shell
http://rash-lang.org
Other
551 stars 31 forks source link

Ctrl-C handling #78

Open benwr opened 3 years ago

benwr commented 3 years ago

In other shells (fish, bash, zsh), pressing ctrl-c partway through entering a command aborts the current expression and puts the user at a new prompt. Rash prints (struct:exn:break user break #<continuation-mark-set> #<escape-continuation>) and seems to leave you in a strange state.

I mostly love rash so far; this is the only hiccup, since I use this behavior a lot in other shells.

willghatch commented 3 years ago

On Sun, Jan 10, 2021 at 11:46:32AM -0800, Ben Weinstein-Raun wrote:

In other shells (fish, bash, zsh), pressing ctrl-c partway through entering a command aborts the current expression and puts the user at a new prompt. Rash prints (struct:exn:break user break #<continuation-mark-set> #<escape-continuation>) and seems to leave you in a strange state.

This is an unfortunate situation with the line editor. Realistically, to solve this issue I need to replace the current line editor (IE the current libreadline FFI package) with a better one. This could be simply a more comprehensive FFI to libreadline that exposes more of libreadline's functionality and provides a different interface on the Racket side than the current FFI, or (what I actually plan) it could be a Racket-native line editor. Basically my plan is to write a little emacs-like editor for editing input expressions. A better editor is key to basically all of my plans for Rash to be more useful in interactive sessions.

Granted, I am not currently writing that (line) editor, and won't within the next several months. But I have big plans for it once I finish up some other projects (some Rash-related, others not) and make some time for it!

I mostly love rash so far; this is the only hiccup, since I use this behavior a lot in other shells.

Thanks! It's heartening to hear that people like it. It does still have plenty of these rough parts that need more engineering time to polish, though. I'll continue to work on them as I have time! This one may be a while, though.

In the meantime, maybe try C-a C-k for “go to the beginning and delete to the end”, which is similar if not quite the same.

singpolyma commented 3 years ago

Is readline eating ^C before rash can bind it, then? It's very nice that rash uses readline so all my custom inputrc keys "just work" but this papercut bites me as well.

willghatch commented 3 years ago

The thing is that in terminals, C-c is weird. Unlike most key events where the process just gets characters written to its input, C-c is handled specially by the terminal. Instead of sending a byte through the file descriptor to the controlling process, the terminal basically sends a signal to the kernel, which then sends SIGINT to the process. (This is a bit hand-wavey, as I would have to check some reference material to remember the exact details.) Programs that do something other than exit when C-c is pressed do so by registering a handler for C-c that does something sensible.

Anyway, Racket's handling of C-c is essentially to raise an exn:break exception, and there's not currently a good way to change that.

My plan for how to deal with this situation in a Racket-native editor is to either just catch that exception in the editing loop and translate it into a key event to do whatever is bound to C-c or actually change the process signal handler to do something similar. In principle this could be done with a readline FFI layer, but the current wrapper library is pretty simplistic, and doesn't actually expose much of the actual readline interface. In particular, it provides no way to programmatically edit the buffer. This could be fixed with a better readline FFI library, perhaps with much less effort than writing a Racket-native line editor, but ultimately my planned racket-native editor will be much more powerful than readline in various ways that I care about (IE be much more fully like Emacs -- pervasively programmable).

singpolyma commented 3 years ago

So, I have found that readline actually contains defaults to do what we want (https://tiswww.cwru.edu/php/chet/readline/readline.html#SEC44) but apparently the racket wrapper somehow overrides this and breaks even racket's own repl (https://github.com/racket/racket/issues/2432)