From eb5a86b7cd37dc39d20f6ce122f671f94f51b75a Mon Sep 17 00:00:00 2001 From: rabite Date: Sat, 2 Mar 2019 19:39:24 +0100 Subject: [PATCH] moved window stuff to widget itself --- src/fail.rs | 35 +++- src/file_browser.rs | 176 ++++++++++---------- src/files.rs | 7 +- src/hbox.rs | 62 ++++--- src/listview.rs | 116 +++++++------ src/main.rs | 43 +++-- src/miller_columns.rs | 80 ++++----- src/minibuffer.rs | 34 ++-- src/preview.rs | 201 ++++++++++------------- src/proclist.rs | 135 +++++++-------- src/tabview.rs | 87 +++++----- src/term.rs | 30 +++- src/textview.rs | 71 ++++---- src/widget.rs | 325 +++++++++++++++++++++++++++--------- src/window.rs | 374 +++++++++++++++++++++--------------------- 15 files changed, 983 insertions(+), 793 deletions(-) diff --git a/src/fail.rs b/src/fail.rs index ff9ad2e..1c0575b 100644 --- a/src/fail.rs +++ b/src/fail.rs @@ -1,5 +1,6 @@ use failure; use failure::Fail; +use failure::Backtrace; use std::path::PathBuf; @@ -28,21 +29,45 @@ pub enum HError { #[fail(display = "Was None!")] NoneError, #[fail(display = "Not ready yet!")] - WillBeNotReady, + WillBeNotReady(Backtrace), #[fail(display = "No widget found")] - NoWidgetError, + NoWidgetError(Backtrace), #[fail(display = "Path: {:?} not in this directory: {:?}", path, dir)] WrongDirectoryError{ path: PathBuf, dir: PathBuf }, #[fail(display = "Widget finnished")] PopupFinnished, - #[fail(display = "Input finnished")] - InputFinnished, #[fail(display = "No completions found")] NoCompletionsError, #[fail(display = "No more history")] - NoHistoryError + NoHistoryError, + #[fail(display = "No core for widget")] + NoWidgetCoreError(Backtrace), + #[fail(display = "No header for widget")] + NoHeaderError, } +pub trait ErrorLog where Self: Sized { + fn log(self) {} +} + +impl ErrorLog for HResult { + fn log(self) { + if let Err(err) = self { + eprintln!("{:?}", err); + } + } +} + + + + +// impl From<&HError> for HError { +// fn from(error: &HError) -> Self { +// dbg!(&error); +// (error.clone()) +// } +// } + impl From for HError { fn from(error: std::io::Error) -> Self { dbg!(&error); diff --git a/src/file_browser.rs b/src/file_browser.rs index a950f0a..13533c1 100644 --- a/src/file_browser.rs +++ b/src/file_browser.rs @@ -1,22 +1,20 @@ use termion::event::Key; use notify::{INotifyWatcher, Watcher, DebouncedEvent, RecursiveMode}; -use std::error::Error; use std::io::Write; use std::sync::{Arc, Mutex}; -use std::sync::mpsc::{channel, Receiver}; +use std::sync::mpsc::{channel, Receiver, Sender}; use std::time::Duration; use std::path::PathBuf; -use crate::coordinates::{Coordinates}; 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::fail::{HResult, HError}; -use crate::window::{Events, send_event}; +use crate::fail::{HResult, HError, ErrorLog}; +use crate::widget::{Events, WidgetCore}; use crate::proclist::ProcView; @@ -24,6 +22,7 @@ use crate::proclist::ProcView; pub struct FileBrowser { pub columns: MillerColumns>>, pub cwd: File, + core: WidgetCore, watcher: INotifyWatcher, watches: Vec, dir_events: Arc>>, @@ -31,22 +30,24 @@ pub struct FileBrowser { } impl Tabbable for TabView { - fn new_tab(&mut self) { - let mut tab = FileBrowser::new().unwrap(); + fn new_tab(&mut self) -> HResult<()> { + let mut tab = FileBrowser::new_cored(&self.active_tab_().core)?; let proc_view = self.active_tab_().proc_view.clone(); tab.proc_view = proc_view; - self.push_widget(tab); + self.push_widget(tab)?; self.active += 1; + Ok(()) } - fn close_tab(&mut self) { - self.close_tab_(); + fn close_tab(&mut self) -> HResult<()> { + self.close_tab_() } - fn next_tab(&mut self) { + fn next_tab(&mut self) -> HResult<()> { self.next_tab_(); + Ok(()) } fn get_tab_names(&self) -> Vec> { @@ -66,18 +67,18 @@ impl Tabbable for TabView { self.active_tab_mut_() } - fn on_next_tab(&mut self) { - self.active_tab_mut().refresh(); + fn on_next_tab(&mut self) -> HResult<()> { + self.active_tab_mut().refresh() } - fn on_key_sub(&mut self, key: Key) { + fn on_key_sub(&mut self, key: Key) -> HResult<()> { match key { Key::Char('!') => { let tab_dirs = self.widgets.iter().map(|w| w.cwd.clone()) .collect::>(); - self.widgets[self.active].exec_cmd(tab_dirs).ok(); + self.widgets[self.active].exec_cmd(tab_dirs) } - _ => { self.active_tab_mut().on_key(key).ok(); } + _ => { self.active_tab_mut().on_key(key) } } } } @@ -86,11 +87,13 @@ impl Tabbable for TabView { -fn watch_dir(rx: Receiver, dir_events: Arc>>) { +fn watch_dir(rx: Receiver, + dir_events: Arc>>, + sender: Sender) { std::thread::spawn(move || { for event in rx.iter() { dir_events.lock().unwrap().push(event); - send_event(Events::WidgetReady).unwrap(); + sender.send(Events::WidgetReady).unwrap(); } }); } @@ -100,24 +103,23 @@ fn watch_dir(rx: Receiver, dir_events: Arc Result> { + pub fn new_cored(core: &WidgetCore) -> HResult { let cwd = std::env::current_dir().unwrap(); - let coords = Coordinates::new_at(crate::term::xsize(), - crate::term::ysize() - 2, - 1, - 2); + let coords = core.coordinates.clone(); + let core_ = core.clone(); - let mut miller = MillerColumns::new(); - miller.set_coordinates(&coords); + let mut miller = MillerColumns::new(core); + miller.set_coordinates(&coords)?; let (_, main_coords, _) = miller.calculate_coordinates(); let main_path: std::path::PathBuf = cwd.ancestors().take(1).map(|path| std::path::PathBuf::from(path)).collect(); - let main_widget = WillBeWidget::new(Box::new(move |_| { - let mut list = ListView::new(Files::new_from_path(&main_path).unwrap()); - list.set_coordinates(&main_coords); - list.animate_slide_up(); + let main_widget = WillBeWidget::new(&core, Box::new(move |_| { + let mut list = ListView::new(&core_, + Files::new_from_path(&main_path).unwrap()); + list.set_coordinates(&main_coords).log(); + list.animate_slide_up().log(); Ok(list) })); @@ -129,13 +131,14 @@ impl FileBrowser { let (tx_watch, rx_watch) = channel(); let watcher = INotifyWatcher::new(tx_watch, Duration::from_secs(2)).unwrap(); - watch_dir(rx_watch, dir_events.clone()); + watch_dir(rx_watch, dir_events.clone(), core.get_sender()); - let mut proc_view = ProcView::new(); - proc_view.set_coordinates(&coords); + let mut proc_view = ProcView::new(core); + proc_view.set_coordinates(&coords).log(); Ok(FileBrowser { columns: miller, cwd: cwd, + core: core.clone(), watcher: watcher, watches: vec![], dir_events: dir_events, @@ -145,16 +148,17 @@ 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(Box::new(move |_| { + let view = WillBeWidget::new(&core.clone(), Box::new(move |_| { let files = files.clone(); - let mut list = ListView::new(files); - list.set_coordinates(&coords); - list.animate_slide_up(); + let mut list = ListView::new(&core, files); + list.set_coordinates(&coords).log(); + list.animate_slide_up().log(); Ok(list) })); self.columns.push_widget(view); @@ -167,12 +171,12 @@ impl FileBrowser { match status { Ok(status) => self.show_status(&format!("\"{}\" exited with {}", - "rifle", status)), + "rifle", status)).log(), Err(err) => self.show_status(&format!("Can't run this \"{}\": {}", - "rifle", err)) + "rifle", err)).log() - } + }; } } Ok(()) @@ -185,8 +189,7 @@ impl FileBrowser { self.cwd = new_cwd; } - self.refresh(); - Ok(()) + self.refresh() } pub fn update_preview(&mut self) -> HResult<()> { @@ -207,10 +210,12 @@ impl FileBrowser { let cwd = self.selected_file()?.clone(); if let Ok(grand_parent) = cwd.grand_parent_as_file() { let (coords, _, _) = self.columns.calculate_coordinates(); - let left_view = WillBeWidget::new(Box::new(move |_| { + let core = self.core.clone(); + let left_view = WillBeWidget::new(&self.core, Box::new(move |_| { let mut view - = ListView::new(Files::new_from_path(&grand_parent.path)?); - view.set_coordinates(&coords); + = ListView::new(&core, + Files::new_from_path(&grand_parent.path)?); + view.set_coordinates(&coords).log(); Ok(view) })); self.columns.prepend_widget(left_view); @@ -341,17 +346,19 @@ impl FileBrowser { 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 middle = WillBeWidget::new(Box::new(move |_| { + let middle = WillBeWidget::new(&self.core, Box::new(move |_| { let files = Files::new_from_path(&dir.clone())?; - let mut listview = ListView::new(files); - listview.set_coordinates(&main_coords); + let mut listview = ListView::new(&mcore, files); + listview.set_coordinates(&main_coords).log(); Ok(listview) })); - let left = WillBeWidget::new(Box::new(move |_| { + let left = WillBeWidget::new(&self.core, Box::new(move |_| { let files = Files::new_from_path(&left_dir.parent()?)?; - let mut listview = ListView::new(files); - listview.set_coordinates(&left_coords); + let mut listview = ListView::new(&lcore, files); + listview.set_coordinates(&left_coords).log(); Ok(listview) })); self.columns.push_widget(left); @@ -373,7 +380,7 @@ impl FileBrowser { let cmd = self.minibuffer("exec:")?; - self.show_status(&format!("Running: \"{}\"", &cmd)); + self.show_status(&format!("Running: \"{}\"", &cmd)).log(); let mut cmd = if file_names.len() == 0 { cmd.replace("$s", &format!("{}", &filename)) @@ -397,35 +404,28 @@ impl FileBrowser { } impl Widget for FileBrowser { - fn get_coordinates(&self) -> &Coordinates { - &self.columns.coordinates + fn get_core(&self) -> HResult<&WidgetCore> { + Ok(&self.core) } - fn set_coordinates(&mut self, coordinates: &Coordinates) { - self.columns.set_coordinates(coordinates); - self.proc_view.lock().unwrap().set_coordinates(coordinates); - self.refresh(); - } - fn render_header(&self) -> String { - if self.main_widget().is_err() { return "".to_string() } - let xsize = self.get_coordinates().xsize(); - let file = self.selected_file().unwrap(); + fn render_header(&self) -> HResult { + let xsize = self.get_coordinates()?.xsize(); + let file = self.selected_file()?; let name = &file.name; let color = if file.is_dir() || file.color.is_none() { crate::term::highlight_color() } else { crate::term::from_lscolor(file.color.as_ref().unwrap()) }; - let path = file.path.parent().unwrap().to_string_lossy().to_string(); + let path = file.path.parent()?.to_string_lossy().to_string(); let pretty_path = format!("{}/{}{}", path, &color, name ); let sized_path = crate::term::sized_string(&pretty_path, xsize); - sized_path + Ok(sized_path) } - fn render_footer(&self) -> String { - if self.main_widget().is_err() { return "".to_string() } - let xsize = self.get_coordinates().xsize(); - let ypos = self.get_coordinates().position().y(); - let file = self.selected_file().unwrap(); + fn render_footer(&self) -> HResult { + let xsize = self.get_coordinates()?.xsize(); + let ypos = self.get_coordinates()?.position().y(); + let file = self.selected_file()?; let permissions = file.pretty_print_permissions().unwrap_or("NOPERMS".into()); let user = file.pretty_user().unwrap_or("NOUSER".into()); @@ -433,8 +433,8 @@ impl Widget for FileBrowser { let mtime = file.pretty_mtime().unwrap_or("NOMTIME".into()); - let selection = (*self.main_widget().as_ref().unwrap().lock().unwrap()).as_ref().unwrap().get_selection(); - let file_count = (*self.main_widget().unwrap().lock().unwrap()).as_ref().unwrap().content.len(); + 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 file_count = format!("{}", file_count); let digits = file_count.len(); let file_count = format!("{:digits$}/{:digits$}", @@ -442,42 +442,44 @@ impl Widget for FileBrowser { file_count, digits = digits); let count_xpos = xsize - file_count.len() as u16; - let count_ypos = ypos + self.get_coordinates().ysize(); + let count_ypos = ypos + self.get_coordinates()?.ysize(); - format!("{} {}:{} {} {} {}", permissions, user, group, mtime, - crate::term::goto_xy(count_xpos, count_ypos), file_count) + Ok(format!("{} {}:{} {} {} {}", permissions, user, group, mtime, + crate::term::goto_xy(count_xpos, count_ypos), file_count)) } - fn refresh(&mut self) { - self.handle_dir_events().ok(); - self.columns.refresh(); + fn refresh(&mut self) -> HResult<()> { + //self.proc_view.lock()?.set_coordinates(self.get_coordinates()?); + self.handle_dir_events()?; + self.columns.refresh().ok(); self.fix_left().ok(); self.fix_selection().ok(); self.set_cwd().ok(); self.update_watches().ok(); self.update_preview().ok(); + Ok(()) } - fn get_drawlist(&self) -> String { + fn get_drawlist(&self) -> HResult { if self.columns.get_left_widget().is_err() { - self.columns.get_clearlist() + &self.columns.get_drawlist() + Ok(self.columns.get_clearlist()? + &self.columns.get_drawlist()?) } else { - self.columns.get_drawlist() + Ok(self.columns.get_drawlist()?) } } fn on_key(&mut self, key: Key) -> HResult<()> { match key { - Key::Char('/') => { self.turbo_cd().ok(); }, - Key::Char('Q') => { self.quit_with_dir().ok(); }, - Key::Right | Key::Char('f') => { self.enter_dir().ok(); }, - Key::Left | Key::Char('b') => { self.go_back().ok(); }, + Key::Char('/') => { self.turbo_cd()?; }, + Key::Char('Q') => { self.quit_with_dir()?; }, + Key::Right | Key::Char('f') => { self.enter_dir()?; }, + Key::Left | Key::Char('b') => { self.go_back()?; }, Key::Char('w') => { - self.proc_view.lock()?.popup().ok(); + self.proc_view.lock()?.popup()?; } , - _ => { self.columns.get_main_widget_mut()?.on_key(key).ok(); }, + _ => { self.columns.get_main_widget_mut()?.on_key(key)?; }, } - self.update_preview().ok(); + self.update_preview()?; Ok(()) } } diff --git a/src/files.rs b/src/files.rs index 44863e6..fe0dc8b 100644 --- a/src/files.rs +++ b/src/files.rs @@ -2,17 +2,18 @@ use std::cmp::{Ord, Ordering}; use std::ops::Index; use std::os::unix::fs::MetadataExt; use std::path::{Path, PathBuf}; +use std::sync::{Arc, Mutex}; use lscolors::LsColors; use mime_detective; use users; use chrono::TimeZone; use failure::Error; -use notify::{INotifyWatcher, Watcher, DebouncedEvent, RecursiveMode}; +use notify::DebouncedEvent; use crate::fail::{HResult, HError}; -use std::sync::{Arc, Mutex}; + lazy_static! { @@ -200,7 +201,7 @@ impl Files { DebouncedEvent::Write(path) | DebouncedEvent::Chmod(path) => { self.path_in_here(&path)?; let file = self.find_file_with_path(&path)?; - file.reload_meta(); + file.reload_meta()?; }, DebouncedEvent::Remove(path) => { self.path_in_here(&path)?; diff --git a/src/hbox.rs b/src/hbox.rs index 7e27656..6a2aa8e 100644 --- a/src/hbox.rs +++ b/src/hbox.rs @@ -1,20 +1,20 @@ use termion::event::{Event}; -use crate::widget::Widget; +use crate::widget::{Widget, WidgetCore}; use crate::coordinates::{Coordinates, Size, Position}; -use crate::fail::HResult; +use crate::fail::{HResult, ErrorLog}; #[derive(PartialEq)] pub struct HBox { - pub coordinates: Coordinates, + pub core: WidgetCore, pub widgets: Vec, pub active: Option, } impl HBox where T: Widget + PartialEq { - pub fn new() -> HBox { - HBox { coordinates: Coordinates::new(), + pub fn new(core: &WidgetCore) -> HBox { + HBox { core: core.clone(), widgets: vec![], active: None } @@ -27,34 +27,35 @@ impl HBox where T: Widget + PartialEq { |w| self.calculate_coordinates(w)).collect(); for (widget, coord) in self.widgets.iter_mut().zip(coords.iter()) { - widget.set_coordinates(coord); + widget.set_coordinates(coord).log(); } } pub fn push_widget(&mut self, widget: T) where T: PartialEq { self.widgets.push(widget); self.resize_children(); - self.refresh(); + self.refresh().log(); } pub fn pop_widget(&mut self) -> Option { let widget = self.widgets.pop(); self.resize_children(); - self.refresh(); + self.refresh().log(); widget } pub fn prepend_widget(&mut self, widget: T) { self.widgets.insert(0, widget); self.resize_children(); - self.refresh(); + self.refresh().log(); } - pub fn calculate_coordinates(&self, widget: &T) + pub fn calculate_coordinates(&self, widget: &T) -> Coordinates where T: PartialEq { - let xsize = self.coordinates.xsize(); - let ysize = self.coordinates.ysize(); - let top = self.coordinates.top().y(); + let coordinates = self.get_coordinates().unwrap(); + let xsize = coordinates.xsize(); + let ysize = coordinates.ysize(); + let top = coordinates.top().y(); let pos = self.widgets.iter().position(|w | w == widget).unwrap(); let num = self.widgets.len(); @@ -69,7 +70,7 @@ impl HBox where T: Widget + PartialEq { top)) } } - + pub fn active_widget(&self) -> &T { &self.widgets.last().unwrap() } @@ -80,35 +81,32 @@ impl HBox where T: Widget + PartialEq { impl Widget for HBox where T: Widget + PartialEq { - fn render_header(&self) -> String { + 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 { self.active_widget().render_header() } - fn refresh(&mut self) { + fn refresh(&mut self) -> HResult<()> { self.resize_children(); for child in &mut self.widgets { - child.refresh(); + child.refresh()? } + Ok(()) } - fn get_drawlist(&self) -> String { - self.widgets.iter().map(|child| { - child.get_drawlist() - }).collect() + fn get_drawlist(&self) -> HResult { + Ok(self.widgets.iter().map(|child| { + child.get_drawlist().unwrap() + }).collect()) } - fn get_coordinates(&self) -> &Coordinates { - &self.coordinates - } - fn set_coordinates(&mut self, coordinates: &Coordinates) { - if self.coordinates == *coordinates { - return; - } - self.coordinates = coordinates.clone(); - self.refresh(); - } fn on_event(&mut self, event: Event) -> HResult<()> { - self.widgets.last_mut()?.on_event(event).ok(); + self.widgets.last_mut()?.on_event(event)?; Ok(()) } } diff --git a/src/listview.rs b/src/listview.rs index 0a25dca..64ec5ac 100644 --- a/src/listview.rs +++ b/src/listview.rs @@ -3,17 +3,16 @@ use unicode_width::UnicodeWidthStr; use std::path::{Path, PathBuf}; -use crate::coordinates::{Coordinates, Position, Size}; use crate::files::{File, Files}; -use crate::fail::HResult; +use crate::fail::{HResult, ErrorLog}; use crate::term; -use crate::widget::{Widget}; +use crate::widget::{Widget, WidgetCore}; pub trait Listable { fn len(&self) -> usize; fn render(&self) -> Vec; - fn on_refresh(&mut self) {} - fn on_key(&mut self, _key: Key) {} + fn on_refresh(&mut self) -> HResult<()> { Ok(()) } + fn on_key(&mut self, _key: Key) -> HResult<()> { Ok(()) } } impl Listable for ListView { @@ -25,26 +24,27 @@ impl Listable for ListView { self.render() } - fn on_refresh(&mut self) { - let visible_file_num = self.selection + self.get_coordinates().ysize() as usize; + fn on_refresh(&mut self) -> HResult<()> { + let visible_file_num = self.selection + self.get_coordinates()?.ysize() as usize; self.content.meta_upto(visible_file_num); + Ok(()) } - fn on_key(&mut self, key: Key) { + fn on_key(&mut self, key: Key) -> HResult<()> { match key { Key::Up | Key::Char('p') => { self.move_up(); - self.refresh(); + self.refresh()?; } - Key::Char('P') => { for _ in 0..10 { self.move_up() } self.refresh(); } - Key::Char('N') => { for _ in 0..10 { self.move_down() } self.refresh(); } + Key::Char('P') => { for _ in 0..10 { self.move_up() } self.refresh()?; } + Key::Char('N') => { for _ in 0..10 { self.move_down() } self.refresh()?; } Key::Down | Key::Char('n') => { self.move_down(); - self.refresh(); + self.refresh()?; }, Key::Ctrl('s') => { self.find_file().ok(); } - Key::Left => self.goto_grand_parent(), - Key::Right => self.goto_selected(), + Key::Left => self.goto_grand_parent()?, + Key::Right => self.goto_selected()?, Key::Char(' ') => self.multi_select_file(), Key::Char('h') => self.toggle_hidden(), Key::Char('r') => self.reverse_sort(), @@ -52,8 +52,9 @@ impl Listable for ListView { Key::Char('K') => self.select_next_mtime(), Key::Char('k') => self.select_prev_mtime(), Key::Char('d') => self.toggle_dirs_first(), - _ => self.bad(Event::Key(key)) + _ => { self.bad(Event::Key(key))?; } } + Ok(()) } } @@ -65,7 +66,7 @@ pub struct ListView where ListView: Listable selection: usize, offset: usize, buffer: Vec, - coordinates: Coordinates, + core: WidgetCore, seeking: bool, } @@ -74,17 +75,14 @@ where ListView: Widget, ListView: Listable { - pub fn new(content: T) -> ListView { + pub fn new(core: &WidgetCore, content: T) -> ListView { let view = ListView:: { content: content, lines: 0, selection: 0, offset: 0, buffer: Vec::new(), - coordinates: Coordinates { - size: Size((1, 1)), - position: Position((1, 1)), - }, + core: core.clone(), seeking: false }; view @@ -104,7 +102,7 @@ where } pub fn move_down(&mut self) { let lines = self.lines; - let y_size = self.coordinates.ysize() as usize; + let y_size = self.get_coordinates().unwrap().ysize() as usize; if self.lines == 0 || self.selection == lines - 1 { return; @@ -123,7 +121,7 @@ where } fn set_selection(&mut self, position: usize) { - let ysize = self.coordinates.ysize() as usize; + let ysize = self.get_coordinates().unwrap().ysize() as usize; let mut offset = 0; while position + 2 @@ -145,7 +143,7 @@ where } else { (name.clone(), "".to_string()) }; - let xsize = self.get_coordinates().xsize(); + let xsize = self.get_coordinates().unwrap().xsize(); let sized_string = term::sized_string(&name, xsize); let size_pos = xsize - (size.to_string().len() as u16 + unit.to_string().len() as u16); @@ -202,30 +200,29 @@ impl ListView self.selected_file().grand_parent() } - pub fn goto_grand_parent(&mut self) { + pub fn goto_grand_parent(&mut self) -> HResult<()> { match self.grand_parent() { Some(grand_parent) => self.goto_path(&grand_parent), - None => self.show_status("Can't go further!"), + None => { self.show_status("Can't go further!") }, } } - fn goto_selected(&mut self) { + fn goto_selected(&mut self) -> HResult<()> { let path = self.selected_file().path(); - self.goto_path(&path); + self.goto_path(&path) } - pub fn goto_path(&mut self, path: &Path) { + pub fn goto_path(&mut self, path: &Path) -> HResult<()> { match crate::files::Files::new_from_path(path) { Ok(files) => { self.content = files; self.selection = 0; self.offset = 0; - self.refresh(); + self.refresh() } Err(err) => { - self.show_status(&format!("Can't open this path: {}", err)); - return; + self.show_status(&format!("Can't open this path: {}", err)) } } } @@ -245,8 +242,8 @@ impl ListView self.content.cycle_sort(); self.content.sort(); self.select_file(&file); - self.refresh(); - self.show_status(&format!("Sorting by: {}", self.content.sort)); + self.refresh().log(); + self.show_status(&format!("Sorting by: {}", self.content.sort)).log(); } fn reverse_sort(&mut self) { @@ -254,8 +251,8 @@ impl ListView self.content.reverse_sort(); self.content.sort(); self.select_file(&file); - self.refresh(); - self.show_status(&format!("Reversed sorting by: {}", self.content.sort)); + self.refresh().log(); + self.show_status(&format!("Reversed sorting by: {}", self.content.sort)).log(); } fn select_next_mtime(&mut self) { @@ -283,7 +280,7 @@ impl ListView self.select_file(&file); self.seeking = true; - self.refresh(); + self.refresh().log(); } fn select_prev_mtime(&mut self) { @@ -310,7 +307,7 @@ impl ListView self.select_file(&file); self.seeking = true; - self.refresh(); + self.refresh().log(); } fn toggle_hidden(&mut self) { @@ -318,7 +315,7 @@ impl ListView self.content.toggle_hidden(); self.content.reload_files(); self.select_file(&file); - self.refresh(); + self.refresh().log(); } fn toggle_dirs_first(&mut self) { @@ -326,15 +323,16 @@ impl ListView self.content.dirs_first = !self.content.dirs_first; self.content.sort(); self.select_file(&file); - self.refresh(); - self.show_status(&format!("Direcories first: {}", self.content.dirs_first)); + self.refresh().log(); + self.show_status(&format!("Direcories first: {}", + self.content.dirs_first)).log(); } fn multi_select_file(&mut self) { let file = self.selected_file_mut(); file.toggle_selection(); self.move_down(); - self.refresh(); + self.refresh().log(); } fn find_file(&mut self) -> HResult<()> { @@ -352,7 +350,7 @@ impl ListView } fn render(&self) -> Vec { - let ysize = self.get_coordinates().ysize() as usize; + let ysize = self.get_coordinates().unwrap().ysize() as usize; let offset = self.offset; self.content .files @@ -366,29 +364,26 @@ impl ListView impl Widget for ListView where ListView: Listable { - fn get_coordinates(&self) -> &Coordinates { - &self.coordinates + fn get_core(&self) -> HResult<&WidgetCore> { + Ok(&self.core) } - fn set_coordinates(&mut self, coordinates: &Coordinates) { - if self.coordinates == *coordinates { - return; - } - self.coordinates = coordinates.clone(); - self.refresh(); + fn get_core_mut(&mut self) -> HResult<&mut WidgetCore> { + Ok(&mut self.core) } - fn refresh(&mut self) { - self.on_refresh(); + fn refresh(&mut self) -> HResult<()> { + self.on_refresh().log(); self.lines = self.len(); if self.selection >= self.lines && self.selection != 0 { self.selection -= 1; } self.buffer = self.render(); + Ok(()) } - fn get_drawlist(&self) -> String { + fn get_drawlist(&self) -> HResult { let mut output = term::reset(); - let (xpos, ypos) = self.coordinates.position().position(); + let (xpos, ypos) = self.get_coordinates().unwrap().position().position(); output += &self .buffer @@ -410,16 +405,15 @@ impl Widget for ListView where ListView: Listable { }) .collect::(); - output += &self.get_redraw_empty_list(self.buffer.len()); + output += &self.get_redraw_empty_list(self.buffer.len())?; - output + Ok(output) } - fn render_header(&self) -> String { - format!("{} files", self.len()) + fn render_header(&self) -> HResult { + Ok(format!("{} files", self.len())) } fn on_key(&mut self, key: Key) -> HResult<()> { - Listable::on_key(self, key); - Ok(()) + Listable::on_key(self, key) } } diff --git a/src/main.rs b/src/main.rs index 09d05d9..b8ecd00 100644 --- a/src/main.rs +++ b/src/main.rs @@ -18,6 +18,8 @@ extern crate rayon; extern crate libc; extern crate notify; +use failure::Fail; + use termion::input::MouseTerminal; use termion::raw::IntoRawMode; use termion::screen::AlternateScreen; @@ -34,7 +36,6 @@ mod term; mod textview; mod widget; mod win_main; -mod window; mod hbox; mod tabview; mod async_widget; @@ -45,23 +46,41 @@ mod proclist; -use window::Window; +use widget::{Widget, WidgetCore}; +use term::ScreenExt; +use fail::HResult; +use file_browser::FileBrowser; +use tabview::TabView; -fn main() { +fn main() -> HResult<()> { + match run() { + Ok(_) => Ok(()), + Err(err) => { + eprintln!("{:?}\n{:?}", err, err.cause()); + return Err(err); + } + } +} + +fn run() -> HResult<()> { let bufout = std::io::BufWriter::new(std::io::stdout()); // Need to do this here to actually turn terminal into raw mode... - let mut _screen = AlternateScreen::from(Box::new(bufout)); - let mut _stdout = MouseTerminal::from(stdout().into_raw_mode().unwrap()); + let mut screen = AlternateScreen::from(bufout); + let mut _stdout = MouseTerminal::from(stdout().into_raw_mode()?); + screen.cursor_hide()?; + screen.flush()?; + let core = WidgetCore::new()?; - let filebrowser = crate::file_browser::FileBrowser::new().unwrap(); - let mut tabview = crate::tabview::TabView::new(); - tabview.push_widget(filebrowser); + let filebrowser = FileBrowser::new_cored(&core)?; + let mut tabview = TabView::new(&core); + tabview.push_widget(filebrowser)?; - let mut win = Window::new(tabview); - win.draw(); - win.handle_input(); + tabview.handle_input()?; - write!(_stdout, "{}", termion::cursor::Show).unwrap(); + screen.cursor_show()?; + screen.flush()?; + + Ok(()) } diff --git a/src/miller_columns.rs b/src/miller_columns.rs index e6c5c54..3a240cb 100644 --- a/src/miller_columns.rs +++ b/src/miller_columns.rs @@ -1,43 +1,44 @@ use termion::event::Key; +use failure::Backtrace; use crate::coordinates::{Coordinates, Position, Size}; use crate::preview::Previewer; -use crate::widget::Widget; +use crate::widget::{Widget, WidgetCore}; use crate::hbox::HBox; -use crate::fail::{HError, HResult}; +use crate::fail::{HError, HResult, ErrorLog}; #[derive(PartialEq)] pub struct MillerColumns where T: Widget { pub widgets: HBox, + pub core: WidgetCore, // pub left: Option, // pub main: Option, //pub preview: AsyncPreviewer, pub preview: Previewer, pub ratio: (u16, u16, u16), - pub coordinates: Coordinates, } impl MillerColumns where T: Widget + PartialEq, { - pub fn new() -> MillerColumns { + pub fn new(core: &WidgetCore) -> MillerColumns { MillerColumns { - widgets: HBox::new(), - coordinates: Coordinates::new(), + widgets: HBox::new(core), + core: core.clone(), ratio: (20, 30, 50), - preview: Previewer::new() + preview: Previewer::new(core) } } pub fn push_widget(&mut self, widget: T) { self.widgets.push_widget(widget); - self.refresh(); + self.refresh().log(); } pub fn pop_widget(&mut self) -> Option { let widget = self.widgets.pop_widget(); - self.refresh(); + self.refresh().log(); widget } @@ -46,14 +47,15 @@ where } pub fn calculate_coordinates(&self) -> (Coordinates, Coordinates, Coordinates) { - let xsize = self.coordinates.xsize(); - let ysize = self.coordinates.ysize(); - let top = self.coordinates.top().y(); + let coordinates = self.get_coordinates().unwrap(); + let xsize = coordinates.xsize(); + let ysize = coordinates.ysize(); + let top = coordinates.top().y(); let ratio = self.ratio; let left_xsize = xsize * ratio.0 / 100; let left_size = Size((left_xsize, ysize)); - let left_pos = self.coordinates.top(); + let left_pos = coordinates.top(); let main_xsize = xsize * ratio.1 / 100; let main_size = Size((main_xsize, ysize)); @@ -84,7 +86,7 @@ where pub fn get_left_widget(&self) -> HResult<&T> { let len = self.widgets.widgets.len(); if len < 2 { - return Err(HError::NoWidgetError); + return Err(HError::NoWidgetError(Backtrace::new())); } let widget = self.widgets.widgets.get(len - 2)?; Ok(widget) @@ -92,7 +94,7 @@ where pub fn get_left_widget_mut(&mut self) -> HResult<&mut T> { let len = self.widgets.widgets.len(); if len < 2 { - return Err(HError::NoWidgetError); + return Err(HError::NoWidgetError(Backtrace::new())); } let widget = self.widgets.widgets.get_mut(len - 2)?; Ok(widget) @@ -112,51 +114,39 @@ where T: Widget, T: PartialEq { - fn get_coordinates(&self) -> &Coordinates { - &self.coordinates + fn get_core(&self) -> HResult<&WidgetCore> { + Ok(&self.core) } - fn set_coordinates(&mut self, coordinates: &Coordinates) { - if self.coordinates == *coordinates { - return; - } - self.coordinates = coordinates.clone(); - self.refresh(); + fn get_core_mut(&mut self) -> HResult<&mut WidgetCore> { + Ok(&mut self.core) } - fn render_header(&self) -> String { - "".to_string() - } - fn refresh(&mut self) { + fn refresh(&mut self) -> HResult<()> { let (left_coords, main_coords, preview_coords) = self.calculate_coordinates(); if let Ok(left_widget) = self.get_left_widget_mut() { - left_widget.set_coordinates(&left_coords); + left_widget.set_coordinates(&left_coords).log(); } if let Ok(main_widget) = self.get_main_widget_mut() { - main_widget.set_coordinates(&main_coords); + main_widget.set_coordinates(&main_coords).log(); } let preview_widget = &mut self.preview; - preview_widget.set_coordinates(&preview_coords); + preview_widget.set_coordinates(&preview_coords)?; + Ok(()) } - fn get_drawlist(&self) -> String { - let left_widget = match self.get_left_widget() { - Ok(widget) => widget.get_drawlist(), - Err(_) => "".into(), - }; - let main_widget = self.get_main_widget(); - match main_widget { - Ok(main_widget) => { - let preview = self.preview.get_drawlist(); - format!("{}{}{}", main_widget.get_drawlist(), left_widget, preview) - } - Err(_) => "".to_string() - } + fn get_drawlist(&self) -> HResult { + let left_widget = self.get_left_widget()?; + let main_widget = self.get_main_widget()?; + let preview = self.preview.get_drawlist()?; + Ok(format!("{}{}{}", + main_widget.get_drawlist()?, + left_widget.get_drawlist()?, + preview)) } fn on_key(&mut self, key: Key) -> HResult<()> { - self.get_main_widget_mut().unwrap().on_key(key); - Ok(()) + self.get_main_widget_mut().unwrap().on_key(key) } } diff --git a/src/minibuffer.rs b/src/minibuffer.rs index 985fbd5..f9a0f2f 100644 --- a/src/minibuffer.rs +++ b/src/minibuffer.rs @@ -2,12 +2,13 @@ use termion::event::Key; use std::io::{stdout, Write}; use crate::coordinates::{Coordinates}; -use crate::widget::Widget; +use crate::widget::{Widget, WidgetCore}; use crate::fail::{HResult, HError}; use crate::term; +#[derive(Debug)] pub struct MiniBuffer { - coordinates: Coordinates, + core: WidgetCore, query: String, input: String, position: usize, @@ -18,12 +19,14 @@ pub struct MiniBuffer { } impl MiniBuffer { - pub fn new() -> MiniBuffer { + pub fn new(core: &WidgetCore) -> MiniBuffer { let xsize = crate::term::xsize(); let ysize = crate::term::ysize(); let coordinates = Coordinates::new_at(xsize, 1, 1, ysize); + let mut core = core.clone(); + core.coordinates = coordinates; MiniBuffer { - coordinates: coordinates, + core: core, query: String::new(), input: String::new(), position: 0, @@ -283,26 +286,23 @@ pub fn find_files(comp_name: String) -> HResult> { } impl Widget for MiniBuffer { - fn get_coordinates(&self) -> &Coordinates { - &self.coordinates + fn get_core(&self) -> HResult<&WidgetCore> { + Ok(&self.core) } - fn set_coordinates(&mut self, coordinates: &Coordinates) { - self.coordinates = coordinates.clone(); - self.refresh(); + fn get_core_mut(&mut self) -> HResult<&mut WidgetCore> { + Ok(&mut self.core) } - fn render_header(&self) -> String { - "".to_string() - } - fn refresh(&mut self) { + fn refresh(&mut self) -> HResult<()> { + Ok(()) } - fn get_drawlist(&self) -> String { - let (xpos, ypos) = self.get_coordinates().u16position(); - format!("{}{}{}: {}", + fn get_drawlist(&self) -> HResult { + let (xpos, ypos) = self.get_coordinates()?.u16position(); + Ok(format!("{}{}{}: {}", crate::term::goto_xy(xpos, ypos), termion::clear::CurrentLine, self.query, - self.input) + self.input)) } fn on_key(&mut self, key: Key) -> HResult<()> { diff --git a/src/preview.rs b/src/preview.rs index fade5b2..c780588 100644 --- a/src/preview.rs +++ b/src/preview.rs @@ -1,14 +1,15 @@ use std::sync::{Arc, Mutex}; -use crate::coordinates::{Coordinates}; +use failure::Backtrace; + use crate::files::{File, Files, Kind}; use crate::listview::ListView; use crate::textview::TextView; -use crate::widget::Widget; -use crate::fail::HError; +use crate::widget::{Widget, WidgetCore}; +use crate::fail::{HResult, HError, ErrorLog}; + -type HResult = Result; type HClosure = Box>) -> Result + Send>; type WidgetO = Box; @@ -63,8 +64,8 @@ impl WillBe where { let got_thing = closure(stale); match got_thing { Ok(got_thing) => { - *thing.try_lock().unwrap() = Some(got_thing); - *state.try_lock().unwrap() = State::Is; + *thing.lock().unwrap() = Some(got_thing); + *state.lock().unwrap() = State::Is; match *on_ready_fn.lock().unwrap() { Some(ref on_ready) => { on_ready(thing.clone()).ok(); }, None => {} @@ -76,14 +77,14 @@ impl WillBe where { } pub fn set_stale(&mut self) -> HResult<()> { - *self.stale.try_lock()? = true; + *self.stale.lock()? = true; Ok(()) } pub fn check(&self) -> HResult<()> { - match *self.state.try_lock()? { + match *self.state.lock()? { State::Is => Ok(()), - _ => Err(HError::WillBeNotReady) + _ => Err(HError::WillBeNotReady(Backtrace::new())) } } @@ -93,15 +94,16 @@ impl WillBe where { if self.check().is_ok() { fun(self.thing.clone())?; } else { - *self.on_ready.try_lock()? = Some(fun); + *self.on_ready.lock()? = Some(fun); } Ok(()) } } -impl PartialEq for WillBeWidget { +impl PartialEq for WillBeWidget { fn eq(&self, other: &WillBeWidget) -> bool { - if self.coordinates == other.coordinates { + if self.get_coordinates().unwrap() == + other.get_coordinates().unwrap() { true } else { false @@ -111,19 +113,20 @@ impl PartialEq for WillBeWidget { pub struct WillBeWidget { willbe: WillBe, - coordinates: Coordinates + core: WidgetCore } impl WillBeWidget { - pub fn new(closure: HClosure) -> WillBeWidget { + pub fn new(core: &WidgetCore, closure: HClosure) -> WillBeWidget { + let sender = core.get_sender(); let mut willbe = WillBe::new_become(Box::new(move |stale| closure(stale))); - willbe.on_ready(Box::new(|_| { - crate::window::send_event(crate::window::Events::WidgetReady)?; + willbe.on_ready(Box::new(move |_| { + sender.send(crate::widget::Events::WidgetReady)?; Ok(()) })).ok(); WillBeWidget { willbe: willbe, - coordinates: Coordinates::new() + core: core.clone() } } pub fn set_stale(&mut self) -> HResult<()> { @@ -147,49 +150,36 @@ impl WillBeWidget { //} impl Widget for WillBeWidget { - fn get_coordinates(&self) -> &Coordinates { - &self.coordinates + fn get_core(&self) -> HResult<&WidgetCore> { + Ok(&self.core) } - fn set_coordinates(&mut self, coordinates: &Coordinates) { - self.coordinates = coordinates.clone(); - - { - if self.willbe.check().is_err() { return } - let widget = self.widget().unwrap(); - let mut widget = widget.try_lock().unwrap(); - let widget = widget.as_mut().unwrap(); - widget.set_coordinates(&coordinates.clone()); - } - - self.refresh(); + fn get_core_mut(&mut self) -> HResult<&mut WidgetCore> { + Ok(&mut self.core) } - fn render_header(&self) -> String { - "".to_string() + fn refresh(&mut self) -> HResult<()> { + let widget = self.widget()?; + let mut widget = widget.lock()?; + let widget = widget.as_mut()?; + widget.set_coordinates(self.get_coordinates()?).log(); + widget.refresh() } - fn refresh(&mut self) { - if self.willbe.check().is_err() { return } - let widget = self.widget().unwrap(); - let mut widget = widget.try_lock().unwrap(); - let widget = widget.as_mut().unwrap(); - widget.refresh(); - } - fn get_drawlist(&self) -> String { + fn get_drawlist(&self) -> HResult { if self.willbe.check().is_err() { - let clear = self.get_clearlist(); - let (xpos, ypos) = self.get_coordinates().u16position(); + let clear = self.get_clearlist()?; + let (xpos, ypos) = self.get_coordinates()?.u16position(); let pos = crate::term::goto_xy(xpos, ypos); - return clear + &pos + "..." + return Ok(clear + &pos + "...") } - let widget = self.widget().unwrap(); - let widget = widget.try_lock().unwrap(); - let widget = widget.as_ref().unwrap(); + let widget = self.widget()?; + let widget = widget.lock()?; + let widget = widget.as_ref()?; widget.get_drawlist() } fn on_key(&mut self, key: termion::event::Key) -> HResult<()> { if self.willbe.check().is_err() { return Ok(()) } - let widget = self.widget().unwrap(); - let mut widget = widget.try_lock().unwrap(); - let widget = widget.as_mut().unwrap(); + let widget = self.widget()?; + let mut widget = widget.lock()?; + let widget = widget.as_mut()?; widget.on_key(key) } } @@ -197,7 +187,8 @@ impl Widget for WillBeWidget { impl PartialEq for Previewer { fn eq(&self, other: &Previewer) -> bool { - if self.widget.coordinates == other.widget.coordinates { + if self.widget.get_coordinates().unwrap() == + other.widget.get_coordinates().unwrap() { true } else { false @@ -207,59 +198,61 @@ impl PartialEq for Previewer { pub struct Previewer { widget: WillBeWidget>, + core: WidgetCore, file: Option } impl Previewer { - pub fn new() -> Previewer { - let willbe = WillBeWidget::new(Box::new(move |_| { - Ok(Box::new(crate::textview::TextView::new_blank()) + pub fn new(core: &WidgetCore) -> Previewer { + let core_ = core.clone(); + let willbe = WillBeWidget::new(&core, Box::new(move |_| { + Ok(Box::new(crate::textview::TextView::new_blank(&core_)) as Box) })); Previewer { widget: willbe, + core: core.clone(), file: None} } fn become_preview(&mut self, widget: HResult>) { - let coordinates = self.get_coordinates().clone(); + let coordinates = self.get_coordinates().unwrap().clone(); self.widget = widget.unwrap(); - self.set_coordinates(&coordinates); + self.widget.set_coordinates(&coordinates).ok(); } pub fn set_file(&mut self, file: &File) { if Some(file) == self.file.as_ref() { return } self.file = Some(file.clone()); - let coordinates = self.get_coordinates().clone(); + let coordinates = self.get_coordinates().unwrap().clone(); let file = file.clone(); + let core = self.core.clone(); self.widget.set_stale().ok(); - self.become_preview(Ok(WillBeWidget::new(Box::new(move |stale| { + self.become_preview(Ok(WillBeWidget::new(&self.core, Box::new(move |stale| { kill_proc().unwrap(); let file = file.clone(); if file.kind == Kind::Directory { - let preview = Previewer::preview_dir(&file, &coordinates, stale.clone()); + let preview = Previewer::preview_dir(&file, &core, stale.clone()); return preview; } if file.get_mime() == Some("text".to_string()) { - return Previewer::preview_text(&file, &coordinates, stale.clone()) + return Previewer::preview_text(&file, &core, stale.clone()) } - let preview = Previewer::preview_external(&file, - &coordinates, - stale.clone()); + let preview = Previewer::preview_external(&file, &core, stale.clone()); if preview.is_ok() { return preview; } else { - let mut blank = Box::new(TextView::new_blank()); - blank.set_coordinates(&coordinates); - blank.refresh(); - blank.animate_slide_up(); + let mut blank = Box::new(TextView::new_blank(&core)); + blank.set_coordinates(&coordinates).log(); + blank.refresh().log(); + blank.animate_slide_up().log(); return Ok(blank) } })))); @@ -276,40 +269,41 @@ impl Previewer { Err(HError::PreviewFailed { file: file.name.clone() }) } - fn preview_dir(file: &File, coordinates: &Coordinates, stale: Arc>) + fn preview_dir(file: &File, core: &WidgetCore, stale: Arc>) -> Result { let files = Files::new_from_path_cancellable(&file.path, stale.clone())?; let len = files.len(); - + if len == 0 || is_stale(&stale)? { return Previewer::preview_failed(&file) } - let mut file_list = ListView::new(files); - file_list.set_coordinates(&coordinates); - file_list.refresh(); + let mut file_list = ListView::new(&core, files); + file_list.set_coordinates(&core.coordinates)?; + file_list.refresh()?; if is_stale(&stale)? { return Previewer::preview_failed(&file) } - file_list.animate_slide_up(); + file_list.animate_slide_up()?; Ok(Box::new(file_list) as Box) } - fn preview_text(file: &File, coordinates: &Coordinates, stale: Arc>) + fn preview_text(file: &File, core: &WidgetCore, stale: Arc>) -> HResult { - let lines = coordinates.ysize() as usize; + let lines = core.coordinates.ysize() as usize; let mut textview - = TextView::new_from_file_limit_lines(&file, - lines); + = TextView::new_from_file_limit_lines(&core, + &file, + lines)?; if is_stale(&stale)? { return Previewer::preview_failed(&file) } - textview.set_coordinates(&coordinates); - textview.refresh(); + textview.set_coordinates(&core.coordinates)?; + textview.refresh()?; if is_stale(&stale)? { return Previewer::preview_failed(&file) } - textview.animate_slide_up(); + textview.animate_slide_up()?; Ok(Box::new(textview)) } - fn preview_external(file: &File, coordinates: &Coordinates, stale: Arc>) + fn preview_external(file: &File, core: &WidgetCore, stale: Arc>) -> Result, HError> { let process = std::process::Command::new("scope.sh") @@ -349,10 +343,10 @@ impl Previewer { let mut textview = TextView { lines: output.lines().map(|s| s.to_string()).collect(), buffer: String::new(), - coordinates: Coordinates::new() }; - textview.set_coordinates(&coordinates); - textview.refresh(); - textview.animate_slide_up(); + core: core.clone()}; + textview.set_coordinates(&core.coordinates).log(); + textview.refresh().log(); + textview.animate_slide_up().log(); return Ok(Box::new(textview)) } Err(HError::PreviewFailed{file: file.name.clone()}) @@ -363,22 +357,16 @@ impl Previewer { impl Widget for Previewer { - fn get_coordinates(&self) -> &Coordinates { - &self.widget.coordinates + fn get_core(&self) -> HResult<&WidgetCore> { + Ok(&self.core) } - fn set_coordinates(&mut self, coordinates: &Coordinates) { - if self.widget.coordinates == *coordinates { - return; - } - self.widget.set_coordinates(coordinates); + fn get_core_mut(&mut self) -> HResult<&mut WidgetCore> { + Ok(&mut self.core) } - fn render_header(&self) -> String { - "".to_string() + fn refresh(&mut self) -> HResult<()> { + self.widget.refresh() } - fn refresh(&mut self) { - self.widget.refresh(); - } - fn get_drawlist(&self) -> String { + fn get_drawlist(&self) -> HResult { self.widget.get_drawlist() } } @@ -538,23 +526,16 @@ impl Widget for Previewer { impl Widget for Box where T: Widget + ?Sized { - fn get_coordinates(&self) -> &Coordinates { - (**self).get_coordinates() + fn get_core(&self) -> HResult<&WidgetCore> { + Ok((**self).get_core()?) } - fn set_coordinates(&mut self, coordinates: &Coordinates) { - if (**self).get_coordinates() == coordinates { - return; - } - (**self).set_coordinates(&coordinates); - (**self).refresh(); - } - fn render_header(&self) -> String { + fn render_header(&self) -> HResult { (**self).render_header() } - fn refresh(&mut self) { + fn refresh(&mut self) -> HResult<()> { (**self).refresh() } - fn get_drawlist(&self) -> String { + fn get_drawlist(&self) -> HResult { (**self).get_drawlist() } } diff --git a/src/proclist.rs b/src/proclist.rs index 5e578c5..9a747c2 100644 --- a/src/proclist.rs +++ b/src/proclist.rs @@ -1,7 +1,6 @@ use std::sync::{Arc, Mutex}; +use std::sync::mpsc::Sender; use std::process::Child; -use std::process::Stdio; -use std::os::unix::io::FromRawFd; use std::io::{BufRead, BufReader}; use termion::event::Key; @@ -10,10 +9,9 @@ use unicode_width::UnicodeWidthStr; use crate::coordinates::{Coordinates, Size, Position}; use crate::listview::{Listable, ListView}; use crate::textview::TextView; -use crate::widget::Widget; -use crate::window::{send_event, Events}; +use crate::widget::{Widget, Events, WidgetCore}; use crate::preview::WillBeWidget; -use crate::fail::{HResult, HError}; +use crate::fail::{HResult, HError, ErrorLog}; use crate::term; #[derive(Debug)] @@ -22,7 +20,9 @@ struct Process { handle: Arc>, output: Arc>, status: Arc>>, - success: Arc>> + success: Arc>>, + sender: Sender + } impl Process { @@ -31,6 +31,7 @@ impl Process { let output = self.output.clone(); let status = self.status.clone(); let success = self.success.clone(); + let sender = self.sender.clone(); std::thread::spawn(move || { let stdout = handle.lock().unwrap().stdout.take().unwrap(); @@ -41,7 +42,7 @@ impl Process { Ok(0) => break, Ok(_) => { output.lock().unwrap().push_str(&line); - send_event(Events::WidgetReady).unwrap(); + sender.send(Events::WidgetReady).unwrap(); } Err(err) => { dbg!(err); @@ -63,7 +64,7 @@ impl Listable for ListView> { fn len(&self) -> usize { self.content.len() } fn render(&self) -> Vec { self.content.iter().map(|proc| { - self.render_proc(proc) + self.render_proc(proc).unwrap() }).collect() } } @@ -75,14 +76,16 @@ impl ListView> { .arg(cmd) .stdin(std::process::Stdio::null()) .stdout(std::process::Stdio::piped()) - .stderr(unsafe { Stdio::from_raw_fd(2) }) + //.stderr(unsafe { Stdio::from_raw_fd(2) }) + .stderr(std::process::Stdio::piped()) .spawn()?; let mut proc = Process { cmd: cmd.to_string(), handle: Arc::new(Mutex::new(handle)), output: Arc::new(Mutex::new(String::new())), status: Arc::new(Mutex::new(None)), - success: Arc::new(Mutex::new(None)) + success: Arc::new(Mutex::new(None)), + sender: self.get_core()?.get_sender() }; proc.read_proc()?; self.content.push(proc); @@ -107,13 +110,13 @@ impl ListView> { self.content.get_mut(selection) } - pub fn render_proc(&self, proc: &Process) -> String { + pub fn render_proc(&self, proc: &Process) -> HResult { let status = match *proc.status.lock().unwrap() { Some(status) => format!("{}", status), None => "".to_string() }; - let xsize = self.get_coordinates().xsize(); + let xsize = self.get_coordinates()?.xsize(); let sized_string = term::sized_string(&proc.cmd, xsize); let status_pos = xsize - status.len() as u16; let padding = sized_string.len() - sized_string.width_cjk(); @@ -124,7 +127,7 @@ impl ListView> { _ => { status } }; - format!( + Ok(format!( "{}{}{}{}{}{}", termion::cursor::Save, format!("{}{}{:padding$}{}", @@ -136,24 +139,25 @@ impl ListView> { termion::cursor::Restore, termion::cursor::Right(status_pos), term::highlight_color(), - color_status - ) + color_status)) } } pub struct ProcView { - coordinates: Coordinates, + core: WidgetCore, proc_list: ListView>, - textview: Option>, + textview: WillBeWidget, viewing: Option } impl ProcView { - pub fn new() -> ProcView { + pub fn new(core: &WidgetCore) -> ProcView { + let tcore = core.clone(); + let textview = Box::new(move |_| Ok(TextView::new_blank(&tcore))); ProcView { - coordinates: Coordinates::new(), - proc_list: ListView::new(vec![]), - textview: None, + core: core.clone(), + proc_list: ListView::new(&core, vec![]), + textview: WillBeWidget::new(&core, textview), viewing: None } } @@ -166,16 +170,17 @@ impl ProcView { pub fn remove_proc(&mut self) -> HResult<()> { let (_, coords) = self.calculate_coordinates(); let coords2 = coords.clone(); + let mut core = self.core.clone(); + core.coordinates = coords; self.proc_list.remove_proc()?; - self.textview = Some(WillBeWidget::new(Box::new(move |_| { - let mut textview = TextView::new_blank(); - textview.set_coordinates(&coords); - textview.refresh(); - textview.animate_slide_up(); + self.textview = WillBeWidget::new(&core.clone(), Box::new(move |_| { + let mut textview = TextView::new_blank(&core); + textview.refresh().log(); + textview.animate_slide_up().log(); Ok(textview) - }))); - self.textview.as_mut().unwrap().set_coordinates(&coords2); + })); + self.textview.set_coordinates(&coords2).log(); Ok(()) } @@ -185,29 +190,29 @@ impl ProcView { } let output = self.proc_list.selected_proc()?.output.lock()?.clone(); let (_, coords) = self.calculate_coordinates(); - let coords2 = coords.clone(); + let mut core = self.core.clone(); + core.coordinates = coords; - self.textview = Some(WillBeWidget::new(Box::new(move |_| { - let mut textview = TextView::new_blank(); - textview.set_coordinates(&coords); - textview.set_text(&output); - textview.animate_slide_up(); + self.textview = WillBeWidget::new(&core.clone(), Box::new(move |_| { + let mut textview = TextView::new_blank(&core); + textview.set_text(&output).log(); + textview.animate_slide_up().log(); Ok(textview) - }))); - self.textview.as_mut().unwrap().set_coordinates(&coords2); + })); self.viewing = Some(self.proc_list.get_selection()); Ok(()) } pub fn calculate_coordinates(&self) -> (Coordinates, Coordinates) { - let xsize = self.coordinates.xsize(); - let ysize = self.coordinates.ysize(); - let top = self.coordinates.top().y(); + let coordinates = self.get_coordinates().unwrap(); + let xsize = coordinates.xsize(); + let ysize = coordinates.ysize(); + let top = coordinates.top().y(); let ratio = (33, 66); let left_xsize = xsize * ratio.0 / 100; let left_size = Size((left_xsize, ysize)); - let left_pos = self.coordinates.top(); + let left_pos = coordinates.top(); let main_xsize = xsize * ratio.1 / 100; let main_size = Size((main_xsize, ysize)); @@ -224,7 +229,6 @@ impl ProcView { size: main_size, position: main_pos, }; - (left_coords, main_coords) } @@ -232,36 +236,25 @@ impl ProcView { } impl Widget for ProcView { - fn get_coordinates(&self) -> &Coordinates { - &self.coordinates + fn get_core(&self) -> HResult<&WidgetCore> { + Ok(&self.core) } - fn set_coordinates(&mut self, coordinates: &Coordinates) { - self.coordinates = coordinates.clone(); - + fn get_core_mut(&mut self) -> HResult<&mut WidgetCore> { + Ok(&mut self.core) + } + fn refresh(&mut self) -> HResult<()> { let (lcoord, rcoord) = self.calculate_coordinates(); - self.proc_list.set_coordinates(&lcoord); - if let Some(textview) = &mut self.textview { - textview.set_coordinates(&rcoord); - } + self.proc_list.set_coordinates(&lcoord).log(); + self.textview.set_coordinates(&rcoord).log(); - self.refresh(); + self.show_output().log(); + self.proc_list.refresh().log(); + self.textview.refresh().log(); + + Ok(()) } - fn render_header(&self) -> String { - "".to_string() - } - fn refresh(&mut self) { - self.show_output(); - self.proc_list.refresh(); - if let Some(textview) = &mut self.textview { - textview.refresh(); - } - } - fn get_drawlist(&self) -> String { - if let Some(textview) = &self.textview { - self.proc_list.get_drawlist() + &textview.get_drawlist() - } else { - self.proc_list.get_drawlist() - } + fn get_drawlist(&self) -> HResult { + Ok(self.proc_list.get_drawlist()? + &self.textview.get_drawlist()?) } fn on_key(&mut self, key: Key) -> HResult<()> { match key { @@ -270,18 +263,14 @@ impl Widget for ProcView { Key::Char('k') => { self.proc_list.kill_proc()? } Key::Up | Key::Char('p') => { self.proc_list.move_up(); - self.proc_list.refresh(); - self.show_output().ok(); } Key::Down | Key::Char('n') => { self.proc_list.move_down(); - self.proc_list.refresh(); - self.show_output().ok(); } _ => {} } - self.refresh(); - self.draw()?; + self.refresh().log(); + self.draw().log(); Ok(()) } } diff --git a/src/tabview.rs b/src/tabview.rs index e4904a5..faa212f 100644 --- a/src/tabview.rs +++ b/src/tabview.rs @@ -1,21 +1,22 @@ use termion::event::Key; -use crate::coordinates::{Coordinates}; -use crate::widget::Widget; -use crate::fail::HResult; +use crate::widget::{Widget, WidgetCore}; +use crate::fail::{HResult, ErrorLog}; pub trait Tabbable { - fn new_tab(&mut self); - fn close_tab(&mut self); - fn next_tab(&mut self); - fn on_next_tab(&mut self); + fn new_tab(&mut self) -> HResult<()>; + fn close_tab(&mut self) -> HResult<()>; + fn next_tab(&mut self) -> HResult<()>; + fn on_next_tab(&mut self) -> HResult<()> { + Ok(()) + } fn get_tab_names(&self) -> Vec>; fn active_tab(&self) -> &dyn Widget; fn active_tab_mut(&mut self) -> &mut dyn Widget; - fn on_key_sub(&mut self, key: Key); - fn on_key(&mut self, key: Key) { + fn on_key_sub(&mut self, key: Key) -> HResult<()>; + fn on_key(&mut self, key: Key) -> HResult<()> { match key { - Key::Ctrl('t') => { self.new_tab(); }, + Key::Ctrl('t') => self.new_tab(), Key::Ctrl('w') => self.close_tab(), Key::Char('\t') => self.next_tab(), _ => self.on_key_sub(key) @@ -28,27 +29,27 @@ pub trait Tabbable { pub struct TabView where T: Widget, TabView: Tabbable { pub widgets: Vec, pub active: usize, - coordinates: Coordinates + core: WidgetCore } impl TabView where T: Widget, TabView: Tabbable { - pub fn new() -> TabView { + pub fn new(core: &WidgetCore) -> TabView { TabView { widgets: vec![], active: 0, - coordinates: Coordinates::new() + core: core.clone() } } - pub fn push_widget(&mut self, widget: T) { + pub fn push_widget(&mut self, widget: T) -> HResult<()> { self.widgets.push(widget); - self.refresh(); + self.refresh() } - pub fn pop_widget(&mut self) -> Option { - let widget = self.widgets.pop(); - self.refresh(); - widget + pub fn pop_widget(&mut self) -> HResult { + let widget = self.widgets.pop()?; + self.refresh()?; + Ok(widget) } pub fn active_tab_(&self) -> &T { @@ -59,11 +60,10 @@ impl TabView where T: Widget, TabView: Tabbable { &mut self.widgets[self.active] } - pub fn close_tab_(&mut self) { - if self.active == 0 { return } - if self.active + 1 >= self.widgets.len() { self.active -= 1 } - - self.pop_widget(); + pub fn close_tab_(&mut self) -> HResult<()> { + self.pop_widget()?; + self.active -= 1; + Ok(()) } pub fn next_tab_(&mut self) { @@ -72,14 +72,17 @@ impl TabView where T: Widget, TabView: Tabbable { } else { self.active += 1 } - self.on_next_tab(); + self.on_next_tab().log(); } } impl Widget for TabView where T: Widget, TabView: Tabbable { - fn render_header(&self) -> String { - let xsize = self.get_coordinates().xsize(); - let header = self.active_tab_().render_header(); + fn get_core(&self) -> HResult<&WidgetCore> { + Ok(&self.core) + } + fn render_header(&self) -> HResult { + let xsize = self.get_coordinates()?.xsize(); + let header = self.active_tab_().render_header()?; let tab_names = self.get_tab_names(); let mut nums_length = 0; let tabnums = (0..self.widgets.len()).map(|num| { @@ -100,38 +103,28 @@ impl Widget for TabView where T: Widget, TabView: Tabbable { let nums_pos = xsize - nums_length as u16; - format!("{}{}{}{}", + Ok(format!("{}{}{}{}", header, crate::term::header_color(), crate::term::goto_xy(nums_pos, 1), - tabnums) + tabnums)) } - fn render_footer(&self) -> String { + fn render_footer(&self) -> HResult + { self.active_tab_().render_footer() } - fn refresh(&mut self) { - self.active_tab_mut().refresh(); + fn refresh(&mut self) -> HResult<()> { + self.active_tab_mut().refresh() } - fn get_drawlist(&self) -> String { + fn get_drawlist(&self) -> HResult { self.active_tab_().get_drawlist() } - fn get_coordinates(&self) -> &Coordinates { - &self.coordinates - } - fn set_coordinates(&mut self, coordinates: &Coordinates) { - if self.coordinates == *coordinates { - return; - } - self.coordinates = coordinates.clone(); - self.refresh(); - } - fn on_key(&mut self, key: Key) -> HResult<()> { - Tabbable::on_key(self, key); - Ok(()) + Tabbable::on_key(self, key)?; + self.refresh() } } diff --git a/src/term.rs b/src/term.rs index 950a410..317f5d5 100644 --- a/src/term.rs +++ b/src/term.rs @@ -1,20 +1,36 @@ -use std::io::{Stdout, Write}; +use std::io::{Stdout, Write, BufWriter}; + use termion; use termion::screen::AlternateScreen; +use crate::fail::HResult; + pub trait ScreenExt: Write { - fn cursor_hide(&mut self) { - write!(self, "{}", termion::cursor::Hide).unwrap(); + fn cursor_hide(&mut self) -> HResult<()> { + write!(self, "{}", termion::cursor::Hide)?; + self.flush()?; + Ok(()) } - fn cursor_show(&mut self) { - write!(self, "{}", termion::cursor::Show).unwrap(); + fn cursor_show(&mut self) -> HResult<()> { + write!(self, "{}", termion::cursor::Show)?; + self.flush()?; + Ok(()) } - fn reset(&mut self) { - write!(self, "{}", termion::style::Reset).unwrap(); + fn reset(&mut self) -> HResult<()> { + write!(self, "{}", termion::style::Reset)?; + self.flush()?; + Ok(()) + } + fn write_str(&mut self, str: &str) -> HResult<()> { + write!(self, "{}", str)?; + self.flush()?; + Ok(()) } } impl ScreenExt for AlternateScreen> {} +impl ScreenExt for AlternateScreen {} +impl ScreenExt for AlternateScreen> {} pub fn xsize() -> u16 { let (xsize, _) = termion::terminal_size().unwrap(); diff --git a/src/textview.rs b/src/textview.rs index 455e961..2d7fafd 100644 --- a/src/textview.rs +++ b/src/textview.rs @@ -1,77 +1,79 @@ use std::io::BufRead; -use crate::coordinates::{Coordinates}; use crate::files::File; use crate::term::sized_string; -use crate::widget::Widget; +use crate::widget::{Widget, WidgetCore}; +use crate::fail::HResult; #[derive(PartialEq)] pub struct TextView { pub lines: Vec, pub buffer: String, - pub coordinates: Coordinates, + pub core: WidgetCore } impl TextView { - pub fn new_blank() -> TextView { + pub fn new_blank(core: &WidgetCore) -> TextView { TextView { lines: vec![], buffer: String::new(), - coordinates: Coordinates::new() + core: core.clone() } } - pub fn new_from_file(file: &File) -> TextView { - let file = std::fs::File::open(&file.path).unwrap(); + pub fn new_from_file(core: &WidgetCore, file: &File) -> HResult { + let file = std::fs::File::open(&file.path)?; let file = std::io::BufReader::new(file); let lines = file.lines().map(|line| - line.unwrap() - .replace("\t", " ")).collect(); + Ok(line? + .replace("\t", " "))) + .filter_map(|l: HResult| l.ok()) + .collect(); - TextView { + Ok(TextView { lines: lines, buffer: String::new(), - coordinates: Coordinates::new(), - } + core: core.clone() + }) } - pub fn new_from_file_limit_lines(file: &File, num: usize) -> TextView { + pub fn new_from_file_limit_lines(core: &WidgetCore, + file: &File, + num: usize) -> HResult { let file = std::fs::File::open(&file.path).unwrap(); let file = std::io::BufReader::new(file); let lines = file.lines() .take(num) .map(|line| - line.unwrap() - .replace("\t", " ")).collect(); + Ok(line? + .replace("\t", " "))) + .filter_map(|l: HResult| l.ok()) + .collect(); - TextView { + Ok(TextView { lines: lines, buffer: String::new(), - coordinates: Coordinates::new(), - } + core: core.clone() + }) } - pub fn set_text(&mut self, text: &str) { + pub fn set_text(&mut self, text: &str) -> HResult<()> { let lines = text.lines().map(|l| l.to_string()).collect(); self.lines = lines; - self.refresh(); + self.refresh() } } impl Widget for TextView { - fn get_coordinates(&self) -> &Coordinates { - &self.coordinates + fn get_core(&self) -> HResult<&WidgetCore> { + Ok(&self.core) } - fn set_coordinates(&mut self, coordinates: &Coordinates) { - self.coordinates = coordinates.clone(); - self.refresh(); + fn get_core_mut(&mut self) -> HResult<&mut WidgetCore> { + Ok(&mut self.core) } - fn render_header(&self) -> String { - "".to_string() - } - fn refresh(&mut self) { - let (xsize, ysize) = self.get_coordinates().size().size(); - let (xpos, ypos) = self.get_coordinates().position().position(); + fn refresh(&mut self) -> HResult<()> { + let (xsize, ysize) = self.get_coordinates()?.size().size(); + let (xpos, ypos) = self.get_coordinates()?.position().position(); - self.buffer = self.get_clearlist() + + self.buffer = self.get_clearlist()? + &self .lines .iter() @@ -85,9 +87,10 @@ impl Widget for TextView { sized_string(&line, xsize)) }) .collect::(); + Ok(()) } - fn get_drawlist(&self) -> String { - self.buffer.clone() + fn get_drawlist(&self) -> HResult { + Ok(self.buffer.clone()) } } diff --git a/src/widget.rs b/src/widget.rs index 2e47b28..f2be282 100644 --- a/src/widget.rs +++ b/src/widget.rs @@ -1,28 +1,115 @@ -use std::sync::mpsc::channel; +use std::sync::{Arc, Mutex}; +use std::sync::mpsc::{Sender, Receiver, channel}; use termion::event::{Event, Key, MouseEvent}; use termion::input::TermRead; +use termion::screen::AlternateScreen; +use failure::Backtrace; + use crate::coordinates::{Coordinates, Position, Size}; -use crate::fail::{HResult, HError}; -use crate::window::{send_event, Events}; +use crate::fail::{HResult, HError, ErrorLog}; +use crate::minibuffer::MiniBuffer; +use crate::term; +use crate::term::ScreenExt; -use std::io::{BufWriter, Write, stdin}; +use std::io::{BufWriter, stdin, stdout, Stdout}; +#[derive(Debug)] +pub enum Events { + InputEvent(Event), + WidgetReady, + ExclusiveEvent(Option>), +} + +impl PartialEq for WidgetCore { + fn eq(&self, other: &WidgetCore) -> bool { + if self.coordinates == other.coordinates { + true + } else { + false + } + } +} + +impl std::fmt::Debug for WidgetCore { + fn fmt(&self, formatter: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> { + let output = format!("{:?}{:?}{:?}", + self.coordinates, + self.minibuffer, + self.status_bar_content); + formatter.write_str(&output) + } +} + +#[derive(Clone)] +pub struct WidgetCore { + pub screen: Arc>>>, + pub coordinates: Coordinates, + pub minibuffer: Arc>>, + pub event_sender: Sender, + event_receiver: Arc>>>, + pub status_bar_content: Arc>> +} + +impl WidgetCore { + pub fn new() -> HResult { + let screen = AlternateScreen::from(BufWriter::new(stdout())); + let coords = Coordinates::new_at(term::xsize(), + term::ysize() - 2, + 1, + 2); + let (sender, receiver) = channel(); + let status_bar_content = Arc::new(Mutex::new(None)); + + let core = WidgetCore { + screen: Arc::new(Mutex::new(screen)), + coordinates: coords, + minibuffer: Arc::new(Mutex::new(None)), + event_sender: sender, + event_receiver: Arc::new(Mutex::new(Some(receiver))), + status_bar_content: status_bar_content }; + + let minibuffer = MiniBuffer::new(&core); + *core.minibuffer.lock().unwrap() = Some(minibuffer); + Ok(core) + } + + pub fn get_sender(&self) -> Sender { + self.event_sender.clone() + } +} pub trait Widget { fn get_widget(&self) -> Box { - Box::new(crate::textview::TextView::new_blank()) + Box::new(crate::textview::TextView::new_blank(self.get_core().unwrap())) } - fn get_coordinates(&self) -> &Coordinates; - fn set_coordinates(&mut self, coordinates: &Coordinates); - fn render_header(&self) -> String; - fn render_footer(&self) -> String { "".into() } - fn refresh(&mut self); - fn get_drawlist(&self) -> String; + fn get_core(&self) -> HResult<&WidgetCore> { + Err(HError::NoWidgetCoreError(Backtrace::new())) + } + fn get_core_mut(&mut self) -> HResult<&mut WidgetCore> { + Err(HError::NoWidgetCoreError(Backtrace::new())) + } + fn get_coordinates(&self) -> HResult<&Coordinates> { + Ok(&self.get_core()?.coordinates) + } + fn set_coordinates(&mut self, coordinates: &Coordinates) -> HResult<()> { + self.get_core_mut()?.coordinates = coordinates.clone(); + self.refresh()?; + Ok(()) + } + fn render_header(&self) -> HResult { + Err(HError::NoHeaderError) + } + fn render_footer(&self) -> HResult { + Err(HError::NoHeaderError) + } + fn refresh(&mut self) -> HResult<()>; + fn get_drawlist(&self) -> HResult; fn after_draw(&self) -> HResult<()> { Ok(()) } + fn on_event(&mut self, event: Event) -> HResult<()> { match event { Event::Key(Key::Char('q')) => panic!("It's your fault!"), @@ -34,67 +121,59 @@ pub trait Widget { fn on_key(&mut self, key: Key) -> HResult<()> { match key { - _ => self.bad(Event::Key(key)), + _ => { self.bad(Event::Key(key)).unwrap() }, } Ok(()) } fn on_mouse(&mut self, event: MouseEvent) -> HResult<()> { match event { - _ => self.bad(Event::Mouse(event)), + _ => { self.bad(Event::Mouse(event)).unwrap() }, } Ok(()) } fn on_wtf(&mut self, event: Vec) -> HResult<()> { match event { - _ => self.bad(Event::Unsupported(event)), + _ => { self.bad(Event::Unsupported(event)).unwrap() }, } Ok(()) } - fn show_status(&self, status: &str) { - crate::window::show_status(status); + fn bad(&mut self, event: Event) -> HResult<()> { + self.show_status(&format!("Stop the nasty stuff!! {:?} does nothing!", event)) } - fn minibuffer(&self, query: &str) -> HResult { - crate::window::minibuffer(query) - } - - fn bad(&mut self, event: Event) { - self.show_status(&format!("Stop the nasty stuff!! {:?} does nothing!", event)); - } - - fn get_header_drawlist(&mut self) -> String { - format!( + fn get_header_drawlist(&mut self) -> HResult { + Ok(format!( "{}{}{:xsize$}{}{}", crate::term::goto_xy(1, 1), crate::term::header_color(), " ", crate::term::goto_xy(1, 1), - self.render_header(), - xsize = self.get_coordinates().xsize() as usize - ) + self.render_header()?, + xsize = self.get_coordinates()?.xsize() as usize + )) } - fn get_footer_drawlist(&mut self) -> String { - let xsize = self.get_coordinates().xsize(); + fn get_footer_drawlist(&mut self) -> HResult { + let xsize = self.get_coordinates()?.xsize(); let ypos = crate::term::ysize(); - format!( + Ok(format!( "{}{}{:xsize$}{}{}", crate::term::goto_xy(1, ypos), crate::term::header_color(), " ", crate::term::goto_xy(1, ypos), - self.render_footer(), - xsize = xsize as usize) + self.render_footer()?, + xsize = xsize as usize)) } - fn get_clearlist(&self) -> String { - let (xpos, ypos) = self.get_coordinates().u16position(); - let (xsize, ysize) = self.get_coordinates().u16size(); + fn get_clearlist(&self) -> HResult { + let (xpos, ypos) = self.get_coordinates()?.u16position(); + let (xsize, ysize) = self.get_coordinates()?.u16size(); - (ypos..ysize + 2) + Ok((ypos..ysize + 2) .map(|line| { format!( "{}{}{:xsize$}", @@ -104,15 +183,15 @@ pub trait Widget { xsize = xsize as usize ) }) - .collect() + .collect()) } - fn get_redraw_empty_list(&self, lines: usize) -> String { - let (xpos, ypos) = self.get_coordinates().u16position(); - let (xsize, ysize) = self.get_coordinates().u16size(); + fn get_redraw_empty_list(&self, lines: usize) -> HResult { + let (xpos, ypos) = self.get_coordinates()?.u16position(); + let (xsize, ysize) = self.get_coordinates()?.u16size(); let start_y = lines + ypos as usize; - (start_y..(ysize + 2) as usize) + Ok((start_y..(ysize + 2) as usize) .map(|i| { format!( "{}{:xsize$}", @@ -121,30 +200,21 @@ pub trait Widget { xsize = xsize as usize ) }) - .collect() - } - - fn draw(&self) -> HResult<()> { - let drawlist = self.get_drawlist(); - let mut bufout = BufWriter::new(std::io::stdout()); - - write!(bufout, "{}", drawlist)?; - bufout.flush()?; - Ok(()) + .collect()) } fn popup(&mut self) -> HResult<()> { - self.run_widget(); - send_event(Events::ExclusiveEvent(None))?; + self.run_widget().log(); + self.get_core()?.get_sender().send(Events::ExclusiveEvent(None))?; Ok(()) } fn run_widget(&mut self) -> HResult<()> { let (tx_event, rx_event) = channel(); - send_event(Events::ExclusiveEvent(Some(tx_event)))?; + self.get_core()?.get_sender().send(Events::ExclusiveEvent(Some(tx_event)))?; self.clear()?; - self.refresh(); + self.refresh().log(); self.draw()?; for event in rx_event.iter() { @@ -155,32 +225,31 @@ pub trait Widget { } } Events::WidgetReady => { - self.refresh(); + self.refresh().log(); } _ => {} } - self.draw(); - self.after_draw(); + self.draw().log(); + self.after_draw().log(); } Ok(()) } fn clear(&self) -> HResult<()> { - let clearlist = self.get_clearlist(); - write!(std::io::stdout(), "{}", clearlist)?; - std::io::stdout().flush()?; - Ok(()) + let clearlist = self.get_clearlist()?; + self.write_to_screen(&clearlist) } - fn animate_slide_up(&mut self) { - let coords = self.get_coordinates().clone(); + fn animate_slide_up(&mut self) -> HResult<()> { + let coords = self.get_coordinates()?.clone(); let xpos = coords.position().x(); let ypos = coords.position().y(); let xsize = coords.xsize(); let ysize = coords.ysize(); - let clear = self.get_clearlist(); + let clear = self.get_clearlist()?; let pause = std::time::Duration::from_millis(5); - let mut bufout = BufWriter::new(std::io::stdout()); + + self.write_to_screen(&clear).log(); for i in (0..10).rev() { let coords = Coordinates { size: Size((xsize,ysize-i)), @@ -188,13 +257,123 @@ pub trait Widget { ((xpos, ypos+i)) }; - self.set_coordinates(&coords); - let buffer = self.get_drawlist(); - write!(bufout, "{}{}", - clear, buffer).unwrap(); - bufout.flush().ok(); + self.set_coordinates(&coords).log(); + let buffer = self.get_drawlist()?; + self.write_to_screen(&buffer).log(); std::thread::sleep(pause); } + Ok(()) + } + + fn draw(&mut self) -> HResult<()> { + let output = + self.get_drawlist().unwrap_or("".to_string()) + + &self.get_header_drawlist().unwrap_or("".to_string()) + + &self.get_footer_drawlist().unwrap_or("".to_string()); + self.write_to_screen(&output).log(); + Ok(()) + } + + fn handle_input(&mut self) -> HResult<()> { + let (tx_event, rx_event) = channel(); + let (tx_internal_event, rx_internal_event) = channel(); + let rx_global_event = self.get_core()?.event_receiver.lock()?.take()?; + + input_thread(tx_event.clone()); + global_event_thread(rx_global_event, tx_event.clone()); + dispatch_events(rx_event, tx_internal_event); + + for event in rx_internal_event.iter() { + match event { + Events::InputEvent(event) => { + self.on_event(event).ok(); + self.draw().ok(); + }, + _ => { + self.refresh().ok(); + self.draw().ok(); + }, + } + } + Ok(()) + } + + fn draw_status(&self) -> HResult<()> { + let xsize = term::xsize() as u16; + let status = &self.get_core()?.status_bar_content; + + let status = status.lock()?; + + self.write_to_screen( + &format!( + "{}{}{:xsize$}{}{}", + term::move_bottom(), + term::status_bg(), + " ", + term::move_bottom(), + status.as_ref()?, + xsize = xsize as usize + )).log(); + + Ok(()) + } + + fn show_status(&self, status: &str) -> HResult<()> { + { + let mut status_content = self.get_core()?.status_bar_content.lock()?; + *status_content = Some(status.to_string()); + } + self.draw_status()?; + Ok(()) + } + + fn minibuffer(&self, query: &str) -> HResult { + let answer = self.get_core()?.minibuffer.lock()?.as_mut()?.query(query); + let mut screen = self.get_core()?.screen.lock()?; + screen.cursor_hide().log(); + answer + } + + fn write_to_screen(&self, s: &str) -> HResult<()> { + let mut screen = self.get_core()?.screen.lock()?; + screen.write_str(s) } } + +fn dispatch_events(rx: Receiver, tx: Sender) { + std::thread::spawn(move || { + let mut tx_exclusive_event: Option> = None; + for event in rx.iter() { + match &event { + Events::ExclusiveEvent(tx_event) => { + tx_exclusive_event = tx_event.clone(); + } + _ => {} + } + if let Some(tx_event) = &tx_exclusive_event { + tx_event.send(event).unwrap(); + } else { + tx.send(event).unwrap(); + } + } + }); +} + +fn global_event_thread(rx_global: Receiver, + tx: Sender) { + std::thread::spawn(move || { + for event in rx_global.iter() { + tx.send(event).unwrap(); + } + }); +} + +fn input_thread(tx: Sender) { + std::thread::spawn(move || { + for input in stdin().events() { + let input = input.unwrap(); + tx.send(Events::InputEvent(input)).unwrap(); + } + }); +} diff --git a/src/window.rs b/src/window.rs index 6152ed3..213fe8b 100644 --- a/src/window.rs +++ b/src/window.rs @@ -1,214 +1,214 @@ -use std::io::{stdin, stdout, Stdout, Write}; -use std::sync::{Arc, Mutex}; -use std::sync::mpsc::{Sender, Receiver, channel}; +// use std::io::{stdin, stdout, Stdout, Write}; +// use std::sync::{Arc, Mutex}; +// use std::sync::mpsc::{Sender, Receiver, channel}; -use termion::event::Event; -use termion::input::TermRead; -use termion::screen::AlternateScreen; +// use termion::event::Event; +// use termion::input::TermRead; +// use termion::screen::AlternateScreen; -use crate::term; -use crate::term::ScreenExt; +// use crate::term; +// use crate::term::ScreenExt; -use crate::coordinates::{Coordinates, Position, Size}; -use crate::widget::Widget; -use crate::minibuffer::MiniBuffer; -use crate::fail::HResult; +// use crate::coordinates::{Coordinates, Position, Size}; +// use crate::widget::Widget; +// use crate::minibuffer::MiniBuffer; +// use crate::fail::HResult; -lazy_static! { - static ref TX_EVENT: Arc>>> = { Arc::new(Mutex::new(None)) }; - static ref MINIBUFFER: Arc> - = Arc::new(Mutex::new(MiniBuffer::new())); -} +// lazy_static! { +// static ref TX_EVENT: Arc>>> = { Arc::new(Mutex::new(None)) }; +// static ref MINIBUFFER: Arc> +// = Arc::new(Mutex::new(MiniBuffer::new())); +// } -#[derive(Debug)] -pub enum Events { - InputEvent(Event), - WidgetReady, - ExclusiveEvent(Option>), -} +// #[derive(Debug)] +// pub enum Events { +// InputEvent(Event), +// WidgetReady, +// ExclusiveEvent(Option>), +// } -pub struct Window -where - T: Widget, -{ - pub selection: usize, - pub widget: T, - pub status: Arc>>, - pub screen: AlternateScreen>, - pub coordinates: Coordinates, -} +// pub struct Window +// where +// T: Widget, +// { +// pub selection: usize, +// pub widget: T, +// pub status: Arc>>, +// pub screen: AlternateScreen>, +// pub coordinates: Coordinates, +// } -impl Window -where - T: Widget, -{ - pub fn new(widget: T) -> Window { - let mut screen = AlternateScreen::from(Box::new(stdout())); - screen.cursor_hide(); - let (xsize, ysize) = termion::terminal_size().unwrap(); - let mut win = Window:: { - selection: 0, - widget: widget, - status: STATUS_BAR_CONTENT.clone(), - screen: screen, - coordinates: Coordinates { - size: Size((xsize, ysize)), - position: Position((1, 1)), - }, - }; +// impl Window +// where +// T: Widget, +// { +// pub fn new(widget: T) -> Window { +// let mut screen = AlternateScreen::from(Box::new(stdout())); +// screen.cursor_hide(); +// let (xsize, ysize) = termion::terminal_size().unwrap(); +// let mut win = Window:: { +// selection: 0, +// widget: widget, +// status: STATUS_BAR_CONTENT.clone(), +// screen: screen, +// coordinates: Coordinates { +// size: Size((xsize, ysize)), +// position: Position((1, 1)), +// }, +// }; - win.widget.set_coordinates(&Coordinates { - size: Size((xsize, ysize - 2)), - position: Position((1, 2)), - }); - win.widget.refresh(); - win - } +// win.widget.set_coordinates(&Coordinates { +// size: Size((xsize, ysize - 2)), +// position: Position((1, 2)), +// }); +// win.widget.refresh(); +// win +// } - pub fn draw(&mut self) { - let output = self.widget.get_drawlist() + &self.widget.get_header_drawlist() - + &self.widget.get_footer_drawlist(); - self.screen.write(output.as_ref()).unwrap(); +// pub fn draw(&mut self) { +// let output = self.widget.get_drawlist() + &self.widget.get_header_drawlist() +// + &self.widget.get_footer_drawlist(); +// self.screen.write(output.as_ref()).unwrap(); - self.screen.flush().unwrap(); - } +// self.screen.flush().unwrap(); +// } - // pub fn show_status(status: &str) { - // show_status(status); - // } +// // pub fn show_status(status: &str) { +// // show_status(status); +// // } - // pub fn draw_status() { - // draw_status(); - // } +// // pub fn draw_status() { +// // draw_status(); +// // } - // pub fn clear_status() { - // Self::show_status(""); - // } +// // pub fn clear_status() { +// // Self::show_status(""); +// // } - pub fn handle_input(&mut self) { - let (tx_event, rx_event) = channel(); - let (tx_global_event, rx_global_event) = channel(); - *TX_EVENT.try_lock().unwrap() = Some(tx_global_event); - let (tx_internal_event, rx_internal_event) = channel(); +// pub fn handle_input(&mut self) { +// let (tx_event, rx_event) = channel(); +// let (tx_global_event, rx_global_event) = channel(); +// *TX_EVENT.try_lock().unwrap() = Some(tx_global_event); +// let (tx_internal_event, rx_internal_event) = channel(); - input_thread(tx_event.clone()); - global_event_thread(rx_global_event, tx_event.clone()); - dispatch_events(rx_event, tx_internal_event); +// input_thread(tx_event.clone()); +// global_event_thread(rx_global_event, tx_event.clone()); +// dispatch_events(rx_event, tx_internal_event); - for event in rx_internal_event.iter() { - match event { - Events::InputEvent(event) => { - self.widget.on_event(event); - self.screen.cursor_hide(); - self.draw(); - }, - _ => { - self.widget.refresh(); - self.draw(); - }, - } - } - } -} +// for event in rx_internal_event.iter() { +// match event { +// Events::InputEvent(event) => { +// self.widget.on_event(event); +// self.screen.cursor_hide(); +// self.draw(); +// }, +// _ => { +// self.widget.refresh(); +// self.draw(); +// }, +// } +// } +// } +// } -fn dispatch_events(rx: Receiver, tx: Sender) { - std::thread::spawn(move || { - let mut tx_exclusive_event: Option> = None; - for event in rx.iter() { - match &event { - Events::ExclusiveEvent(tx_event) => { - tx_exclusive_event = tx_event.clone(); - } - _ => {} - } - if let Some(tx_event) = &tx_exclusive_event { - tx_event.send(event).unwrap(); - } else { - tx.send(event).unwrap(); - } - } - }); -} +// fn dispatch_events(rx: Receiver, tx: Sender) { +// std::thread::spawn(move || { +// let mut tx_exclusive_event: Option> = None; +// for event in rx.iter() { +// match &event { +// Events::ExclusiveEvent(tx_event) => { +// tx_exclusive_event = tx_event.clone(); +// } +// _ => {} +// } +// if let Some(tx_event) = &tx_exclusive_event { +// tx_event.send(event).unwrap(); +// } else { +// tx.send(event).unwrap(); +// } +// } +// }); +// } -fn global_event_thread(rx_global: Receiver, - tx: Sender) { - std::thread::spawn(move || { - for event in rx_global.iter() { - tx.send(event).unwrap(); - } - }); -} +// fn global_event_thread(rx_global: Receiver, +// tx: Sender) { +// std::thread::spawn(move || { +// for event in rx_global.iter() { +// tx.send(event).unwrap(); +// } +// }); +// } -fn input_thread(tx: Sender) { - std::thread::spawn(move || { - for input in stdin().events() { - let input = input.unwrap(); - tx.send(Events::InputEvent(input)).unwrap(); - } - }); -} +// fn input_thread(tx: Sender) { +// std::thread::spawn(move || { +// for input in stdin().events() { +// let input = input.unwrap(); +// tx.send(Events::InputEvent(input)).unwrap(); +// } +// }); +// } -pub fn send_event(event: Events) -> HResult<()> { - let tx = TX_EVENT.lock()?.clone()?.clone(); - tx.send(event)?; - Ok(()) -} +// pub fn send_event(event: Events) -> HResult<()> { +// let tx = TX_EVENT.lock()?.clone()?.clone(); +// tx.send(event)?; +// Ok(()) +// } -impl Drop for Window -where - T: Widget, -{ - fn drop(&mut self) { - // When done, restore the defaults to avoid messing with the terminal. - self.screen - .write( - format!( - "{}{}{}{}{}", - termion::screen::ToMainScreen, - termion::clear::All, - termion::style::Reset, - termion::cursor::Show, - termion::cursor::Goto(1, 1) - ) - .as_ref(), - ) - .unwrap(); - } -} +// impl Drop for Window +// where +// T: Widget, +// { +// fn drop(&mut self) { +// // When done, restore the defaults to avoid messing with the terminal. +// self.screen +// .write( +// format!( +// "{}{}{}{}{}", +// termion::screen::ToMainScreen, +// termion::clear::All, +// termion::style::Reset, +// termion::cursor::Show, +// termion::cursor::Goto(1, 1) +// ) +// .as_ref(), +// ) +// .unwrap(); +// } +// } -lazy_static! { - static ref STATUS_BAR_CONTENT: Arc>> = Arc::new(Mutex::new(None)); -} +// lazy_static! { +// static ref STATUS_BAR_CONTENT: Arc>> = Arc::new(Mutex::new(None)); +// } -pub fn draw_status() { - let xsize = term::xsize() as u16; - let status = STATUS_BAR_CONTENT.try_lock().unwrap().clone(); +// pub fn draw_status() { +// let xsize = term::xsize() as u16; +// let status = STATUS_BAR_CONTENT.try_lock().unwrap().clone(); - status.or(Some("".to_string())).and_then(|status| { - write!( - stdout(), - "{}{}{:xsize$}{}{}", - term::move_bottom(), - term::status_bg(), - " ", - term::move_bottom(), - status, - xsize = xsize as usize - ) - .ok() - }); - stdout().flush().unwrap(); -} +// status.or(Some("".to_string())).and_then(|status| { +// write!( +// stdout(), +// "{}{}{:xsize$}{}{}", +// term::move_bottom(), +// term::status_bg(), +// " ", +// term::move_bottom(), +// status, +// xsize = xsize as usize +// ) +// .ok() +// }); +// stdout().flush().unwrap(); +// } -pub fn show_status(status: &str) { - { - let mut status_content = STATUS_BAR_CONTENT.try_lock().unwrap(); - *status_content = Some(status.to_string()); - } - draw_status(); -} +// pub fn show_status(status: &str) { +// { +// let mut status_content = STATUS_BAR_CONTENT.try_lock().unwrap(); +// *status_content = Some(status.to_string()); +// } +// draw_status(); +// } -pub fn minibuffer(query: &str) -> HResult { - MINIBUFFER.lock()?.query(query) -} +// pub fn minibuffer(query: &str) -> HResult { +// MINIBUFFER.lock()?.query(query) +// }