diff options
Diffstat (limited to 'src/history.rs')
-rw-r--r-- | src/history.rs | 177 |
1 files changed, 113 insertions, 64 deletions
diff --git a/src/history.rs b/src/history.rs index 35e7eed..e28a107 100644 --- a/src/history.rs +++ b/src/history.rs @@ -1,18 +1,16 @@ -use std::collections::{hash_map::Entry, HashMap}; +use std::collections::HashMap; +use std::fs; +use std::io; use std::path::{Path, PathBuf}; -use crate::fs::{JoshutoDirEntry, JoshutoDirList}; +use crate::fs::{JoshutoDirEntry, JoshutoDirList, JoshutoMetadata}; use crate::util::display::DisplayOption; pub trait DirectoryHistory { - fn populate_to_root(&mut self, path: &Path, options: &DisplayOption) -> std::io::Result<()>; - fn create_or_soft_update( - &mut self, - path: &Path, - options: &DisplayOption, - ) -> std::io::Result<()>; - fn create_or_reload(&mut self, path: &Path, options: &DisplayOption) -> std::io::Result<()>; - fn reload(&mut self, path: &Path, options: &DisplayOption) -> std::io::Result<()>; + fn populate_to_root(&mut self, path: &Path, options: &DisplayOption) -> io::Result<()>; + fn create_or_soft_update(&mut self, path: &Path, options: &DisplayOption) -> io::Result<()>; + fn create_or_reload(&mut self, path: &Path, options: &DisplayOption) -> io::Result<()>; + fn reload(&mut self, path: &Path, options: &DisplayOption) -> io::Result<()>; fn depreciate_all_entries(&mut self); fn depreciate_entry(&mut self, path: &Path); @@ -21,78 +19,67 @@ pub trait DirectoryHistory { pub type JoshutoHistory = HashMap<PathBuf, JoshutoDirList>; impl DirectoryHistory for JoshutoHistory { - fn populate_to_root(&mut self, path: &Path, options: &DisplayOption) -> std::io::Result<()> { + fn populate_to_root(&mut self, path: &Path, options: &DisplayOption) -> io::Result<()> { + let mut dirlists = Vec::new(); + let mut prev: Option<&Path> = None; for curr in path.ancestors() { - match self.entry(curr.to_path_buf()) { - Entry::Occupied(mut entry) => { - let dirlist = entry.get_mut(); - dirlist.reload_contents(options)?; - if let Some(ancestor) = prev.as_ref() { - if let Some(i) = get_index_of_value(&dirlist.contents, ancestor) { - dirlist.index = Some(i); - } + if self.contains_key(curr) { + let mut new_dirlist = create_dirlist_with_history(self, curr, &options)?; + if let Some(ancestor) = prev.as_ref() { + if let Some(i) = get_index_of_value(&new_dirlist.contents, ancestor) { + new_dirlist.index = Some(i); } - prev = Some(curr); } - Entry::Vacant(entry) => { - let mut dirlist = JoshutoDirList::new(curr.to_path_buf().clone(), options)?; - if let Some(ancestor) = prev.as_ref() { - if let Some(i) = get_index_of_value(&dirlist.contents, ancestor) { - dirlist.index = Some(i); - } + dirlists.push(new_dirlist); + } else { + let mut new_dirlist = + JoshutoDirList::from_path(curr.to_path_buf().clone(), options)?; + if let Some(ancestor) = prev.as_ref() { + if let Some(i) = get_index_of_value(&new_dirlist.contents, ancestor) { + new_dirlist.index = Some(i); } - entry.insert(dirlist); - prev = Some(curr); } + dirlists.push(new_dirlist); } + prev = Some(curr); + } + for dirlist in dirlists { + self.insert(dirlist.file_path().to_path_buf(), dirlist); } Ok(()) } - fn create_or_soft_update( - &mut self, - path: &Path, - options: &DisplayOption, - ) -> std::io::Result<()> { - match self.entry(path.to_path_buf()) { - Entry::Occupied(mut entry) => { - let dirlist = entry.get_mut(); - if dirlist.need_update() { - dirlist.reload_contents(options)?; - } - } - Entry::Vacant(entry) => { - let dirlist = JoshutoDirList::new(path.to_path_buf(), options)?; - entry.insert(dirlist); - } + fn create_or_soft_update(&mut self, path: &Path, options: &DisplayOption) -> io::Result<()> { + let (contains_key, need_update) = if let Some(dirlist) = self.get(path) { + (true, dirlist.need_update()) + } else { + (false, true) + }; + if need_update { + let dirlist = if contains_key { + create_dirlist_with_history(self, path, &options)? + } else { + JoshutoDirList::from_path(path.to_path_buf(), options)? + }; + self.insert(path.to_path_buf(), dirlist); } Ok(()) } - fn create_or_reload(&mut self, path: &Path, options: &DisplayOption) -> std::io::Result<()> { - match self.entry(path.to_path_buf()) { - Entry::Occupied(mut entry) => { - let dirlist = entry.get_mut(); - if dirlist.reload_contents(options).is_err() { - entry.remove_entry(); - } - } - Entry::Vacant(entry) => { - let dirlist = JoshutoDirList::new(path.to_path_buf(), options)?; - entry.insert(dirlist); - } - } + fn create_or_reload(&mut self, path: &Path, options: &DisplayOption) -> io::Result<()> { + let dirlist = if self.contains_key(path) { + create_dirlist_with_history(self, path, &options)? + } else { + JoshutoDirList::from_path(path.to_path_buf(), options)? + }; + self.insert(path.to_path_buf(), dirlist); Ok(()) } - fn reload(&mut self, path: &Path, options: &DisplayOption) -> std::io::Result<()> { - if let Entry::Occupied(mut entry) = self.entry(path.to_path_buf()) { - let dirlist = entry.get_mut(); - if dirlist.reload_contents(options).is_err() { - entry.remove_entry(); - } - } + fn reload(&mut self, path: &Path, options: &DisplayOption) -> io::Result<()> { + let dirlist = JoshutoDirList::from_path(path.to_path_buf(), options)?; + self.insert(path.to_path_buf(), dirlist); Ok(()) } @@ -116,3 +103,65 @@ fn get_index_of_value(arr: &[JoshutoDirEntry], val: &Path) -> Option<usize> { } }) } + +pub fn create_dirlist_with_history( + history: &JoshutoHistory, + path: &Path, + options: &DisplayOption, +) -> io::Result<JoshutoDirList> { + let filter_func = options.filter_func(); + let mut contents = read_directory(path, filter_func, options)?; + for entry in contents.iter_mut() { + if entry.metadata.is_dir() { + if let Some(lst) = history.get(entry.file_path()) { + entry.metadata.update_directory_size(lst.len()); + } + } + } + + let sort_options = options.sort_options_ref(); + contents.sort_by(|f1, f2| sort_options.compare(f1, f2)); + + let contents_len = contents.len(); + let index: Option<usize> = if contents_len == 0 { + None + } else { + match history.get(path) { + Some(dirlist) => match dirlist.index { + Some(i) if i >= contents_len => Some(contents_len - 1), + Some(i) => { + let entry = &dirlist.contents[i]; + contents + .iter() + .enumerate() + .find(|(_, e)| e.file_name() == entry.file_name()) + .map(|(i, _)| i) + .or(Some(i)) + } + None => Some(0), + }, + None => Some(0), + } + }; + + let metadata = JoshutoMetadata::from(path)?; + let dirlist = JoshutoDirList::new(path.to_path_buf(), contents, index, metadata); + + Ok(dirlist) +} + +pub fn read_directory<F>( + path: &Path, + filter_func: F, + options: &DisplayOption, +) -> io::Result<Vec<JoshutoDirEntry>> +where + F: Fn(&Result<fs::DirEntry, io::Error>) -> bool, +{ + let results: Vec<JoshutoDirEntry> = fs::read_dir(path)? + .filter(filter_func) + .filter_map(|res| JoshutoDirEntry::from(&res.ok()?, options).ok()) + .collect(); + + Ok(results) +} |