This commit is contained in:
sxyazi 2023-09-06 20:05:14 +08:00
parent 5a6179005c
commit 358ce77581
No known key found for this signature in database
9 changed files with 67 additions and 45 deletions

View file

@ -128,16 +128,17 @@ impl App {
manager.refresh(); manager.refresh();
} }
Event::Files(op) => { Event::Files(op) => {
let read = matches!(op, FilesOp::Read(..)); let calc = matches!(op, FilesOp::Full(..) | FilesOp::Part(..));
let b = match op { let b = match op {
FilesOp::Read(..) => manager.update_read(op), FilesOp::Full(..) => manager.update_read(op),
FilesOp::Part(..) => manager.update_read(op),
FilesOp::Size(..) => manager.update_read(op), FilesOp::Size(..) => manager.update_read(op),
FilesOp::IOErr(..) => manager.update_ioerr(op), FilesOp::IOErr(..) => manager.update_ioerr(op),
}; };
if b { if b {
emit!(Render); emit!(Render);
} }
if read { if calc {
tasks.precache_size(&manager.current().files); tasks.precache_size(&manager.current().files);
} }
} }

View file

@ -1,15 +1,16 @@
use std::{collections::{BTreeMap, BTreeSet}, mem, ops::Deref, time::Duration}; use std::{collections::{BTreeMap, BTreeSet}, mem, ops::Deref, sync::atomic::Ordering};
use anyhow::Result; use anyhow::Result;
use config::manager::SortBy; use config::manager::SortBy;
use shared::Url; use shared::Url;
use tokio::{fs, select, sync::mpsc::{self, UnboundedReceiver}, time::sleep}; use tokio::{fs, select, sync::mpsc::{self, UnboundedReceiver}};
use super::{File, FilesSorter}; use super::{File, FilesSorter, FILES_VERSION};
pub struct Files { pub struct Files {
items: Vec<File>, items: Vec<File>,
hidden: Vec<File>, hidden: Vec<File>,
version: u64,
sizes: BTreeMap<Url, u64>, sizes: BTreeMap<Url, u64>,
selected: BTreeSet<Url>, selected: BTreeSet<Url>,
@ -21,8 +22,9 @@ pub struct Files {
impl Default for Files { impl Default for Files {
fn default() -> Self { fn default() -> Self {
Self { Self {
items: Default::default(), items: Default::default(),
hidden: Default::default(), hidden: Default::default(),
version: Default::default(),
sizes: Default::default(), sizes: Default::default(),
selected: Default::default(), selected: Default::default(),
@ -108,8 +110,22 @@ impl Files {
applied applied
} }
pub fn update_read(&mut self, items: Vec<File>) -> bool { pub fn update_full(&mut self, mut items: Vec<File>) -> bool {
if !self.show_hidden {
(self.hidden, items) = items.into_iter().partition(|f| f.is_hidden);
}
self.sorter.sort(&mut items);
self.items = items;
self.version = FILES_VERSION.fetch_add(1, Ordering::Relaxed);
true
}
pub fn update_part(&mut self, version: u64, items: Vec<File>) -> bool {
if !items.is_empty() { if !items.is_empty() {
if version != self.version {
return false;
}
if self.show_hidden { if self.show_hidden {
self.items.extend(items); self.items.extend(items);
} else { } else {
@ -122,6 +138,7 @@ impl Files {
return true; return true;
} }
self.version = version;
if !self.items.is_empty() { if !self.items.is_empty() {
self.items.clear(); self.items.clear();
self.hidden.clear(); self.hidden.clear();

View file

@ -1,12 +1,16 @@
use std::collections::BTreeMap; use std::{collections::BTreeMap, sync::atomic::{AtomicU64, Ordering}};
use shared::Url; use shared::Url;
use super::File; use super::File;
use crate::emit;
pub(super) static FILES_VERSION: AtomicU64 = AtomicU64::new(0);
#[derive(Debug)] #[derive(Debug)]
pub enum FilesOp { pub enum FilesOp {
Read(Url, Vec<File>), Full(Url, Vec<File>),
Part(Url, u64, Vec<File>),
Size(Url, BTreeMap<Url, u64>), Size(Url, BTreeMap<Url, u64>),
IOErr(Url), IOErr(Url),
} }
@ -15,7 +19,8 @@ impl FilesOp {
#[inline] #[inline]
pub fn url(&self) -> Url { pub fn url(&self) -> Url {
match self { match self {
Self::Read(url, _) => url, Self::Full(url, _) => url,
Self::Part(url, ..) => url,
Self::Size(url, _) => url, Self::Size(url, _) => url,
Self::IOErr(url) => url, Self::IOErr(url) => url,
} }
@ -23,5 +28,9 @@ impl FilesOp {
} }
#[inline] #[inline]
pub fn clear(url: &Url) -> Self { Self::Read(url.clone(), Vec::new()) } pub fn prepare(url: &Url) -> u64 {
let version = FILES_VERSION.fetch_add(1, Ordering::Relaxed);
emit!(Files(Self::Part(url.clone(), version, Vec::new())));
version
}
} }

View file

@ -27,7 +27,8 @@ impl From<&Url> for Folder {
impl Folder { impl Folder {
pub fn update(&mut self, op: FilesOp) -> bool { pub fn update(&mut self, op: FilesOp) -> bool {
let b = match op { let b = match op {
FilesOp::Read(_, items) => self.files.update_read(items), FilesOp::Full(_, items) => self.files.update_full(items),
FilesOp::Part(_, version, items) => self.files.update_part(version, items),
FilesOp::Size(_, items) => self.files.update_size(items), FilesOp::Size(_, items) => self.files.update_size(items),
_ => unreachable!(), _ => unreachable!(),
}; };

View file

@ -351,7 +351,7 @@ impl Manager {
pub fn update_ioerr(&mut self, op: FilesOp) -> bool { pub fn update_ioerr(&mut self, op: FilesOp) -> bool {
let url = op.url(); let url = op.url();
let op = FilesOp::clear(&url); let op = FilesOp::Full(url.clone(), Vec::new());
if url == *self.cwd() { if url == *self.cwd() {
self.current_mut().update(op); self.current_mut().update(op);

View file

@ -89,17 +89,17 @@ impl Preview {
return; return;
}; };
if files.is_some() {
emit!(Files(FilesOp::Full(url, UnboundedReceiverStream::new(rx).collect().await)));
return;
}
let rx = UnboundedReceiverStream::new(rx).chunks_timeout(10000, Duration::from_millis(500)); let rx = UnboundedReceiverStream::new(rx).chunks_timeout(10000, Duration::from_millis(500));
pin!(rx); pin!(rx);
let mut first = false; let version = FilesOp::prepare(&url);
while let Some(chunk) = rx.next().await { while let Some(chunk) = rx.next().await {
if first { emit!(Files(FilesOp::Part(url.clone(), version, chunk)));
emit!(Files(FilesOp::clear(&url)));
first = false;
}
emit!(Files(FilesOp::Read(url.clone(), chunk)));
} }
})); }));
} }

View file

@ -252,9 +252,9 @@ impl Tab {
let rx = UnboundedReceiverStream::new(rx).chunks_timeout(1000, Duration::from_millis(300)); let rx = UnboundedReceiverStream::new(rx).chunks_timeout(1000, Duration::from_millis(300));
pin!(rx); pin!(rx);
emit!(Files(FilesOp::clear(&cwd))); let version = FilesOp::prepare(&cwd);
while let Some(chunk) = rx.next().await { while let Some(chunk) = rx.next().await {
emit!(Files(FilesOp::Read(cwd.clone(), chunk))); emit!(Files(FilesOp::Part(cwd.clone(), version, chunk)));
} }
Ok(()) Ok(())
})); }));
@ -268,8 +268,7 @@ impl Tab {
if self.current.cwd.is_search() { if self.current.cwd.is_search() {
self.preview_reset_image(); self.preview_reset_image();
let cwd = self.current.cwd.clone(); let rep = self.history_new(&self.current.cwd.to_none());
let rep = self.history_new(&cwd);
drop(mem::replace(&mut self.current, rep)); drop(mem::replace(&mut self.current, rep));
emit!(Refresh); emit!(Refresh);
} }

View file

@ -174,9 +174,6 @@ impl Watcher {
return; return;
}; };
let rx = UnboundedReceiverStream::new(rx).chunks_timeout(10000, Duration::from_millis(500));
pin!(rx);
let linked_files = |files: &[File], ori: &Url| -> Vec<File> { let linked_files = |files: &[File], ori: &Url| -> Vec<File> {
let mut new = Vec::with_capacity(files.len()); let mut new = Vec::with_capacity(files.len());
for file in files { for file in files {
@ -187,20 +184,11 @@ impl Watcher {
new new
}; };
let mut first = true; let files: Vec<_> = UnboundedReceiverStream::new(rx).collect().await;
while let Some(chunk) = rx.next().await { for ori in linked {
if first { let files = linked_files(&files, &ori);
emit!(Files(FilesOp::clear(url))); emit!(Files(FilesOp::Full(ori, files)));
for ori in &linked {
emit!(Files(FilesOp::clear(ori)));
}
first = false;
}
for ori in &linked {
emit!(Files(FilesOp::Read(ori.clone(), linked_files(&chunk, ori))));
}
emit!(Files(FilesOp::Read(url.clone(), chunk)));
} }
emit!(Files(FilesOp::Full(url.clone(), files)));
} }
} }

View file

@ -85,6 +85,13 @@ impl Url {
#[inline] #[inline]
pub fn is_none(&self) -> bool { self.scheme == UrlScheme::None } pub fn is_none(&self) -> bool { self.scheme == UrlScheme::None }
#[inline]
pub fn to_none(&self) -> Self {
let mut url = self.clone();
url.scheme = UrlScheme::None;
url
}
#[inline] #[inline]
pub fn is_search(&self) -> bool { self.scheme == UrlScheme::Search } pub fn is_search(&self) -> bool { self.scheme == UrlScheme::Search }