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)? {
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)),
}
};