From 4fdc0f120f3689e33bbea514c01429fa3ad5b646 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=89=E5=92=B2=E9=9B=85=20misaki=20masa?= Date: Sat, 31 May 2025 00:08:50 +0800 Subject: [PATCH] fix: make every effort to carry hidden states for dummy files (#2814) --- yazi-core/src/mgr/commands/bulk_rename.rs | 2 +- yazi-core/src/mgr/commands/create.rs | 8 +- yazi-core/src/mgr/commands/open.rs | 2 +- yazi-core/src/mgr/commands/rename.rs | 12 +- yazi-core/src/mgr/watcher.rs | 8 +- yazi-core/src/tab/commands/cd.rs | 21 +- yazi-core/src/tab/commands/search.rs | 2 +- yazi-core/src/tab/folder.rs | 4 +- yazi-core/src/tab/preview.rs | 2 +- yazi-fs/src/cha/cha.rs | 223 ++++++++++++---------- yazi-fs/src/file.rs | 16 +- yazi-fs/src/files.rs | 6 +- yazi-fs/src/op.rs | 2 +- yazi-plugin/src/bindings/cha.rs | 8 +- yazi-plugin/src/external/fd.rs | 2 +- yazi-plugin/src/external/rg.rs | 2 +- yazi-plugin/src/external/rga.rs | 2 +- yazi-plugin/src/fs/fs.rs | 4 +- yazi-plugin/src/macros.rs | 2 +- yazi-proxy/src/tab.rs | 2 +- yazi-scheduler/src/file/file.rs | 6 +- yazi-shared/src/event/data.rs | 4 + 22 files changed, 175 insertions(+), 165 deletions(-) diff --git a/yazi-core/src/mgr/commands/bulk_rename.rs b/yazi-core/src/mgr/commands/bulk_rename.rs index f70c1a70..744764cb 100644 --- a/yazi-core/src/mgr/commands/bulk_rename.rs +++ b/yazi-core/src/mgr/commands/bulk_rename.rs @@ -94,7 +94,7 @@ impl Mgr { failed.push((o, n, anyhow!("Destination already exists"))); } else if let Err(e) = fs::rename(&old, &new).await { failed.push((o, n, e.into())); - } else if let Ok(f) = File::from(new.into()).await { + } else if let Ok(f) = File::new(new.into()).await { succeeded.insert(Url::from(old), f); } else { failed.push((o, n, anyhow!("Failed to retrieve file info"))); diff --git a/yazi-core/src/mgr/commands/create.rs b/yazi-core/src/mgr/commands/create.rs index 38541db3..4307ab5f 100644 --- a/yazi-core/src/mgr/commands/create.rs +++ b/yazi-core/src/mgr/commands/create.rs @@ -1,5 +1,3 @@ -use std::collections::{HashMap, HashSet}; - use anyhow::Result; use tokio::fs; use yazi_config::popup::{ConfirmCfg, InputCfg}; @@ -50,7 +48,7 @@ impl Mgr { fs::create_dir_all(&new).await?; } else if let Some(real) = realname(&new).await { ok_or_not_found(fs::remove_file(&new).await)?; - FilesOp::Deleting(parent.clone(), HashSet::from_iter([UrnBuf::from(real)])).emit(); + FilesOp::Deleting(parent.clone(), [UrnBuf::from(real)].into()).emit(); fs::File::create(&new).await?; } else { fs::create_dir_all(&parent).await.ok(); @@ -58,8 +56,8 @@ impl Mgr { fs::File::create(&new).await?; } - if let Ok(f) = File::from(new.clone()).await { - FilesOp::Upserting(parent, HashMap::from_iter([(f.urn_owned(), f)])).emit(); + if let Ok(f) = File::new(new.clone()).await { + FilesOp::Upserting(parent, [(f.urn_owned(), f)].into()).emit(); TabProxy::reveal(&new) } Ok(()) diff --git a/yazi-core/src/mgr/commands/open.rs b/yazi-core/src/mgr/commands/open.rs index 716a0948..b2ecc31f 100644 --- a/yazi-core/src/mgr/commands/open.rs +++ b/yazi-core/src/mgr/commands/open.rs @@ -56,7 +56,7 @@ impl Mgr { tokio::spawn(async move { let mut files = Vec::with_capacity(todo.len()); for u in todo { - if let Ok(f) = File::from(u).await { + if let Ok(f) = File::new(u).await { files.push(f); } } diff --git a/yazi-core/src/mgr/commands/rename.rs b/yazi-core/src/mgr/commands/rename.rs index bf6e809d..44e80c21 100644 --- a/yazi-core/src/mgr/commands/rename.rs +++ b/yazi-core/src/mgr/commands/rename.rs @@ -1,4 +1,4 @@ -use std::{borrow::Cow, collections::{HashMap, HashSet}}; +use std::borrow::Cow; use anyhow::Result; use tokio::fs; @@ -80,15 +80,15 @@ impl Mgr { if let Some(o) = overwritten { ok_or_not_found(fs::rename(p_new.join(&o), &new).await)?; - FilesOp::Deleting(p_new.clone(), HashSet::from_iter([UrnBuf::from(o)])).emit(); + FilesOp::Deleting(p_new.clone(), [UrnBuf::from(o)].into()).emit(); } - let file = File::from(new.clone()).await?; + let file = File::new(new.clone()).await?; if p_new == p_old { - FilesOp::Upserting(p_old, HashMap::from_iter([(n_old, file)])).emit(); + FilesOp::Upserting(p_old, [(n_old, file)].into()).emit(); } else { - FilesOp::Deleting(p_old, HashSet::from_iter([n_old])).emit(); - FilesOp::Upserting(p_new, HashMap::from_iter([(n_new, file)])).emit(); + FilesOp::Deleting(p_old, [n_old].into()).emit(); + FilesOp::Upserting(p_new, [(n_new, file)].into()).emit(); } TabProxy::reveal(&new); diff --git a/yazi-core/src/mgr/watcher.rs b/yazi-core/src/mgr/watcher.rs index 6fc747d7..610e985f 100644 --- a/yazi-core/src/mgr/watcher.rs +++ b/yazi-core/src/mgr/watcher.rs @@ -134,8 +134,8 @@ impl Watcher { for u in urls { let Some((parent, urn)) = u.pair() else { continue }; - let Ok(file) = File::from(u).await else { - ops.push(FilesOp::Deleting(parent, HashSet::from_iter([urn]))); + let Ok(file) = File::new(u).await else { + ops.push(FilesOp::Deleting(parent, [urn].into())); continue; }; @@ -144,11 +144,11 @@ impl Watcher { || realname_unchecked(u, &mut cached).await.is_ok_and(|s| urn.as_urn() == s); if !eq { - ops.push(FilesOp::Deleting(parent, HashSet::from_iter([urn]))); + ops.push(FilesOp::Deleting(parent, [urn].into())); continue; } - ops.push(FilesOp::Upserting(parent, HashMap::from_iter([(urn, file)]))); + ops.push(FilesOp::Upserting(parent, [(urn, file)].into())); } FilesOp::mutate(ops); diff --git a/yazi-core/src/tab/commands/cd.rs b/yazi-core/src/tab/commands/cd.rs index 4350b51c..887a6b76 100644 --- a/yazi-core/src/tab/commands/cd.rs +++ b/yazi-core/src/tab/commands/cd.rs @@ -1,10 +1,10 @@ use std::{mem, time::Duration}; -use tokio::{fs, pin}; +use tokio::pin; use tokio_stream::{StreamExt, wrappers::UnboundedReceiverStream}; use yazi_config::popup::InputCfg; use yazi_dds::Pubsub; -use yazi_fs::expand_path; +use yazi_fs::{File, FilesOp, expand_path}; use yazi_macro::render; use yazi_proxy::{CmpProxy, InputProxy, MgrProxy, TabProxy}; use yazi_shared::{Debounce, errors::InputError, event::CmdCow, url::Url}; @@ -94,16 +94,17 @@ impl Tab { while let Some(result) = rx.next().await { match result { Ok(s) => { - let u = Url::from(expand_path(s)); - let Ok(meta) = fs::metadata(&u).await else { - return; - }; + let url = Url::from(expand_path(s)); - if meta.is_dir() { - TabProxy::cd(&u); - } else { - TabProxy::reveal(&u); + let Ok(file) = File::new(url.clone()).await else { return }; + if file.is_dir() { + return TabProxy::cd(&url); } + + if let Some(p) = url.parent_url() { + FilesOp::Upserting(p, [(url.urn_owned(), file)].into()).emit(); + } + TabProxy::reveal(&url); } Err(InputError::Completed(before, ticket)) => { CmpProxy::trigger(&before, ticket); diff --git a/yazi-core/src/tab/commands/search.rs b/yazi-core/src/tab/commands/search.rs index 7a98c618..febbc4d2 100644 --- a/yazi-core/src/tab/commands/search.rs +++ b/yazi-core/src/tab/commands/search.rs @@ -70,7 +70,7 @@ impl Tab { while let Some(chunk) = rx.next().await { FilesOp::Part(cwd.clone(), chunk, ticket).emit(); } - FilesOp::Done(cwd, Cha::dummy(), ticket).emit(); + FilesOp::Done(cwd, Cha::default(), ticket).emit(); Ok(()) })); diff --git a/yazi-core/src/tab/folder.rs b/yazi-core/src/tab/folder.rs index 8ffa6497..67fd7e09 100644 --- a/yazi-core/src/tab/folder.rs +++ b/yazi-core/src/tab/folder.rs @@ -46,7 +46,7 @@ impl Folder { (self.cha, self.stage) = (cha, FolderStage::Loaded); } FilesOp::Part(_, ref files, _) if files.is_empty() => { - (self.cha, self.stage) = (Cha::dummy(), FolderStage::Loading); + (self.cha, self.stage) = (Cha::default(), FolderStage::Loading); } FilesOp::Part(_, _, ticket) if ticket == self.files.ticket() => { self.stage = FolderStage::Loading; @@ -55,7 +55,7 @@ impl Folder { (self.cha, self.stage) = (cha, FolderStage::Loaded); } FilesOp::IOErr(_, kind) => { - (self.cha, self.stage) = (Cha::dummy(), FolderStage::Failed(kind)); + (self.cha, self.stage) = (Cha::default(), FolderStage::Failed(kind)); } _ => {} } diff --git a/yazi-core/src/tab/preview.rs b/yazi-core/src/tab/preview.rs index d7cacd26..4e30110e 100644 --- a/yazi-core/src/tab/preview.rs +++ b/yazi-core/src/tab/preview.rs @@ -48,7 +48,7 @@ impl Preview { Some(PreviewLock { url: wd.clone(), cha, mime: MIME_DIR.to_owned(), ..Default::default() }); 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 Some(new) = Files::assert_stale(&wd, dir.unwrap_or_default()).await else { return }; let rx = match Files::from_dir(&wd).await { Ok(rx) => rx, diff --git a/yazi-fs/src/cha/cha.rs b/yazi-fs/src/cha/cha.rs index 16d49427..28de0cca 100644 --- a/yazi-fs/src/cha/cha.rs +++ b/yazi-fs/src/cha/cha.rs @@ -1,10 +1,12 @@ use std::{fs::{FileType, Metadata}, path::Path, time::SystemTime}; +use tokio::fs; use yazi_macro::{unix_either, win_either}; +use yazi_shared::url::Url; use super::ChaKind; -#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)] +#[derive(Clone, Copy, Debug, PartialEq, Eq)] pub struct Cha { pub kind: ChaKind, pub len: u64, @@ -25,8 +27,110 @@ pub struct Cha { pub nlink: libc::nlink_t, } -impl From<&Metadata> for Cha { - fn from(m: &Metadata) -> Self { +impl Default for Cha { + fn default() -> Self { + Self { + kind: ChaKind::DUMMY, + len: 0, + atime: None, + btime: None, + #[cfg(unix)] + ctime: None, + mtime: None, + #[cfg(unix)] + mode: 0, + #[cfg(unix)] + dev: 0, + #[cfg(unix)] + uid: 0, + #[cfg(unix)] + gid: 0, + #[cfg(unix)] + nlink: 0, + } + } +} + +impl Cha { + #[inline] + pub fn new(path: &Path, meta: Metadata) -> Self { + Self::from_just_meta(&meta).attach(ChaKind::hidden(path, &meta)) + } + + #[inline] + pub async fn from_url(url: &Url) -> std::io::Result { + Ok(Self::from_follow(url, fs::symlink_metadata(url).await?).await) + } + + pub async fn from_follow(path: &Path, mut meta: Metadata) -> Self { + let mut attached = ChaKind::hidden(path, &meta); + if meta.is_symlink() { + attached |= ChaKind::LINK; + meta = fs::metadata(path).await.unwrap_or(meta); + } + if meta.is_symlink() { + attached |= ChaKind::ORPHAN; + } + + Self::from_just_meta(&meta).attach(attached) + } + + #[inline] + pub fn from_dummy(url: &Url, ft: Option) -> Self { + let mut me = ft.map(Self::from_half_ft).unwrap_or_default(); + #[cfg(unix)] + if yazi_shared::url::Urn::new(url).is_hidden() { + me.kind |= ChaKind::HIDDEN; + } + me + } + + fn from_half_ft(ft: FileType) -> Self { + let mut kind = ChaKind::DUMMY; + + #[cfg(unix)] + let mode = { + use std::os::unix::fs::FileTypeExt; + if ft.is_dir() { + kind |= ChaKind::DIR; + libc::S_IFDIR + } else if ft.is_symlink() { + kind |= ChaKind::LINK; + libc::S_IFLNK + } else if ft.is_block_device() { + libc::S_IFBLK + } else if ft.is_char_device() { + libc::S_IFCHR + } else if ft.is_fifo() { + libc::S_IFIFO + } else if ft.is_socket() { + libc::S_IFSOCK + } else { + 0 + } + }; + + #[cfg(windows)] + { + if ft.is_dir() { + kind |= ChaKind::DIR; + } else if ft.is_symlink() { + kind |= ChaKind::LINK; + } + } + + Self { + kind, + #[cfg(unix)] + mode, + ..Default::default() + } + } + + fn from_just_meta(m: &Metadata) -> Self { + #[cfg(unix)] + use std::{os::unix::{fs::MetadataExt, prelude::PermissionsExt}, time::{Duration, UNIX_EPOCH}}; + let mut kind = ChaKind::empty(); if m.is_dir() { kind |= ChaKind::DIR; @@ -40,115 +144,20 @@ impl From<&Metadata> for Cha { atime: m.accessed().ok(), btime: m.created().ok(), #[cfg(unix)] - ctime: { - use std::{os::unix::fs::MetadataExt, time::{Duration, UNIX_EPOCH}}; - UNIX_EPOCH.checked_add(Duration::new(m.ctime() as u64, m.ctime_nsec() as u32)) - }, + ctime: UNIX_EPOCH.checked_add(Duration::new(m.ctime() as u64, m.ctime_nsec() as u32)), mtime: m.modified().ok(), - #[cfg(unix)] - mode: { - use std::os::unix::prelude::PermissionsExt; - m.permissions().mode() as _ - }, + mode: m.permissions().mode() as _, #[cfg(unix)] - dev: { - use std::os::unix::fs::MetadataExt; - m.dev() as _ - }, + dev: m.dev() as _, #[cfg(unix)] - uid: { - use std::os::unix::fs::MetadataExt; - m.uid() as _ - }, + uid: m.uid() as _, #[cfg(unix)] - gid: { - use std::os::unix::fs::MetadataExt; - m.gid() as _ - }, + gid: m.gid() as _, #[cfg(unix)] - nlink: { - use std::os::unix::fs::MetadataExt; - m.nlink() as _ - }, + nlink: m.nlink() as _, } } -} - -impl From for Cha { - fn from(m: Metadata) -> Self { Self::from(&m) } -} - -impl From for Cha { - fn from(t: FileType) -> Self { - let mut kind = ChaKind::DUMMY; - - #[cfg(unix)] - let mode = { - use std::os::unix::fs::FileTypeExt; - if t.is_dir() { - kind |= ChaKind::DIR; - libc::S_IFDIR - } else if t.is_symlink() { - kind |= ChaKind::LINK; - libc::S_IFLNK - } else if t.is_block_device() { - libc::S_IFBLK - } else if t.is_char_device() { - libc::S_IFCHR - } else if t.is_fifo() { - libc::S_IFIFO - } else if t.is_socket() { - libc::S_IFSOCK - } else { - 0 - } - }; - - #[cfg(windows)] - { - if t.is_dir() { - kind |= ChaKind::DIR; - } else if t.is_symlink() { - kind |= ChaKind::LINK; - } - } - - Self { - kind, - #[cfg(unix)] - mode, - ..Default::default() - } - } -} - -impl Cha { - pub async fn new(path: &Path, mut meta: Metadata) -> Self { - let mut attached = ChaKind::hidden(path, &meta); - - if meta.is_symlink() { - attached |= ChaKind::LINK; - meta = tokio::fs::metadata(path).await.unwrap_or(meta); - } - if meta.is_symlink() { - attached |= ChaKind::ORPHAN; - } - - let mut me = Self::from(meta); - me.kind |= attached; - me - } - - #[inline] - pub fn new_nofollow(_path: &Path, meta: Metadata) -> Self { - let mut me = Self::from(&meta); - me.kind |= ChaKind::hidden(_path, &meta); - me - } - - #[inline] - pub fn dummy() -> Self { Self { kind: ChaKind::DUMMY, ..Default::default() } } #[inline] pub fn hits(self, c: Self) -> bool { @@ -159,6 +168,12 @@ impl Cha { && self.kind == c.kind && unix_either!(self.mode == c.mode, true) } + + #[inline] + fn attach(mut self, kind: ChaKind) -> Self { + self.kind |= kind; + self + } } impl Cha { diff --git a/yazi-fs/src/file.rs b/yazi-fs/src/file.rs index 18d7ba77..e26fa30f 100644 --- a/yazi-fs/src/file.rs +++ b/yazi-fs/src/file.rs @@ -23,29 +23,25 @@ impl Deref for File { impl File { #[inline] - pub async fn from(url: Url) -> Result { + pub async fn new(url: Url) -> Result { let meta = fs::symlink_metadata(&url).await?; - Ok(Self::from_meta(url, meta).await) + Ok(Self::from_follow(url, meta).await) } #[inline] - pub async fn from_meta(url: Url, meta: Metadata) -> Self { + pub async fn from_follow(url: Url, meta: Metadata) -> Self { let link_to = if meta.is_symlink() { fs::read_link(&url).await.map(Url::from).ok() } else { None }; - let cha = Cha::new(&url, meta).await; + let cha = Cha::from_follow(&url, meta).await; Self { url, cha, link_to, icon: Default::default() } } #[inline] pub fn from_dummy(url: Url, ft: Option) -> Self { - Self { - url, - cha: ft.map_or_else(Cha::dummy, Cha::from), - link_to: None, - icon: Default::default(), - } + let cha = Cha::from_dummy(&url, ft); + Self { url, cha, link_to: None, icon: Default::default() } } #[inline] diff --git a/yazi-fs/src/files.rs b/yazi-fs/src/files.rs index 61a332ca..5ba7fc92 100644 --- a/yazi-fs/src/files.rs +++ b/yazi-fs/src/files.rs @@ -41,7 +41,7 @@ impl Files { result = item.metadata() => { let url = Url::from(item.path()); _ = tx.send(match result { - Ok(meta) => File::from_meta(url, meta).await, + Ok(meta) => File::from_follow(url, meta).await, Err(_) => File::from_dummy(url, item.file_type().await.ok()) }); } @@ -65,7 +65,7 @@ impl Files { for entry in entries { let url = Url::from(entry.path()); files.push(match entry.metadata().await { - Ok(meta) => File::from_meta(url, meta).await, + Ok(meta) => File::from_follow(url, meta).await, Err(_) => File::from_dummy(url, entry.file_type().await.ok()), }); } @@ -83,7 +83,7 @@ impl Files { pub async fn assert_stale(dir: &Url, cha: Cha) -> Option { use std::io::ErrorKind; - match fs::metadata(dir).await.map(Cha::from) { + match Cha::from_url(dir).await { 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), diff --git a/yazi-fs/src/op.rs b/yazi-fs/src/op.rs index bc3bba78..1c0c07f1 100644 --- a/yazi-fs/src/op.rs +++ b/yazi-fs/src/op.rs @@ -125,7 +125,7 @@ impl FilesOp { } 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(); + Self::Deleting(p, [n].into()).emit(); } } diff --git a/yazi-plugin/src/bindings/cha.rs b/yazi-plugin/src/bindings/cha.rs index dca7ef50..8eee53be 100644 --- a/yazi-plugin/src/bindings/cha.rs +++ b/yazi-plugin/src/bindings/cha.rs @@ -4,7 +4,7 @@ use mlua::{ExternalError, FromLua, IntoLua, Lua, Table, UserData, UserDataFields use yazi_fs::cha::ChaKind; #[derive(Clone, Copy, FromLua)] -pub struct Cha(yazi_fs::cha::Cha); +pub struct Cha(pub yazi_fs::cha::Cha); impl Deref for Cha { type Target = yazi_fs::cha::Cha; @@ -12,10 +12,6 @@ impl Deref for Cha { fn deref(&self) -> &Self::Target { &self.0 } } -impl> From for Cha { - fn from(cha: T) -> Self { Self(cha.into()) } -} - impl Cha { pub fn install(lua: &Lua) -> mlua::Result<()> { #[inline] @@ -33,7 +29,7 @@ impl Cha { let kind = ChaKind::from_bits(t.raw_get("kind")?).ok_or_else(|| "Invalid kind".into_lua_err())?; - Self::from(yazi_fs::cha::Cha { + Self(yazi_fs::cha::Cha { kind, len: t.raw_get("len").unwrap_or_default(), atime: parse_time(t.raw_get("atime").ok())?, diff --git a/yazi-plugin/src/external/fd.rs b/yazi-plugin/src/external/fd.rs index f5097d67..5739f32d 100644 --- a/yazi-plugin/src/external/fd.rs +++ b/yazi-plugin/src/external/fd.rs @@ -20,7 +20,7 @@ pub fn fd(opt: FdOpt) -> Result> { tokio::spawn(async move { while let Ok(Some(line)) = it.next_line().await { - if let Ok(file) = File::from(opt.cwd.join(line)).await { + if let Ok(file) = File::new(opt.cwd.join(line)).await { tx.send(file).ok(); } } diff --git a/yazi-plugin/src/external/rg.rs b/yazi-plugin/src/external/rg.rs index c4d5674e..a14d9d1e 100644 --- a/yazi-plugin/src/external/rg.rs +++ b/yazi-plugin/src/external/rg.rs @@ -29,7 +29,7 @@ pub fn rg(opt: RgOpt) -> Result> { tokio::spawn(async move { while let Ok(Some(line)) = it.next_line().await { - if let Ok(file) = File::from(opt.cwd.join(line)).await { + if let Ok(file) = File::new(opt.cwd.join(line)).await { tx.send(file).ok(); } } diff --git a/yazi-plugin/src/external/rga.rs b/yazi-plugin/src/external/rga.rs index d7e6ac6a..b4f6aaf5 100644 --- a/yazi-plugin/src/external/rga.rs +++ b/yazi-plugin/src/external/rga.rs @@ -29,7 +29,7 @@ pub fn rga(opt: RgaOpt) -> Result> { tokio::spawn(async move { while let Ok(Some(line)) = it.next_line().await { - if let Ok(file) = File::from(opt.cwd.join(line)).await { + if let Ok(file) = File::new(opt.cwd.join(line)).await { tx.send(file).ok(); } } diff --git a/yazi-plugin/src/fs/fs.rs b/yazi-plugin/src/fs/fs.rs index eb79912c..18d610cd 100644 --- a/yazi-plugin/src/fs/fs.rs +++ b/yazi-plugin/src/fs/fs.rs @@ -51,7 +51,7 @@ fn cha(lua: &Lua) -> mlua::Result { }; match meta { - Ok(m) => Cha::from(m).into_lua_multi(&lua), + Ok(m) => Cha(yazi_fs::cha::Cha::new(&url, m)).into_lua_multi(&lua), Err(e) => (Value::Nil, Error::Io(e)).into_lua_multi(&lua), } }) @@ -138,7 +138,7 @@ fn read_dir(lua: &Lua) -> mlua::Result { let file = if !resolve { yazi_fs::File::from_dummy(url, next.file_type().await.ok()) } else if let Ok(meta) = next.metadata().await { - yazi_fs::File::from_meta(url, meta).await + yazi_fs::File::from_follow(url, meta).await } else { yazi_fs::File::from_dummy(url, next.file_type().await.ok()) }; diff --git a/yazi-plugin/src/macros.rs b/yazi-plugin/src/macros.rs index c4b23549..b2710b5c 100644 --- a/yazi-plugin/src/macros.rs +++ b/yazi-plugin/src/macros.rs @@ -83,7 +83,7 @@ macro_rules! impl_style_shorthands { #[macro_export] macro_rules! impl_file_fields { ($fields:ident) => { - yazi_binding::cached_field!($fields, cha, |_, me| Ok($crate::bindings::Cha::from(me.cha))); + yazi_binding::cached_field!($fields, cha, |_, me| Ok($crate::bindings::Cha(me.cha))); yazi_binding::cached_field!($fields, url, |_, me| Ok(yazi_binding::Url::new(me.url_owned()))); yazi_binding::cached_field!($fields, link_to, |_, me| Ok( me.link_to.clone().map(yazi_binding::Url::new) diff --git a/yazi-proxy/src/tab.rs b/yazi-proxy/src/tab.rs index ef70941d..e6b448a2 100644 --- a/yazi-proxy/src/tab.rs +++ b/yazi-proxy/src/tab.rs @@ -13,7 +13,7 @@ impl TabProxy { #[inline] pub fn reveal(target: &Url) { - emit!(Call(Cmd::args("mgr:reveal", &[target]))); + emit!(Call(Cmd::args("mgr:reveal", &[target]).with("no-dummy", true))); } #[inline] diff --git a/yazi-scheduler/src/file/file.rs b/yazi-scheduler/src/file/file.rs index a8a47ee4..c7db540e 100644 --- a/yazi-scheduler/src/file/file.rs +++ b/yazi-scheduler/src/file/file.rs @@ -328,15 +328,15 @@ impl File { #[inline] async fn cha(path: &Path, follow: bool) -> io::Result { let meta = fs::symlink_metadata(path).await?; - Ok(if follow { Cha::new(path, meta).await } else { Cha::new_nofollow(path, meta) }) + Ok(if follow { Cha::from_follow(path, meta).await } else { Cha::new(path, meta) }) } #[inline] async fn cha_from(entry: DirEntry, path: &Path, follow: bool) -> io::Result { Ok(if follow { - Cha::new(path, entry.metadata().await?).await + Cha::from_follow(path, entry.metadata().await?).await } else { - Cha::new_nofollow(path, entry.metadata().await?) + Cha::new(path, entry.metadata().await?) }) } } diff --git a/yazi-shared/src/event/data.rs b/yazi-shared/src/event/data.rs index f2a9a251..afe929d5 100644 --- a/yazi-shared/src/event/data.rs +++ b/yazi-shared/src/event/data.rs @@ -86,6 +86,10 @@ impl Data { } } +impl From for Data { + fn from(value: bool) -> Self { Self::Boolean(value) } +} + impl From for Data { fn from(value: usize) -> Self { Self::Id(value.into()) } }