diff --git a/Cargo.lock b/Cargo.lock index 51578f85..b430a646 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1006,14 +1006,15 @@ checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" [[package]] name = "iana-time-zone" -version = "0.1.61" +version = "0.1.62" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220" +checksum = "b2fd658b06e56721792c5df4475705b6cda790e9298d19d2f8af083457bcd127" dependencies = [ "android_system_properties", "core-foundation-sys", "iana-time-zone-haiku", "js-sys", + "log", "wasm-bindgen", "windows-core 0.52.0", ] @@ -1257,9 +1258,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.26" +version = "0.4.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30bde2b3dc3671ae49d8e2e9f044c7c005836e7a023ee57cffa25ab82764bb9e" +checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" [[package]] name = "loop9" @@ -2407,9 +2408,9 @@ dependencies = [ [[package]] name = "time" -version = "0.3.40" +version = "0.3.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d9c75b47bdff86fa3334a3db91356b8d7d86a9b839dab7d0bdc5c3d3a077618" +checksum = "8a7619e19bc266e0f9c5e6686659d394bc57973859340060a69221e57dbc0c40" dependencies = [ "deranged", "itoa", @@ -2430,9 +2431,9 @@ checksum = "c9e9a38711f559d9e3ce1cdb06dd7c5b8ea546bc90052da6d06bb76da74bb07c" [[package]] name = "time-macros" -version = "0.2.21" +version = "0.2.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29aa485584182073ed57fd5004aa09c371f021325014694e432313345865fd04" +checksum = "3526739392ec93fd8b359c8e98514cb3e8e021beb4e5f597b00a0221f8ed8a49" dependencies = [ "num-conv", "time-core", @@ -3390,18 +3391,18 @@ dependencies = [ [[package]] name = "zerocopy" -version = "0.8.23" +version = "0.8.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd97444d05a4328b90e75e503a34bad781f14e28a823ad3557f0750df1ebcbc6" +checksum = "2586fea28e186957ef732a5f8b3be2da217d65c5969d4b1e17f973ebbe876879" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.23" +version = "0.8.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6352c01d0edd5db859a63e2605f4ea3183ddbd15e2c4a9e7d32184df75e4f154" +checksum = "a996a8f63c5c4448cd959ac1bab0aaa3306ccfd060472f85943ee0750f0169be" dependencies = [ "proc-macro2", "quote", diff --git a/yazi-core/src/mgr/watcher.rs b/yazi-core/src/mgr/watcher.rs index 757ed98f..f4eaea8c 100644 --- a/yazi-core/src/mgr/watcher.rs +++ b/yazi-core/src/mgr/watcher.rs @@ -86,8 +86,9 @@ impl Watcher { async fn go(cwd: Url, cha: Cha) { let Some(cha) = Files::assert_stale(&cwd, cha).await else { return }; - if let Ok(files) = Files::from_dir_bulk(&cwd).await { - FilesOp::Full(cwd, files, cha).emit(); + match Files::from_dir_bulk(&cwd).await { + Ok(files) => FilesOp::Full(cwd, files, cha).emit(), + Err(e) => FilesOp::issue_error(&cwd, e.kind()).await, } } diff --git a/yazi-core/src/tab/preview.rs b/yazi-core/src/tab/preview.rs index b2ed79c7..d7cacd26 100644 --- a/yazi-core/src/tab/preview.rs +++ b/yazi-core/src/tab/preview.rs @@ -49,7 +49,11 @@ impl Preview { self.folder_loader.take().map(|h| h.abort()); self.folder_loader = Some(tokio::spawn(async move { let Some(new) = Files::assert_stale(&wd, dir.unwrap_or(Cha::dummy())).await else { return }; - let Ok(rx) = Files::from_dir(&wd).await else { return }; + + let rx = match Files::from_dir(&wd).await { + Ok(rx) => rx, + Err(e) => return FilesOp::issue_error(&wd, e.kind()).await, + }; let stream = UnboundedReceiverStream::new(rx).chunks_timeout(50000, Duration::from_millis(500)); diff --git a/yazi-fm/src/lives/folder.rs b/yazi-fm/src/lives/folder.rs index 1d8a3da1..f67b130b 100644 --- a/yazi-fm/src/lives/folder.rs +++ b/yazi-fm/src/lives/folder.rs @@ -1,6 +1,6 @@ use std::ops::{Deref, Range}; -use mlua::{AnyUserData, Lua, UserData, UserDataFields}; +use mlua::{AnyUserData, IntoLuaMulti, Lua, MetaMethod, UserData, UserDataFields, UserDataMethods}; use yazi_config::LAYOUT; use yazi_plugin::url::Url; @@ -38,7 +38,13 @@ impl Folder { pub(super) fn register(lua: &Lua) -> mlua::Result<()> { lua.register_userdata_type::(|reg| { - reg.add_field_method_get("is_loading", |_, me| Ok(*me == yazi_fs::FolderStage::Loading)); + use yazi_fs::FolderStage; + + reg.add_meta_method(MetaMethod::Call, |lua, me, ()| match me { + FolderStage::Loading => false.into_lua_multi(lua), + FolderStage::Loaded => true.into_lua_multi(lua), + FolderStage::Failed(kind) => (true, yazi_plugin::Error::IoKind(*kind)).into_lua_multi(lua), + }); })?; Ok(()) diff --git a/yazi-fs/src/files.rs b/yazi-fs/src/files.rs index 6d195c61..344c8974 100644 --- a/yazi-fs/src/files.rs +++ b/yazi-fs/src/files.rs @@ -4,7 +4,7 @@ use tokio::{fs::{self, DirEntry}, select, sync::mpsc::{self, UnboundedReceiver}} use yazi_shared::{Id, url::{Url, Urn, UrnBuf}}; use super::{FilesSorter, Filter}; -use crate::{FILES_TICKET, File, FilesOp, SortBy, cha::Cha, maybe_exists, mounts::PARTITIONS}; +use crate::{FILES_TICKET, File, FilesOp, SortBy, cha::Cha, mounts::PARTITIONS}; #[derive(Default)] pub struct Files { @@ -81,20 +81,13 @@ impl Files { ) } - pub async fn assert_stale(cwd: &Url, cha: Cha) -> Option { - match fs::metadata(cwd).await.map(Cha::from) { - Ok(c) if !c.is_dir() => { - FilesOp::IOErr(cwd.clone(), std::io::ErrorKind::NotADirectory).emit(); - } + pub async fn assert_stale(dir: &Url, cha: Cha) -> Option { + use std::io::ErrorKind; + match fs::metadata(dir).await.map(Cha::from) { + Ok(c) if !c.is_dir() => FilesOp::issue_error(dir, ErrorKind::NotADirectory).await, Ok(c) if c.hits(cha) && PARTITIONS.read().heuristic(cha) => {} Ok(c) => return Some(c), - Err(e) => { - if maybe_exists(cwd).await { - FilesOp::IOErr(cwd.clone(), e.kind()).emit(); - } else if let Some((p, n)) = cwd.pair() { - FilesOp::Deleting(p, HashSet::from_iter([n])).emit(); - } - } + Err(e) => FilesOp::issue_error(dir, e.kind()).await, } None } diff --git a/yazi-fs/src/op.rs b/yazi-fs/src/op.rs index fe22c95e..bc3bba78 100644 --- a/yazi-fs/src/op.rs +++ b/yazi-fs/src/op.rs @@ -3,7 +3,7 @@ use std::collections::{HashMap, HashSet}; use yazi_shared::{Id, Ids, event::Cmd, url::{Url, UrnBuf}}; use super::File; -use crate::cha::Cha; +use crate::{cha::Cha, maybe_exists}; pub static FILES_TICKET: Ids = Ids::new(); @@ -118,6 +118,17 @@ impl FilesOp { } } + pub async fn issue_error(cwd: &Url, kind: std::io::ErrorKind) { + use std::io::ErrorKind; + if kind != ErrorKind::NotFound { + Self::IOErr(cwd.clone(), kind).emit(); + } else if maybe_exists(cwd).await { + Self::IOErr(cwd.clone(), kind).emit(); + } else if let Some((p, n)) = cwd.pair() { + Self::Deleting(p, HashSet::from_iter([n])).emit(); + } + } + pub fn diff_recoverable(&self, contains: impl Fn(&Url) -> bool) -> (Vec, Vec) { match self { Self::Deleting(cwd, urns) => (urns.iter().map(|u| cwd.join(u)).collect(), vec![]), diff --git a/yazi-plugin/preset/components/current.lua b/yazi-plugin/preset/components/current.lua index 702544f9..cfd60b8e 100644 --- a/yazi-plugin/preset/components/current.lua +++ b/yazi-plugin/preset/components/current.lua @@ -11,15 +11,16 @@ function Current:new(area, tab) end function Current:empty() - local text + local s if self._folder.files.filter then - text = ui.Text("No filter results") + s = "No filter results" else - text = ui.Text(self._folder.stage.is_loading and "Loading..." or "No items") + local done, err = self._folder.stage() + s = not done and "Loading..." or not err and "No items" or string.format("Error: %s", err) end return { - text:area(self._area):align(ui.Text.CENTER), + ui.Text(s):area(self._area):align(ui.Text.CENTER), } end diff --git a/yazi-plugin/preset/plugins/folder.lua b/yazi-plugin/preset/plugins/folder.lua index c2b8efa0..a7727b0d 100644 --- a/yazi-plugin/preset/plugins/folder.lua +++ b/yazi-plugin/preset/plugins/folder.lua @@ -14,8 +14,10 @@ function M:peek(job) end if #folder.files == 0 then + local done, err = folder.stage() + local s = not done and "Loading..." or not err and "No items" or string.format("Error: %s", err) return ya.preview_widgets(job, { - ui.Text(folder.stage.is_loading and "Loading..." or "No items"):area(job.area):align(ui.Text.CENTER), + ui.Text(s):area(job.area):align(ui.Text.CENTER), }) end diff --git a/yazi-plugin/src/error.rs b/yazi-plugin/src/error.rs index 0a9598b2..69feed13 100644 --- a/yazi-plugin/src/error.rs +++ b/yazi-plugin/src/error.rs @@ -6,6 +6,7 @@ const EXPECTED: &str = "expected a Error"; pub enum Error { Io(std::io::Error), + IoKind(std::io::ErrorKind), Serde(serde_json::Error), Custom(String), } @@ -20,6 +21,7 @@ impl Error { fn to_string(&self) -> Cow { match self { Error::Io(e) => Cow::Owned(e.to_string()), + Error::IoKind(e) => Cow::Owned(e.to_string()), Error::Serde(e) => Cow::Owned(e.to_string()), Error::Custom(s) => Cow::Borrowed(s), } @@ -30,6 +32,7 @@ impl Display for Error { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { Error::Io(e) => write!(f, "{e}"), + Error::IoKind(e) => write!(f, "{e}"), Error::Serde(e) => write!(f, "{e}"), Error::Custom(s) => write!(f, "{s}"), }