Fix "Fix Ctrl-C Handling in the REPL"#25835
Conversation
| if first == -1 then -1 | ||
| else | ||
| bytes(offset) = first.toByte | ||
| inputQueue.drainTo(bytes, offset + 1, length - 1) + 1 |
There was a problem hiding this comment.
isnt it possible for state to flip from available to closed between read() and drainTo()? so i guess this method should be synchronized also
There was a problem hiding this comment.
answering myself: No because the readUserInputByte() doesnt exit until either the upstream is closed (-1) or it buffered some stuff to inputQueue, in which case drainTo is just clearing what was buffered - and not performing IO.
SolalPirelli
left a comment
There was a problem hiding this comment.
This seems correct to me... it's a shame we have to implement a distributed system just to read user input, but having tried everything short of that for my previous PR, I realize it's necessary.
|
I took another pass cleaning up the PR and addressing review feedback |
Follow-up from #25782. This PR lets us get the best of both worlds: `Ctrl-C` handling works even in the subprocess scenario, and `System.in.read()` works too. Basically rather than having two threads reading from `System.in` at the same time, we wrap `System.in` in our own wrapper such that we can peek at it without dropping the characters we read on the floor. This lets us check for Ctrl-C from the REPL infrastructure while still ensuring that all System.in characters end up being correctly sent to any `System.in.read()` calls made by user code in the REPL I haven't looked at the JShell sources since that is prohibited, but it seems they do a similar sort of wrapping, as empirically JShell is able to handle `System.in.read` while still capturing Ctrl-C and handling that appropriately as well, and `System.in` in JShell is a wrapper input rather than a raw `java.io.BufferedInputStream` ```scala jshell> System.in $1 ==> jdk.jshell.execution.Util$1@31a5c39e ``` ## How much have you relied on LLM-based tools in this contribution? Extensively ## How was the solution tested? Tested manually via `./mill repl`. 1. Verified that without this PR `Ctrl-C` handling does not work due to the REPL running in a subprocess, with this PR Ctrl-C is properly caught. 2. Also verified that without this PR, `System.in.read()` in the REPL returns `-1`, whereas with this PR `System.in.read()` in the REPL correctly prompts the user to enter input, and prints the ascii code of the character entered Also verified the original `def askQuestion` scenario which now seems to work [Cherry-picked 7fd3dcd]
Backports #25835 to the 3.8.4-RC2. PR submitted by the release tooling.
Follow-up from scala#25782. This PR lets us get the best of both worlds: `Ctrl-C` handling works even in the subprocess scenario, and `System.in.read()` works too. Basically rather than having two threads reading from `System.in` at the same time, we wrap `System.in` in our own wrapper such that we can peek at it without dropping the characters we read on the floor. This lets us check for Ctrl-C from the REPL infrastructure while still ensuring that all System.in characters end up being correctly sent to any `System.in.read()` calls made by user code in the REPL I haven't looked at the JShell sources since that is prohibited, but it seems they do a similar sort of wrapping, as empirically JShell is able to handle `System.in.read` while still capturing Ctrl-C and handling that appropriately as well, and `System.in` in JShell is a wrapper input rather than a raw `java.io.BufferedInputStream` ```scala jshell> System.in $1 ==> jdk.jshell.execution.Util$1@31a5c39e ``` ## How much have you relied on LLM-based tools in this contribution? Extensively ## How was the solution tested? Tested manually via `./mill repl`. 1. Verified that without this PR `Ctrl-C` handling does not work due to the REPL running in a subprocess, with this PR Ctrl-C is properly caught. 2. Also verified that without this PR, `System.in.read()` in the REPL returns `-1`, whereas with this PR `System.in.read()` in the REPL correctly prompts the user to enter input, and prints the ascii code of the character entered Also verified the original `def askQuestion` scenario which now seems to work
Follow-up from #25782. This PR lets us get the best of both worlds:
Ctrl-Chandling works even in the subprocess scenario, andSystem.in.read()works too.Basically rather than having two threads reading from
System.inat the same time, we wrapSystem.inin our own wrapper such that we can peek at it without dropping the characters we read on the floor. This lets us check for Ctrl-C from the REPL infrastructure while still ensuring that all System.in characters end up being correctly sent to anySystem.in.read()calls made by user code in the REPLI haven't looked at the JShell sources since that is prohibited, but it seems they do a similar sort of wrapping, as empirically JShell is able to handle
System.in.readwhile still capturing Ctrl-C and handling that appropriately as well, andSystem.inin JShell is a wrapper input rather than a rawjava.io.BufferedInputStreamHow much have you relied on LLM-based tools in this contribution?
Extensively
How was the solution tested?
Tested manually via
./mill repl.Ctrl-Chandling does not work due to the REPL running in a subprocess, with this PR Ctrl-C is properly caught.System.in.read()in the REPL returns-1, whereas with this PRSystem.in.read()in the REPL correctly prompts the user to enter input, and prints the ascii code of the character enteredAlso verified the original
def askQuestionscenario which now seems to work