feat: time-based selection order preservation

This commit is contained in:
sxyazi 2024-03-27 23:35:23 +08:00
parent e619a97ee2
commit 058d3f9c4e
No known key found for this signature in database
6 changed files with 26 additions and 24 deletions

View file

@ -28,7 +28,7 @@ impl Tab {
let (removal, addition): (Vec<_>, Vec<_>) = match opt.into().state {
Some(true) => (vec![], iter.collect()),
Some(false) => (iter.collect(), vec![]),
None => iter.partition(|&u| self.selected.contains(u)),
None => iter.partition(|&u| self.selected.contains_key(u)),
};
let same = !self.current.cwd.is_search();

View file

@ -1,15 +1,15 @@
use std::{collections::{BTreeSet, HashMap}, ops::Deref};
use std::{collections::HashMap, ops::Deref};
use yazi_shared::fs::{FilesOp, Url};
use yazi_shared::{fs::{FilesOp, Url}, timestamp_us};
#[derive(Default)]
pub struct Selected {
inner: BTreeSet<Url>,
inner: HashMap<Url, u64>,
parents: HashMap<Url, usize>,
}
impl Deref for Selected {
type Target = BTreeSet<Url>;
type Target = HashMap<Url, u64>;
fn deref(&self) -> &Self::Target { &self.inner }
}
@ -43,7 +43,7 @@ impl Selected {
let mut parent = urls[0].parent_url();
let mut parents = vec![];
while let Some(u) = parent {
if self.inner.contains(&u) {
if self.inner.contains_key(&u) {
return 0;
}
@ -51,8 +51,8 @@ impl Selected {
parents.push(u);
}
let len = self.inner.len();
self.inner.extend(urls.iter().map(|&&u| u.clone()));
let (now, len) = (timestamp_us(), self.inner.len());
self.inner.extend(urls.iter().enumerate().map(|(i, &&u)| (u.clone(), now + i as u64)));
for u in parents {
*self.parents.entry(u).or_insert(0) += self.inner.len() - len;
@ -78,7 +78,7 @@ impl Selected {
}
fn remove_same(&mut self, urls: &[impl AsRef<Url>]) -> usize {
let count = urls.iter().map(|u| self.inner.remove(u.as_ref())).filter(|&b| b).count();
let count = urls.iter().map(|u| self.inner.remove(u.as_ref())).filter_map(|v| v).count();
if count == 0 {
return 0;
}
@ -106,7 +106,7 @@ impl Selected {
let (removal, addition) = match op {
FilesOp::Deleting(_, urls) => (urls.iter().collect(), vec![]),
FilesOp::Updating(_, urls) | FilesOp::Upserting(_, urls) => {
urls.iter().filter(|(u, _)| self.contains(u)).map(|(u, f)| (u, &f.url)).unzip()
urls.iter().filter(|&(u, _)| self.contains_key(u)).map(|(u, f)| (u, &f.url)).unzip()
}
_ => (vec![], vec![]),
};

View file

@ -90,7 +90,7 @@ impl File {
_ => 0u8,
})
});
reg.add_method("is_selected", |_, me, ()| Ok(me.tab().selected.contains(&me.url)));
reg.add_method("is_selected", |_, me, ()| Ok(me.tab().selected.contains_key(&me.url)));
reg.add_method("in_parent", |_, me, ()| {
Ok(me.tab().parent.as_ref().is_some_and(|f| me.folder().cwd == f.cwd))
});

View file

@ -1,4 +1,4 @@
use std::{collections::{btree_set, BTreeSet}, ops::Deref};
use std::{collections::{hash_map, HashMap}, ops::Deref};
use mlua::{AnyUserData, IntoLuaMulti, Lua, MetaMethod, UserDataMethods, UserDataRefMut};
use yazi_plugin::{bindings::Cast, url::Url};
@ -7,18 +7,20 @@ use super::{Iter, SCOPE};
#[derive(Clone, Copy)]
pub(super) struct Selected {
inner: *const BTreeSet<yazi_shared::fs::Url>,
inner: *const HashMap<yazi_shared::fs::Url, u64>,
}
impl Deref for Selected {
type Target = BTreeSet<yazi_shared::fs::Url>;
type Target = HashMap<yazi_shared::fs::Url, u64>;
fn deref(&self) -> &Self::Target { self.inner() }
}
impl Selected {
#[inline]
pub(super) fn make(inner: &BTreeSet<yazi_shared::fs::Url>) -> mlua::Result<AnyUserData<'static>> {
pub(super) fn make(
inner: &HashMap<yazi_shared::fs::Url, u64>,
) -> mlua::Result<AnyUserData<'static>> {
SCOPE.create_any_userdata(Self { inner })
}
@ -28,7 +30,7 @@ impl Selected {
reg.add_meta_method(MetaMethod::Pairs, |lua, me, ()| {
let iter = lua.create_function(
|lua, mut iter: UserDataRefMut<Iter<btree_set::Iter<yazi_shared::fs::Url>, _>>| {
|lua, mut iter: UserDataRefMut<Iter<hash_map::Keys<yazi_shared::fs::Url, u64>, _>>| {
if let Some(next) = iter.next() {
(next.0, Url::cast(lua, next.1.clone())?).into_lua_multi(lua)
} else {
@ -37,7 +39,7 @@ impl Selected {
},
)?;
Ok((iter, Iter::make(me.inner().iter())))
Ok((iter, Iter::make(me.inner().keys())))
});
})?;
@ -45,5 +47,5 @@ impl Selected {
}
#[inline]
fn inner(&self) -> &'static BTreeSet<yazi_shared::fs::Url> { unsafe { &*self.inner } }
fn inner(&self) -> &'static HashMap<yazi_shared::fs::Url, u64> { unsafe { &*self.inner } }
}

View file

@ -2,7 +2,7 @@ use std::{fmt::Debug, mem, sync::atomic::{AtomicU64, AtomicUsize, Ordering}, tim
use parking_lot::Mutex;
use crate::timestamp_ms;
use crate::timestamp_us;
#[derive(Debug)]
pub struct Throttle<T> {
@ -17,7 +17,7 @@ impl<T> Throttle<T> {
Self {
total: AtomicUsize::new(total),
interval,
last: AtomicU64::new(timestamp_ms() - interval.as_millis() as u64),
last: AtomicU64::new(timestamp_us() - interval.as_micros() as u64),
buf: Default::default(),
}
}
@ -32,8 +32,8 @@ impl<T> Throttle<T> {
}
let last = self.last.load(Ordering::Relaxed);
let now = timestamp_ms();
if now > self.interval.as_millis() as u64 + last {
let now = timestamp_us();
if now > self.interval.as_micros() as u64 + last {
self.last.store(now, Ordering::Relaxed);
return self.flush(data, f);
}

View file

@ -1,5 +1,5 @@
use std::time::{self, SystemTime};
pub fn timestamp_ms() -> u64 {
SystemTime::now().duration_since(time::UNIX_EPOCH).unwrap().as_millis() as u64
pub fn timestamp_us() -> u64 {
SystemTime::now().duration_since(time::UNIX_EPOCH).unwrap().as_micros() as u64
}