Skip to content

Commit

Permalink
Add '--hard' option to 'link' command
Browse files Browse the repository at this point in the history
Resolves sxyazi#1258.
  • Loading branch information
Ape committed Jul 9, 2024
1 parent 40c78c5 commit 5a06e85
Show file tree
Hide file tree
Showing 5 changed files with 56 additions and 15 deletions.
7 changes: 5 additions & 2 deletions yazi-core/src/manager/commands/link.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,14 @@ use crate::{manager::Manager, tasks::Tasks};

pub struct Opt {
relative: bool,
hard: bool,
force: bool,
}

impl From<Cmd> for Opt {
fn from(c: Cmd) -> Self { Self { relative: c.bool("relative"), force: c.bool("force") } }
fn from(c: Cmd) -> Self {
Self { relative: c.bool("relative"), hard: c.bool("hard"), force: c.bool("force") }
}
}

impl Manager {
Expand All @@ -18,6 +21,6 @@ impl Manager {
}

let opt = opt.into() as Opt;
tasks.file_link(&self.yanked, self.cwd(), opt.relative, opt.force);
tasks.file_link(&self.yanked, self.cwd(), opt.relative, opt.hard, opt.force);
}
}
4 changes: 2 additions & 2 deletions yazi-core/src/tasks/file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,13 @@ impl Tasks {
}
}

pub fn file_link(&self, src: &HashSet<Url>, dest: &Url, relative: bool, force: bool) {
pub fn file_link(&self, src: &HashSet<Url>, dest: &Url, relative: bool, hard: bool, force: bool) {
for u in src {
let to = dest.join(u.file_name().unwrap());
if force && *u == to {
debug!("file_link: same file, skipping {:?}", to);
} else {
self.scheduler.file_link(u.clone(), to, relative, force);
self.scheduler.file_link(u.clone(), to, relative, hard, force);
}
}
}
Expand Down
45 changes: 36 additions & 9 deletions yazi-scheduler/src/file/file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,16 +81,25 @@ impl File {
};

ok_or_not_found(fs::remove_file(&task.to).await)?;
#[cfg(unix)]
{
fs::symlink(src, &task.to).await?
}
#[cfg(windows)]
{
if meta.is_dir() {
fs::symlink_dir(src, &task.to).await?

if task.hard {
if !src.is_symlink() && src.is_dir() {
hard_link_directory(src, &task.to).await?;
} else {
fs::symlink_file(src, &task.to).await?
fs::hard_link(src, &task.to).await?;
}
} else {
#[cfg(unix)]
{
fs::symlink(src, &task.to).await?
}
#[cfg(windows)]
{
if meta.is_dir() {
fs::symlink_dir(src, &task.to).await?
} else {
fs::symlink_file(src, &task.to).await?
}
}
}

Expand Down Expand Up @@ -276,6 +285,24 @@ impl File {
}
}

async fn hard_link_directory(src: impl AsRef<Path>, dst: impl AsRef<Path>) -> Result<()> {
fs::create_dir(&dst).await?;

let mut directory = fs::read_dir(src).await?;

while let Some(entry) = directory.next_entry().await? {
let target_path = dst.as_ref().join(entry.file_name());

if entry.file_type().await?.is_dir() {
Box::pin(hard_link_directory(entry.path(), target_path)).await?;
} else {
fs::hard_link(entry.path(), target_path).await?;
}
}

Ok(())
}

impl File {
#[inline]
fn succ(&self, id: usize) -> Result<()> { Ok(self.prog.send(TaskProg::Succ(id))?) }
Expand Down
2 changes: 2 additions & 0 deletions yazi-scheduler/src/file/op.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ pub struct FileOpLink {
pub meta: Option<Metadata>,
pub resolve: bool,
pub relative: bool,
pub hard: bool,
pub delete: bool,
}

Expand All @@ -66,6 +67,7 @@ impl From<FileOpPaste> for FileOpLink {
meta: value.meta,
resolve: true,
relative: false,
hard: false,
delete: value.cut,
}
}
Expand Down
13 changes: 11 additions & 2 deletions yazi-scheduler/src/scheduler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ impl Scheduler {
);
}

pub fn file_link(&self, from: Url, mut to: Url, relative: bool, force: bool) {
pub fn file_link(&self, from: Url, mut to: Url, relative: bool, hard: bool, force: bool) {
let name = format!("Link {from:?} to {to:?}");
let id = self.ongoing.lock().add(TaskKind::User, name);

Expand All @@ -145,7 +145,16 @@ impl Scheduler {
to = unique_path(to).await;
}
file
.link(FileOpLink { id, from, to, meta: None, resolve: false, relative, delete: false })
.link(FileOpLink {
id,
from,
to,
meta: None,
resolve: false,
relative,
hard,
delete: false,
})
.await
.ok();
}
Expand Down

0 comments on commit 5a06e85

Please sign in to comment.