This commit is contained in:
sxyazi 2025-07-29 15:00:53 +08:00
parent 2ba4f6a958
commit e670a818c1
No known key found for this signature in database
9 changed files with 65 additions and 29 deletions

View file

@ -2,7 +2,7 @@ use anyhow::Result;
use yazi_core::mgr::Yanked;
use yazi_macro::{act, render};
use yazi_parser::mgr::YankOpt;
use yazi_shared::event::Data;
use yazi_shared::{event::Data, url::CovUrl};
use crate::{Actor, Ctx};
@ -16,7 +16,8 @@ impl Actor for Yank {
fn act(cx: &mut Ctx, opt: Self::Options) -> Result<Data> {
act!(mgr:escape_visual, cx)?;
cx.mgr.yanked = Yanked::new(opt.cut, cx.tab().selected_or_hovered().cloned().collect());
cx.mgr.yanked =
Yanked::new(opt.cut, cx.tab().selected_or_hovered().cloned().map(CovUrl).collect());
render!(cx.mgr.yanked.catchup_revision(true));
act!(mgr:escape_select, cx)

View file

@ -1,7 +1,7 @@
use std::{borrow::Cow, ops::Deref};
use mlua::{AnyUserData, ExternalError, FromLua, Lua, MetaMethod, UserData, UserDataFields, UserDataMethods, UserDataRef, Value};
use yazi_shared::url::Scheme;
use yazi_shared::url::{CovUrl, Scheme};
use crate::{Urn, cached_field};
@ -41,6 +41,10 @@ impl<'a> From<&'a Url> for Cow<'a, yazi_shared::url::Url> {
fn from(value: &'a Url) -> Self { Cow::Borrowed(&value.inner) }
}
impl From<Url> for yazi_shared::url::CovUrl {
fn from(value: Url) -> Self { CovUrl(value.inner) }
}
impl TryFrom<&[u8]> for Url {
type Error = mlua::Error;

View file

@ -3,28 +3,28 @@ use std::{collections::HashSet, ops::Deref};
use yazi_dds::Pubsub;
use yazi_fs::FilesOp;
use yazi_macro::err;
use yazi_shared::url::Url;
use yazi_shared::url::{CovUrl, Url};
#[derive(Debug, Default)]
pub struct Yanked {
pub cut: bool,
urls: HashSet<Url>,
urls: HashSet<CovUrl>,
version: u64,
revision: u64,
}
impl Deref for Yanked {
type Target = HashSet<Url>;
type Target = HashSet<CovUrl>;
fn deref(&self) -> &Self::Target { &self.urls }
}
impl Yanked {
pub fn new(cut: bool, urls: HashSet<Url>) -> Self { Self { cut, urls, ..Default::default() } }
pub fn new(cut: bool, urls: HashSet<CovUrl>) -> Self { Self { cut, urls, ..Default::default() } }
pub fn remove(&mut self, url: &Url) {
if self.urls.remove(url) {
if self.urls.remove(CovUrl::new(url)) {
self.revision += 1;
}
}
@ -38,11 +38,15 @@ impl Yanked {
self.revision += 1;
}
#[inline]
pub fn contains(&self, url: impl AsRef<Url>) -> bool { self.urls.contains(CovUrl::new(&url)) }
pub fn contains_in(&self, dir: &Url) -> bool {
self.urls.iter().any(|u| {
let mut it = u.components();
// FIXME
it.next_back().is_some() && it == dir.components() && u.parent_url().as_ref() == Some(dir)
it.next_back().is_some()
&& it.covariant(&dir.components())
&& u.parent_url().is_some_and(|p| p == *dir)
})
}
@ -56,7 +60,7 @@ impl Yanked {
if !addition.is_empty() {
let old = self.urls.len();
self.urls.extend(addition);
self.urls.extend(addition.into_iter().map(CovUrl));
self.revision += (old != self.urls.len()) as u64;
}
}

View file

@ -1,51 +1,51 @@
use std::collections::HashSet;
use tracing::debug;
use yazi_shared::url::Url;
use yazi_shared::url::{CovUrl, Url};
use super::Tasks;
impl Tasks {
pub fn file_cut(&self, src: &[&Url], dest: &Url, force: bool) {
pub fn file_cut(&self, src: &[&CovUrl], dest: &Url, force: bool) {
for &u in src {
let to = dest.join(u.file_name().unwrap());
if force && *u == to {
debug!("file_cut: same file, skipping {:?}", to);
} else {
self.scheduler.file_cut(u.clone(), to, force);
self.scheduler.file_cut(u.0.clone(), to, force);
}
}
}
pub fn file_copy(&self, src: &[&Url], dest: &Url, force: bool, follow: bool) {
pub fn file_copy(&self, src: &[&CovUrl], dest: &Url, force: bool, follow: bool) {
for &u in src {
let to = dest.join(u.file_name().unwrap());
if force && *u == to {
debug!("file_copy: same file, skipping {:?}", to);
} else {
self.scheduler.file_copy(u.clone(), to, force, follow);
self.scheduler.file_copy(u.0.clone(), to, force, follow);
}
}
}
pub fn file_link(&self, src: &HashSet<Url>, dest: &Url, relative: bool, force: bool) {
pub fn file_link(&self, src: &HashSet<CovUrl>, dest: &Url, relative: 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.0.clone(), to, relative, force);
}
}
}
pub fn file_hardlink(&self, src: &HashSet<Url>, dest: &Url, force: bool, follow: bool) {
pub fn file_hardlink(&self, src: &HashSet<CovUrl>, dest: &Url, force: bool, follow: bool) {
for u in src {
let to = dest.join(u.file_name().unwrap());
if force && *u == to {
debug!("file_hardlink: same file, skipping {:?}", to);
} else {
self.scheduler.file_hardlink(u.clone(), to, force, follow);
self.scheduler.file_hardlink(u.0.clone(), to, force, follow);
}
}
}

View file

@ -3,7 +3,7 @@ use std::{borrow::Cow, collections::HashSet};
use mlua::{IntoLua, Lua, Value};
use serde::{Deserialize, Serialize};
use yazi_parser::mgr::UpdateYankedOpt;
use yazi_shared::url::Url;
use yazi_shared::url::CovUrl;
use super::Body;
@ -11,13 +11,13 @@ use super::Body;
pub struct BodyYank<'a>(UpdateYankedOpt<'a>);
impl<'a> BodyYank<'a> {
pub fn borrowed(cut: bool, urls: &'a HashSet<Url>) -> Body<'a> {
pub fn borrowed(cut: bool, urls: &'a HashSet<CovUrl>) -> Body<'a> {
Self(UpdateYankedOpt { cut, urls: Cow::Borrowed(urls) }).into()
}
}
impl BodyYank<'static> {
pub fn owned(cut: bool, _: &HashSet<Url>) -> Body<'static> {
pub fn owned(cut: bool, _: &HashSet<CovUrl>) -> Body<'static> {
Self(UpdateYankedOpt { cut, urls: Default::default() }).into()
}
}

View file

@ -5,7 +5,7 @@ use mlua::Function;
use parking_lot::RwLock;
use yazi_boot::BOOT;
use yazi_fs::FolderStage;
use yazi_shared::{Id, RoCell, url::Url};
use yazi_shared::{Id, RoCell, url::{CovUrl, Url}};
use crate::{Client, ID, PEERS, body::{Body, BodyBulk, BodyHi, BodyMoveItem}};
@ -157,7 +157,7 @@ impl Pubsub {
pub_after!(rename(tab: Id, from: &Url, to: &Url), (tab, from, to));
pub_after!(@yank(cut: bool, urls: &HashSet<Url>), (cut, urls));
pub_after!(@yank(cut: bool, urls: &HashSet<CovUrl>), (cut, urls));
pub_after!(move(items: Vec<BodyMoveItem>), (&items), (items));

View file

@ -4,17 +4,17 @@ use anyhow::bail;
use mlua::{AnyUserData, ExternalError, IntoLua, Lua, MetaMethod, MultiValue, ObjectLike, UserData, UserDataFields, UserDataMethods, Value};
use serde::{Deserialize, Serialize};
use yazi_binding::get_metatable;
use yazi_shared::{event::CmdCow, url::Url};
use yazi_shared::{event::CmdCow, url::CovUrl};
type Iter = yazi_binding::Iter<
std::iter::Map<std::collections::hash_set::IntoIter<Url>, fn(Url) -> yazi_binding::Url>,
std::iter::Map<std::collections::hash_set::IntoIter<CovUrl>, fn(CovUrl) -> yazi_binding::Url>,
yazi_binding::Url,
>;
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
pub struct UpdateYankedOpt<'a> {
pub cut: bool,
pub urls: Cow<'a, HashSet<Url>>,
pub urls: Cow<'a, HashSet<CovUrl>>,
}
impl TryFrom<CmdCow> for UpdateYankedOpt<'_> {

View file

@ -84,6 +84,15 @@ impl<'a> Components<'a> {
s.push(path);
s.into()
}
pub fn covariant(&self, other: &Self) -> bool {
match (self.scheme_yielded, other.scheme_yielded) {
(false, false) => {}
(true, true) if self.scheme.covariant(other.scheme) => {}
_ => return false,
}
self.inner == other.inner
}
}
impl<'a> Iterator for Components<'a> {

View file

@ -1,8 +1,10 @@
use std::{hash::{Hash, Hasher}, ops::Deref};
use serde::{Deserialize, Serialize};
use crate::url::Url;
#[derive(Clone, Debug, Eq)]
#[derive(Clone, Debug, Deserialize, Eq, Serialize)]
#[repr(transparent)]
pub struct CovUrl(pub Url);
@ -12,6 +14,18 @@ impl Deref for CovUrl {
fn deref(&self) -> &Self::Target { &self.0 }
}
impl AsRef<Url> for CovUrl {
fn as_ref(&self) -> &Url { &self.0 }
}
impl From<Url> for CovUrl {
fn from(value: Url) -> Self { Self(value) }
}
impl From<CovUrl> for Url {
fn from(value: CovUrl) -> Self { value.0 }
}
impl Hash for CovUrl {
fn hash<H: Hasher>(&self, state: &mut H) {
self.loc.hash(state);
@ -25,6 +39,10 @@ impl PartialEq for CovUrl {
fn eq(&self, other: &Self) -> bool { self.covariant(other) }
}
impl PartialEq<Url> for CovUrl {
fn eq(&self, other: &Url) -> bool { self.covariant(other) }
}
impl CovUrl {
#[inline]
pub fn new<T: AsRef<Url>>(u: &T) -> &Self {