From 1b98b74606d5abe7ff2de60eb184f0fd503752d4 Mon Sep 17 00:00:00 2001 From: sxyazi Date: Tue, 29 Jul 2025 14:15:35 +0800 Subject: [PATCH] feat: URL covariance for selected and yanked files --- yazi-actor/src/cmp/trigger.rs | 14 +++++++------- yazi-actor/src/mgr/copy.rs | 28 +++++++++++++++++++--------- yazi-shared/src/url/loc.rs | 4 ++++ yazi-shared/src/url/url.rs | 2 +- 4 files changed, 31 insertions(+), 17 deletions(-) diff --git a/yazi-actor/src/cmp/trigger.rs b/yazi-actor/src/cmp/trigger.rs index d2e715ca..29f435b5 100644 --- a/yazi-actor/src/cmp/trigger.rs +++ b/yazi-actor/src/cmp/trigger.rs @@ -115,12 +115,12 @@ mod tests { fn test_split() { yazi_fs::init(); compare("foo", "", "foo"); - compare("foo\\", "foo\\", ""); - compare("foo\\bar", "foo\\", "bar"); - compare("foo\\bar\\", "foo\\bar\\", ""); - compare("C:\\", "C:\\", ""); - compare("C:\\foo", "C:\\", "foo"); - compare("C:\\foo\\", "C:\\foo\\", ""); - compare("C:\\foo\\bar", "C:\\foo\\", "bar"); + compare(r"foo\", r"foo\", ""); + compare(r"foo\bar", r"foo\", "bar"); + compare(r"foo\bar\", r"foo\bar\", ""); + compare(r"C:\", r"C:\", ""); + compare(r"C:\foo", r"C:\", "foo"); + compare(r"C:\foo\", r"C:\foo\", ""); + compare(r"C:\foo\bar", r"C:\foo\", "bar"); } } diff --git a/yazi-actor/src/mgr/copy.rs b/yazi-actor/src/mgr/copy.rs index d615d0f2..573aa94f 100644 --- a/yazi-actor/src/mgr/copy.rs +++ b/yazi-actor/src/mgr/copy.rs @@ -1,5 +1,4 @@ -// FIXME: VFS -use std::{ffi::OsString, path::Path}; +use std::ffi::OsString; use anyhow::{Result, bail}; use yazi_macro::{act, succ}; @@ -28,13 +27,24 @@ impl Actor for Copy { .peekable(); while let Some(u) = it.next() { - s.push(match opt.r#type.as_ref() { - "path" => opt.separator.transform(u), - "dirname" => opt.separator.transform(u.parent().unwrap_or(Path::new(""))), - "filename" => opt.separator.transform(u.name()), - "name_without_ext" => opt.separator.transform(u.file_stem().unwrap_or_default()), + match opt.r#type.as_ref() { + // TODO: rename to "url" + "path" => { + s.push(opt.separator.transform(&u.os_str())); + } + "dirname" => { + if let Some(p) = u.parent_url() { + s.push(opt.separator.transform(&p.os_str())); + } + } + "filename" => { + s.push(opt.separator.transform(u.name())); + } + "name_without_ext" => { + s.push(opt.separator.transform(u.file_stem().unwrap_or_default())); + } _ => bail!("Unknown copy type: {}", opt.r#type), - }); + }; if it.peek().is_some() { s.push("\n"); } @@ -42,7 +52,7 @@ impl Actor for Copy { // Copy the CWD path regardless even if the directory is empty if s.is_empty() && opt.r#type == "dirname" { - s.push(opt.separator.transform(cx.cwd())); + s.push(opt.separator.transform(&cx.cwd().os_str())); } futures::executor::block_on(CLIPBOARD.set(s)); diff --git a/yazi-shared/src/url/loc.rs b/yazi-shared/src/url/loc.rs index 17db445b..7c48d651 100644 --- a/yazi-shared/src/url/loc.rs +++ b/yazi-shared/src/url/loc.rs @@ -15,6 +15,10 @@ impl Deref for Loc { fn deref(&self) -> &Self::Target { &self.inner } } +impl AsRef for Loc { + fn as_ref(&self) -> &Path { &self.inner } +} + impl PartialEq for Loc { fn eq(&self, other: &Self) -> bool { self.inner == other.inner } } diff --git a/yazi-shared/src/url/url.rs b/yazi-shared/src/url/url.rs index 7217d9ac..58414c61 100644 --- a/yazi-shared/src/url/url.rs +++ b/yazi-shared/src/url/url.rs @@ -165,7 +165,7 @@ impl Url { } Some(Self { - loc: self.loc.strip_prefix(base.loc.as_path()).ok()?.into(), + loc: self.loc.strip_prefix(&base.loc).ok()?.into(), scheme: self.scheme.clone(), }) }