feat: terminal response detection under async stdin

This commit is contained in:
sxyazi 2025-02-16 18:25:54 +08:00
parent 22c8f370dc
commit 8655cf0193
No known key found for this signature in database
4 changed files with 90 additions and 5 deletions

10
Cargo.lock generated
View file

@ -726,9 +726,9 @@ checksum = "c7f84e12ccf0a7ddc17a6c41c93326024c42920d7ee630d04950e6926645c0fe"
[[package]]
name = "equivalent"
version = "1.0.1"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
[[package]]
name = "erased-serde"
@ -2390,9 +2390,9 @@ dependencies = [
[[package]]
name = "smallvec"
version = "1.13.2"
version = "1.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67"
checksum = "7fcf8323ef1faaee30a44a340193b1ac6814fd9b7b4e88e9d4519a3e4abe1cfd"
[[package]]
name = "smawk"
@ -3324,10 +3324,12 @@ dependencies = [
"crossterm",
"futures",
"image",
"libc",
"ratatui",
"scopeguard",
"tokio",
"tracing",
"windows-sys 0.59.0",
"yazi-config",
"yazi-macro",
"yazi-shared",

View file

@ -26,5 +26,11 @@ scopeguard = { workspace = true }
tokio = { workspace = true }
tracing = { workspace = true }
[target."cfg(unix)".dependencies]
libc = { workspace = true }
[target.'cfg(windows)'.dependencies]
windows-sys = { version = "0.59.0", features = [ "Win32_UI_Shell" ] }
[target.'cfg(target_os = "macos")'.dependencies]
crossterm = { workspace = true, features = [ "use-dev-tty", "libc" ] }

View file

@ -2,7 +2,7 @@
yazi_macro::mod_pub!(drivers);
yazi_macro::mod_flat!(adapter brand dimension emulator image info mux unknown);
yazi_macro::mod_flat!(adapter brand dimension emulator image info mux stdin unknown);
use yazi_shared::{SyncCell, in_wsl};

77
yazi-adapter/src/stdin.rs Normal file
View file

@ -0,0 +1,77 @@
use std::{io, ops::{Deref, DerefMut}};
pub struct AsyncStdin {
inner: std::io::StdinLock<'static>,
#[cfg(unix)]
fds: libc::fd_set,
}
impl Deref for AsyncStdin {
type Target = std::io::StdinLock<'static>;
fn deref(&self) -> &Self::Target { &self.inner }
}
impl DerefMut for AsyncStdin {
fn deref_mut(&mut self) -> &mut Self::Target { &mut self.inner }
}
#[cfg(unix)]
impl AsyncStdin {
pub fn new(inner: std::io::StdinLock<'static>) -> Self {
let mut me = Self { inner, fds: unsafe { std::mem::MaybeUninit::zeroed().assume_init() } };
me.reset();
me
}
pub fn poll(&mut self, timeout: std::time::Duration) -> std::io::Result<bool> {
use std::os::unix::io::AsRawFd;
let mut tv = libc::timeval {
tv_sec: timeout.as_secs() as libc::time_t,
tv_usec: timeout.subsec_micros() as libc::suseconds_t,
};
let result = unsafe {
libc::select(
self.inner.as_raw_fd() + 1,
&mut self.fds,
std::ptr::null_mut(),
std::ptr::null_mut(),
&mut tv,
)
};
match result {
-1 => Err(io::Error::last_os_error()),
0 => Ok(false),
_ => {
self.reset();
Ok(true)
}
}
}
fn reset(&mut self) {
use std::os::unix::io::AsRawFd;
unsafe {
libc::FD_ZERO(&mut self.fds);
libc::FD_SET(self.inner.as_raw_fd(), &mut self.fds);
}
}
}
#[cfg(windows)]
impl AsyncStdin {
pub fn new(inner: std::io::StdinLock<'static>) -> Self { Self { inner } }
pub fn poll(&mut self) -> std::io::Result<bool> {
let handle = HANDLE(self.inner.as_raw_handle() as isize);
match unsafe { WaitForSingleObject(handle, 5000) } {
WAIT_TIMEOUT => Ok(false),
_ => Ok(true),
}
}
}