Fixed logic for EINTR propagation

This commit is contained in:
2026-01-28 20:48:29 -05:00
parent 7f3e1cfcee
commit 70f0e849ba
7 changed files with 121 additions and 34 deletions

View File

@@ -48,11 +48,22 @@ impl Readline for FernVi {
loop {
raw_mode_guard.disable_for(|| self.print_line())?;
let Some(key) = self.reader.read_key()? else {
raw_mode_guard.disable_for(|| self.writer.flush_write("\n"))?;
std::mem::drop(raw_mode_guard);
return Err(ShErr::simple(ShErrKind::ReadlineErr, "EOF"));
};
let key = match self.reader.read_key() {
Ok(Some(key)) => key,
Err(e) if matches!(e.kind(), ShErrKind::IoErr(std::io::ErrorKind::Interrupted)) => {
flog!(DEBUG, "readline interrupted");
let partial: String = self.editor.as_str().to_string();
return Err(ShErr::simple(ShErrKind::ReadlineIntr(partial), ""));
}
Err(_) | Ok(None) => {
flog!(DEBUG, "EOF detected");
raw_mode_guard.disable_for(|| self.writer.flush_write("\n"))?;
std::mem::drop(raw_mode_guard);
return Err(ShErr::simple(ShErrKind::ReadlineErr, "EOF"));
}
};
flog!(DEBUG, key);
if self.should_accept_hint(&key) {

View File

@@ -28,6 +28,8 @@ pub fn raw_mode() -> RawModeGuard {
.expect("Failed to get terminal attributes");
let mut raw = orig.clone();
termios::cfmakeraw(&mut raw);
// Keep ISIG enabled so Ctrl+C/Ctrl+Z still generate signals
raw.local_flags |= termios::LocalFlags::ISIG;
termios::tcsetattr(
unsafe { BorrowedFd::borrow_raw(STDIN_FILENO) },
termios::SetArg::TCSANOW,
@@ -230,11 +232,17 @@ impl TermBuffer {
impl Read for TermBuffer {
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
assert!(isatty(self.tty).is_ok_and(|r| r));
match nix::unistd::read(self.tty, buf) {
Ok(n) => Ok(n),
Err(Errno::EINTR) => Err(Errno::EINTR.into()),
Err(e) => Err(std::io::Error::from_raw_os_error(e as i32)),
}
flog!(DEBUG, "TermBuffer::read() ENTERING read syscall");
let result = nix::unistd::read(self.tty, buf);
flog!(DEBUG, "TermBuffer::read() EXITED read syscall: {:?}", result);
match result {
Ok(n) => Ok(n),
Err(Errno::EINTR) => {
flog!(DEBUG, "TermBuffer::read() returning EINTR");
Err(Errno::EINTR.into())
}
Err(e) => Err(std::io::Error::from_raw_os_error(e as i32)),
}
}
}
@@ -258,6 +266,8 @@ impl RawModeGuard {
// Re-enable raw mode
let mut raw = self.orig.clone();
termios::cfmakeraw(&mut raw);
// Keep ISIG enabled so Ctrl+C/Ctrl+Z still generate signals
raw.local_flags |= termios::LocalFlags::ISIG;
termios::tcsetattr(fd, termios::SetArg::TCSANOW, &raw).expect("Failed to re-enable raw mode");
result
@@ -315,7 +325,7 @@ impl TermReader {
pub fn next_byte(&mut self) -> std::io::Result<u8> {
let mut buf = [0u8];
self.buffer.read_exact(&mut buf)?;
let _n = self.buffer.read(&mut buf)?;
Ok(buf[0])
}