]> Repositorios git - scryer-prolog.git/commitdiff
Raise interrupt exception on Ctrl-C at the read prompt
authorJavier Sagredo <[email protected]>
Wed, 17 Jun 2026 22:02:07 +0000 (00:02 +0200)
committerJavier Sagredo <[email protected]>
Wed, 17 Jun 2026 22:02:07 +0000 (00:02 +0200)
While rustyline holds the terminal in raw mode, Ctrl-C is delivered as
`ReadlineError::Interrupted` rather than as a `SIGINT`, so the ctrlc handler
never sets the `INTERRUPT` flag. `call_readline` also pushed Interrupted
into the generic IO-error arm, which read_term then mis-classified as
`end_of_file` so Ctrl-C at a `read/1` prompt unified `end_of_file` instead
of interrupting.

Handle `ReadlineError::Interrupted` explicitly: set `INTERRUPT` and return an
Interrupted IO error. `read_term` now checks the flag in its error arm and
raises the interrupt exception instead of falling through to the EOF or
syntax-error handling.

src/machine/machine_state.rs
src/read.rs

index 0bfb65a7914122a7cad9f6946b00f605b1946630..71cde90312e168dd0e28a50f3763e9227be8f587 100644 (file)
@@ -865,6 +865,16 @@ impl MachineState {
             match self.read(stream, &indices.op_dir) {
                 Ok(term_write_result) => return self.read_term_body(term_write_result),
                 Err(err) => {
+                    // A Ctrl-C at the read prompt surfaces as an error here (and,
+                    // under rustyline's raw mode, would otherwise be mis-read as
+                    // end_of_file). If the interrupt flag is set, raise the
+                    // interrupt exception instead.
+                    if crate::machine::INTERRUPT.swap(false, std::sync::atomic::Ordering::Relaxed) {
+                        let interrupt_err = self.interrupt_error();
+                        let src = functor_stub(atom!("repl"), 0);
+                        return Err(self.error_form(interrupt_err, src));
+                    }
+
                     match &err {
                         CompilationError::ParserError(e) if e.is_unexpected_eof() => {
                             match eof_handler(self, stream)? {
index f0346ad219ad01f6a4d3000272c5adaaaef14fa8..759f5f1a849d0db75878886259f05a6ceaf152b6 100644 (file)
@@ -209,6 +209,15 @@ impl ReadlineStream {
             match self.rl.readline(get_prompt()) {
                 Ok(text) => Ok(text),
                 Err(ReadlineError::Eof) => Err(Error::from(ErrorKind::UnexpectedEof)),
+                Err(ReadlineError::Interrupted) => {
+                    // While rustyline holds the terminal in raw mode, Ctrl-C is
+                    // delivered as ReadlineError::Interrupted rather than as a
+                    // SIGINT, so the ctrlc handler never sets INTERRUPT. Set it
+                    // here so read_term raises the interrupt exception instead of
+                    // mis-reading the error as end_of_file.
+                    crate::machine::INTERRUPT.store(true, std::sync::atomic::Ordering::Relaxed);
+                    Err(Error::from(ErrorKind::Interrupted))
+                }
                 Err(e) => Err(Error::new(ErrorKind::InvalidInput, e)),
             }
         };