diff --git a/README.md b/README.md
index 5ae75e2e4..bb31463d9 100644
--- a/README.md
+++ b/README.md
@@ -2,6 +2,8 @@
For breaking changes, see [Migrating to Yazi v0.4.0](https://github.com/sxyazi/yazi/issues/1772).
+
+
@@ -56,7 +58,7 @@ https://github.com/sxyazi/yazi/assets/17523360/92ff23fa-0cd5-4f04-b387-894c12265
| [VSCode](https://github.com/microsoft/vscode) | [Inline images protocol](https://iterm2.com/documentation-images.html) | ✅ Built-in |
| [Tabby](https://github.com/Eugeny/tabby) | [Inline images protocol](https://iterm2.com/documentation-images.html) | ✅ Built-in |
| [Hyper](https://github.com/vercel/hyper) | [Inline images protocol](https://iterm2.com/documentation-images.html) | ✅ Built-in |
-| [Rio](https://github.com/raphamorim/rio) | [Inline images protocol](https://iterm2.com/documentation-images.html) | ✅ Built-in |
+| [Rio](https://github.com/raphamorim/rio) | [Inline images protocol](https://iterm2.com/documentation-images.html) | ❌ Rio doesn't correctly clear images (#1786) |
| X11 / Wayland | Window system protocol | ☑️ [Überzug++](https://github.com/jstkdng/ueberzugpp) required |
| Fallback | [ASCII art (Unicode block)](https://en.wikipedia.org/wiki/ASCII_art) | ☑️ [Chafa](https://hpjansson.org/chafa/) required |
diff --git a/yazi-core/src/manager/watcher.rs b/yazi-core/src/manager/watcher.rs
index 33ebae065..1e6f41720 100644
--- a/yazi-core/src/manager/watcher.rs
+++ b/yazi-core/src/manager/watcher.rs
@@ -136,7 +136,7 @@ impl Watcher {
};
let u = &file.url;
- let eq = (!file.is_linkable() && fs::canonicalize(u).await.is_ok_and(|p| p == ***u))
+ let eq = (!file.is_link() && fs::canonicalize(u).await.is_ok_and(|p| p == ***u))
|| realname_unchecked(u, &mut cached).await.is_ok_and(|s| urn.as_urn() == s);
if !eq {
diff --git a/yazi-plugin/src/fs/fs.rs b/yazi-plugin/src/fs/fs.rs
index ca6544ca2..fed446ad1 100644
--- a/yazi-plugin/src/fs/fs.rs
+++ b/yazi-plugin/src/fs/fs.rs
@@ -111,7 +111,7 @@ pub fn install(lua: &Lua) -> mlua::Result<()> {
(
"unique_name",
lua.create_async_function(|lua, url: UrlRef| async move {
- match yazi_shared::fs::unique_name(url.clone()).await {
+ match yazi_shared::fs::unique_name(url.clone(), async { false }).await {
Ok(u) => (Url::cast(lua, u)?, Value::Nil).into_lua_multi(lua),
Err(e) => (Value::Nil, e.raw_os_error()).into_lua_multi(lua),
}
diff --git a/yazi-scheduler/src/file/file.rs b/yazi-scheduler/src/file/file.rs
index f08aa1f11..e46cdae5b 100644
--- a/yazi-scheduler/src/file/file.rs
+++ b/yazi-scheduler/src/file/file.rs
@@ -163,7 +163,7 @@ impl File {
let id = task.id;
self.prog.send(TaskProg::New(id, cha.len))?;
- if cha.is_linkable() {
+ if cha.is_orphan() || (cha.is_link() && !task.follow) {
self.queue(FileOp::Link(task.into()), NORMAL).await?;
} else {
self.queue(FileOp::Paste(task), LOW).await?;
@@ -208,7 +208,7 @@ impl File {
let to = dest.join(from.file_name().unwrap());
self.prog.send(TaskProg::New(task.id, cha.len))?;
- if cha.is_linkable() {
+ if cha.is_orphan() || (cha.is_link() && !task.follow) {
self.queue(FileOp::Link(task.spawn(from, to, cha).into()), NORMAL).await?;
} else {
self.queue(FileOp::Paste(task.spawn(from, to, cha)), LOW).await?;
diff --git a/yazi-scheduler/src/scheduler.rs b/yazi-scheduler/src/scheduler.rs
index 08f958f39..075e517b5 100644
--- a/yazi-scheduler/src/scheduler.rs
+++ b/yazi-scheduler/src/scheduler.rs
@@ -7,7 +7,7 @@ use tokio::{fs, select, sync::{mpsc::{self, UnboundedReceiver}, oneshot}, task::
use yazi_config::{TASKS, open::Opener, plugin::{Fetcher, Preloader}};
use yazi_dds::Pump;
use yazi_proxy::ManagerProxy;
-use yazi_shared::{Throttle, event::Data, fs::{Url, remove_dir_clean, unique_name}};
+use yazi_shared::{Throttle, event::Data, fs::{Url, must_be_dir, remove_dir_clean, unique_name}};
use super::{Ongoing, TaskProg, TaskStage};
use crate::{HIGH, LOW, NORMAL, TaskKind, TaskOp, file::{File, FileOpDelete, FileOpHardlink, FileOpLink, FileOpPaste, FileOpTrash}, plugin::{Plugin, PluginOpEntry}, prework::{Prework, PreworkOpFetch, PreworkOpLoad, PreworkOpSize}, process::{Process, ProcessOpBg, ProcessOpBlock, ProcessOpOrphan}};
@@ -97,7 +97,7 @@ impl Scheduler {
let file = self.file.clone();
self.send_micro(id, LOW, async move {
if !force {
- to = unique_name(to).await?;
+ to = unique_name(to, must_be_dir(&from)).await?;
}
file.paste(FileOpPaste { id, from, to, cha: None, cut: true, follow: false, retry: 0 }).await
});
@@ -114,7 +114,7 @@ impl Scheduler {
let file = self.file.clone();
self.send_micro(id, LOW, async move {
if !force {
- to = unique_name(to).await?;
+ to = unique_name(to, must_be_dir(&from)).await?;
}
file.paste(FileOpPaste { id, from, to, cha: None, cut: false, follow, retry: 0 }).await
});
@@ -126,7 +126,7 @@ impl Scheduler {
let file = self.file.clone();
self.send_micro(id, LOW, async move {
if !force {
- to = unique_name(to).await?;
+ to = unique_name(to, must_be_dir(&from)).await?;
}
file
.link(FileOpLink { id, from, to, cha: None, resolve: false, relative, delete: false })
@@ -145,7 +145,7 @@ impl Scheduler {
let file = self.file.clone();
self.send_micro(id, LOW, async move {
if !force {
- to = unique_name(to).await?;
+ to = unique_name(to, must_be_dir(&from)).await?;
}
file.hardlink(FileOpHardlink { id, from, to, cha: None, follow }).await
});
diff --git a/yazi-shared/src/fs/cha.rs b/yazi-shared/src/fs/cha.rs
index 14a080898..294ffed13 100644
--- a/yazi-shared/src/fs/cha.rs
+++ b/yazi-shared/src/fs/cha.rs
@@ -42,6 +42,8 @@ impl From for Cha {
let mut kind = ChaKind::empty();
if m.is_dir() {
kind |= ChaKind::DIR;
+ } else if m.is_symlink() {
+ kind |= ChaKind::LINK;
}
Self {
@@ -91,7 +93,7 @@ impl From for Cha {
kind |= ChaKind::DIR;
libc::S_IFDIR
} else if t.is_symlink() {
- kind |= ChaKind::ORPHAN;
+ kind |= ChaKind::LINK;
libc::S_IFLNK
} else if t.is_block_device() {
libc::S_IFBLK
@@ -130,8 +132,11 @@ impl Cha {
let mut attached = ChaKind::empty();
if meta.is_symlink() {
+ attached |= ChaKind::LINK;
meta = tokio::fs::metadata(path).await.unwrap_or(meta);
- attached |= if meta.is_symlink() { ChaKind::ORPHAN } else { ChaKind::LINK };
+ }
+ if meta.is_symlink() {
+ attached |= ChaKind::ORPHAN;
}
let mut cha = Self::new_nofollow(path, meta);
@@ -187,9 +192,6 @@ impl Cha {
#[inline]
pub const fn is_orphan(&self) -> bool { self.kind.contains(ChaKind::ORPHAN) }
- #[inline]
- pub const fn is_linkable(&self) -> bool { self.is_link() || self.is_orphan() }
-
#[inline]
pub const fn is_dummy(&self) -> bool { self.kind.contains(ChaKind::DUMMY) }
diff --git a/yazi-shared/src/fs/fns.rs b/yazi-shared/src/fs/fns.rs
index e33c3a78a..d0e3286aa 100644
--- a/yazi-shared/src/fs/fns.rs
+++ b/yazi-shared/src/fs/fns.rs
@@ -16,6 +16,11 @@ pub async fn maybe_exists(p: impl AsRef) -> bool {
}
}
+#[inline]
+pub async fn must_be_dir(p: impl AsRef) -> bool {
+ fs::metadata(p).await.map_or(false, |m| m.is_dir())
+}
+
#[inline]
pub fn ok_or_not_found(result: io::Result<()>) -> io::Result<()> {
match result {
diff --git a/yazi-shared/src/fs/path.rs b/yazi-shared/src/fs/path.rs
index 592e4f172..48a7d7cc4 100644
--- a/yazi-shared/src/fs/path.rs
+++ b/yazi-shared/src/fs/path.rs
@@ -1,4 +1,4 @@
-use std::{borrow::Cow, env, ffi::OsString, io, path::{Component, Path, PathBuf}};
+use std::{borrow::Cow, env, ffi::OsString, future::Future, io, path::{Component, Path, PathBuf}};
use tokio::fs;
@@ -74,38 +74,51 @@ fn _expand_path(p: &Path) -> PathBuf {
}
}
-pub async fn unique_name(mut u: Url) -> io::Result {
+pub async fn unique_name(u: Url, append: F) -> io::Result
+where
+ F: Future