diff options
author | rabite <rabite@posteo.de> | 2019-03-29 02:53:21 +0100 |
---|---|---|
committer | rabite <rabite@posteo.de> | 2019-03-29 02:53:21 +0100 |
commit | b52e63fd8d74ed7587db6d37aca585f6185c77a3 (patch) | |
tree | 2e4a24610b1ab090dcb133ca542f39595e831436 /src/file_browser.rs | |
parent | 8d8d9631b5fce48e2e65410aa4d0df64948f5ad8 (diff) |
global file cache/event dispatch
Diffstat (limited to 'src/file_browser.rs')
-rw-r--r-- | src/file_browser.rs | 277 |
1 files changed, 110 insertions, 167 deletions
diff --git a/src/file_browser.rs b/src/file_browser.rs index 3cf05e7..469b2d8 100644 --- a/src/file_browser.rs +++ b/src/file_browser.rs @@ -1,19 +1,15 @@ use termion::event::Key; -use notify::{INotifyWatcher, Watcher, DebouncedEvent, RecursiveMode}; use std::io::Write; use std::sync::{Arc, Mutex}; -use std::sync::mpsc::{channel, Receiver, Sender}; -use std::time::Duration; use std::path::PathBuf; -use std::collections::HashMap; use std::ffi::OsString; use crate::files::{File, Files, PathBufExt}; +use crate::fscache::FsCache; use crate::listview::ListView; use crate::hbox::HBox; use crate::widget::Widget; -use crate::dirty::Dirtyable; use crate::tabview::{TabView, Tabbable}; use crate::preview::{Previewer, AsyncWidget}; use crate::fail::{HResult, HError, ErrorLog}; @@ -68,35 +64,37 @@ pub struct FileBrowser { pub columns: HBox<FileBrowserWidgets>, pub cwd: File, pub prev_cwd: Option<File>, - selections: HashMap<File, File>, - cached_files: HashMap<File, Files>, core: WidgetCore, - watcher: INotifyWatcher, - watches: Vec<PathBuf>, - dir_events: Arc<Mutex<Vec<DebouncedEvent>>>, proc_view: Arc<Mutex<ProcView>>, bookmarks: Arc<Mutex<BMPopup>>, - log_view: Arc<Mutex<LogView>> + log_view: Arc<Mutex<LogView>>, + fs_cache: FsCache, } impl Tabbable for TabView<FileBrowser> { fn new_tab(&mut self) -> HResult<()> { - let mut tab = FileBrowser::new_cored(&self.active_tab_().core)?; + let cur_tab = self.active_tab_(); - let proc_view = self.active_tab_().proc_view.clone(); - let bookmarks = self.active_tab_().bookmarks.clone(); - let log_view = self.active_tab_().log_view.clone(); + let settings = cur_tab.fs_cache.tab_settings.read()?.clone(); + let cache = cur_tab.fs_cache.new_client(settings).ok(); + + let mut tab = FileBrowser::new(&self.active_tab_().core, cache)?; + + let proc_view = cur_tab.proc_view.clone(); + let bookmarks = cur_tab.bookmarks.clone(); + let log_view = cur_tab.log_view.clone(); tab.proc_view = proc_view; tab.bookmarks = bookmarks; tab.log_view = log_view; self.push_widget(tab)?; - self.active += 1; + self.active = self.widgets.len() - 1; Ok(()) } fn close_tab(&mut self) -> HResult<()> { - self.close_tab_() + self.close_tab_().log(); + Ok(()) } fn next_tab(&mut self) -> HResult<()> { @@ -148,29 +146,36 @@ impl Tabbable for TabView<FileBrowser> { _ => { self.active_tab_mut().on_key(key) } } } -} - - + fn on_refresh(&mut self) -> HResult<()> { + let fs_changes = self.active_tab_() + .fs_cache + .fs_changes + .write()? + .drain(..) + .collect::<Vec<_>>(); - -fn watch_dir(rx: Receiver<DebouncedEvent>, - dir_events: Arc<Mutex<Vec<DebouncedEvent>>>, - sender: Sender<Events>) { - std::thread::spawn(move || { - for event in rx.iter() { - dir_events.lock().unwrap().push(event); - sender.send(Events::WidgetReady).unwrap(); + for tab in &mut self.widgets { + for (dir, old_file, new_file) in fs_changes.iter() { + tab.replace_file(&dir, + old_file.as_ref(), + new_file.as_ref()).log() + } } - }); + Ok(()) + } } + + impl FileBrowser { - pub fn new_cored(core: &WidgetCore) -> HResult<FileBrowser> { + pub fn new(core: &WidgetCore, cache: Option<FsCache>) -> HResult<FileBrowser> { + let fs_cache = cache.unwrap_or_else(|| FsCache::new(core.get_sender())); + let cwd = std::env::current_dir().unwrap(); let mut core_m = core.clone(); let mut core_l = core.clone(); @@ -191,18 +196,40 @@ impl FileBrowser { }).last()?; let left_path = main_path.parent().map(|p| p.to_path_buf()); + let cache = fs_cache.clone(); let main_widget = AsyncWidget::new(&core, Box::new(move |_| { - let mut list = ListView::new(&core_m, - Files::new_from_path(&main_path)?); + let main_dir = File::new(&main_path.file_name()? + .to_string_lossy() + .to_string(), + main_path.clone(), + None); + let files = cache.get_files_sync(&main_dir)?; + let selection = cache.get_selection(&main_dir).ok(); + let mut list = ListView::new(&core_m.clone(), + files); + if let Some(file) = selection { + list.select_file(&file); + } list.animate_slide_up().log(); list.content.meta_all(); Ok(list) })); + let cache = fs_cache.clone(); if let Some(left_path) = left_path { let left_widget = AsyncWidget::new(&core, Box::new(move |_| { + let left_dir = File::new(&left_path.file_name()? + .to_string_lossy() + .to_string(), + left_path.clone(), + None); + let files = cache.get_files_sync(&left_dir)?; + let selection = cache.get_selection(&left_dir).ok(); let mut list = ListView::new(&core_l, - Files::new_from_path(&left_path)?); + files); + if let Some(file) = selection { + list.select_file(&file); + } list.animate_slide_up().log(); Ok(list) })); @@ -210,7 +237,7 @@ impl FileBrowser { columns.push_widget(left_widget); } - let previewer = Previewer::new(&core_p); + let previewer = Previewer::new(&core_p, fs_cache.clone()); columns.push_widget(FileBrowserWidgets::FileList(main_widget)); columns.push_widget(FileBrowserWidgets::Previewer(previewer)); @@ -219,11 +246,6 @@ impl FileBrowser { let cwd = File::new_from_path(&cwd, None).unwrap(); - let dir_events = Arc::new(Mutex::new(vec![])); - - let (tx_watch, rx_watch) = channel(); - let watcher = INotifyWatcher::new(tx_watch, Duration::from_secs(2)).unwrap(); - watch_dir(rx_watch, dir_events.clone(), core.get_sender()); let proc_view = ProcView::new(&core); let bookmarks = BMPopup::new(&core); @@ -234,15 +256,12 @@ impl FileBrowser { Ok(FileBrowser { columns: columns, cwd: cwd, prev_cwd: None, - selections: HashMap::new(), - cached_files: HashMap::new(), core: core.clone(), - watcher: watcher, - watches: vec![], - dir_events: dir_events, proc_view: Arc::new(Mutex::new(proc_view)), bookmarks: Arc::new(Mutex::new(bookmarks)), - log_view: Arc::new(Mutex::new(log_view)) }) + log_view: Arc::new(Mutex::new(log_view)), + fs_cache: fs_cache, + }) } pub fn enter_dir(&mut self) -> HResult<()> { @@ -306,33 +325,25 @@ impl FileBrowser { } pub fn main_widget_goto(&mut self, dir: &File) -> HResult<()> { - + self.cache_files().log(); let dir = dir.clone(); - let selected_file = self.get_selection(&dir).ok().cloned(); - - self.get_files().and_then(|files| self.cache_files(files)).log(); - self.get_left_files().and_then(|files| self.cache_files(files)).log(); - let cached_files = self.get_cached_files(&dir).ok(); + let cache = self.fs_cache.clone(); self.prev_cwd = Some(self.cwd.clone()); self.cwd = dir.clone(); let main_async_widget = self.main_async_widget_mut()?; main_async_widget.change_to(Box::new(move |stale, core| { - let path = dir.path(); - let cached_files = cached_files.clone(); - - let files = cached_files.or_else(|| { - Files::new_from_path_cancellable(&path, stale.clone()).ok() - })?; + let (selected_file, files) = cache.get_files(&dir, stale)?; + let files = files.wait()?; let mut list = ListView::new(&core, files); list.content.meta_set_fresh().log(); - if let Some(file) = &selected_file { - list.select_file(file); + if let Some(file) = selected_file { + list.select_file(&file); } Ok(list) })).log(); @@ -341,7 +352,7 @@ impl FileBrowser { self.left_widget_goto(&grand_parent).log(); } else { self.left_async_widget_mut()?.clear().log(); - self.screen()?.flush(); + Ok(self.screen()?.flush()?).log(); self.left_async_widget_mut()?.set_stale().log(); } @@ -349,17 +360,15 @@ impl FileBrowser { } pub fn left_widget_goto(&mut self, dir: &File) -> HResult<()> { - let cached_files = self.get_cached_files(&dir).ok(); + let cache = self.fs_cache.clone(); let dir = dir.clone(); let left_async_widget = self.left_async_widget_mut()?; left_async_widget.change_to(Box::new(move |stale, core| { - let path = dir.path(); - let cached_files = cached_files.clone(); + let cached_files = cache.get_files(&dir, stale)?; + let (_, files) = cached_files; - let files = cached_files.or_else(|| { - Files::new_from_path_cancellable(&path, stale).ok() - })?; + let files = files.wait()?; let list = ListView::new(&core, files); Ok(list) @@ -430,10 +439,8 @@ impl FileBrowser { return Ok(()); } let file = self.selected_file()?.clone(); - let selection = self.get_selection(&file).ok().cloned(); - let cached_files = self.get_cached_files(&file).ok(); let preview = self.preview_widget_mut()?; - preview.set_file(&file, selection, cached_files).log(); + preview.set_file(&file).log(); Ok(()) } @@ -441,47 +448,45 @@ impl FileBrowser { if !self.left_async_widget_mut()?.ready() { return Ok(()) } if self.cwd.parent().is_none() { return Ok(()) } - let parent = self.cwd()?.parent_as_file(); + let selection = self.cwd()?.clone(); - let left_selection = self.get_selection(&parent?)?.clone(); - self.left_widget_mut()?.select_file(&left_selection); + self.left_widget_mut()?.select_file(&selection); Ok(()) } - pub fn get_selection(&self, dir: &File) -> HResult<&File> { - Ok(self.selections.get(dir)?) - } - - pub fn get_files(&mut self) -> HResult<Files> { + pub fn get_files(&self) -> HResult<Files> { Ok(self.main_widget()?.content.clone()) } - pub fn get_left_files(&mut self) -> HResult<Files> { + pub fn get_left_files(&self) -> HResult<Files> { Ok(self.left_widget()?.content.clone()) } - pub fn cache_files(&mut self, files: Files) -> HResult<()> { - let dir = files.directory.clone(); - self.cached_files.insert(dir, files); - Ok(()) - } - - pub fn get_cached_files(&mut self, dir: &File) -> HResult<Files> { - Ok(self.cached_files.get(dir)?.clone()) - } - - pub fn save_selection(&mut self) -> HResult<()> { - let cwd = self.cwd()?.clone(); - if let Ok(main_selection) = self.selected_file() { - self.selections.insert(cwd.clone(), main_selection); + pub fn cache_files(&self) -> HResult<()> { + if !self.fs_cache.is_cached(&self.cwd)? { + let files = self.get_files()?; + let selected_file = self.selected_file().ok(); + self.fs_cache.put_files(files, selected_file).log(); + } else { + let files = &self.main_widget()?.content; + let selected_file = self.selected_file().ok(); + self.fs_cache.save_settings(&files, selected_file).log(); } - if let Ok(left_dir) = self.cwd()?.parent_as_file() { - self.selections.insert(left_dir, cwd); + + if !self.fs_cache.is_cached(&self.left_widget()?.content.directory)? { + let left_selection = self.left_widget()?.clone_selected_file(); + let left_files = self.get_left_files()?; + self.fs_cache.put_files(left_files, Some(left_selection)).log(); + } else { + let files = &self.left_widget()?.content; + let selected_file = self.left_widget()?.clone_selected_file(); + self.fs_cache.save_settings(&files, Some(selected_file)).log(); } Ok(()) } + pub fn cwd(&self) -> HResult<&File> { Ok(&self.cwd) } @@ -492,77 +497,25 @@ impl FileBrowser { Ok(()) } - pub fn left_dir(&self) -> HResult<File> { + pub fn left_dir(&self) -> HResult<&File> { let widget = self.left_widget()?; - let dir = widget.content.directory.clone(); + let dir = &widget.content.directory; Ok(dir) } - fn update_watches(&mut self) -> HResult<()> { - if !self.left_async_widget_mut()?.ready() || - !self.main_async_widget_mut()?.ready() { - return Ok(()) - } - let watched_dirs = self.watches.clone(); - let cwd = self.cwd()?.clone(); - let left_dir = self.left_dir()?; - let preview_dir = self.selected_file().ok().map(|f| f.path); - - for watched_dir in watched_dirs.iter() { - if watched_dir != &cwd.path && watched_dir != &left_dir.path && - Some(watched_dir.clone()) != preview_dir { - self.watcher.unwatch(&watched_dir).ok(); - self.watches.remove_item(&watched_dir); - } - } - if !watched_dirs.contains(&cwd.path) { - self.watcher.watch(&cwd.path, RecursiveMode::NonRecursive)?; - self.watches.push(cwd.path); - } - if !watched_dirs.contains(&left_dir.path) { - self.watcher.watch(&left_dir.path, RecursiveMode::NonRecursive)?; - self.watches.push(left_dir.path); + fn replace_file(&mut self, + dir: &File, + old: Option<&File>, + new: Option<&File>) -> HResult<()> { + if &self.cwd == dir { + self.main_widget_mut()?.content.replace_file(old, new.cloned()).log(); } - if let Some(preview_dir) = preview_dir { - if !watched_dirs.contains(&preview_dir) && preview_dir.is_dir() { - match self.watcher.watch(&preview_dir, RecursiveMode::NonRecursive) { - Ok(_) => self.watches.push(preview_dir), - Err(notify::Error::Io(ioerr)) => { - if ioerr.kind() != std::io::ErrorKind::PermissionDenied { - Err(ioerr)? - } - } - err @ _ => err? - } - } + if &self.left_dir()? == &dir { + self.left_widget_mut()?.content.replace_file(old, new.cloned()).log(); } Ok(()) } - fn handle_dir_events(&mut self) -> HResult<()> { - let dir_events = self.dir_events.clone(); - for event in dir_events.lock()?.iter() { - let main_widget = self.main_widget_mut()?; - let main_result = main_widget.content.handle_event(event); - - let left_widget = self.left_widget_mut()?; - let left_result = left_widget.content.handle_event(event); - - match main_result { - Err(HError::WrongDirectoryError { .. }) => { - match left_result { - Err(HError::WrongDirectoryError { .. }) => { - let preview = self.preview_widget_mut()?; - preview.reload(); - }, _ => {} - } - }, _ => {} - } - } - dir_events.lock()?.clear(); - Ok(()) - } - pub fn selected_file(&self) -> HResult<File> { let widget = self.main_widget()?; let file = widget.selected_file().clone(); @@ -631,13 +584,6 @@ impl FileBrowser { widget } - // pub fn preview_widget(&self) -> HResult<&Previewer> { - // match self.columns.widgets.get(2)? { - // FileBrowserWidgets::Previewer(previewer) => Ok(previewer), - // _ => { return HError::wrong_widget("filelist", "previewer"); } - // } - // } - pub fn preview_widget_mut(&mut self) -> HResult<&mut Previewer> { match self.columns.widgets.get_mut(2)? { FileBrowserWidgets::Previewer(previewer) => Ok(previewer), @@ -843,16 +789,13 @@ impl Widget for FileBrowser { } } fn refresh(&mut self) -> HResult<()> { - //self.proc_view.lock()?.set_coordinates(self.get_coordinates()?); self.set_title().log(); - self.handle_dir_events().log(); self.columns.refresh().log(); self.set_left_selection().log(); - self.save_selection().log(); self.set_cwd().log(); - self.update_watches().log(); if !self.columns.zoom_active { self.update_preview().log(); } self.columns.refresh().log(); + self.cache_files().log(); Ok(()) } |