mirror of
https://github.com/sxyazi/yazi.git
synced 2026-07-25 08:41:05 +00:00
..
This commit is contained in:
parent
1b98b74606
commit
2ba4f6a958
11 changed files with 80 additions and 83 deletions
|
|
@ -121,7 +121,7 @@ impl UserData for File {
|
||||||
_ => 0u8,
|
_ => 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, ()| {
|
methods.add_method("found", |lua, me, ()| {
|
||||||
lua.named_registry_value::<AnyUserData>("cx")?.borrow_scoped(|core: &yazi_core::Core| {
|
lua.named_registry_value::<AnyUserData>("cx")?.borrow_scoped(|core: &yazi_core::Core| {
|
||||||
let Some(finder) = &core.active().finder else {
|
let Some(finder) = &core.active().finder else {
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
use indexmap::IndexMap;
|
|
||||||
use mlua::AnyUserData;
|
use mlua::AnyUserData;
|
||||||
|
|
||||||
use super::Lives;
|
use super::Lives;
|
||||||
|
|
@ -9,11 +8,11 @@ pub(super) struct Selected;
|
||||||
|
|
||||||
impl Selected {
|
impl Selected {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(super) fn make(inner: &IndexMap<yazi_shared::url::Url, u64>) -> mlua::Result<AnyUserData> {
|
pub(super) fn make(inner: &yazi_core::tab::Selected) -> mlua::Result<AnyUserData> {
|
||||||
let inner = PtrCell::from(inner);
|
let inner = PtrCell::from(inner);
|
||||||
|
|
||||||
Lives::scoped_userdata(yazi_binding::Iter::new(
|
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()),
|
Some(inner.len()),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,8 +23,8 @@ impl Actor for ToggleAll {
|
||||||
Some(true) => Right((vec![], opt.urls)),
|
Some(true) => Right((vec![], opt.urls)),
|
||||||
Some(false) if opt.urls.is_empty() => Left((it.collect(), vec![])),
|
Some(false) if opt.urls.is_empty() => Left((it.collect(), vec![])),
|
||||||
Some(false) => Right((opt.urls, vec![])),
|
Some(false) => Right((opt.urls, vec![])),
|
||||||
None if opt.urls.is_empty() => Left(it.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_key(u))),
|
None => Right(opt.urls.into_iter().partition(|u| tab.selected.contains(u))),
|
||||||
};
|
};
|
||||||
|
|
||||||
let warn = match either {
|
let warn = match either {
|
||||||
|
|
|
||||||
|
|
@ -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::Eq, |_, me, other: UrlRef| Ok(me.inner == other.inner));
|
||||||
methods.add_meta_method(MetaMethod::ToString, |lua, me, ()| {
|
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| {
|
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())
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,21 +2,29 @@ use std::{collections::HashMap, ops::Deref};
|
||||||
|
|
||||||
use indexmap::IndexMap;
|
use indexmap::IndexMap;
|
||||||
use yazi_fs::FilesOp;
|
use yazi_fs::FilesOp;
|
||||||
use yazi_shared::{timestamp_us, url::Url};
|
use yazi_shared::{timestamp_us, url::{CovUrl, Url}};
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct Selected {
|
pub struct Selected {
|
||||||
inner: IndexMap<Url, u64>,
|
inner: IndexMap<CovUrl, u64>,
|
||||||
parents: HashMap<Url, usize>,
|
parents: HashMap<CovUrl, usize>,
|
||||||
}
|
|
||||||
|
|
||||||
impl Deref for Selected {
|
|
||||||
type Target = IndexMap<Url, u64>;
|
|
||||||
|
|
||||||
fn deref(&self) -> &Self::Target { &self.inner }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Selected {
|
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<Item = &Url> { self.inner.keys().map(Deref::deref) }
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn contains(&self, url: impl AsRef<Url>) -> bool {
|
||||||
|
self.inner.contains_key(CovUrl::new(&url))
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn add(&mut self, url: &Url) -> bool { self.add_same(&[url]) == 1 }
|
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<Url>]) -> usize {
|
fn add_same(&mut self, urls: &[impl AsRef<Url>]) -> usize {
|
||||||
// If it has appeared as a parent
|
// If it has appeared as a parent
|
||||||
let urls: Vec<_> =
|
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() {
|
if urls.is_empty() {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -79,12 +87,12 @@ impl Selected {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn remove_same(&mut self, urls: &[impl AsRef<Url>]) -> usize {
|
fn remove_same(&mut self, urls: &[impl AsRef<Url>]) -> 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 {
|
if count == 0 {
|
||||||
return 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 {
|
while let Some(u) = parent {
|
||||||
let n = self.parents.get_mut(&u).unwrap();
|
let n = self.parents.get_mut(&u).unwrap();
|
||||||
|
|
||||||
|
|
@ -104,7 +112,7 @@ impl Selected {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn apply_op(&mut self, op: &FilesOp) {
|
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() {
|
if !removal.is_empty() {
|
||||||
self.remove_many(&removal);
|
self.remove_many(&removal);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -89,7 +89,7 @@ impl Tab {
|
||||||
if self.selected.is_empty() {
|
if self.selected.is_empty() {
|
||||||
Box::new(self.hovered().map(|h| &h.url).into_iter())
|
Box::new(self.hovered().map(|h| &h.url).into_iter())
|
||||||
} else {
|
} else {
|
||||||
Box::new(self.selected.keys())
|
Box::new(self.selected.values())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -98,7 +98,7 @@ impl Tab {
|
||||||
if self.selected.is_empty() {
|
if self.selected.is_empty() {
|
||||||
Box::new([&h.url, &h.url].into_iter())
|
Box::new([&h.url, &h.url].into_iter())
|
||||||
} else {
|
} else {
|
||||||
Box::new([&h.url].into_iter().chain(self.selected.keys()))
|
Box::new([&h.url].into_iter().chain(self.selected.values()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -74,13 +74,15 @@ impl<'a> Components<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn os_str(&self) -> Cow<'a, OsStr> {
|
pub fn os_str(&self) -> Cow<'a, OsStr> {
|
||||||
|
let path = self.inner.as_path();
|
||||||
if !self.scheme.is_virtual() || self.scheme_yielded {
|
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));
|
let mut s = OsString::from(format!("{}", self.scheme));
|
||||||
oss.push(self.inner.as_path());
|
s.reserve_exact(path.as_os_str().len());
|
||||||
Cow::Owned(oss)
|
s.push(path);
|
||||||
|
s.into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
36
yazi-shared/src/url/cov.rs
Normal file
36
yazi-shared/src/url/cov.rs
Normal file
|
|
@ -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<H: Hasher>(&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<T: AsRef<Url>>(u: &T) -> &Self {
|
||||||
|
unsafe { &*(u.as_ref() as *const Url as *const Self) }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn parent_url(&self) -> Option<CovUrl> { self.0.parent_url().map(CovUrl) }
|
||||||
|
}
|
||||||
|
|
@ -1 +1 @@
|
||||||
yazi_macro::mod_flat!(component display loc scheme url urn);
|
yazi_macro::mod_flat!(component cov display loc scheme url urn);
|
||||||
|
|
|
||||||
|
|
@ -47,17 +47,9 @@ impl Scheme {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
pub fn covariant(&self, other: &Self) -> bool {
|
pub fn covariant(&self, other: &Self) -> bool {
|
||||||
match (self, other) {
|
if self.is_virtual() || other.is_virtual() { self == other } else { true }
|
||||||
// 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,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
|
|
||||||
|
|
@ -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 percent_encoding::percent_decode;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
@ -6,7 +6,7 @@ use serde::{Deserialize, Serialize};
|
||||||
use super::UrnBuf;
|
use super::UrnBuf;
|
||||||
use crate::{IntoOsStr, url::{Components, Display, Loc, Scheme}};
|
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 struct Url {
|
||||||
pub loc: Loc,
|
pub loc: Loc,
|
||||||
pub scheme: Scheme,
|
pub scheme: Scheme,
|
||||||
|
|
@ -18,19 +18,6 @@ impl Deref for Url {
|
||||||
fn deref(&self) -> &Self::Target { &self.loc }
|
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<Loc> for Url {
|
impl From<Loc> for Url {
|
||||||
fn from(loc: Loc) -> Self { Self { loc, scheme: Scheme::Regular } }
|
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() }
|
pub fn into_path(self) -> PathBuf { self.loc.into_path() }
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Hash for Url {
|
impl Debug for Url {
|
||||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||||
self.loc.hash(state);
|
write!(f, "{}{}", self.scheme, self.loc.display())
|
||||||
|
|
||||||
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,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue