mirror of
https://github.com/fish-shell/fish-shell.git
synced 2026-05-31 20:31:19 -03:00
Allow ctrl-C to work in fish_indent builtin
Since fish_indent became a builtin, it cannot be canceled with control-C, because Rust's `read_to_end` retries on EINTR. Add our own function which propagates EINTR and use it. Fixes #12238
This commit is contained in:
@@ -11,7 +11,7 @@
|
||||
use super::prelude::*;
|
||||
use crate::ast::{self, AsNode, Ast, Kind, Leaf, Node, NodeVisitor, SourceRangeList, Traversal};
|
||||
use crate::common::{
|
||||
PROGRAM_NAME, UnescapeFlags, UnescapeStringStyle, bytes2wcstring, get_program_name,
|
||||
PROGRAM_NAME, ReadExt, UnescapeFlags, UnescapeStringStyle, bytes2wcstring, get_program_name,
|
||||
unescape_string, wcs2bytes,
|
||||
};
|
||||
use crate::env::EnvStack;
|
||||
@@ -1045,12 +1045,16 @@ enum OutputType {
|
||||
use std::os::fd::FromRawFd;
|
||||
let mut fd = unsafe { std::fs::File::from_raw_fd(streams.stdin_fd) };
|
||||
let mut buf = vec![];
|
||||
match fd.read_to_end(&mut buf) {
|
||||
match fd.read_to_end_interruptible(&mut buf) {
|
||||
Ok(_) => {}
|
||||
Err(_) => {
|
||||
Err(err) => {
|
||||
// Don't close the fd
|
||||
std::mem::forget(fd);
|
||||
return Err(STATUS_CMD_ERROR);
|
||||
return if err.kind() == std::io::ErrorKind::Interrupted {
|
||||
Err(128 + libc::SIGINT)
|
||||
} else {
|
||||
Err(STATUS_CMD_ERROR)
|
||||
};
|
||||
}
|
||||
}
|
||||
std::mem::forget(fd);
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
use std::cell::{Cell, RefCell};
|
||||
use std::env;
|
||||
use std::ffi::{CStr, CString, OsString};
|
||||
use std::io::Read;
|
||||
use std::mem;
|
||||
use std::ops::{Deref, DerefMut};
|
||||
use std::os::unix::prelude::*;
|
||||
@@ -1237,6 +1238,23 @@ pub fn read_blocked(fd: RawFd, buf: &mut [u8]) -> nix::Result<usize> {
|
||||
}
|
||||
}
|
||||
|
||||
pub trait ReadExt {
|
||||
/// Like [`read_to_end`], but does not retry on EINTR.
|
||||
fn read_to_end_interruptible(&mut self, buf: &mut Vec<u8>) -> std::io::Result<()>;
|
||||
}
|
||||
|
||||
impl<T: Read + ?Sized> ReadExt for T {
|
||||
fn read_to_end_interruptible(&mut self, buf: &mut Vec<u8>) -> std::io::Result<()> {
|
||||
let mut chunk = [0_u8; 4096];
|
||||
loop {
|
||||
match self.read(&mut chunk)? {
|
||||
0 => return Ok(()),
|
||||
n => buf.extend_from_slice(&chunk[..n]),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Test if the string is a valid function name.
|
||||
pub fn valid_func_name(name: &wstr) -> bool {
|
||||
!(name.is_empty()
|
||||
|
||||
17
tests/pexpects/fish_indent_interrupt.py
Normal file
17
tests/pexpects/fish_indent_interrupt.py
Normal file
@@ -0,0 +1,17 @@
|
||||
#!/usr/bin/env python3
|
||||
from pexpect_helper import SpawnedProc
|
||||
|
||||
sp = SpawnedProc(timeout=2)
|
||||
send, sendline, sleep, expect_prompt = (
|
||||
sp.send,
|
||||
sp.sendline,
|
||||
sp.sleep,
|
||||
sp.expect_prompt,
|
||||
)
|
||||
|
||||
# Verify that the fish_indent builtin can be interrupted with ctrl-c.
|
||||
expect_prompt()
|
||||
sendline("fish_indent")
|
||||
sleep(0.1)
|
||||
send("\x03") # ctrl-c
|
||||
expect_prompt()
|
||||
Reference in New Issue
Block a user