mirror of
https://github.com/sxyazi/yazi.git
synced 2026-07-25 08:41:05 +00:00
..
This commit is contained in:
parent
fa6e57d0ce
commit
f294881de6
4 changed files with 56 additions and 28 deletions
|
|
@ -105,7 +105,7 @@ impl Executor {
|
||||||
if *cut {
|
if *cut {
|
||||||
cx.tasks.file_cut(src, dest, force)
|
cx.tasks.file_cut(src, dest, force)
|
||||||
} else {
|
} else {
|
||||||
cx.tasks.file_copy(src, dest, force, exec.named.contains_key("follow"))
|
cx.tasks.file_copy(src, dest, force)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"link" => {
|
"link" => {
|
||||||
|
|
|
||||||
|
|
@ -56,7 +56,6 @@
|
||||||
- paste: Paste the files.
|
- paste: Paste the files.
|
||||||
|
|
||||||
- `--force`: Overwrite the destination file if it exists.
|
- `--force`: Overwrite the destination file if it exists.
|
||||||
- `--follow`: Copy the file pointed to by a symbolic link, rather than the link itself. Only valid during copying.
|
|
||||||
|
|
||||||
- remove: Move the files to the trash/recycle bin.
|
- remove: Move the files to the trash/recycle bin.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -218,7 +218,7 @@ impl Scheduler {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn file_copy(&self, from: Url, mut to: Url, force: bool, follow: bool) {
|
pub(super) fn file_copy(&self, from: Url, mut to: Url, force: bool) {
|
||||||
let name = format!("Copy {:?} to {:?}", from, to);
|
let name = format!("Copy {:?} to {:?}", from, to);
|
||||||
let id = self.running.write().add(name);
|
let id = self.running.write().add(name);
|
||||||
|
|
||||||
|
|
@ -228,13 +228,13 @@ impl Scheduler {
|
||||||
if !force {
|
if !force {
|
||||||
to = unique_path(to).await;
|
to = unique_path(to).await;
|
||||||
}
|
}
|
||||||
file.paste(FileOpPaste { id, from, to, cut: false, follow, retry: 0 }).await.ok();
|
file.paste(FileOpPaste { id, from, to, cut: false, follow: true, retry: 0 }).await.ok();
|
||||||
}
|
}
|
||||||
.boxed()
|
.boxed()
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn file_link(&self, from: Url, mut to: Url, force: bool) {
|
pub(super) fn file_link(&self, from: Url, mut to: Url, force: bool, relative: bool) {
|
||||||
let name = format!("Link {from:?} to {to:?}");
|
let name = format!("Link {from:?} to {to:?}");
|
||||||
let id = self.running.write().add(name);
|
let id = self.running.write().add(name);
|
||||||
|
|
||||||
|
|
@ -244,7 +244,10 @@ impl Scheduler {
|
||||||
if !force {
|
if !force {
|
||||||
to = unique_path(to).await;
|
to = unique_path(to).await;
|
||||||
}
|
}
|
||||||
file.link(FileOpLink { id, from, to }).await.ok();
|
file
|
||||||
|
.link(FileOpLink { id, from, to, meta: None, resolve: false, relative, delete: false })
|
||||||
|
.await
|
||||||
|
.ok();
|
||||||
}
|
}
|
||||||
.boxed()
|
.boxed()
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
use std::{collections::VecDeque, fs::Metadata, path::{Path, PathBuf}};
|
use std::{borrow::Cow, collections::VecDeque, fs::Metadata, path::{Path, PathBuf}};
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use config::TASKS;
|
use config::TASKS;
|
||||||
use futures::{future::BoxFuture, FutureExt};
|
use futures::{future::BoxFuture, FutureExt};
|
||||||
use shared::{calculate_size, copy_with_progress, Url};
|
use shared::{calculate_size, copy_with_progress, path_relative_to, Url};
|
||||||
use tokio::{fs, io::{self, ErrorKind::{AlreadyExists, NotFound}}, sync::mpsc};
|
use tokio::{fs, io::{self, ErrorKind::{AlreadyExists, NotFound}}, sync::mpsc};
|
||||||
use tracing::trace;
|
use tracing::trace;
|
||||||
|
|
||||||
|
|
@ -36,11 +36,13 @@ pub(crate) struct FileOpPaste {
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub(crate) struct FileOpLink {
|
pub(crate) struct FileOpLink {
|
||||||
pub id: usize,
|
pub id: usize,
|
||||||
pub from: Url,
|
pub from: Url,
|
||||||
pub to: Url,
|
pub to: Url,
|
||||||
pub cut: bool,
|
pub meta: Option<Metadata>,
|
||||||
pub length: u64,
|
pub resolve: bool,
|
||||||
|
pub relative: bool,
|
||||||
|
pub delete: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
|
|
@ -114,15 +116,23 @@ impl File {
|
||||||
self.sch.send(TaskOp::Adv(task.id, 1, 0))?;
|
self.sch.send(TaskOp::Adv(task.id, 1, 0))?;
|
||||||
}
|
}
|
||||||
FileOp::Link(task) => {
|
FileOp::Link(task) => {
|
||||||
let src = match fs::read_link(&task.from).await {
|
let meta = task.meta.as_ref().unwrap();
|
||||||
Ok(src) => src,
|
|
||||||
Err(e) if e.kind() == NotFound => {
|
let src = if task.resolve {
|
||||||
self.log(task.id, format!("Link task partially done: {:?}", task))?;
|
match fs::read_link(&task.from).await {
|
||||||
return Ok(self.sch.send(TaskOp::Adv(task.id, 1, task.length))?);
|
Ok(p) => Cow::Owned(p),
|
||||||
|
Err(e) if e.kind() == NotFound => {
|
||||||
|
self.log(task.id, format!("Link task partially done: {:?}", task))?;
|
||||||
|
return Ok(self.sch.send(TaskOp::Adv(task.id, 1, meta.len()))?);
|
||||||
|
}
|
||||||
|
Err(e) => Err(e)?,
|
||||||
}
|
}
|
||||||
Err(e) => Err(e)?,
|
} else {
|
||||||
|
Cow::Borrowed(task.from.as_path())
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let src = if task.relative { path_relative_to(&src, &task.to) } else { src };
|
||||||
|
|
||||||
match fs::remove_file(&task.to).await {
|
match fs::remove_file(&task.to).await {
|
||||||
Err(e) if e.kind() != NotFound => Err(e)?,
|
Err(e) if e.kind() != NotFound => Err(e)?,
|
||||||
_ => {
|
_ => {
|
||||||
|
|
@ -132,15 +142,19 @@ impl File {
|
||||||
}
|
}
|
||||||
#[cfg(target_os = "windows")]
|
#[cfg(target_os = "windows")]
|
||||||
{
|
{
|
||||||
fs::symlink_file(src, &task.to).await?
|
if meta.is_dir() {
|
||||||
|
fs::symlink_dir(src, &task.to).await?
|
||||||
|
} else {
|
||||||
|
fs::symlink_file(src, &task.to).await?
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if task.cut {
|
if task.delete {
|
||||||
fs::remove_file(&task.from).await.ok();
|
fs::remove_file(&task.from).await.ok();
|
||||||
}
|
}
|
||||||
self.sch.send(TaskOp::Adv(task.id, 1, task.length))?;
|
self.sch.send(TaskOp::Adv(task.id, 1, meta.len()))?;
|
||||||
}
|
}
|
||||||
FileOp::Delete(task) => {
|
FileOp::Delete(task) => {
|
||||||
if let Err(e) = fs::remove_file(&task.target).await {
|
if let Err(e) = fs::remove_file(&task.target).await {
|
||||||
|
|
@ -192,7 +206,7 @@ impl File {
|
||||||
if meta.is_file() {
|
if meta.is_file() {
|
||||||
self.tx.send(FileOp::Paste(task)).await?;
|
self.tx.send(FileOp::Paste(task)).await?;
|
||||||
} else if meta.is_symlink() {
|
} else if meta.is_symlink() {
|
||||||
self.tx.send(FileOp::Link(task.to_link(meta.len()))).await?;
|
self.tx.send(FileOp::Link(task.to_link(meta))).await?;
|
||||||
}
|
}
|
||||||
return self.done(id);
|
return self.done(id);
|
||||||
}
|
}
|
||||||
|
|
@ -237,16 +251,20 @@ impl File {
|
||||||
if meta.is_file() {
|
if meta.is_file() {
|
||||||
self.tx.send(FileOp::Paste(task.clone())).await?;
|
self.tx.send(FileOp::Paste(task.clone())).await?;
|
||||||
} else if meta.is_symlink() {
|
} else if meta.is_symlink() {
|
||||||
self.tx.send(FileOp::Link(task.to_link(meta.len()))).await?;
|
self.tx.send(FileOp::Link(task.to_link(meta))).await?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.done(task.id)
|
self.done(task.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) async fn link(&self, task: FileOpLink) -> Result<()> {
|
pub(crate) async fn link(&self, mut task: FileOpLink) -> Result<()> {
|
||||||
let id = task.id;
|
let id = task.id;
|
||||||
self.sch.send(TaskOp::New(id, 0))?;
|
if task.meta.is_none() {
|
||||||
|
task.meta = Some(fs::symlink_metadata(&task.from).await?);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.sch.send(TaskOp::New(id, task.meta.as_ref().unwrap().len()))?;
|
||||||
self.tx.send(FileOp::Link(task)).await?;
|
self.tx.send(FileOp::Link(task)).await?;
|
||||||
self.done(id)
|
self.done(id)
|
||||||
}
|
}
|
||||||
|
|
@ -328,7 +346,15 @@ impl File {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FileOpPaste {
|
impl FileOpPaste {
|
||||||
fn to_link(&self, length: u64) -> FileOpLink {
|
fn to_link(&self, meta: Metadata) -> FileOpLink {
|
||||||
FileOpLink { id: self.id, from: self.from.clone(), to: self.to.clone(), cut: self.cut, length }
|
FileOpLink {
|
||||||
|
id: self.id,
|
||||||
|
from: self.from.clone(),
|
||||||
|
to: self.to.clone(),
|
||||||
|
meta: Some(meta),
|
||||||
|
resolve: true,
|
||||||
|
relative: false,
|
||||||
|
delete: self.cut,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue