From 7b348ad96ef6289e06491824f71f6ca8817409dd Mon Sep 17 00:00:00 2001 From: sxyazi Date: Sun, 16 Feb 2025 21:57:20 +0800 Subject: [PATCH] .. --- yazi-adapter/src/emulator.rs | 70 ++++++++--------------- yazi-adapter/src/mux.rs | 2 +- yazi-adapter/src/stdin.rs | 104 ++++++++++++++++++++++++++--------- yazi-fm/src/term.rs | 9 +-- 4 files changed, 105 insertions(+), 80 deletions(-) diff --git a/yazi-adapter/src/emulator.rs b/yazi-adapter/src/emulator.rs index c9164b5c..873f6851 100644 --- a/yazi-adapter/src/emulator.rs +++ b/yazi-adapter/src/emulator.rs @@ -1,13 +1,13 @@ use std::{io::{LineWriter, stderr}, time::Duration}; -use anyhow::{Result, bail}; +use anyhow::Result; use crossterm::{cursor::{RestorePosition, SavePosition}, execute, style::Print, terminal::{disable_raw_mode, enable_raw_mode}}; use scopeguard::defer; -use tokio::{io::{AsyncReadExt, BufReader}, time::{sleep, timeout}}; +use tokio::time::sleep; use tracing::{debug, error, warn}; use yazi_shared::Either; -use crate::{Adapter, Brand, Mux, TMUX, Unknown}; +use crate::{Adapter, AsyncStdin, Brand, Mux, TMUX, Unknown}; #[derive(Clone, Copy, Debug)] pub struct Emulator { @@ -43,7 +43,7 @@ impl Emulator { RestorePosition )?; - let resp = futures::executor::block_on(Self::read_until_da1()); + let resp = Self::read_until_da1(); Mux::tmux_drain()?; let kind = if let Some(b) = Brand::from_csi(&resp).or(resort) { @@ -105,63 +105,37 @@ impl Emulator { result } - pub async fn read_until_da1() -> String { - let mut buf: Vec = Vec::with_capacity(200); - let read = async { - let mut stdin = BufReader::new(tokio::io::stdin()); - loop { - let mut c = [0; 1]; - if stdin.read(&mut c).await? == 0 { - bail!("unexpected EOF"); - } - buf.push(c[0]); - if c[0] != b'c' || !buf.contains(&0x1b) { - continue; - } - if buf.rsplitn(2, |&b| b == 0x1b).next().is_some_and(|s| s.starts_with(b"[?")) { - break; - } - } - Ok(()) - }; - + pub fn read_until_da1() -> String { let h = tokio::spawn(async move { sleep(Duration::from_millis(300)).await; Self::error_to_user().ok(); }); - match timeout(Duration::from_secs(2), read).await { - Ok(Ok(())) => debug!("read_until_da1: {buf:?}"), - Err(e) => error!("read_until_da1 timed out: {buf:?}, error: {e:?}"), - Ok(Err(e)) => error!("read_until_da1 failed: {buf:?}, error: {e:?}"), + let (buf, result) = AsyncStdin::default().read_until(Duration::from_secs(5), |b, buf| { + b == b'c' + && buf.contains(&0x1b) + && buf.rsplitn(2, |&b| b == 0x1b).next().is_some_and(|s| s.starts_with(b"[?")) + }); + + match result { + Ok(()) => debug!("read_until_da1: {buf:?}"), + Err(e) => error!("read_until_da1 failed: {buf:?}, error: {e:?}"), } h.abort(); String::from_utf8_lossy(&buf).into_owned() } - pub async fn read_until_dsr() -> String { - let mut buf: Vec = Vec::with_capacity(200); - let read = async { - let mut stdin = BufReader::new(tokio::io::stdin()); - loop { - let mut c = [0; 1]; - if stdin.read(&mut c).await? == 0 { - bail!("unexpected EOF"); - } - buf.push(c[0]); - if c[0] == b'n' && (buf.ends_with(b"\x1b[0n") || buf.ends_with(b"\x1b[3n")) { - break; - } - } - Ok(()) - }; + pub fn read_until_dsr() -> String { + let (buf, result) = AsyncStdin::default().read_until(Duration::from_millis(500), |b, buf| { + b == b'n' && (buf.ends_with(b"\x1b[0n") || buf.ends_with(b"\x1b[3n")) + }); - match timeout(Duration::from_millis(500), read).await { - Ok(Ok(())) => debug!("read_until_dsr: {buf:?}"), - Err(e) => error!("read_until_dsr timed out: {buf:?}, error: {e:?}"), - Ok(Err(e)) => error!("read_until_dsr failed: {buf:?}, error: {e:?}"), + match result { + Ok(()) => debug!("read_until_dsr: {buf:?}"), + Err(e) => error!("read_until_dsr failed: {buf:?}, error: {e:?}"), } + String::from_utf8_lossy(&buf).into_owned() } diff --git a/yazi-adapter/src/mux.rs b/yazi-adapter/src/mux.rs index 0c304420..282b6497 100644 --- a/yazi-adapter/src/mux.rs +++ b/yazi-adapter/src/mux.rs @@ -43,7 +43,7 @@ impl Mux { pub fn tmux_drain() -> Result<()> { if TMUX.get() { crossterm::execute!(std::io::stderr(), crossterm::style::Print(Mux::csi("\x1b[5n")))?; - _ = futures::executor::block_on(Emulator::read_until_dsr()); + _ = Emulator::read_until_dsr(); } Ok(()) } diff --git a/yazi-adapter/src/stdin.rs b/yazi-adapter/src/stdin.rs index 9693c84e..fcf97a5b 100644 --- a/yazi-adapter/src/stdin.rs +++ b/yazi-adapter/src/stdin.rs @@ -1,32 +1,53 @@ -use std::{ops::{Deref, DerefMut}, time::Duration}; +use std::{io::{Error, ErrorKind}, time::{Duration, Instant}}; pub struct AsyncStdin { - inner: std::io::StdinLock<'static>, #[cfg(unix)] - fds: libc::fd_set, + fds: libc::fd_set, } -impl Deref for AsyncStdin { - type Target = std::io::StdinLock<'static>; +impl AsyncStdin { + pub fn read_until

(&mut self, timeout: Duration, predicate: P) -> (Vec, std::io::Result<()>) + where + P: Fn(u8, &[u8]) -> bool, + { + let mut buf: Vec = Vec::with_capacity(200); + let now = Instant::now(); - fn deref(&self) -> &Self::Target { &self.inner } + let mut read = || { + loop { + if now.elapsed() > timeout { + return Err(Error::new(ErrorKind::TimedOut, "timed out")); + } else if !self.poll(Duration::from_millis(50))? { + continue; + } + + let b = Self::read_u8()?; + buf.push(b); + + if predicate(b, &buf) { + break; + } + } + Ok(()) + }; + + let result = read(); + (buf, result) + } } -impl DerefMut for AsyncStdin { - fn deref_mut(&mut self) -> &mut Self::Target { &mut self.inner } +#[cfg(unix)] +impl Default for AsyncStdin { + fn default() -> Self { + let mut me = Self { fds: unsafe { std::mem::MaybeUninit::zeroed().assume_init() } }; + me.reset(); + me + } } #[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: Duration) -> std::io::Result { - 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, @@ -34,7 +55,7 @@ impl AsyncStdin { let result = unsafe { libc::select( - self.inner.as_raw_fd() + 1, + libc::STDIN_FILENO + 1, &mut self.fds, std::ptr::null_mut(), std::ptr::null_mut(), @@ -43,7 +64,7 @@ impl AsyncStdin { }; match result { - -1 => Err(std::io::Error::last_os_error()), + -1 => Err(Error::last_os_error()), 0 => Ok(false), _ => { self.reset(); @@ -52,30 +73,59 @@ impl AsyncStdin { } } - fn reset(&mut self) { - use std::os::unix::io::AsRawFd; + pub fn read_u8() -> std::io::Result { + let mut b = 0; + match unsafe { libc::read(libc::STDIN_FILENO, &mut b as *mut _ as *mut _, 1) } { + -1 => Err(Error::last_os_error()), + 0 => Err(Error::new(ErrorKind::UnexpectedEof, "unexpected EOF")), + _ => Ok(b), + } + } + fn reset(&mut self) { unsafe { libc::FD_ZERO(&mut self.fds); - libc::FD_SET(self.inner.as_raw_fd(), &mut self.fds); + libc::FD_SET(libc::STDIN_FILENO, &mut self.fds); } } } #[cfg(windows)] -impl AsyncStdin { - pub fn new(inner: std::io::StdinLock<'static>) -> Self { Self { inner } } +impl Default for AsyncStdin { + fn default() -> Self { Self {} } +} +#[cfg(windows)] +impl AsyncStdin { pub fn poll(&mut self, timeout: Duration) -> std::io::Result { use std::os::windows::io::AsRawHandle; - use windows_sys::Win32::{Foundation::WAIT_TIMEOUT, System::Threading::WaitForSingleObject}; + use windows_sys::Win32::{Foundation::{WAIT_FAILED, WAIT_OBJECT_0}, System::Threading::WaitForSingleObject}; - let handle = self.inner.as_raw_handle(); + let handle = std::io::stdin().as_raw_handle(); let millis = timeout.as_millis(); match unsafe { WaitForSingleObject(handle, millis as u32) } { - WAIT_TIMEOUT => Ok(false), - _ => Ok(true), + WAIT_FAILED => Err(Error::last_os_error()), + WAIT_OBJECT_0 => Ok(true), + _ => Ok(false), } } + + pub fn read_u8() -> std::io::Result { + use std::os::windows::io::AsRawHandle; + + use windows_sys::Win32::Storage::FileSystem::ReadFile; + + let mut buf = 0; + let mut bytes = 0; + + let success = unsafe { + ReadFile(std::io::stdin().as_raw_handle(), &mut buf, 1, &mut bytes, std::ptr::null_mut()) + }; + + if success == 0 { + return Err(Error::last_os_error()); + } + Ok(buf) + } } diff --git a/yazi-fm/src/term.rs b/yazi-fm/src/term.rs index 3d390850..7a4f783e 100644 --- a/yazi-fm/src/term.rs +++ b/yazi-fm/src/term.rs @@ -42,13 +42,14 @@ impl Term { mouse::SetMouse(true), )?; - let da = futures::executor::block_on(Emulator::read_until_da1()); + let resp = Emulator::read_until_da1(); Mux::tmux_drain()?; - CSI_U.store(da.contains("\x1b[?0u"), Ordering::Relaxed); - BLINK.store(da.contains("\x1b[?12;1$y"), Ordering::Relaxed); + CSI_U.store(resp.contains("\x1b[?0u"), Ordering::Relaxed); + BLINK.store(resp.contains("\x1b[?12;1$y"), Ordering::Relaxed); SHAPE.store( - da.split_once("\x1bP1$r") + resp + .split_once("\x1bP1$r") .and_then(|(_, s)| s.bytes().next()) .filter(|&b| matches!(b, b'0'..=b'6')) .map_or(u8::MAX, |b| b - b'0'),