From 2ba4f6a958f3891edd0a096c8e6d957b6a7c6988 Mon Sep 17 00:00:00 2001 From: sxyazi Date: Tue, 29 Jul 2025 14:24:51 +0800 Subject: [PATCH] .. --- yazi-actor/src/lives/file.rs | 2 +- yazi-actor/src/lives/selected.rs | 5 ++-- yazi-actor/src/mgr/toggle_all.rs | 4 +-- yazi-binding/src/url.rs | 4 +-- yazi-core/src/tab/selected.rs | 34 +++++++++++++--------- yazi-core/src/tab/tab.rs | 4 +-- yazi-shared/src/url/component.rs | 10 ++++--- yazi-shared/src/url/cov.rs | 36 +++++++++++++++++++++++ yazi-shared/src/url/mod.rs | 2 +- yazi-shared/src/url/scheme.rs | 12 ++------ yazi-shared/src/url/url.rs | 50 ++++---------------------------- 11 files changed, 80 insertions(+), 83 deletions(-) create mode 100644 yazi-shared/src/url/cov.rs diff --git a/yazi-actor/src/lives/file.rs b/yazi-actor/src/lives/file.rs index 2de0a85b..11dce848 100644 --- a/yazi-actor/src/lives/file.rs +++ b/yazi-actor/src/lives/file.rs @@ -121,7 +121,7 @@ impl UserData for File { _ => 0u8, }) }); - methods.add_method("is_selected", |_, me, ()| Ok(me.tab.selected.contains_key(&me.url))); + methods.add_method("is_selected", |_, me, ()| Ok(me.tab.selected.contains(&me.url))); methods.add_method("found", |lua, me, ()| { lua.named_registry_value::("cx")?.borrow_scoped(|core: &yazi_core::Core| { let Some(finder) = &core.active().finder else { diff --git a/yazi-actor/src/lives/selected.rs b/yazi-actor/src/lives/selected.rs index dcab02b3..dd513b33 100644 --- a/yazi-actor/src/lives/selected.rs +++ b/yazi-actor/src/lives/selected.rs @@ -1,4 +1,3 @@ -use indexmap::IndexMap; use mlua::AnyUserData; use super::Lives; @@ -9,11 +8,11 @@ pub(super) struct Selected; impl Selected { #[inline] - pub(super) fn make(inner: &IndexMap) -> mlua::Result { + pub(super) fn make(inner: &yazi_core::tab::Selected) -> mlua::Result { let inner = PtrCell::from(inner); Lives::scoped_userdata(yazi_binding::Iter::new( - inner.as_static().keys().cloned().map(yazi_binding::Url::new), + inner.as_static().values().cloned().map(yazi_binding::Url::new), Some(inner.len()), )) } diff --git a/yazi-actor/src/mgr/toggle_all.rs b/yazi-actor/src/mgr/toggle_all.rs index f79252c5..ec2d5101 100644 --- a/yazi-actor/src/mgr/toggle_all.rs +++ b/yazi-actor/src/mgr/toggle_all.rs @@ -23,8 +23,8 @@ impl Actor for ToggleAll { Some(true) => Right((vec![], opt.urls)), Some(false) if opt.urls.is_empty() => Left((it.collect(), vec![])), Some(false) => Right((opt.urls, vec![])), - None if opt.urls.is_empty() => Left(it.partition(|&u| tab.selected.contains_key(u))), - None => Right(opt.urls.into_iter().partition(|u| tab.selected.contains_key(u))), + None if opt.urls.is_empty() => Left(it.partition(|&u| tab.selected.contains(u))), + None => Right(opt.urls.into_iter().partition(|u| tab.selected.contains(u))), }; let warn = match either { diff --git a/yazi-binding/src/url.rs b/yazi-binding/src/url.rs index 91261abb..4c8a600a 100644 --- a/yazi-binding/src/url.rs +++ b/yazi-binding/src/url.rs @@ -159,10 +159,10 @@ impl UserData for Url { methods.add_meta_method(MetaMethod::Eq, |_, me, other: UrlRef| Ok(me.inner == other.inner)); methods.add_meta_method(MetaMethod::ToString, |lua, me, ()| { - lua.create_string(me.as_os_str().as_encoded_bytes()) + lua.create_string(me.os_str().as_encoded_bytes()) }); methods.add_meta_method(MetaMethod::Concat, |lua, lhs, rhs: mlua::String| { - lua.create_string([lhs.as_os_str().as_encoded_bytes(), &rhs.as_bytes()].concat()) + lua.create_string([lhs.os_str().as_encoded_bytes(), &rhs.as_bytes()].concat()) }); } } diff --git a/yazi-core/src/tab/selected.rs b/yazi-core/src/tab/selected.rs index 769e626f..3a0dc99f 100644 --- a/yazi-core/src/tab/selected.rs +++ b/yazi-core/src/tab/selected.rs @@ -2,21 +2,29 @@ use std::{collections::HashMap, ops::Deref}; use indexmap::IndexMap; use yazi_fs::FilesOp; -use yazi_shared::{timestamp_us, url::Url}; +use yazi_shared::{timestamp_us, url::{CovUrl, Url}}; #[derive(Default)] pub struct Selected { - inner: IndexMap, - parents: HashMap, -} - -impl Deref for Selected { - type Target = IndexMap; - - fn deref(&self) -> &Self::Target { &self.inner } + inner: IndexMap, + parents: HashMap, } impl Selected { + #[inline] + pub fn len(&self) -> usize { self.inner.len() } + + #[inline] + pub fn is_empty(&self) -> bool { self.inner.is_empty() } + + #[inline] + pub fn values(&self) -> impl Iterator { self.inner.keys().map(Deref::deref) } + + #[inline] + pub fn contains(&self, url: impl AsRef) -> bool { + self.inner.contains_key(CovUrl::new(&url)) + } + #[inline] pub fn add(&mut self, url: &Url) -> bool { self.add_same(&[url]) == 1 } @@ -33,7 +41,7 @@ impl Selected { fn add_same(&mut self, urls: &[impl AsRef]) -> usize { // If it has appeared as a parent let urls: Vec<_> = - urls.iter().map(|u| u.as_ref()).filter(|&u| !self.parents.contains_key(u)).collect(); + urls.iter().map(CovUrl::new).filter(|&u| !self.parents.contains_key(u)).collect(); if urls.is_empty() { return 0; } @@ -79,12 +87,12 @@ impl Selected { } fn remove_same(&mut self, urls: &[impl AsRef]) -> usize { - let count = urls.iter().filter_map(|u| self.inner.swap_remove(u.as_ref())).count(); + let count = urls.iter().filter_map(|u| self.inner.swap_remove(CovUrl::new(u))).count(); if count == 0 { return 0; } - let mut parent = urls[0].as_ref().parent_url(); + let mut parent = CovUrl::new(&urls[0]).parent_url(); while let Some(u) = parent { let n = self.parents.get_mut(&u).unwrap(); @@ -104,7 +112,7 @@ impl Selected { } pub fn apply_op(&mut self, op: &FilesOp) { - let (removal, addition) = op.diff_recoverable(|u| self.contains_key(u)); + let (removal, addition) = op.diff_recoverable(|u| self.contains(u)); if !removal.is_empty() { self.remove_many(&removal); } diff --git a/yazi-core/src/tab/tab.rs b/yazi-core/src/tab/tab.rs index 63ea995b..9d4af76b 100644 --- a/yazi-core/src/tab/tab.rs +++ b/yazi-core/src/tab/tab.rs @@ -89,7 +89,7 @@ impl Tab { if self.selected.is_empty() { Box::new(self.hovered().map(|h| &h.url).into_iter()) } else { - Box::new(self.selected.keys()) + Box::new(self.selected.values()) } } @@ -98,7 +98,7 @@ impl Tab { if self.selected.is_empty() { Box::new([&h.url, &h.url].into_iter()) } else { - Box::new([&h.url].into_iter().chain(self.selected.keys())) + Box::new([&h.url].into_iter().chain(self.selected.values())) } } diff --git a/yazi-shared/src/url/component.rs b/yazi-shared/src/url/component.rs index 164361af..4fcd3058 100644 --- a/yazi-shared/src/url/component.rs +++ b/yazi-shared/src/url/component.rs @@ -74,13 +74,15 @@ impl<'a> Components<'a> { } pub fn os_str(&self) -> Cow<'a, OsStr> { + let path = self.inner.as_path(); if !self.scheme.is_virtual() || self.scheme_yielded { - return Cow::Borrowed(self.inner.as_path().as_os_str()); + return path.as_os_str().into(); } - let mut oss = OsString::from(format!("{}", self.scheme)); - oss.push(self.inner.as_path()); - Cow::Owned(oss) + let mut s = OsString::from(format!("{}", self.scheme)); + s.reserve_exact(path.as_os_str().len()); + s.push(path); + s.into() } } diff --git a/yazi-shared/src/url/cov.rs b/yazi-shared/src/url/cov.rs new file mode 100644 index 00000000..0a9f51ab --- /dev/null +++ b/yazi-shared/src/url/cov.rs @@ -0,0 +1,36 @@ +use std::{hash::{Hash, Hasher}, ops::Deref}; + +use crate::url::Url; + +#[derive(Clone, Debug, Eq)] +#[repr(transparent)] +pub struct CovUrl(pub Url); + +impl Deref for CovUrl { + type Target = Url; + + fn deref(&self) -> &Self::Target { &self.0 } +} + +impl Hash for CovUrl { + fn hash(&self, state: &mut H) { + self.loc.hash(state); + if self.scheme.is_virtual() { + self.scheme.hash(state); + } + } +} + +impl PartialEq for CovUrl { + fn eq(&self, other: &Self) -> bool { self.covariant(other) } +} + +impl CovUrl { + #[inline] + pub fn new>(u: &T) -> &Self { + unsafe { &*(u.as_ref() as *const Url as *const Self) } + } + + #[inline] + pub fn parent_url(&self) -> Option { self.0.parent_url().map(CovUrl) } +} diff --git a/yazi-shared/src/url/mod.rs b/yazi-shared/src/url/mod.rs index b9aa25b3..08f48576 100644 --- a/yazi-shared/src/url/mod.rs +++ b/yazi-shared/src/url/mod.rs @@ -1 +1 @@ -yazi_macro::mod_flat!(component display loc scheme url urn); +yazi_macro::mod_flat!(component cov display loc scheme url urn); diff --git a/yazi-shared/src/url/scheme.rs b/yazi-shared/src/url/scheme.rs index 3034fa4c..948f05a7 100644 --- a/yazi-shared/src/url/scheme.rs +++ b/yazi-shared/src/url/scheme.rs @@ -47,17 +47,9 @@ impl Scheme { }) } + #[inline] pub fn covariant(&self, other: &Self) -> bool { - match (self, other) { - // Local files - ( - Self::Regular | Self::Search(_) | Self::SearchItem, - Self::Regular | Self::Search(_) | Self::SearchItem, - ) => true, - - // Virtual files within the same namespace - (a, b) => a == b, - } + if self.is_virtual() || other.is_virtual() { self == other } else { true } } #[inline] diff --git a/yazi-shared/src/url/url.rs b/yazi-shared/src/url/url.rs index 58414c61..1540624f 100644 --- a/yazi-shared/src/url/url.rs +++ b/yazi-shared/src/url/url.rs @@ -1,4 +1,4 @@ -use std::{borrow::Cow, ffi::OsStr, fmt::{Debug, Formatter}, hash::{BuildHasher, Hash, Hasher}, ops::Deref, path::{Path, PathBuf}}; +use std::{borrow::Cow, ffi::OsStr, fmt::{Debug, Formatter}, hash::BuildHasher, ops::Deref, path::{Path, PathBuf}}; use percent_encoding::percent_decode; use serde::{Deserialize, Serialize}; @@ -6,7 +6,7 @@ use serde::{Deserialize, Serialize}; use super::UrnBuf; use crate::{IntoOsStr, url::{Components, Display, Loc, Scheme}}; -#[derive(Clone, Default, Eq, Ord, PartialOrd)] +#[derive(Clone, Default, Eq, Ord, PartialOrd, PartialEq, Hash)] pub struct Url { pub loc: Loc, pub scheme: Scheme, @@ -18,19 +18,6 @@ impl Deref for Url { fn deref(&self) -> &Self::Target { &self.loc } } -impl Debug for Url { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - let Self { scheme, loc } = self; - match scheme { - Scheme::Regular => write!(f, "{scheme}{}", loc.display()), - Scheme::Search(_) => write!(f, "{scheme}{}", loc.display()), - Scheme::SearchItem => write!(f, "{scheme}{}", loc.display()), - Scheme::Archive(_) => write!(f, "{scheme}{}", loc.display()), - Scheme::Sftp(_) => write!(f, "{scheme}{}", loc.display()), - } - } -} - impl From for Url { fn from(loc: Loc) -> Self { Self { loc, scheme: Scheme::Regular } } } @@ -229,36 +216,9 @@ impl Url { pub fn into_path(self) -> PathBuf { self.loc.into_path() } } -impl Hash for Url { - fn hash(&self, state: &mut H) { - self.loc.hash(state); - - match &self.scheme { - Scheme::Regular => {} - Scheme::Search(_) => { - self.scheme.hash(state); - } - Scheme::SearchItem => {} - Scheme::Archive(_) => { - self.scheme.hash(state); - } - Scheme::Sftp(_) => { - self.scheme.hash(state); - } - } - } -} - -impl PartialEq for Url { - fn eq(&self, other: &Self) -> bool { - if self.loc != other.loc { - return false; - } - - match (&self.scheme, &other.scheme) { - (Scheme::Regular | Scheme::SearchItem, Scheme::Regular | Scheme::SearchItem) => true, - _ => self.scheme == other.scheme, - } +impl Debug for Url { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!(f, "{}{}", self.scheme, self.loc.display()) } }