mirror of
https://github.com/sxyazi/yazi.git
synced 2026-07-21 23:01:05 +00:00
feat: show error message when directory fails to load (#2527)
This commit is contained in:
parent
e138364102
commit
4bef557b7f
9 changed files with 58 additions and 36 deletions
25
Cargo.lock
generated
25
Cargo.lock
generated
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
|
|
|||
|
|
@ -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::<yazi_fs::FolderStage>(|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(())
|
||||
|
|
|
|||
|
|
@ -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<Cha> {
|
||||
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<Cha> {
|
||||
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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<Url>, Vec<Url>) {
|
||||
match self {
|
||||
Self::Deleting(cwd, urns) => (urns.iter().map(|u| cwd.join(u)).collect(), vec![]),
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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<str> {
|
||||
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}"),
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue