diff --git a/app/src/app.rs b/app/src/app.rs index 4b653c12..c61bf189 100644 --- a/app/src/app.rs +++ b/app/src/app.rs @@ -131,7 +131,7 @@ impl App { let calc = matches!(op, FilesOp::Read(..) | FilesOp::Search(..)); let b = match op { FilesOp::Read(..) => manager.update_read(op), - FilesOp::Sort(..) => manager.update_read(op), + FilesOp::Size(..) => manager.update_read(op), FilesOp::Search(..) => manager.update_search(op), FilesOp::IOErr(..) => manager.update_ioerr(op), }; @@ -144,7 +144,7 @@ impl App { } Event::Pages(page) => { if manager.current().page == page { - let targets = self.cx.manager.current().paginate().into_iter().map(|(_, f)| f).collect(); + let targets = self.cx.manager.current().paginate(); tasks.precache_mime(targets, &self.cx.manager.mimetype); } } diff --git a/app/src/manager/folder.rs b/app/src/manager/folder.rs index 755f120c..a4e5f436 100644 --- a/app/src/manager/folder.rs +++ b/app/src/manager/folder.rs @@ -56,16 +56,17 @@ impl<'a> Widget for Folder<'a> { let items = window .iter() .enumerate() - .map(|(i, (k, v))| { + .map(|(i, f)| { let icon = THEME .icons .iter() - .find(|x| x.name.match_path(k, Some(v.meta.is_dir()))) + .find(|x| x.name.match_path(&f.path, Some(f.meta.is_dir()))) .map(|x| x.display.as_ref()) .unwrap_or(""); - if (!self.is_selection && v.is_selected) - || (self.is_selection && mode.pending(i, v.is_selected)) + let is_selected = self.folder.files.is_selected(&f.path); + if (!self.is_selection && is_selected) + || (self.is_selection && mode.pending(i, is_selected)) { buf.set_style( Rect { x: area.x.saturating_sub(1), y: i as u16 + 1, width: 1, height: 1 }, @@ -77,17 +78,17 @@ impl<'a> Widget for Folder<'a> { ); } - let hovered = matches!(self.folder.hovered, Some(ref h) if h.path == *k); + let hovered = matches!(self.folder.hovered, Some(ref h) if h.path == f.path); let style = if self.is_preview && hovered { THEME.preview.hovered.get() } else if hovered { THEME.selection.hovered.get() } else { - self.file_style(v) + self.file_style(f) }; - let mut path = format!(" {icon} {}", readable_path(k, &self.folder.cwd)); - if let Some(ref link_to) = v.link_to { + let mut path = format!(" {icon} {}", readable_path(&f.path, &self.folder.cwd)); + if let Some(ref link_to) = f.link_to { if MANAGER.show_symlink { path.push_str(&format!(" -> {}", link_to.display())); } diff --git a/core/src/files/file.rs b/core/src/files/file.rs index f0bb37f9..c66420fc 100644 --- a/core/src/files/file.rs +++ b/core/src/files/file.rs @@ -5,13 +5,12 @@ use tokio::fs; #[derive(Clone, Debug)] pub struct File { - pub path: PathBuf, - pub meta: Metadata, - pub length: Option, - pub link_to: Option, - pub is_link: bool, - pub is_hidden: bool, - pub is_selected: bool, + pub path: PathBuf, + pub meta: Metadata, + pub length: Option, + pub link_to: Option, + pub is_link: bool, + pub is_hidden: bool, } impl File { @@ -32,7 +31,7 @@ impl File { let length = if meta.is_dir() { None } else { Some(meta.len()) }; let is_hidden = path.file_name().map(|s| s.to_string_lossy().starts_with('.')).unwrap_or(false); - File { path: path.to_path_buf(), meta, length, link_to, is_link, is_hidden, is_selected: false } + File { path: path.to_path_buf(), meta, length, link_to, is_link, is_hidden } } } @@ -41,8 +40,8 @@ impl File { pub fn path(&self) -> PathBuf { self.path.clone() } #[inline] - pub fn set_path(mut self, path: &Path) -> Self { - self.path = path.to_path_buf(); + pub fn set_path(mut self, path: PathBuf) -> Self { + self.path = path; self } diff --git a/core/src/files/files.rs b/core/src/files/files.rs index 255af694..6f3abcbd 100644 --- a/core/src/files/files.rs +++ b/core/src/files/files.rs @@ -1,22 +1,32 @@ -use std::{collections::BTreeMap, ops::{Deref, DerefMut}, path::{Path, PathBuf}}; +use std::{collections::{BTreeMap, BTreeSet}, ops::Range, path::{Path, PathBuf}}; use anyhow::Result; use config::MANAGER; -use indexmap::IndexMap; use tokio::fs; -use super::{File, FilesSorter}; +use super::{File, FilesSorter, NonHiddenFiles}; pub struct Files { - items: IndexMap, + items: Vec, + length: usize, + + sizes: BTreeMap, + selected: BTreeSet, + pub sorter: FilesSorter, + // TODO: XXX pub show_hidden: bool, } impl Default for Files { fn default() -> Self { Self { - items: Default::default(), + items: Default::default(), + length: Default::default(), + + sizes: Default::default(), + selected: Default::default(), + sorter: Default::default(), show_hidden: MANAGER.show_hidden, } @@ -24,86 +34,111 @@ impl Default for Files { } impl Files { - pub async fn read(paths: Vec) -> BTreeMap { - let mut items = BTreeMap::new(); + pub async fn read(paths: &[impl AsRef]) -> Vec { + let mut items = Vec::with_capacity(paths.len()); for path in paths { - if let Ok(file) = File::from(&path).await { - items.insert(path, file); + if let Ok(file) = File::from(path.as_ref()).await { + items.push(file); } } items } - pub async fn read_dir(path: &Path) -> Result> { + pub async fn read_dir(path: &Path) -> Result> { let mut it = fs::read_dir(path).await?; - let mut items = BTreeMap::new(); + let mut items = Vec::new(); while let Ok(Some(item)) = it.next_entry().await { if let Ok(meta) = item.metadata().await { - let path = item.path(); - let file = File::from_meta(&path, meta).await; - items.insert(path, file); + items.push(File::from_meta(&item.path(), meta).await); } } Ok(items) } #[inline] - pub fn duplicate(&self, idx: usize) -> Option { - self.items.get_index(idx).map(|(_, file)| file.clone()) + pub fn select(&mut self, path: &Path, state: Option) -> bool { + let old = self.selected.contains(path); + let new = if let Some(new) = state { new } else { !old }; + + if new == old { + return false; + } + + if new { + self.selected.insert(path.to_owned()); + } else { + self.selected.remove(path); + } + true + } + + pub fn select_many(&mut self, path: Option<&Path>, state: Option) -> bool { + if let Some(path) = path { + return self.select(path, state); + } + + let mut applied = false; + for item in self.iter() { + todo!(); + // applied |= self.select(&item.path, state); + } + applied + } + + pub fn select_index(&mut self, indices: &BTreeSet, state: Option) -> bool { + let mut applied = false; + for item in self.pick(indices) { + todo!(); + // applied |= self.select(&item.path, state); + } + applied } #[inline] - pub fn set_sorter(&mut self, sort: FilesSorter) -> bool { - if self.sorter == sort { + pub fn set_sorter(&mut self, sorter: FilesSorter) -> bool { + if self.sorter == sorter { return false; } - self.sorter = sort; + self.sorter = sorter; self.sorter.sort(&mut self.items) } - pub fn update_read(&mut self, mut items: BTreeMap) -> bool { - if !self.show_hidden { - items.retain(|_, item| !item.is_hidden); + #[inline] + pub fn set_show_hidden(&mut self, state: bool) -> bool { + if self.show_hidden == state { + return false; } - for (path, item) in &mut items { - if let Some(old) = self.items.get(path) { - item.is_selected = old.is_selected; + self.length = + if state { self.items.len() } else { self.items.iter().filter(|f| !f.is_hidden).count() }; + self.show_hidden = state; + true + } - // Calculate the size of directories is expensive, so we keep the old value, - // before a new value is calculated and comes to. - if item.meta.is_dir() { - item.length = old.length; - } - } - } + pub fn update_read(&mut self, mut items: Vec) -> bool { + self.sorter.sort(&mut items); + self.length = + if self.show_hidden { items.len() } else { items.iter().filter(|f| !f.is_hidden).count() }; + self.items = items; + true + } - self.items.clear(); - self.items.extend(items); + pub fn update_size(&mut self, items: BTreeMap) -> bool { + self.sizes.extend(items); self.sorter.sort(&mut self.items); true } - pub fn update_sort(&mut self, mut items: BTreeMap) -> bool { - for (path, item) in &mut items { - if let Some(old) = self.items.get(path) { - item.is_selected = old.is_selected; - } - } - - self.items.extend(items); - self.sorter.sort(&mut self.items); - true - } - - pub fn update_search(&mut self, items: BTreeMap) -> bool { + pub fn update_search(&mut self, items: Vec) -> bool { if !items.is_empty() { + self.length = items.len(); self.items.extend(items); self.sorter.sort(&mut self.items); return true; } if !self.items.is_empty() { + self.length = 0; self.items.clear(); return true; } @@ -112,39 +147,64 @@ impl Files { } } -impl Deref for Files { - type Target = IndexMap; - - fn deref(&self) -> &Self::Target { &self.items } -} - -impl DerefMut for Files { - fn deref_mut(&mut self) -> &mut Self::Target { &mut self.items } -} - -#[derive(Debug)] -pub enum FilesOp { - Read(PathBuf, BTreeMap), - Sort(PathBuf, BTreeMap), - Search(PathBuf, BTreeMap), - IOErr(PathBuf), -} - -impl FilesOp { +impl Files { #[inline] - pub fn path(&self) -> PathBuf { - match self { - Self::Read(path, _) => path, - Self::Sort(path, _) => path, - Self::Search(path, _) => path, - Self::IOErr(path) => path, + pub fn len(&self) -> usize { self.length } + + #[inline] + pub fn iter<'a>(&'a self) -> Box + 'a> { + if self.show_hidden { + return Box::new(self.items.iter()); } - .clone() + Box::new(NonHiddenFiles::new(&self.items, self.length)) } #[inline] - pub fn read_empty(path: &Path) -> Self { Self::Read(path.to_path_buf(), BTreeMap::new()) } + pub fn range(&self, range: Range) -> Vec<&File> { + self.iter().skip(range.start).take(range.end - range.start).collect() + } + + pub fn pick<'a>(&'a self, indices: &BTreeSet) -> Vec<&'a File> { + let mut items = Vec::with_capacity(indices.len()); + for (i, item) in self.iter().enumerate() { + if indices.contains(&i) { + items.push(item); + } + } + items + } #[inline] - pub fn search_empty(path: &Path) -> Self { Self::Search(path.to_path_buf(), BTreeMap::new()) } + pub fn position(&self, path: &Path) -> Option { self.iter().position(|f| f.path == path) } + + #[inline] + pub fn duplicate(&self, idx: usize) -> Option { self.items.get(idx).cloned() } + + pub fn selected(&self, pending: &BTreeSet, unset: bool) -> Vec<&File> { + if self.selected.is_empty() && (unset || pending.is_empty()) { + return Default::default(); + } + + let mut items = Vec::with_capacity(self.selected.len() + pending.len()); + for (i, item) in self.iter().enumerate() { + let b = self.selected.contains(&item.path); + if !unset && (b || pending.contains(&i)) { + items.push(item); + } else if unset && b && !pending.contains(&i) { + items.push(item); + } + } + items + } + + #[inline] + pub fn is_selected(&self, path: &Path) -> bool { self.selected.contains(path) } + + #[inline] + pub fn has_selected(&self) -> bool { + if self.selected.is_empty() { + return false; + } + self.iter().any(|f| self.selected.contains(&f.path)) + } } diff --git a/core/src/files/iterator.rs b/core/src/files/iterator.rs new file mode 100644 index 00000000..090400dc --- /dev/null +++ b/core/src/files/iterator.rs @@ -0,0 +1,29 @@ +use super::File; + +pub struct NonHiddenFiles<'a> { + items: &'a Vec, + + cur: usize, + max: usize, +} + +impl<'a> NonHiddenFiles<'a> { + pub fn new(items: &'a Vec, max: usize) -> Self { Self { items, cur: 0, max } } +} + +impl<'a> Iterator for NonHiddenFiles<'a> { + type Item = &'a File; + + fn next(&mut self) -> Option { + while self.cur < self.items.len() { + let item = &self.items[self.cur]; + self.cur += 1; + if !item.is_hidden { + return Some(&item); + } + } + None + } + + fn size_hint(&self) -> (usize, Option) { (self.max, Some(self.max)) } +} diff --git a/core/src/files/mod.rs b/core/src/files/mod.rs index 9d437be9..e3e55b87 100644 --- a/core/src/files/mod.rs +++ b/core/src/files/mod.rs @@ -1,7 +1,11 @@ mod file; mod files; +mod iterator; +mod op; mod sorter; pub use file::*; pub use files::*; +pub use iterator::*; +pub use op::*; pub use sorter::*; diff --git a/core/src/files/op.rs b/core/src/files/op.rs new file mode 100644 index 00000000..c9208162 --- /dev/null +++ b/core/src/files/op.rs @@ -0,0 +1,30 @@ +use std::{collections::BTreeMap, path::{Path, PathBuf}}; + +use super::File; + +#[derive(Debug)] +pub enum FilesOp { + Read(PathBuf, Vec), + Size(PathBuf, BTreeMap), + Search(PathBuf, Vec), + IOErr(PathBuf), +} + +impl FilesOp { + #[inline] + pub fn path(&self) -> PathBuf { + match self { + Self::Read(path, _) => path, + Self::Size(path, _) => path, + Self::Search(path, _) => path, + Self::IOErr(path) => path, + } + .clone() + } + + #[inline] + pub fn read_empty(path: &Path) -> Self { Self::Read(path.to_path_buf(), Vec::new()) } + + #[inline] + pub fn search_empty(path: &Path) -> Self { Self::Search(path.to_path_buf(), Vec::new()) } +} diff --git a/core/src/files/sorter.rs b/core/src/files/sorter.rs index c7dc7bc5..0be05287 100644 --- a/core/src/files/sorter.rs +++ b/core/src/files/sorter.rs @@ -1,7 +1,6 @@ -use std::{cmp::Ordering, path::PathBuf}; +use std::cmp::Ordering; use config::{manager::SortBy, MANAGER}; -use indexmap::IndexMap; use super::File; @@ -23,41 +22,41 @@ impl Default for FilesSorter { } impl FilesSorter { - pub(super) fn sort(&self, items: &mut IndexMap) -> bool { + pub(super) fn sort(&self, items: &mut Vec) -> bool { if items.is_empty() { return false; } match self.by { SortBy::Alphabetical => { - items.sort_unstable_by(|_, a, _, b| self.cmp(&a.path, &b.path, self.promote(a, b))) + items.sort_unstable_by(|a, b| self.cmp(&a.path, &b.path, self.promote(a, b))) } - SortBy::Created => items.sort_unstable_by(|_, a, _, b| { + SortBy::Created => items.sort_unstable_by(|a, b| { if let (Ok(aa), Ok(bb)) = (a.meta.created(), b.meta.created()) { return self.cmp(aa, bb, self.promote(a, b)); } Ordering::Equal }), - SortBy::Modified => items.sort_unstable_by(|_, a, _, b| { + SortBy::Modified => items.sort_unstable_by(|a, b| { if let (Ok(aa), Ok(bb)) = (a.meta.modified(), b.meta.modified()) { return self.cmp(aa, bb, self.promote(a, b)); } Ordering::Equal }), SortBy::Natural => self.sort_naturally(items), - SortBy::Size => items.sort_unstable_by(|_, a, _, b| { + SortBy::Size => items.sort_unstable_by(|a, b| { self.cmp(a.length.unwrap_or(0), b.length.unwrap_or(0), self.promote(a, b)) }), } true } - fn sort_naturally(&self, items: &mut IndexMap) { + fn sort_naturally(&self, items: &mut Vec) { let mut indices = Vec::with_capacity(items.len()); let mut entities = Vec::with_capacity(items.len()); - for (i, (path, file)) in items.into_iter().enumerate() { + for (i, file) in items.into_iter().enumerate() { indices.push(i); - entities.push((path.to_string_lossy(), file)); + entities.push((file.path.to_string_lossy(), &*file)); } indices.sort_unstable_by(|&a, &b| { @@ -71,12 +70,7 @@ impl FilesSorter { } }); - let mut new = IndexMap::with_capacity(indices.len()); - for i in indices { - let file = entities[i].1.clone(); - new.insert(file.path(), file); - } - *items = new; + items.sort_unstable_by_key(|_| indices.pop().unwrap()); } #[inline] diff --git a/core/src/manager/folder.rs b/core/src/manager/folder.rs index f633e5a0..750ddadc 100644 --- a/core/src/manager/folder.rs +++ b/core/src/manager/folder.rs @@ -1,7 +1,6 @@ use std::path::{Path, PathBuf}; use config::MANAGER; -use indexmap::map::Slice; use ratatui::layout::Rect; use crate::{emit, files::{File, Files, FilesOp}}; @@ -28,7 +27,7 @@ impl Folder { pub fn update(&mut self, op: FilesOp) -> bool { let b = match op { FilesOp::Read(_, items) => self.files.update_read(items), - FilesOp::Sort(_, items) => self.files.update_sort(items), + FilesOp::Size(_, items) => self.files.update_size(items), FilesOp::Search(_, items) => self.files.update_search(items), _ => unreachable!(), }; @@ -103,53 +102,20 @@ impl Folder { } #[inline] - pub fn window(&self) -> &Slice { + pub fn window(&self) -> Vec<&File> { let end = (self.offset + MANAGER.layout.folder_height()).min(self.files.len()); - self.files.get_range(self.offset..end).unwrap() + self.files.range(self.offset..end) } #[inline] - pub fn window_for(&self, offset: usize) -> &Slice { + pub fn window_for(&self, offset: usize) -> Vec<&File> { let start = offset.min(self.files.len().saturating_sub(1)); let end = (offset + MANAGER.layout.folder_height()).min(self.files.len()); - self.files.get_range(start..end).unwrap() - } - - pub fn select(&mut self, idx: Option, state: Option) -> bool { - let len = self.files.len(); - let mut apply = |idx: usize, state: Option| -> bool { - let Some(state) = state else { - self.files[idx].is_selected = !self.files[idx].is_selected; - return true; - }; - - if state != self.files[idx].is_selected { - self.files[idx].is_selected = state; - return true; - } - - false - }; - - if let Some(idx) = idx { - if idx < len { - return apply(idx, state); - } - } else { - let mut applied = false; - for i in 0..len { - if apply(i, state) { - applied = true; - } - } - return applied; - } - - false + self.files.range(start..end) } pub fn hover(&mut self, path: &Path) -> bool { - let new = self.position(path).unwrap_or(self.cursor); + let new = self.files.position(path).unwrap_or(self.cursor); if new > self.cursor { self.next(new - self.cursor) } else { self.prev(self.cursor - new) } } @@ -170,25 +136,17 @@ impl Folder { #[inline] pub fn cursor(&self) -> usize { self.cursor } - #[inline] - pub fn position(&self, path: &Path) -> Option { - self.files.iter().position(|(p, _)| p == path) - } - - pub fn paginate(&self) -> &Slice { + pub fn paginate(&self) -> Vec<&File> { let len = self.files.len(); let limit = MANAGER.layout.folder_height(); let start = (self.page * limit).min(len.saturating_sub(1)); let end = (start + limit).min(len); - self.files.get_range(start..end).unwrap() + self.files.range(start..end) } - #[inline] - pub fn has_selected(&self) -> bool { self.files.iter().any(|(_, f)| f.is_selected) } - pub fn rect_current(&self, path: &Path) -> Option { - let y = self.position(path)? - self.offset; + let y = self.files.position(path)? - self.offset; let mut rect = MANAGER.layout.folder_rect(); rect.y = rect.y.saturating_sub(1) + y as u16; diff --git a/core/src/manager/mode.rs b/core/src/manager/mode.rs index a5145306..5dacbd6b 100644 --- a/core/src/manager/mode.rs +++ b/core/src/manager/mode.rs @@ -49,6 +49,12 @@ impl Mode { } impl Mode { + #[inline] + pub fn is_select(&self) -> bool { matches!(self, Mode::Select(..)) } + + #[inline] + pub fn is_unset(&self) -> bool { matches!(self, Mode::Unset(..)) } + #[inline] pub fn is_visual(&self) -> bool { matches!(self, Mode::Select(..) | Mode::Unset(..)) } } diff --git a/core/src/manager/tab.rs b/core/src/manager/tab.rs index f1287162..ac8ff7f4 100644 --- a/core/src/manager/tab.rs +++ b/core/src/manager/tab.rs @@ -1,4 +1,4 @@ -use std::{collections::{BTreeMap, BTreeSet}, ffi::{OsStr, OsString}, mem, path::{Path, PathBuf}}; +use std::{borrow::Cow, collections::{BTreeMap, BTreeSet}, ffi::{OsStr, OsString}, mem, path::{Path, PathBuf}}; use anyhow::{Error, Result}; use config::{open::Opener, MANAGER}; @@ -36,11 +36,7 @@ impl Tab { pub fn escape(&mut self) -> bool { if let Some((_, indices)) = self.mode.visual() { - let b = matches!(self.mode, Mode::Select(..)); - for idx in indices.iter() { - self.current.select(Some(*idx), Some(b)); - } - + self.current.files.select_index(indices, Some(self.mode.is_select())); self.mode = Mode::Normal; return true; } @@ -187,11 +183,15 @@ impl Tab { pub fn forward(&mut self) -> bool { false } pub fn select(&mut self, state: Option) -> bool { - let idx = Some(self.current.cursor()); - self.current.select(idx, state) + if let Some(ref hovered) = self.current.hovered { + return self.current.files.select(&hovered.path, state); + } + false } - pub fn select_all(&mut self, state: Option) -> bool { self.current.select(None, state) } + pub fn select_all(&mut self, state: Option) -> bool { + self.current.files.select_many(None, state) + } pub fn visual_mode(&mut self, unset: bool) -> bool { let idx = self.current.cursor(); @@ -243,7 +243,7 @@ impl Tab { emit!(Files(FilesOp::search_empty(&cwd))); while let Some(chunk) = rx.next().await { - emit!(Files(FilesOp::Search(cwd.clone(), Files::read(chunk).await))); + emit!(Files(FilesOp::Search(cwd.clone(), Files::read(&chunk).await))); } Ok(()) })); @@ -363,19 +363,9 @@ impl Tab { pub fn selected(&self) -> Vec<&File> { let mode = self.mode(); - let files = &self.current.files; - - let selected: Vec<_> = if !mode.is_visual() { - files.iter().filter(|(_, f)| f.is_selected).map(|(_, f)| f).collect() - } else { - files - .iter() - .enumerate() - .filter(|(i, (_, f))| mode.pending(*i, f.is_selected)) - .map(|(_, (_, f))| f) - .collect() - }; + let pending = mode.visual().map(|(_, p)| Cow::Borrowed(p)).unwrap_or_default(); + let selected = self.current.files.selected(&pending, mode.is_unset()); if selected.is_empty() { self.current.hovered.as_ref().map(|h| vec![h]).unwrap_or_default() } else { @@ -384,7 +374,9 @@ impl Tab { } #[inline] - pub fn in_selecting(&self) -> bool { self.mode().is_visual() || self.current.has_selected() } + pub fn in_selecting(&self) -> bool { + self.mode().is_visual() || self.current.files.has_selected() + } #[inline] pub fn history(&self, path: &Path) -> Option<&Folder> { self.history.get(path) } diff --git a/core/src/manager/watcher.rs b/core/src/manager/watcher.rs index f1ff33ba..cc2c8b75 100644 --- a/core/src/manager/watcher.rs +++ b/core/src/manager/watcher.rs @@ -1,4 +1,4 @@ -use std::{collections::{BTreeMap, BTreeSet}, path::{Path, PathBuf}, sync::Arc, time::Duration}; +use std::{collections::BTreeSet, path::{Path, PathBuf}, sync::Arc, time::Duration}; use futures::StreamExt; use indexmap::IndexMap; @@ -170,11 +170,11 @@ impl Watcher { for ori in linked { emit!(Files(match &result { Ok(items) => { - let files = BTreeMap::from_iter(items.iter().map(|(p, f)| { - let p = ori.join(p.strip_prefix(path).unwrap()); - let f = f.clone().set_path(&p); - (p, f) - })); + let mut files = Vec::with_capacity(items.len()); + for item in items { + let file = item.clone().set_path(ori.join(item.path.strip_prefix(path).unwrap())); + files.push(file); + } FilesOp::Read(ori, files) } Err(_) => FilesOp::IOErr(ori), diff --git a/core/src/tasks/tasks.rs b/core/src/tasks/tasks.rs index 2ef1ca95..82ffe6bc 100644 --- a/core/src/tasks/tasks.rs +++ b/core/src/tasks/tasks.rs @@ -216,11 +216,8 @@ impl Tasks { return false; } - let targets = targets - .iter() - .filter(|(_, f)| f.meta.is_dir() && f.length.is_none()) - .map(|(p, _)| p.clone()) - .collect::>(); + let targets: Vec<_> = + targets.iter().filter(|f| f.meta.is_dir() && f.length.is_none()).map(|f| f.path()).collect(); if !targets.is_empty() { self.scheduler.precache_size(targets); diff --git a/core/src/tasks/workers/precache.rs b/core/src/tasks/workers/precache.rs index 9f92f211..02f57b71 100644 --- a/core/src/tasks/workers/precache.rs +++ b/core/src/tasks/workers/precache.rs @@ -7,7 +7,7 @@ use parking_lot::Mutex; use shared::{calculate_size, Throttle}; use tokio::{fs, sync::mpsc}; -use crate::{emit, external, files::{File, FilesOp}, tasks::TaskOp}; +use crate::{emit, external, files::FilesOp, tasks::TaskOp}; pub(crate) struct Precache { rx: async_channel::Receiver, @@ -29,7 +29,7 @@ pub(crate) enum PrecacheOp { pub(crate) struct PrecacheOpSize { pub id: usize, pub target: PathBuf, - pub throttle: Arc>, + pub throttle: Arc>, } #[derive(Debug)] @@ -121,21 +121,16 @@ impl Precache { pub(crate) async fn size(&self, task: PrecacheOpSize) -> Result<()> { self.sch.send(TaskOp::New(task.id, 0))?; - let length = Some(calculate_size(&task.target).await); - if let Ok(mut file) = File::from(&task.target).await { - file.length = length; - task.throttle.done((task.target, file), |buf| { - let mut handing = self.size_handing.lock(); - for (path, _) in &buf { - handing.remove(path); - } + let length = calculate_size(&task.target).await; + task.throttle.done((task.target, length), |buf| { + let mut handing = self.size_handing.lock(); + for (path, _) in &buf { + handing.remove(path); + } - let parent = buf[0].0.parent().unwrap().to_path_buf(); - emit!(Files(FilesOp::Sort(parent, BTreeMap::from_iter(buf)))); - }); - } else { - self.size_handing.lock().remove(&task.target); - }; + let parent = buf[0].0.parent().unwrap().to_path_buf(); + emit!(Files(FilesOp::Size(parent, BTreeMap::from_iter(buf)))); + }); self.sch.send(TaskOp::Adv(task.id, 1, 0))?; self.done(task.id)