diff options
Diffstat (limited to 'src/file_browser.rs')
-rw-r--r-- | src/file_browser.rs | 708 |
1 files changed, 449 insertions, 259 deletions
diff --git a/src/file_browser.rs b/src/file_browser.rs index d083896..9458da7 100644 --- a/src/file_browser.rs +++ b/src/file_browser.rs @@ -1,21 +1,19 @@ 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::sync::{Arc, Mutex, RwLock}; use std::path::PathBuf; -use std::collections::HashMap; -use std::ffi::{OsString, OsStr}; +use std::ffi::OsString; +use std::collections::HashSet; -use crate::files::{File, Files, PathBufExt, OsStrTools}; +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, WillBeWidget}; +use crate::preview::{Previewer, AsyncWidget}; +use crate::textview::TextView; use crate::fail::{HResult, HError, ErrorLog}; use crate::widget::{Events, WidgetCore}; use crate::proclist::ProcView; @@ -24,42 +22,50 @@ use crate::term; use crate::term::ScreenExt; use crate::foldview::LogView; use crate::coordinates::Coordinates; +use crate::dirty::Dirtyable; +use crate::stats::{FsStat, FsExt}; #[derive(PartialEq)] pub enum FileBrowserWidgets { - FileList(WillBeWidget<ListView<Files>>), + FileList(AsyncWidget<ListView<Files>>), Previewer(Previewer), + Blank(AsyncWidget<TextView>), } impl Widget for FileBrowserWidgets { fn get_core(&self) -> HResult<&WidgetCore> { match self { FileBrowserWidgets::FileList(widget) => widget.get_core(), - FileBrowserWidgets::Previewer(widget) => widget.get_core() + FileBrowserWidgets::Previewer(widget) => widget.get_core(), + FileBrowserWidgets::Blank(widget) => widget.get_core(), } } fn get_core_mut(&mut self) -> HResult<&mut WidgetCore> { match self { FileBrowserWidgets::FileList(widget) => widget.get_core_mut(), - FileBrowserWidgets::Previewer(widget) => widget.get_core_mut() + FileBrowserWidgets::Previewer(widget) => widget.get_core_mut(), + FileBrowserWidgets::Blank(widget) => widget.get_core_mut(), } } fn set_coordinates(&mut self, coordinates: &Coordinates) -> HResult<()> { match self { FileBrowserWidgets::FileList(widget) => widget.set_coordinates(coordinates), FileBrowserWidgets::Previewer(widget) => widget.set_coordinates(coordinates), + FileBrowserWidgets::Blank(widget) => widget.set_coordinates(coordinates), } } fn refresh(&mut self) -> HResult<()> { match self { FileBrowserWidgets::FileList(widget) => widget.refresh(), - FileBrowserWidgets::Previewer(widget) => widget.refresh() + FileBrowserWidgets::Previewer(widget) => widget.refresh(), + FileBrowserWidgets::Blank(widget) => widget.refresh(), } } fn get_drawlist(&self) -> HResult<String> { match self { FileBrowserWidgets::FileList(widget) => widget.get_drawlist(), - FileBrowserWidgets::Previewer(widget) => widget.get_drawlist() + FileBrowserWidgets::Previewer(widget) => widget.get_drawlist(), + FileBrowserWidgets::Blank(widget) => widget.get_drawlist(), } } } @@ -68,35 +74,39 @@ 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, + fs_stat: Arc<RwLock<FsStat>> } 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 settings = cur_tab.fs_cache.tab_settings.read()?.clone(); + let cache = cur_tab.fs_cache.new_client(settings).ok(); - 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 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; + tab.fs_stat = cur_tab.fs_stat.clone(); 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 +158,79 @@ 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<_>>(); + + 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() + } + } + let open_dirs = self.widgets + .iter() + .fold(HashSet::new(), |mut dirs, tab| { + tab.left_dir().map(|dir| dirs.insert(dir.clone())).ok(); + dirs.insert(tab.cwd.clone()); + tab.preview_widget() + .map(|preview| preview.get_file().map(|file| { + if file.is_dir() { + dirs.insert(file.clone()); + } + })).ok(); + dirs + }); + self.active_tab_mut_().fs_cache.watch_only(open_dirs).log(); + self.active_tab_mut_().fs_stat.write()?.refresh().log(); + Ok(()) + } -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(); + fn on_config_loaded(&mut self) -> HResult<()> { + // hack: wait a bit for widget readyness... + let duration = std::time::Duration::from_millis(100); + std::thread::sleep(duration); + + let show_hidden = self.config().show_hidden(); + for tab in self.widgets.iter_mut() { + tab.left_widget_mut().map(|w| { + w.content.show_hidden = show_hidden; + w.content.dirty_meta.set_dirty(); + w.refresh().log(); + }).ok(); + + tab.main_widget_mut().map(|w| { + w.content.show_hidden = show_hidden; + w.content.dirty_meta.set_dirty(); + w.content.sort(); + w.refresh().log(); + }).ok(); + + tab.preview_widget_mut().map(|w| w.config_loaded()).ok(); } - }); + Ok(()) + } } + + impl FileBrowser { - pub fn new_cored(core: &WidgetCore) -> HResult<FileBrowser> { + pub fn new(core: &WidgetCore, cache: Option<FsCache>) -> HResult<FileBrowser> { + let startup = cache.is_none(); + 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,25 +251,80 @@ impl FileBrowser { }).last()?; let left_path = main_path.parent().map(|p| p.to_path_buf()); - let main_widget = WillBeWidget::new(&core, Box::new(move |_| { - let mut list = ListView::new(&core_m, - Files::new_from_path(&main_path)?); - list.animate_slide_up().log(); + let cache = fs_cache.clone(); + let main_widget = AsyncWidget::new(&core, Box::new(move |_| { + let name = if main_path.parent().is_none() { + "root".to_string() + } else { + main_path.file_name()? + .to_string_lossy() + .to_string() + }; + let main_dir = File::new(&name, + 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.content.meta_all(); + list.content.dirty_meta.set_dirty(); + list.refresh().log(); + + if startup { + list.animate_slide_up(None).log(); + } + + list.content.meta_all(); Ok(list) })); + let cache = fs_cache.clone(); if let Some(left_path) = left_path { - let left_widget = WillBeWidget::new(&core, Box::new(move |_| { + let left_widget = AsyncWidget::new(&core, Box::new(move |_| { + let name = if left_path.parent().is_none() { + "root".to_string() + } else { + left_path.file_name()? + .to_string_lossy() + .to_string() + }; + let left_dir = File::new(&name, + 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)?); - list.animate_slide_up().log(); + files); + if let Some(file) = selection { + list.select_file(&file); + } + + list.refresh().log(); + + if startup { + list.animate_slide_up(None).log(); + } + Ok(list) })); let left_widget = FileBrowserWidgets::FileList(left_widget); columns.push_widget(left_widget); + } else { + let left_widget = AsyncWidget::new(&core, Box::new(move |_| { + let blank = TextView::new_blank(&core_l); + Ok(blank) + })); + + let left_widget = FileBrowserWidgets::Blank(left_widget); + 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)); @@ -217,38 +332,76 @@ impl FileBrowser { columns.refresh().log(); - let cwd = File::new_from_path(&cwd).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 cwd = File::new_from_path(&cwd, None).unwrap(); let proc_view = ProcView::new(&core); let bookmarks = BMPopup::new(&core); let log_view = LogView::new(&core, vec![]); + let fs_stat = FsStat::new().unwrap(); 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, + fs_stat: Arc::new(RwLock::new(fs_stat)) + }) } pub fn enter_dir(&mut self) -> HResult<()> { let file = self.selected_file()?; if file.is_dir() { - self.main_widget_goto(&file).log(); + let dir = file; + match dir.is_readable() { + Ok(true) => {}, + Ok(false) => { + let status = + format!("{}Stop right there, cowboy! Check your permisions!", + term::color_red()); + self.show_status(&status).log(); + return Ok(()); + } + err @ Err(_) => err.log() + } + + let previewer_files = self.preview_widget_mut()?.take_files().ok(); + + self.columns.remove_widget(0); + + self.prev_cwd = Some(self.cwd.clone()); + self.cwd = dir.clone(); + + let core = self.core.clone(); + let cache = self.fs_cache.clone(); + + let main_widget = AsyncWidget::new(&core.clone(), Box::new(move |_| { + let files = match previewer_files { + Some(files) => files, + None => cache.get_files_sync(&dir)? + }; + + let selection = cache.get_selection(&dir).ok(); + + let mut list = ListView::new(&core, files); + + if let Some(file) = selection { + list.select_file(&file); + } + + list.content.meta_all(); + + Ok(list) + })); + + let main_widget = FileBrowserWidgets::FileList(main_widget); + self.columns.insert_widget(1, main_widget); + } else { self.core.get_sender().send(Events::InputEnabled(false))?; @@ -293,40 +446,26 @@ impl FileBrowser { } pub fn main_widget_goto(&mut self, dir: &File) -> HResult<()> { - match dir.is_readable() { - Ok(true) => {}, - Ok(false) => { - let status = - format!("{}Stop right there, cowboy! Check your permisions!", - term::color_red()); - self.show_status(&status).log(); - return Ok(()); - } - err @ Err(_) => err.log() - } + 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(); - 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_widget = self.main_widget_mut()?; - main_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).ok() - })?; + let main_async_widget = self.main_async_widget_mut()?; + main_async_widget.change_to(Box::new(move |stale, core| { + let (selected_file, files) = cache.get_files(&dir, stale)?; + let files = files.wait()?; let mut list = ListView::new(&core, files); - if let Some(file) = &selected_file { - list.select_file(file); + list.content.meta_set_fresh().log(); + list.content.meta_all(); + + if let Some(file) = selected_file { + list.select_file(&file); } Ok(list) })).log(); @@ -334,25 +473,24 @@ impl FileBrowser { if let Ok(grand_parent) = self.cwd()?.parent_as_file() { self.left_widget_goto(&grand_parent).log(); } else { - self.left_widget_mut()?.set_stale().log(); + self.left_async_widget_mut()?.change_to(Box::new(move |_,_| { + HError::stale()? + })).log(); } Ok(()) } pub fn left_widget_goto(&mut self, dir: &File) -> HResult<()> { - 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(); let dir = dir.clone(); - let left_widget = self.left_widget_mut()?; - left_widget.change_to(Box::new(move |stale, core| { - let path = dir.path(); - let cached_files = cached_files.clone(); + let left_async_widget = self.left_async_widget_mut()?; + left_async_widget.change_to(Box::new(move |stale, core| { + 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) @@ -362,9 +500,42 @@ impl FileBrowser { pub fn go_back(&mut self) -> HResult<()> { if let Ok(new_cwd) = self.cwd.parent_as_file() { - self.main_widget_goto(&new_cwd).log(); + let core = self.core.clone(); + let preview_files = self.take_main_files(); + let old_left = self.columns.remove_widget(0); + self.prev_cwd = Some(self.cwd.clone()); + self.cwd = new_cwd.clone(); + + if let Ok(left_dir) = new_cwd.parent_as_file() { + let cache = self.fs_cache.clone(); + let left_widget = AsyncWidget::new(&core.clone(), Box::new(move |_| { + let files = cache.get_files_sync(&left_dir)?; + let list = ListView::new(&core, files); + Ok(list) + })); + + let left_widget = FileBrowserWidgets::FileList(left_widget); + self.columns.prepend_widget(left_widget); + } else { + let left_widget = AsyncWidget::new(&core.clone(), Box::new(move |_| { + let blank = TextView::new_blank(&core); + Ok(blank) + })); + + let left_widget = FileBrowserWidgets::Blank(left_widget); + self.columns.prepend_widget(left_widget); + } + self.columns.replace_widget(1, old_left); + self.main_widget_mut()?.content.meta_all(); + + if let Ok(preview_files) = preview_files { + self.preview_widget_mut().map(|preview| { + preview.put_preview_files(preview_files) + }).ok(); + } } + self.columns.resize_children().log(); self.refresh() } @@ -380,15 +551,26 @@ impl FileBrowser { None => &self.cwd }.path.to_string_lossy().to_string(); + self.bookmarks.lock()?.set_coordinates(&self.core.coordinates).log(); + loop { let bookmark = self.bookmarks.lock()?.pick(cwd.to_string()); if let Err(HError::TerminalResizedError) = bookmark { - self.core.screen.clear().log(); - self.resize().log(); - self.refresh().log(); - self.draw().log(); - continue; + self.core.screen.clear().log(); + self.resize().log(); + self.refresh().log(); + self.draw().log(); + continue; + } + + if let Err(HError::WidgetResizedError) = bookmark { + let coords = &self.core.coordinates; + self.bookmarks.lock()?.set_coordinates(&coords).log(); + self.core.screen.clear().log(); + self.refresh().log(); + self.draw().log(); + continue; } return bookmark; } @@ -396,13 +578,15 @@ impl FileBrowser { pub fn goto_bookmark(&mut self) -> HResult<()> { let path = self.get_boomark()?; - let path = File::new_from_path(&PathBuf::from(path))?; + let path = File::new_from_path(&PathBuf::from(path), None)?; self.main_widget_goto(&path)?; Ok(()) } pub fn add_bookmark(&mut self) -> HResult<()> { let cwd = self.cwd.path.to_string_lossy().to_string(); + let coords = &self.core.coordinates; + self.bookmarks.lock()?.set_coordinates(&coords).log(); self.bookmarks.lock()?.add(&cwd)?; Ok(()) } @@ -415,71 +599,88 @@ impl FileBrowser { } pub fn update_preview(&mut self) -> HResult<()> { - if !self.main_widget()?.ready() { return Ok(()) } + if !self.main_async_widget_mut()?.ready() { return Ok(()) } if self.main_widget()? - .widget()? - .lock()? - .as_ref() - .unwrap() .content .len() == 0 { - self.preview_widget_mut()?.set_stale(); + self.preview_widget_mut()?.set_stale().log(); 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); + preview.set_file(&file).log(); Ok(()) } pub fn set_left_selection(&mut self) -> HResult<()> { - if !self.left_widget()?.ready() { return Ok(()) } if self.cwd.parent().is_none() { return Ok(()) } + if !self.left_async_widget_mut()?.ready() { return Ok(()) } - let parent = self.cwd()?.parent_as_file(); + let selection = self.cwd()?.clone(); - if let Ok(left_selection) = self.get_selection(&parent?) { - self.left_widget()?.widget()?.lock()?.as_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 take_main_files(&mut self) -> HResult<Files> { + let core = self.core.clone(); + let blank = AsyncWidget::new(&core.clone(), Box::new(move |_| { + HError::no_files() + })); + let blank = FileBrowserWidgets::Blank(blank); + + let old_widget = self.columns.replace_widget(1, blank); - pub fn get_files(&mut self) -> HResult<Files> { - Ok(self.main_widget()?.widget()?.lock()?.as_ref()?.content.clone()) + if let FileBrowserWidgets::FileList(main_widget) = old_widget { + let files = main_widget.take_widget()?.content; + return Ok(files) + } + HError::no_files() } - pub fn get_left_files(&mut self) -> HResult<Files> { - Ok(self.left_widget()?.widget()?.lock()?.as_ref()?.content.clone()) + pub fn take_left_files(&mut self) -> HResult<Files> { + let core = self.core.clone(); + let blank = AsyncWidget::new(&core.clone(), Box::new(move |_| { + HError::no_files() + })); + let blank = FileBrowserWidgets::FileList(blank); + + let old_widget = self.columns.replace_widget(0, blank); + + if let FileBrowserWidgets::FileList(left_widget) = old_widget { + let files = left_widget.take_widget()?.content; + return Ok(files) + } + HError::no_files() } - pub fn cache_files(&mut self, files: Files) -> HResult<()> { - let dir = files.directory.clone(); - self.cached_files.insert(dir, files); - Ok(()) + pub fn get_files(&self) -> HResult<&Files> { + Ok(&self.main_widget()?.content) } - pub fn get_cached_files(&mut self, dir: &File) -> HResult<Files> { - Ok(self.cached_files.get(dir)?.clone()) + pub fn get_left_files(&self) -> HResult<&Files> { + Ok(&self.left_widget()?.content) } - 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); - } - if let Ok(left_dir) = self.cwd()?.parent_as_file() { - self.selections.insert(left_dir, cwd); - } + pub fn cache_files(&mut self) -> HResult<()> { + let files = self.get_files()?; + let selected_file = self.selected_file().ok(); + self.fs_cache.put_files(files, selected_file).log(); + self.main_widget_mut()?.content.meta_updated = false; + + + // if self.cwd.parent().is_some() { + // 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(); + // self.left_widget_mut()?.content.meta_updated = false; + // } + Ok(()) } + pub fn cwd(&self) -> HResult<&File> { Ok(&self.cwd) } @@ -490,123 +691,91 @@ impl FileBrowser { Ok(()) } - pub fn left_dir(&self) -> HResult<File> { - let widget = self.left_widget()?.widget()?; - let dir = widget.lock()?.as_ref()?.content.directory.clone(); + pub fn left_dir(&self) -> HResult<&File> { + let widget = self.left_widget()?; + let dir = &widget.content.directory; Ok(dir) } - fn update_watches(&mut self) -> HResult<()> { - if !self.left_widget()?.ready() || !self.main_widget()?.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); - } - 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? - } - } + 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(); } - 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()?.widget()?; - let mut main_widget = main_widget.lock()?; - let main_result = main_widget.as_mut()?.content.handle_event(event); - - let left_widget = self.left_widget()?.widget()?; - let mut left_files = left_widget.lock()?; - let left_result = left_files.as_mut()?.content.handle_event(event); - - match main_result { - Err(HError::WrongDirectoryError { .. }) => { - match left_result { - Err(HError::WrongDirectoryError { .. }) => { - let preview = self.preview_widget_mut()?; - preview.reload(); - }, _ => {} - } - }, _ => {} - } + self.preview_widget_mut()?.replace_file(dir, old, new).ok(); + + if &self.left_dir()? == &dir { + self.left_widget_mut()?.content.replace_file(old, new.cloned()).log(); } - dir_events.lock()?.clear(); Ok(()) } pub fn selected_file(&self) -> HResult<File> { - let widget = self.main_widget()?.widget()?; - let file = widget.lock()?.as_ref()?.selected_file().clone(); + let widget = self.main_widget()?; + let file = widget.selected_file().clone(); Ok(file) } pub fn selected_files(&self) -> HResult<Vec<File>> { - let widget = self.main_widget()?.widget()?; - let files = widget.lock()?.as_ref()?.content.get_selected().into_iter().map(|f| { + let widget = self.main_widget()?; + let files = widget.content.get_selected().into_iter().map(|f| { f.clone() }).collect(); Ok(files) } - pub fn main_widget(&self) -> HResult<&WillBeWidget<ListView<Files>>> { + pub fn main_async_widget_mut(&mut self) -> HResult<&mut AsyncWidget<ListView<Files>>> { + let widget = self.columns.active_widget_mut()?; + + let widget = match widget { + FileBrowserWidgets::FileList(filelist) => filelist, + _ => { HError::wrong_widget("previewer", "filelist")? } + }; + Ok(widget) + } + + pub fn main_widget(&self) -> HResult<&ListView<Files>> { let widget = self.columns.active_widget()?; let widget = match widget { - FileBrowserWidgets::FileList(filelist) => Ok(filelist), + FileBrowserWidgets::FileList(filelist) => filelist.widget(), _ => { HError::wrong_widget("previewer", "filelist")? } }; widget } - pub fn main_widget_mut(&mut self) -> HResult<&mut WillBeWidget<ListView<Files>>> { + pub fn main_widget_mut(&mut self) -> HResult<&mut ListView<Files>> { let widget = self.columns.active_widget_mut()?; let widget = match widget { - FileBrowserWidgets::FileList(filelist) => Ok(filelist), + FileBrowserWidgets::FileList(filelist) => filelist.widget_mut(), _ => { HError::wrong_widget("previewer", "filelist")? } }; widget } - pub fn left_widget(&self) -> HResult<&WillBeWidget<ListView<Files>>> { + pub fn left_async_widget_mut(&mut self) -> HResult<&mut AsyncWidget<ListView<Files>>> { + let widget = match self.columns.widgets.get_mut(0)? { + FileBrowserWidgets::FileList(filelist) => filelist, + _ => { return HError::wrong_widget("previewer", "filelist"); } + }; + Ok(widget) + } + + pub fn left_widget(&self) -> HResult<&ListView<Files>> { let widget = match self.columns.widgets.get(0)? { - FileBrowserWidgets::FileList(filelist) => Ok(filelist), + FileBrowserWidgets::FileList(filelist) => filelist.widget(), _ => { return HError::wrong_widget("previewer", "filelist"); } }; widget } - pub fn left_widget_mut(&mut self) -> HResult<&mut WillBeWidget<ListView<Files>>> { + pub fn left_widget_mut(&mut self) -> HResult<&mut ListView<Files>> { let widget = match self.columns.widgets.get_mut(0)? { - FileBrowserWidgets::FileList(filelist) => Ok(filelist), + FileBrowserWidgets::FileList(filelist) => filelist.widget_mut(), _ => { return HError::wrong_widget("previewer", "filelist"); } }; widget @@ -627,6 +796,7 @@ impl FileBrowser { } pub fn toggle_colums(&mut self) { + self.preview_widget().map(|preview| preview.cancel_animation()).log(); self.columns.toggle_zoom().log(); } @@ -634,13 +804,19 @@ impl FileBrowser { let cwd = self.cwd()?.clone().path; let selected_file = self.selected_file()?; let selected_file = selected_file.path.to_string_lossy(); + let selected_files = self.selected_files()?; + + let selected_files = selected_files.iter().map(|f| { + format!("\"{}\" ", &f.path.to_string_lossy()) + }).collect::<String>(); let mut filepath = dirs_2::home_dir()?; filepath.push(".hunter_cwd"); - let output = format!("HUNTER_CWD=\"{}\"\nF=\"{}\"", + let output = format!("HUNTER_CWD=\"{}\"\nF=\"{}\"\nMF=({})\n", cwd.to_str()?, - selected_file); + selected_file, + selected_files); let mut file = std::fs::File::create(filepath)?; file.write(output.as_bytes())?; @@ -648,36 +824,12 @@ impl FileBrowser { } pub fn turbo_cd(&mut self) -> HResult<()> { - let dir = self.minibuffer("cd"); - - match dir { - Ok(dir) => { - self.columns.widgets.clear(); - let cwd = File::new_from_path(&std::path::PathBuf::from(&dir))?; - self.cwd = cwd; - let dir = std::path::PathBuf::from(&dir); - let left_dir = std::path::PathBuf::from(&dir); - let mcore = self.main_widget()?.get_core()?.clone(); - let lcore = self.left_widget()?.get_core()?.clone();; - - let middle = WillBeWidget::new(&self.core, Box::new(move |_| { - let files = Files::new_from_path(&dir.clone())?; - let listview = ListView::new(&mcore, files); - Ok(listview) - })); - let middle = FileBrowserWidgets::FileList(middle); + let dir = self.minibuffer("cd")?; + + let path = std::path::PathBuf::from(&dir); + let dir = File::new_from_path(&path.canonicalize()?, None)?; + self.main_widget_goto(&dir)?; - let left = WillBeWidget::new(&self.core, Box::new(move |_| { - let files = Files::new_from_path(&left_dir.parent()?)?; - let listview = ListView::new(&lcore, files); - Ok(listview) - })); - let left = FileBrowserWidgets::FileList(left); - self.columns.push_widget(left); - self.columns.push_widget(middle); - }, - Err(_) => {} - } Ok(()) } @@ -713,6 +865,7 @@ impl FileBrowser { pub fn run_subshell(&mut self) -> HResult<()> { self.core.get_sender().send(Events::InputEnabled(false))?; + self.preview_widget().map(|preview| preview.cancel_animation()).log(); self.core.screen.cursor_show().log(); self.core.screen.drop_screen(); @@ -738,22 +891,35 @@ impl FileBrowser { Ok(()) } |