From: Javier Sagredo Date: Wed, 17 Jun 2026 11:04:12 +0000 (+0200) Subject: Raise interrupt exception on Ctrl-C at the read prompt X-Git-Url: https://git.sagredo.dev/?a=commitdiff_plain;h=2c057b7c413c3b8ca55c65bca78b22abbecb3c18;p=scryer-prolog.git Raise interrupt exception on Ctrl-C at the read prompt 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 lumped 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. --- diff --git a/src/machine/machine_state.rs b/src/machine/machine_state.rs index 0bfb65a7..71cde903 100644 --- a/src/machine/machine_state.rs +++ b/src/machine/machine_state.rs @@ -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)? { diff --git a/src/read.rs b/src/read.rs index f0346ad2..759f5f1a 100644 --- a/src/read.rs +++ b/src/read.rs @@ -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)), } };