diff options
Diffstat (limited to 'src/file_browser.rs')
-rw-r--r-- | src/file_browser.rs | 340 |
1 files changed, 222 insertions, 118 deletions
diff --git a/src/file_browser.rs b/src/file_browser.rs index 37a836c..fb8fea2 100644 --- a/src/file_browser.rs +++ b/src/file_browser.rs @@ -6,22 +6,55 @@ 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 crate::files::{File, Files}; use crate::listview::ListView; use crate::miller_columns::MillerColumns; use crate::widget::Widget; use crate::tabview::{TabView, Tabbable}; -use crate::preview::WillBeWidget; +use crate::preview::{Previewer, WillBeWidget}; use crate::fail::{HResult, HError, ErrorLog}; use crate::widget::{Events, WidgetCore}; use crate::proclist::ProcView; +#[derive(PartialEq)] +pub enum FileBrowserWidgets { + FileList(WillBeWidget<ListView<Files>>), + Previewer(Previewer), +} +impl Widget for FileBrowserWidgets { + fn get_core(&self) -> HResult<&WidgetCore> { + match self { + FileBrowserWidgets::FileList(widget) => widget.get_core(), + FileBrowserWidgets::Previewer(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() + } + } + fn refresh(&mut self) -> HResult<()> { + match self { + FileBrowserWidgets::FileList(widget) => widget.refresh(), + FileBrowserWidgets::Previewer(widget) => widget.refresh() + } + } + fn get_drawlist(&self) -> HResult<String> { + match self { + FileBrowserWidgets::FileList(widget) => widget.get_drawlist(), + FileBrowserWidgets::Previewer(widget) => widget.get_drawlist() + } + } +} pub struct FileBrowser { - pub columns: MillerColumns<WillBeWidget<ListView<Files>>>, + pub columns: MillerColumns<FileBrowserWidgets>, pub cwd: File, + selections: HashMap<File, File>, core: WidgetCore, watcher: INotifyWatcher, watches: Vec<PathBuf>, @@ -105,15 +138,17 @@ fn watch_dir(rx: Receiver<DebouncedEvent>, impl FileBrowser { pub fn new_cored(core: &WidgetCore) -> HResult<FileBrowser> { let cwd = std::env::current_dir().unwrap(); - let coords = core.coordinates.clone(); - let core_m = core.clone(); - let core_l = core.clone(); + let mut core_m = core.clone(); + let mut core_l = core.clone(); + let mut core_p = core.clone(); let mut miller = MillerColumns::new(core); - miller.set_coordinates(&coords)?; - + miller.set_ratios(vec![20,30,49]); + let list_coords = miller.calculate_coordinates()?; - let (left_coords, main_coords, _) = miller.calculate_coordinates(); + core_l.coordinates = list_coords[0].clone(); + core_m.coordinates = list_coords[1].clone(); + core_p.coordinates = list_coords[2].clone(); let main_path = cwd.ancestors() .take(1) @@ -125,7 +160,6 @@ impl FileBrowser { let main_widget = WillBeWidget::new(&core, Box::new(move |_| { let mut list = ListView::new(&core_m, Files::new_from_path(&main_path)?); - list.set_coordinates(&main_coords).log(); list.animate_slide_up().log(); Ok(list) })); @@ -134,14 +168,18 @@ impl FileBrowser { let left_widget = WillBeWidget::new(&core, Box::new(move |_| { let mut list = ListView::new(&core_l, Files::new_from_path(&left_path)?); - list.set_coordinates(&left_coords).log(); list.animate_slide_up().log(); Ok(list) })); + let left_widget = FileBrowserWidgets::FileList(left_widget); miller.push_widget(left_widget); } - miller.push_widget(main_widget); + let previewer = Previewer::new(&core_p); + + miller.push_widget(FileBrowserWidgets::FileList(main_widget)); + miller.push_widget(FileBrowserWidgets::Previewer(previewer)); + miller.refresh().log(); let cwd = File::new_from_path(&cwd).unwrap(); @@ -151,11 +189,13 @@ impl FileBrowser { let watcher = INotifyWatcher::new(tx_watch, Duration::from_secs(2)).unwrap(); watch_dir(rx_watch, dir_events.clone(), core.get_sender()); - let mut proc_view = ProcView::new(core); - proc_view.set_coordinates(&coords).log(); + let proc_view = ProcView::new(core); + + Ok(FileBrowser { columns: miller, cwd: cwd, + selections: HashMap::new(), core: core.clone(), watcher: watcher, watches: vec![], @@ -165,112 +205,138 @@ impl FileBrowser { pub fn enter_dir(&mut self) -> HResult<()> { let file = self.selected_file()?; - let (_, coords, _) = self.columns.calculate_coordinates(); - let core = self.core.clone(); - - match file.read_dir() { - Ok(files) => { - std::env::set_current_dir(&file.path).unwrap(); - self.cwd = file.clone(); - let view = WillBeWidget::new(&core.clone(), Box::new(move |_| { - let files = files.clone(); - let mut list = ListView::new(&core, files); - list.set_coordinates(&coords).log(); - list.animate_slide_up().log(); - Ok(list) - })); - self.columns.push_widget(view); - }, - _ => { - let status = std::process::Command::new("rifle") - .args(file.path.file_name()) - .status(); - - match status { - Ok(status) => - self.show_status(&format!("\"{}\" exited with {}", - "rifle", status)).log(), - Err(err) => - self.show_status(&format!("Can't run this \"{}\": {}", - "rifle", err)).log() - - }; + + if file.is_dir() { + self.main_widget_goto(&file).log(); + } else { + let status = std::process::Command::new("rifle") + .args(file.path.file_name()) + .status(); + + match status { + Ok(status) => + self.show_status(&format!("\"{}\" exited with {}", + "rifle", status)).log(), + Err(err) => + self.show_status(&format!("Can't run this \"{}\": {}", + "rifle", err)).log() } } Ok(()) } - pub fn go_back(&mut self) -> HResult<()> { - self.columns.pop_widget(); + pub fn main_widget_goto(&mut self, dir: &File) -> HResult<()> { + self.cwd = dir.clone(); + let dir = dir.clone(); + let selected_file = self.get_selection(&dir).ok().cloned(); + + let main_widget = self.main_widget_mut()?; + main_widget.change_to(Box::new(move |stale, core| { + let path = dir.path(); + let files = Files::new_from_path_cancellable(&path, stale)?; + + let mut list = ListView::new(&core, files); + + if let Some(file) = &selected_file { + list.select_file(file); + } + Ok(list) + })).log(); + + 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(); + } + + Ok(()) + } + + pub fn left_widget_goto(&mut self, dir: &File) -> HResult<()> { + 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 files = Files::new_from_path_cancellable(&path, stale)?; + let list = ListView::new(&core, files); + Ok(list) + }))?; + Ok(()) + } - if let Ok(new_cwd) = self.cwd.grand_parent_as_file() { - self.cwd = new_cwd; + pub fn go_back(&mut self) -> HResult<()> { + if let Ok(new_cwd) = self.cwd.parent_as_file() { + self.main_widget_goto(&new_cwd).log(); } self.refresh() } pub fn update_preview(&mut self) -> HResult<()> { + if !self.main_widget()?.ready() { return Ok(()) } let file = self.selected_file()?.clone(); - let preview = &mut self.columns.preview; - preview.set_file(&file); + let selection = self.get_selection(&file).ok().cloned(); + let preview = self.preview_widget_mut()?; + preview.set_file(&file, selection); Ok(()) } - pub fn fix_selection(&mut self) -> HResult<()> { - let cwd = self.cwd()?; - (*self.left_widget()?.lock()?).as_mut()?.select_file(&cwd); + pub fn set_left_selection(&mut self) -> HResult<()> { + if !self.left_widget()?.ready() { return Ok(()) } + + let parent = self.cwd()?.parent_as_file(); + + let left_selection = self.get_selection(&parent?)?; + self.left_widget()?.widget()?.lock()?.as_mut()?.select_file(&left_selection); + Ok(()) } - pub fn fix_left(&mut self) -> HResult<()> { - if self.left_widget().is_err() { - let cwd = self.selected_file()?.clone(); - if let Ok(grand_parent) = cwd.grand_parent_as_file() { - let (coords, _, _) = self.columns.calculate_coordinates(); - let core = self.core.clone(); - let left_view = WillBeWidget::new(&self.core, Box::new(move |_| { - let mut view - = ListView::new(&core, - Files::new_from_path(&grand_parent.path)?); - view.set_coordinates(&coords).log(); - Ok(view) - })); - self.columns.prepend_widget(left_view); - } + pub fn get_selection(&self, dir: &File) -> HResult<&File> { + Ok(self.selections.get(dir)?) + } + + 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); } Ok(()) } - pub fn cwd(&self) -> HResult<File> { - let widget = self.columns.get_main_widget()?.widget()?; - let cwd = (*widget.lock()?).as_ref()?.content.directory.clone(); - Ok(cwd) + pub fn cwd(&self) -> HResult<&File> { + Ok(&self.cwd) } pub fn set_cwd(&mut self) -> HResult<()> { let cwd = self.cwd()?; std::env::set_current_dir(&cwd.path)?; - self.cwd = cwd; Ok(()) } pub fn left_dir(&self) -> HResult<File> { - let widget = self.columns.get_left_widget()?.widget()?; - let dir = (*widget.lock()?).as_ref()?.content.directory.clone(); + let widget = self.left_widget()?.widget()?; + let dir = widget.lock()?.as_ref()?.content.directory.clone(); 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()?; + 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).unwrap(); + self.watcher.unwatch(&watched_dir).ok(); self.watches.remove_item(&watched_dir); } } @@ -292,51 +358,85 @@ impl FileBrowser { } fn handle_dir_events(&mut self) -> HResult<()> { - let mut dir_events = self.dir_events.lock()?; - for event in dir_events.iter() { - let main_widget = self.columns.get_main_widget()?.widget()?; - let main_files = &mut (*main_widget.lock()?); - let main_files = &mut main_files.as_mut()?.content; - let main_result = main_files.handle_event(event); - - let left_widget = self.columns.get_left_widget()?.widget()?; - let left_files = &mut (*left_widget.lock()?); - let left_files = &mut left_files.as_mut()?.content; - let left_result = left_files.handle_event(event); + 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 = &mut self.columns.preview; + let preview = self.preview_widget_mut()?; preview.reload(); }, _ => {} } }, _ => {} } } - dir_events.clear(); + dir_events.lock()?.clear(); Ok(()) } pub fn selected_file(&self) -> HResult<File> { - let widget = self.main_widget()?; + let widget = self.main_widget()?.widget()?; let file = widget.lock()?.as_ref()?.selected_file().clone(); Ok(file) } - pub fn main_widget(&self) -> HResult<Arc<Mutex<Option<ListView<Files>>>>> { - let widget = self.columns.get_main_widget()?.widget()?; - Ok(widget) + pub fn main_widget(&self) -> HResult<&WillBeWidget<ListView<Files>>> { + let widget = match self.columns.get_main_widget()? { + FileBrowserWidgets::FileList(filelist) => Ok(filelist), + _ => { return HError::wrong_widget("previewer", "filelist"); } + }; + widget + } + + pub fn main_widget_mut(&mut self) -> HResult<&mut WillBeWidget<ListView<Files>>> { + let widget = match self.columns.get_main_widget_mut()? { + FileBrowserWidgets::FileList(filelist) => Ok(filelist), + _ => { return HError::wrong_widget("previewer", "filelist"); } + }; + widget + } + + pub fn left_widget(&self) -> HResult<&WillBeWidget<ListView<Files>>> { + let widget = match self.columns.get_left_widget()? { + FileBrowserWidgets::FileList(filelist) => Ok(filelist), + _ => { return HError::wrong_widget("previewer", "filelist"); } + }; + widget + } + + pub fn left_widget_mut(&mut self) -> HResult<&mut WillBeWidget<ListView<Files>>> { + let widget = match self.columns.get_left_widget_mut()? { + FileBrowserWidgets::FileList(filelist) => Ok(filelist), + _ => { return HError::wrong_widget("previewer", "filelist"); } + }; + widget + } + + pub fn preview_widget(&self) -> HResult<&Previewer> { + match self.columns.get_right_widget()? { + FileBrowserWidgets::Previewer(previewer) => Ok(previewer), + _ => { return HError::wrong_widget("filelist", "previewer"); } + } } - pub fn left_widget(&self) -> HResult<Arc<Mutex<Option<ListView<Files>>>>> { - let widget = self.columns.get_left_widget()?.widget()?; - Ok(widget) + pub fn preview_widget_mut(&mut self) -> HResult<&mut Previewer> { + match self.columns.get_right_widget_mut()? { + FileBrowserWidgets::Previewer(previewer) => Ok(previewer), + _ => { return HError::wrong_widget("filelist", "previewer"); } + } } pub fn quit_with_dir(&self) -> HResult<()> { - let cwd = self.cwd()?.path; + let cwd = self.cwd()?.clone().path; let selected_file = self.selected_file()?; let selected_file = selected_file.path.to_string_lossy(); @@ -362,22 +462,22 @@ impl FileBrowser { self.cwd = cwd; let dir = std::path::PathBuf::from(&dir); let left_dir = std::path::PathBuf::from(&dir); - let (left_coords, main_coords, _) = self.columns.calculate_coordinates(); - let mcore = self.core.clone(); - let lcore = self.core.clone(); + 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 mut listview = ListView::new(&mcore, files); - listview.set_coordinates(&main_coords).log(); + let listview = ListView::new(&mcore, files); Ok(listview) })); + let middle = FileBrowserWidgets::FileList(middle); + let left = WillBeWidget::new(&self.core, Box::new(move |_| { let files = Files::new_from_path(&left_dir.parent()?)?; - let mut listview = ListView::new(&lcore, files); - listview.set_coordinates(&left_coords).log(); + let listview = ListView::new(&lcore, files); Ok(listview) })); + let left = FileBrowserWidgets::FileList(left); self.columns.push_widget(left); self.columns.push_widget(middle); }, @@ -388,9 +488,9 @@ impl FileBrowser { fn exec_cmd(&mut self, tab_dirs: Vec<File>) -> HResult<()> { let filename = self.selected_file()?.name.clone(); - let widget = self.main_widget()?; + let widget = self.main_widget()?.widget()?; let widget = widget.lock()?; - let selected_files = (*widget).as_ref()?.content.get_selected(); + let selected_files = widget.as_ref()?.content.get_selected(); let file_names = selected_files.iter().map(|f| f.name.clone()).collect::<Vec<String>>(); @@ -424,6 +524,9 @@ impl Widget for FileBrowser { fn get_core(&self) -> HResult<&WidgetCore> { Ok(&self.core) } + fn get_core_mut(&mut self) -> HResult<&mut WidgetCore> { + Ok(&mut self.core) + } fn render_header(&self) -> HResult<String> { let xsize = self.get_coordinates()?.xsize(); let file = self.selected_file()?; @@ -449,9 +552,9 @@ impl Widget for FileBrowser { let group = file.pretty_group().unwrap_or("NOGROUP".into()); let mtime = file.pretty_mtime().unwrap_or("NOMTIME".into()); - - let selection = (*self.main_widget().as_ref().unwrap().lock()?).as_ref()?.get_selection(); - let file_count = (*self.main_widget()?.lock()?).as_ref()?.content.len(); + let main_widget = self.main_widget()?.widget()?; + let selection = main_widget.lock()?.as_ref().unwrap().get_selection(); + let file_count = main_widget.lock()?.as_ref().unwrap().content.len(); let file_count = format!("{}", file_count); let digits = file_count.len(); let file_count = format!("{:digits$}/{:digits$}", @@ -466,22 +569,23 @@ impl Widget for FileBrowser { } fn refresh(&mut self) -> HResult<()> { //self.proc_view.lock()?.set_coordinates(self.get_coordinates()?); - self.handle_dir_events()?; + self.handle_dir_events().ok(); self.columns.refresh().ok(); - self.fix_left().ok(); - self.fix_selection().ok(); + self.set_left_selection().log(); + self.save_selection().log(); self.set_cwd().ok(); self.update_watches().ok(); self.update_preview().ok(); + self.columns.refresh().ok(); Ok(()) } fn get_drawlist(&self) -> HResult<String> { - if self.columns.get_left_widget().is_err() { - Ok(self.columns.get_clearlist()? + &self.columns.get_drawlist()?) - } else { - Ok(self.columns.get_drawlist()?) - } + let left = self.left_widget()?.get_drawlist()?; + let main = self.main_widget()?.get_drawlist()?; + let prev = self.preview_widget()?.get_drawlist()?; + + Ok(left + &main + &prev) } fn on_key(&mut self, key: Key) -> HResult<()> { @@ -494,7 +598,7 @@ impl Widget for FileBrowser { self.proc_view.lock()?.popup()?; } , - _ => { self.columns.get_main_widget_mut()?.on_key(key)?; }, + _ => { self.main_widget_mut()?.on_key(key)?; }, } self.update_preview()?; Ok(()) |