diff --git a/yazi-actor/src/cmp/close.rs b/yazi-actor/src/cmp/close.rs index a6c179c3..4f68dc1c 100644 --- a/yazi-actor/src/cmp/close.rs +++ b/yazi-actor/src/cmp/close.rs @@ -17,10 +17,11 @@ impl Actor for Close { fn act(cx: &mut Ctx, opt: Self::Options) -> Result { let cmp = &mut cx.core.cmp; if let Some(item) = cmp.selected().filter(|_| opt.submit).cloned() { - return act!(complete, cx.core.input, CompleteOpt { item, _ticket: cmp.ticket }); + return act!(input:complete, cx, CompleteOpt { item, ticket: cmp.ticket }); } cmp.caches.clear(); + cmp.ticket = Default::default(); succ!(render!(mem::replace(&mut cmp.visible, false))); } } diff --git a/yazi-actor/src/cmp/show.rs b/yazi-actor/src/cmp/show.rs index b747baba..585b9e03 100644 --- a/yazi-actor/src/cmp/show.rs +++ b/yazi-actor/src/cmp/show.rs @@ -29,7 +29,6 @@ impl Actor for Show { succ!(); }; - cmp.ticket = opt.ticket; cmp.cands = Self::match_candidates(opt.word.as_path(), cache); if cmp.cands.is_empty() { succ!(render!(mem::replace(&mut cmp.visible, false))); diff --git a/yazi-actor/src/cmp/trigger.rs b/yazi-actor/src/cmp/trigger.rs index e9c20672..bbe88617 100644 --- a/yazi-actor/src/cmp/trigger.rs +++ b/yazi-actor/src/cmp/trigger.rs @@ -5,7 +5,7 @@ use yazi_fs::{path::clean_url, provider::{DirReader, FileHolder}}; use yazi_macro::{act, render, succ}; use yazi_parser::cmp::{CmpItem, ShowOpt, TriggerOpt}; use yazi_proxy::CmpProxy; -use yazi_shared::{AnyAsciiChar, data::Data, natsort, path::{AsPath, PathBufDyn, PathLike}, scheme::{SchemeCow, SchemeLike}, strand::{AsStrand, StrandLike}, url::{UrlBuf, UrlCow, UrlLike}}; +use yazi_shared::{AnyAsciiChar, BytePredictor, data::Data, natsort, path::{AsPath, PathBufDyn, PathLike}, scheme::{SchemeCow, SchemeLike}, strand::{AsStrand, StrandLike}, url::{UrlBuf, UrlCow, UrlLike}}; use yazi_vfs::provider; use crate::{Actor, Ctx}; @@ -74,11 +74,14 @@ impl Trigger { }; let (scheme, path) = SchemeCow::parse(s.as_bytes()).ok()?; - let scheme = scheme.zeroed(); + if path.is_empty() && !sep.predicate(s.bytes().last()?) { + return None; // We don't complete a `sftp://test`, but `sftp://test/` + } - // We don't complete a `~`, but `~/` + // Scheme + let scheme = scheme.zeroed(); if scheme.is_local() && path.as_strand() == "~" { - return None; + return None; // We don't complete a `~`, but `~/` } // Child @@ -113,7 +116,9 @@ mod tests { fn test_split() { yazi_shared::init_tests(); yazi_fs::init(); - compare("", "", ""); + + assert_eq!(Trigger::split_url(""), None); + assert_eq!(Trigger::split_url("sftp://test"), None); compare(" ", "", " "); compare("/", "/", ""); diff --git a/yazi-actor/src/input/complete.rs b/yazi-actor/src/input/complete.rs new file mode 100644 index 00000000..e5c40a3b --- /dev/null +++ b/yazi-actor/src/input/complete.rs @@ -0,0 +1,23 @@ +use anyhow::Result; +use yazi_macro::{act, succ}; +use yazi_parser::input::CompleteOpt; +use yazi_shared::data::Data; + +use crate::{Actor, Ctx}; + +pub struct Complete; + +impl Actor for Complete { + type Options = CompleteOpt; + + const NAME: &str = "complete"; + + fn act(cx: &mut Ctx, opt: Self::Options) -> Result { + let input = &mut cx.input; + if !input.visible || input.ticket.current() != opt.ticket { + succ!(); + } + + act!(complete, input, opt) + } +} diff --git a/yazi-actor/src/input/mod.rs b/yazi-actor/src/input/mod.rs index d23f3447..16e44b0e 100644 --- a/yazi-actor/src/input/mod.rs +++ b/yazi-actor/src/input/mod.rs @@ -1 +1 @@ -yazi_macro::mod_flat!(close escape show); +yazi_macro::mod_flat!(close complete escape show); diff --git a/yazi-fm/src/executor.rs b/yazi-fm/src/executor.rs index 70416d9b..684ed033 100644 --- a/yazi-fm/src/executor.rs +++ b/yazi-fm/src/executor.rs @@ -253,7 +253,10 @@ impl<'a> Executor<'a> { _ => {} } } - InputMode::Insert | InputMode::Replace => {} + InputMode::Insert => { + on!(complete); + } + InputMode::Replace => {} }; self.app.core.input.execute(cmd) diff --git a/yazi-parser/src/input/complete.rs b/yazi-parser/src/input/complete.rs index 557aad21..cf461b48 100644 --- a/yazi-parser/src/input/complete.rs +++ b/yazi-parser/src/input/complete.rs @@ -6,8 +6,8 @@ use crate::cmp::CmpItem; #[derive(Debug)] pub struct CompleteOpt { - pub item: CmpItem, - pub _ticket: Id, // FIXME: not used + pub item: CmpItem, + pub ticket: Id, } impl TryFrom for CompleteOpt { @@ -18,7 +18,7 @@ impl TryFrom for CompleteOpt { bail!("Invalid 'item' in CompleteOpt"); }; - Ok(Self { item, _ticket: c.get("ticket").unwrap_or_default() }) + Ok(Self { item, ticket: c.get("ticket").unwrap_or_default() }) } } diff --git a/yazi-sftp/src/fs/file.rs b/yazi-sftp/src/fs/file.rs index dd075b86..53b1efb4 100644 --- a/yazi-sftp/src/fs/file.rs +++ b/yazi-sftp/src/fs/file.rs @@ -108,7 +108,7 @@ impl AsyncSeek for File { SeekFrom::End(n) => SeekState::Blocking( n, timeout( - Duration::from_secs(10), + Duration::from_secs(45), self.session.send_sync(requests::Fstat::new(&self.handle))?, ), ), @@ -198,7 +198,7 @@ impl AsyncWrite for File { if me.flush_rx.is_none() { match Operator::from(&me.session).fsync(&me.handle) { - Ok(rx) => me.flush_rx = Some(timeout(Duration::from_secs(10), rx)), + Ok(rx) => me.flush_rx = Some(timeout(Duration::from_secs(45), rx)), Err(Error::Unsupported) => return Poll::Ready(Ok(())), Err(e) => Err(e)?, } diff --git a/yazi-sftp/src/fs/read_dir.rs b/yazi-sftp/src/fs/read_dir.rs index ddc2f0d3..42155922 100644 --- a/yazi-sftp/src/fs/read_dir.rs +++ b/yazi-sftp/src/fs/read_dir.rs @@ -55,7 +55,7 @@ impl ReadDir { let result = self .session - .send_with_timeout(requests::ReadDir::new(&self.handle), Duration::from_mins(5)) + .send_with_timeout(requests::ReadDir::new(&self.handle), Duration::from_mins(45)) .await; self.name = match result { diff --git a/yazi-vfs/src/provider/sftp/conn.rs b/yazi-vfs/src/provider/sftp/conn.rs index 251b41ec..d77cf1c6 100644 --- a/yazi-vfs/src/provider/sftp/conn.rs +++ b/yazi-vfs/src/provider/sftp/conn.rs @@ -1,4 +1,4 @@ -use std::{io, sync::Arc}; +use std::{io, sync::Arc, time::Duration}; use russh::keys::PrivateKeyWithHashAlg; use yazi_config::vfs::ServiceSftp; @@ -53,7 +53,14 @@ impl Conn { use deadpool::managed::PoolError; let pool = *super::CONN.lock().entry(self.config).or_insert_with(|| { - Box::leak(Box::new(deadpool::managed::Pool::builder(self).max_size(5).build().unwrap())) + Box::leak(Box::new( + deadpool::managed::Pool::builder(self) + .runtime(deadpool::Runtime::Tokio1) + .max_size(8) + .create_timeout(Some(Duration::from_secs(45))) + .build() + .unwrap(), + )) }); pool.get().await.map_err(|e| match e { @@ -67,9 +74,8 @@ impl Conn { async fn connect(self) -> Result, russh::Error> { let pref = Arc::new(russh::client::Config { - inactivity_timeout: Some(std::time::Duration::from_secs(30)), + inactivity_timeout: Some(std::time::Duration::from_secs(60)), keepalive_interval: Some(std::time::Duration::from_secs(10)), - nodelay: true, ..Default::default() }); diff --git a/yazi-widgets/src/input/commands/commands.rs b/yazi-widgets/src/input/commands/commands.rs index 86644ee3..1ca38cac 100644 --- a/yazi-widgets/src/input/commands/commands.rs +++ b/yazi-widgets/src/input/commands/commands.rs @@ -43,8 +43,6 @@ impl Input { on!(backspace); on!(kill); - - on!(complete); } InputMode::Replace => {} }