mirror of
https://github.com/sxyazi/yazi.git
synced 2026-07-25 08:41:05 +00:00
Try another way
This commit is contained in:
parent
485e4d6974
commit
2c9ab2d930
6 changed files with 52 additions and 76 deletions
7
Cargo.lock
generated
7
Cargo.lock
generated
|
|
@ -2474,12 +2474,6 @@ dependencies = [
|
|||
"winsafe",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "widestring"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7219d36b6eac893fa81e84ebe06485e7dcbb616177469b142df14f1f4deb1311"
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.3.9"
|
||||
|
|
@ -2970,7 +2964,6 @@ dependencies = [
|
|||
"serde",
|
||||
"shell-words",
|
||||
"tokio",
|
||||
"widestring",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
{"version":"0.2","flagWords":[],"words":["Punct","KEYMAP","splitn","crossterm","YAZI","unar","peekable","ratatui","syntect","pbpaste","pbcopy","ffmpegthumbnailer","oneshot","Posix","Lsar","XADDOS","zoxide","cands","Deque","precache","imageops","IFBLK","IFCHR","IFDIR","IFIFO","IFLNK","IFMT","IFSOCK","IRGRP","IROTH","IRUSR","ISGID","ISUID","ISVTX","IWGRP","IWOTH","IWUSR","IXGRP","IXOTH","IXUSR","libc","winsize","TIOCGWINSZ","xpixel","ypixel","ioerr","appender","Catppuccin","macchiato","gitmodules","Dotfiles","bashprofile","vimrc","flac","webp","exiftool","mediainfo","ripgrep","nvim","indexmap","indexmap","unwatch","canonicalize","serde","fsevent","Ueberzug","iterm","wezterm","sixel","chafa","ueberzugpp","️ Überzug","️ Überzug","Konsole","Alacritty","Überzug","pkgs","paru","unarchiver","pdftoppm","poppler","prebuild","singlefile","jpegopt","EXIF","rustfmt","mktemp","nanos","xclip","xsel","natord","Mintty","nixos","nixpkgs","SIGTSTP","SIGCONT","SIGCONT","mlua","nonstatic","userdata","metatable","natsort","backstack","luajit","Succ","Succ","cand","fileencoding","foldmethod","lightgreen","darkgray","lightred","lightyellow","lightcyan","nushell","msvc","aarch","linemode","sxyazi","rsplit","ZELLIJ","bitflags","bitflags","USERPROFILE","Neovim","vergen","gitcl","Renderable","preloaders","prec","imagesize","Upserting","prio","Ghostty","Catmull","Lanczos","cmds","unyank","scrolloff","headsup","unsub","uzers","scopeguard","SPDLOG","globset","filetime","magick","magick","prefetcher","Prework","prefetchers","PREWORKERS","conds","translit","rxvt","Urxvt","realpath","realname","widestring"],"language":"en"}
|
||||
{"language":"en","flagWords":[],"words":["Punct","KEYMAP","splitn","crossterm","YAZI","unar","peekable","ratatui","syntect","pbpaste","pbcopy","ffmpegthumbnailer","oneshot","Posix","Lsar","XADDOS","zoxide","cands","Deque","precache","imageops","IFBLK","IFCHR","IFDIR","IFIFO","IFLNK","IFMT","IFSOCK","IRGRP","IROTH","IRUSR","ISGID","ISUID","ISVTX","IWGRP","IWOTH","IWUSR","IXGRP","IXOTH","IXUSR","libc","winsize","TIOCGWINSZ","xpixel","ypixel","ioerr","appender","Catppuccin","macchiato","gitmodules","Dotfiles","bashprofile","vimrc","flac","webp","exiftool","mediainfo","ripgrep","nvim","indexmap","indexmap","unwatch","canonicalize","serde","fsevent","Ueberzug","iterm","wezterm","sixel","chafa","ueberzugpp","️ Überzug","️ Überzug","Konsole","Alacritty","Überzug","pkgs","paru","unarchiver","pdftoppm","poppler","prebuild","singlefile","jpegopt","EXIF","rustfmt","mktemp","nanos","xclip","xsel","natord","Mintty","nixos","nixpkgs","SIGTSTP","SIGCONT","SIGCONT","mlua","nonstatic","userdata","metatable","natsort","backstack","luajit","Succ","Succ","cand","fileencoding","foldmethod","lightgreen","darkgray","lightred","lightyellow","lightcyan","nushell","msvc","aarch","linemode","sxyazi","rsplit","ZELLIJ","bitflags","bitflags","USERPROFILE","Neovim","vergen","gitcl","Renderable","preloaders","prec","imagesize","Upserting","prio","Ghostty","Catmull","Lanczos","cmds","unyank","scrolloff","headsup","unsub","uzers","scopeguard","SPDLOG","globset","filetime","magick","magick","prefetcher","Prework","prefetchers","PREWORKERS","conds","translit","rxvt","Urxvt","realpath","realname","REPARSE"],"version":"0.2"}
|
||||
|
|
@ -84,16 +84,7 @@ impl Manager {
|
|||
for (o, n) in todo {
|
||||
let (old, new) = (root.join(&o), root.join(&n));
|
||||
|
||||
let overwrite_safe;
|
||||
#[cfg(windows)]
|
||||
{
|
||||
overwrite_safe = yazi_shared::fs::rename_without_overwriting(&old, &new).await.is_ok();
|
||||
}
|
||||
#[cfg(unix)]
|
||||
{
|
||||
overwrite_safe = yazi_shared::fs::are_paths_equal(&old, &new).await;
|
||||
}
|
||||
if maybe_exists(&new).await && !overwrite_safe {
|
||||
if maybe_exists(&new).await {
|
||||
failed.push((o, n, anyhow!("Destination already exists")));
|
||||
} else {
|
||||
#[cfg(unix)]
|
||||
|
|
|
|||
|
|
@ -62,39 +62,25 @@ impl Manager {
|
|||
}
|
||||
|
||||
let new = hovered.parent().unwrap().join(name);
|
||||
let overwrite_safe;
|
||||
#[cfg(windows)]
|
||||
{
|
||||
overwrite_safe = yazi_shared::fs::rename_without_overwriting(&hovered, &new).await.is_ok();
|
||||
}
|
||||
#[cfg(unix)]
|
||||
{
|
||||
overwrite_safe = yazi_shared::fs::are_paths_equal(&hovered, &new).await;
|
||||
}
|
||||
if opt.force || !maybe_exists(&new).await || overwrite_safe {
|
||||
Self::rename_do(tab, hovered, Url::from(new), overwrite_safe).await.ok();
|
||||
if opt.force || !maybe_exists(&new).await {
|
||||
Self::rename_do(tab, hovered, Url::from(new)).await.ok();
|
||||
return;
|
||||
}
|
||||
|
||||
let mut result = InputProxy::show(InputCfg::overwrite());
|
||||
if let Some(Ok(choice)) = result.recv().await {
|
||||
if choice == "y" || choice == "Y" {
|
||||
Self::rename_do(tab, hovered, Url::from(new), false).await.ok();
|
||||
Self::rename_do(tab, hovered, Url::from(new)).await.ok();
|
||||
}
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
async fn rename_do(tab: usize, old: Url, new: Url, overwrite_safe: bool) -> Result<()> {
|
||||
async fn rename_do(tab: usize, old: Url, new: Url) -> Result<()> {
|
||||
let Some(p_old) = old.parent_url() else { return Ok(()) };
|
||||
let Some(p_new) = new.parent_url() else { return Ok(()) };
|
||||
let _permit = WATCHER.acquire().await.unwrap();
|
||||
|
||||
if overwrite_safe {
|
||||
if !cfg!(windows) {
|
||||
fs::rename(&old, &new).await?;
|
||||
}
|
||||
} else {
|
||||
let overwritten = symlink_realpath(&new).await;
|
||||
fs::rename(&old, &new).await?;
|
||||
|
||||
|
|
@ -102,7 +88,6 @@ impl Manager {
|
|||
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?;
|
||||
|
|
|
|||
|
|
@ -22,8 +22,9 @@ regex = "1.10.5"
|
|||
serde = { version = "1.0.203", features = [ "derive" ] }
|
||||
shell-words = "1.1.0"
|
||||
tokio = { version = "1.38.0", features = [ "full" ] }
|
||||
widestring = "1.1.0"
|
||||
windows-sys = { version = "0.52.0", features = ["Win32_Foundation"] }
|
||||
|
||||
[target."cfg(unix)".dependencies]
|
||||
libc = "0.2.155"
|
||||
|
||||
[target.'cfg(windows)'.dependencies]
|
||||
windows-sys = { version = "0.52.0", features = [ "Win32_Storage_FileSystem" ] }
|
||||
|
|
|
|||
|
|
@ -23,42 +23,48 @@ pub fn ok_or_not_found(result: io::Result<()>) -> io::Result<()> {
|
|||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[cfg(unix)]
|
||||
pub async fn are_paths_equal(old: impl AsRef<Path>, new: impl AsRef<Path>) -> bool {
|
||||
if let (Ok(canonical_old), Ok(canonical_new)) =
|
||||
(fs::canonicalize(&old).await, fs::canonicalize(&new).await)
|
||||
{
|
||||
if let (Ok(old), Ok(new)) =
|
||||
(fs::metadata(&canonical_old).await, fs::metadata(&canonical_new).await)
|
||||
{
|
||||
pub async fn paths_to_same_file(a: &Path, b: &Path) -> io::Result<bool> {
|
||||
use std::os::unix::fs::MetadataExt;
|
||||
old.ino() == new.ino() && old.dev() == new.dev()
|
||||
} else {
|
||||
false
|
||||
}
|
||||
} else {
|
||||
false
|
||||
}
|
||||
|
||||
let (a, b) = (fs::symlink_metadata(a).await?, fs::symlink_metadata(b).await?);
|
||||
Ok(a.ino() == b.ino() && a.dev() == b.dev())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[cfg(windows)]
|
||||
pub async fn rename_without_overwriting(
|
||||
old: impl AsRef<Path>,
|
||||
new: impl AsRef<Path>,
|
||||
) -> io::Result<()> {
|
||||
use widestring::U16CString;
|
||||
use windows_sys::Win32::Storage::FileSystem::MoveFileExW;
|
||||
let old = U16CString::from_os_str(old.as_ref().as_os_str())
|
||||
.map_err(|_| io::Error::new(io::ErrorKind::InvalidInput, "invalid path"))?;
|
||||
let new = U16CString::from_os_str(new.as_ref().as_os_str())
|
||||
.map_err(|_| io::Error::new(io::ErrorKind::InvalidInput, "invalid path"))?;
|
||||
pub async fn paths_to_same_file(a: &Path, b: &Path) -> std::io::Result<bool> {
|
||||
use std::{ffi::OsString, os::windows::{ffi::OsStringExt, io::AsRawHandle}, path::{Path, PathBuf}};
|
||||
|
||||
use windows_sys::Win32::{Foundation::{HANDLE, MAX_PATH}, Storage::FileSystem::{GetFinalPathNameByHandleW, FILE_FLAG_BACKUP_SEMANTICS, FILE_FLAG_OPEN_REPARSE_POINT, VOLUME_NAME_DOS}};
|
||||
|
||||
async fn final_name(p: &Path) -> std::io::Result<PathBuf> {
|
||||
let file = tokio::fs::OpenOptions::new()
|
||||
.access_mode(0)
|
||||
.custom_flags(FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT)
|
||||
.open(p)
|
||||
.await?;
|
||||
|
||||
let mut buf = [0u16; MAX_PATH as usize];
|
||||
tokio::task::spawn_blocking(move || {
|
||||
let result = unsafe { MoveFileExW(old.as_ptr(), new.as_ptr(), 0) };
|
||||
if result != 0 { Ok(()) } else { Err(io::Error::last_os_error()) }
|
||||
let len = unsafe {
|
||||
GetFinalPathNameByHandleW(
|
||||
file.as_raw_handle() as HANDLE,
|
||||
buf.as_mut_ptr(),
|
||||
buf.len() as u32,
|
||||
VOLUME_NAME_DOS,
|
||||
)
|
||||
};
|
||||
|
||||
if len == 0 {
|
||||
Err(std::io::Error::last_os_error())
|
||||
} else {
|
||||
Ok(PathBuf::from(OsString::from_wide(&buf[0..len as usize])))
|
||||
}
|
||||
})
|
||||
.await?
|
||||
}
|
||||
|
||||
Ok(final_name(a).await? == final_name(b).await?)
|
||||
}
|
||||
|
||||
pub async fn symlink_realpath(path: &Path) -> Result<PathBuf> {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue