mirror of
https://github.com/sxyazi/yazi.git
synced 2026-07-25 08:41:05 +00:00
..
This commit is contained in:
parent
6f74d84a6e
commit
f63746371e
4 changed files with 57 additions and 36 deletions
|
|
@ -1 +1 @@
|
||||||
{"flagWords":[],"language":"en","version":"0.2","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"]}
|
{"version":"0.2","flagWords":[],"language":"en","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"]}
|
||||||
|
|
@ -31,7 +31,7 @@ impl File {
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut it = copy_with_progress(&task.from, &task.to);
|
let mut it = copy_with_progress(&task.from, &task.to, task.meta.as_ref().unwrap());
|
||||||
while let Some(res) = it.recv().await {
|
while let Some(res) = it.recv().await {
|
||||||
match res {
|
match res {
|
||||||
Ok(0) => {
|
Ok(0) => {
|
||||||
|
|
@ -142,7 +142,11 @@ impl File {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let meta = Self::metadata(&task.from, task.follow).await?;
|
if task.meta.is_none() {
|
||||||
|
task.meta = Some(Self::metadata(&task.from, task.follow).await?);
|
||||||
|
}
|
||||||
|
|
||||||
|
let meta = task.meta.as_ref().unwrap();
|
||||||
if !meta.is_dir() {
|
if !meta.is_dir() {
|
||||||
let id = task.id;
|
let id = task.id;
|
||||||
self.prog.send(TaskProg::New(id, meta.len()))?;
|
self.prog.send(TaskProg::New(id, meta.len()))?;
|
||||||
|
|
@ -150,7 +154,7 @@ impl File {
|
||||||
if meta.is_file() {
|
if meta.is_file() {
|
||||||
self.queue(FileOp::Paste(task), LOW).await?;
|
self.queue(FileOp::Paste(task), LOW).await?;
|
||||||
} else if meta.is_symlink() {
|
} else if meta.is_symlink() {
|
||||||
self.queue(FileOp::Link(task.to_link(meta)), NORMAL).await?;
|
self.queue(FileOp::Link(task.into()), NORMAL).await?;
|
||||||
}
|
}
|
||||||
return self.succ(id);
|
return self.succ(id);
|
||||||
}
|
}
|
||||||
|
|
@ -168,9 +172,9 @@ impl File {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
let root = task.to.clone();
|
let root = &task.to;
|
||||||
let skip = task.from.components().count();
|
let skip = task.from.components().count();
|
||||||
let mut dirs = VecDeque::from([task.from]);
|
let mut dirs = VecDeque::from([task.from.clone()]);
|
||||||
|
|
||||||
while let Some(src) = dirs.pop_front() {
|
while let Some(src) = dirs.pop_front() {
|
||||||
let dest = root.join(src.components().skip(skip).collect::<PathBuf>());
|
let dest = root.join(src.components().skip(skip).collect::<PathBuf>());
|
||||||
|
|
@ -181,22 +185,21 @@ impl File {
|
||||||
|
|
||||||
let mut it = continue_unless_ok!(fs::read_dir(&src).await);
|
let mut it = continue_unless_ok!(fs::read_dir(&src).await);
|
||||||
while let Ok(Some(entry)) = it.next_entry().await {
|
while let Ok(Some(entry)) = it.next_entry().await {
|
||||||
let src = Url::from(entry.path());
|
let from = Url::from(entry.path());
|
||||||
let meta = continue_unless_ok!(Self::metadata(&src, task.follow).await);
|
let meta = continue_unless_ok!(Self::metadata(&from, task.follow).await);
|
||||||
|
|
||||||
if meta.is_dir() {
|
if meta.is_dir() {
|
||||||
dirs.push_back(src);
|
dirs.push_back(from);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
task.to = dest.join(src.file_name().unwrap());
|
let to = dest.join(from.file_name().unwrap());
|
||||||
task.from = src;
|
|
||||||
self.prog.send(TaskProg::New(task.id, meta.len()))?;
|
self.prog.send(TaskProg::New(task.id, meta.len()))?;
|
||||||
|
|
||||||
if meta.is_file() {
|
if meta.is_file() {
|
||||||
self.queue(FileOp::Paste(task.clone()), LOW).await?;
|
self.queue(FileOp::Paste(task.spawn(to, from, meta)), LOW).await?;
|
||||||
} else if meta.is_symlink() {
|
} else if meta.is_symlink() {
|
||||||
self.queue(FileOp::Link(task.to_link(meta)), NORMAL).await?;
|
self.queue(FileOp::Link(task.spawn(to, from, meta).into()), NORMAL).await?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -303,17 +306,3 @@ impl File {
|
||||||
self.macro_.send(op.into(), priority).await.map_err(|_| anyhow!("Failed to send task"))
|
self.macro_.send(op.into(), priority).await.map_err(|_| anyhow!("Failed to send task"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FileOpPaste {
|
|
||||||
fn to_link(&self, meta: Metadata) -> FileOpLink {
|
|
||||||
FileOpLink {
|
|
||||||
id: self.id,
|
|
||||||
from: self.from.clone(),
|
|
||||||
to: self.to.clone(),
|
|
||||||
meta: Some(meta),
|
|
||||||
resolve: true,
|
|
||||||
relative: false,
|
|
||||||
delete: self.cut,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -26,11 +26,26 @@ pub struct FileOpPaste {
|
||||||
pub id: usize,
|
pub id: usize,
|
||||||
pub from: Url,
|
pub from: Url,
|
||||||
pub to: Url,
|
pub to: Url,
|
||||||
|
pub meta: Option<Metadata>,
|
||||||
pub cut: bool,
|
pub cut: bool,
|
||||||
pub follow: bool,
|
pub follow: bool,
|
||||||
pub retry: u8,
|
pub retry: u8,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl FileOpPaste {
|
||||||
|
pub(super) fn spawn(&self, from: Url, to: Url, meta: Metadata) -> Self {
|
||||||
|
Self {
|
||||||
|
id: self.id,
|
||||||
|
from,
|
||||||
|
to,
|
||||||
|
meta: Some(meta),
|
||||||
|
cut: self.cut,
|
||||||
|
follow: self.follow,
|
||||||
|
retry: self.retry,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct FileOpLink {
|
pub struct FileOpLink {
|
||||||
pub id: usize,
|
pub id: usize,
|
||||||
|
|
@ -42,6 +57,20 @@ pub struct FileOpLink {
|
||||||
pub delete: bool,
|
pub delete: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<FileOpPaste> for FileOpLink {
|
||||||
|
fn from(value: FileOpPaste) -> Self {
|
||||||
|
Self {
|
||||||
|
id: value.id,
|
||||||
|
from: value.from.clone(),
|
||||||
|
to: value.to.clone(),
|
||||||
|
meta: value.meta.clone(),
|
||||||
|
resolve: true,
|
||||||
|
relative: false,
|
||||||
|
delete: value.cut,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct FileOpDelete {
|
pub struct FileOpDelete {
|
||||||
pub id: usize,
|
pub id: usize,
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use std::{collections::VecDeque, path::{Path, PathBuf}};
|
use std::{collections::VecDeque, fs::Metadata, path::{Path, PathBuf}};
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use filetime::{set_file_times, FileTime};
|
use filetime::{set_file_times, FileTime};
|
||||||
|
|
@ -35,22 +35,25 @@ pub async fn calculate_size(path: &Path) -> u64 {
|
||||||
total
|
total
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn copy_with_progress(from: &Path, to: &Path) -> mpsc::Receiver<Result<u64, io::Error>> {
|
pub fn copy_with_progress(
|
||||||
|
from: &Path,
|
||||||
|
to: &Path,
|
||||||
|
meta: &Metadata,
|
||||||
|
) -> mpsc::Receiver<Result<u64, io::Error>> {
|
||||||
let (tx, rx) = mpsc::channel(1);
|
let (tx, rx) = mpsc::channel(1);
|
||||||
let (tick_tx, mut tick_rx) = oneshot::channel();
|
let (tick_tx, mut tick_rx) = oneshot::channel();
|
||||||
|
|
||||||
tokio::spawn({
|
tokio::spawn({
|
||||||
let (from, to) = (from.to_path_buf(), to.to_path_buf());
|
let (from, to, meta) = (from.to_owned(), to.to_owned(), meta.clone());
|
||||||
|
|
||||||
async move {
|
async move {
|
||||||
_ = match fs::copy(&from, &to).await {
|
_ = match fs::copy(&from, &to).await {
|
||||||
Ok(len) => {
|
Ok(len) => {
|
||||||
// Attempt to preserve file's accessed at and modified at timestamps
|
_ = set_file_times(
|
||||||
if let Ok(metadata) = fs::metadata(from).await {
|
to,
|
||||||
let mtime = FileTime::from_last_modification_time(&metadata);
|
FileTime::from_last_access_time(&meta),
|
||||||
let atime = FileTime::from_last_access_time(&metadata);
|
FileTime::from_last_modification_time(&meta),
|
||||||
_ = set_file_times(to, atime, mtime);
|
);
|
||||||
};
|
|
||||||
|
|
||||||
tick_tx.send(Ok(len))
|
tick_tx.send(Ok(len))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue