This commit is contained in:
sxyazi 2024-06-13 20:28:44 +08:00
parent b303219b99
commit 8eb2eea5cc
No known key found for this signature in database
4 changed files with 29 additions and 10 deletions

View file

@ -4,7 +4,7 @@ use anyhow::Result;
use tokio::fs;
use yazi_config::popup::InputCfg;
use yazi_proxy::{InputProxy, TabProxy, WATCHER};
use yazi_shared::{event::Cmd, fs::{maybe_exists, ok_or_not_found, File, FilesOp, Url}};
use yazi_shared::{event::Cmd, fs::{maybe_exists, ok_or_not_found, symlink_realpath, File, FilesOp, Url}};
use crate::manager::Manager;
@ -47,6 +47,10 @@ impl Manager {
if dir {
fs::create_dir_all(&new).await?;
} else if let Ok(real) = symlink_realpath(&new).await {
ok_or_not_found(fs::remove_file(&new).await)?;
FilesOp::Deleting(parent.clone(), vec![Url::from(real)]).emit();
fs::File::create(&new).await?;
} else {
fs::create_dir_all(&parent).await.ok();
ok_or_not_found(fs::remove_file(&new).await)?;
@ -54,7 +58,7 @@ impl Manager {
}
if let Ok(f) = File::from(new.clone()).await {
FilesOp::Upserting(parent, HashMap::from_iter([(new.clone(), f)])).emit();
FilesOp::Upserting(parent, HashMap::from_iter([(f.url(), f)])).emit();
TabProxy::reveal(&new)
}
Ok(())

View file

@ -5,7 +5,7 @@ use tokio::fs;
use yazi_config::popup::InputCfg;
use yazi_dds::Pubsub;
use yazi_proxy::{InputProxy, TabProxy, WATCHER};
use yazi_shared::{event::Cmd, fs::{maybe_exists, File, FilesOp, Url}};
use yazi_shared::{event::Cmd, fs::{maybe_exists, ok_or_not_found, symlink_realpath, File, FilesOp, Url}};
use crate::manager::Manager;
@ -81,7 +81,13 @@ impl Manager {
let Some(p_new) = new.parent_url() else { return Ok(()) };
let _permit = WATCHER.acquire().await.unwrap();
let overwritten = symlink_realpath(&new).await;
fs::rename(&old, &new).await?;
if let Ok(p) = overwritten {
ok_or_not_found(fs::rename(&p, &new).await)?;
FilesOp::Deleting(p_new.clone(), vec![Url::from(p)]).emit();
}
Pubsub::pub_from_rename(tab, &old, &new);
let file = File::from(new.clone()).await?;

View file

@ -8,7 +8,7 @@ use tokio_stream::{wrappers::UnboundedReceiverStream, StreamExt};
use tracing::error;
use yazi_plugin::isolate;
use yazi_proxy::WATCHER;
use yazi_shared::{fs::{symlink_realpath, File, FilesOp, Url}, RoCell};
use yazi_shared::{fs::{symlink_realpath_with, File, FilesOp, Url}, RoCell};
use super::Linked;
use crate::folder::{Files, Folder};
@ -111,7 +111,7 @@ impl Watcher {
};
let realpath = if file.is_link() {
symlink_realpath(&url, &mut cached).await
symlink_realpath_with(&url, &mut cached).await
} else {
fs::canonicalize(&url).await.map(Cow::Owned)
};

View file

@ -24,23 +24,32 @@ pub fn ok_or_not_found(result: io::Result<()>) -> io::Result<()> {
}
}
#[inline]
pub async fn symlink_realpath(path: &Path) -> io::Result<PathBuf> {
if fs::symlink_metadata(path).await?.is_symlink() {
symlink_realpath_with(path, &mut HashMap::new()).await.map(|p| p.into_owned())
} else {
fs::canonicalize(path).await
}
}
// realpath(3) without resolving symlinks. This is useful for case-insensitive
// filesystems.
//
// Make sure the file of the path exists and is a symlink.
pub async fn symlink_realpath<'a>(
pub async fn symlink_realpath_with<'a>(
path: &'a Path,
cached: &'a mut HashMap<PathBuf, PathBuf>,
) -> io::Result<Cow<'a, Path>> {
let Some(parent) = path.parent() else {
return Ok(Cow::Borrowed(path));
};
let lowercased: PathBuf = path.as_os_str().to_ascii_lowercase().into();
if lowercased == path {
return Ok(Cow::Borrowed(path));
}
let Some(parent) = path.parent() else {
return Ok(Cow::Borrowed(path));
};
let case = parent.as_os_str().as_encoded_bytes().iter().any(|&b| b.is_ascii_uppercase());
if !cached.contains_key(parent) {
let mut it = fs::read_dir(parent).await?;