mirror of https://github.com/bobwen-dev/hunter
use enum to allow multiple widget types in hbox
This commit is contained in:
parent
6e02ef6486
commit
5d45653901
16
src/fail.rs
16
src/fail.rs
|
@ -45,13 +45,27 @@ pub enum HError {
|
|||
#[fail(display = "No header for widget")]
|
||||
NoHeaderError,
|
||||
#[fail(display = "You wanted this!")]
|
||||
Quit
|
||||
Quit,
|
||||
#[fail(display = "HBox ratio mismatch: {} widgets, ratio is {:?}", wnum, ratio)]
|
||||
HBoxWrongRatioError{ wnum: usize, ratio: Vec<usize> },
|
||||
#[fail(display = "Got wrong widget: {}! Wanted: {}", got, wanted)]
|
||||
WrongWidgetError{got: String, wanted: String},
|
||||
}
|
||||
|
||||
impl HError {
|
||||
pub fn quit() -> HResult<()> {
|
||||
Err(HError::Quit)
|
||||
}
|
||||
pub fn wrong_ratio<T>(wnum: usize, ratio: Vec<usize>) -> HResult<T> {
|
||||
Err(HError::HBoxWrongRatioError{ wnum: wnum, ratio: ratio })
|
||||
}
|
||||
pub fn no_widget<T>() -> HResult<T> {
|
||||
Err(HError::NoWidgetError(Backtrace::new()))
|
||||
}
|
||||
pub fn wrong_widget<T>(got: &str, wanted: &str) -> HResult<T> {
|
||||
Err(HError::WrongWidgetError{ got: got.to_string(),
|
||||
wanted: wanted.to_string()})
|
||||
}
|
||||
}
|
||||
|
||||
pub trait ErrorLog where Self: Sized {
|
||||
|
|
|
@ -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();
|
||||
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()
|
||||
|
||||
};
|
||||
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();
|
||||
|
||||
if let Ok(new_cwd) = self.cwd.grand_parent_as_file() {
|
||||
self.cwd = new_cwd;
|
||||
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(())
|
||||
}
|
||||
|
||||
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 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.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 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 left_widget(&self) -> HResult<Arc<Mutex<Option<ListView<Files>>>>> {
|
||||
let widget = self.columns.get_left_widget()?.widget()?;
|
||||
Ok(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 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(())
|
||||
|
|
21
src/files.rs
21
src/files.rs
|
@ -3,6 +3,7 @@ use std::ops::Index;
|
|||
use std::os::unix::fs::MetadataExt;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::hash::{Hash, Hasher};
|
||||
|
||||
use lscolors::LsColors;
|
||||
use mime_detective;
|
||||
|
@ -294,6 +295,16 @@ impl PartialEq for File {
|
|||
}
|
||||
}
|
||||
|
||||
impl Hash for File {
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
self.name.hash(state);
|
||||
self.path.hash(state);
|
||||
self.selected.hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for File {}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct File {
|
||||
pub name: String,
|
||||
|
@ -403,6 +414,16 @@ impl File {
|
|||
Some(mime.type_().as_str().to_string())
|
||||
}
|
||||
|
||||
|
||||
pub fn parent(&self) -> Option<PathBuf> {
|
||||
Some(self.path.parent()?.to_path_buf())
|
||||
}
|
||||
|
||||
pub fn parent_as_file(&self) -> HResult<File> {
|
||||
let pathbuf = self.parent()?;
|
||||
File::new_from_path(&pathbuf)
|
||||
}
|
||||
|
||||
pub fn grand_parent(&self) -> Option<PathBuf> {
|
||||
Some(self.path.parent()?.parent()?.to_path_buf())
|
||||
}
|
||||
|
|
91
src/hbox.rs
91
src/hbox.rs
|
@ -2,12 +2,13 @@ use termion::event::{Event};
|
|||
|
||||
use crate::widget::{Widget, WidgetCore};
|
||||
use crate::coordinates::{Coordinates, Size, Position};
|
||||
use crate::fail::{HResult, ErrorLog};
|
||||
use crate::fail::{HResult, HError, ErrorLog};
|
||||
|
||||
#[derive(PartialEq)]
|
||||
pub struct HBox<T: Widget> {
|
||||
pub core: WidgetCore,
|
||||
pub widgets: Vec<T>,
|
||||
pub ratios: Option<Vec<usize>>,
|
||||
pub active: Option<usize>,
|
||||
}
|
||||
|
||||
|
@ -16,59 +17,89 @@ impl<T> HBox<T> where T: Widget + PartialEq {
|
|||
pub fn new(core: &WidgetCore) -> HBox<T> {
|
||||
HBox { core: core.clone(),
|
||||
widgets: vec![],
|
||||
ratios: None,
|
||||
active: None
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub fn resize_children(&mut self) {
|
||||
let coords: Vec<Coordinates>
|
||||
= self.widgets.iter().map(
|
||||
|w|
|
||||
self.calculate_coordinates(w)).collect();
|
||||
pub fn resize_children(&mut self) -> HResult<()> {
|
||||
let len = self.widgets.len();
|
||||
if len == 0 { return Ok(()) }
|
||||
|
||||
let coords: Vec<Coordinates> = self.calculate_coordinates()?;
|
||||
|
||||
|
||||
for (widget, coord) in self.widgets.iter_mut().zip(coords.iter()) {
|
||||
widget.set_coordinates(coord).log();
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn push_widget(&mut self, widget: T) where T: PartialEq {
|
||||
pub fn push_widget(&mut self, widget: T) {
|
||||
self.widgets.push(widget);
|
||||
self.resize_children();
|
||||
self.refresh().log();
|
||||
}
|
||||
|
||||
pub fn pop_widget(&mut self) -> Option<T> {
|
||||
let widget = self.widgets.pop();
|
||||
self.resize_children();
|
||||
self.refresh().log();
|
||||
widget
|
||||
}
|
||||
|
||||
pub fn prepend_widget(&mut self, widget: T) {
|
||||
self.widgets.insert(0, widget);
|
||||
self.resize_children();
|
||||
self.refresh().log();
|
||||
}
|
||||
|
||||
pub fn calculate_coordinates(&self, widget: &T)
|
||||
-> Coordinates where T: PartialEq {
|
||||
let coordinates = self.get_coordinates().unwrap();
|
||||
let xsize = coordinates.xsize();
|
||||
let ysize = coordinates.ysize();
|
||||
let top = coordinates.top().y();
|
||||
pub fn set_ratios(&mut self, ratios: Vec<usize>) {
|
||||
self.ratios = Some(ratios);
|
||||
}
|
||||
|
||||
let pos = self.widgets.iter().position(|w | w == widget).unwrap();
|
||||
let num = self.widgets.len();
|
||||
pub fn calculate_equal_ratios(&self) -> HResult<Vec<usize>> {
|
||||
let len = self.widgets.len();
|
||||
if len == 0 { return HError::no_widget(); }
|
||||
|
||||
let widget_xsize = (xsize / num as u16) + 1;
|
||||
let widget_xpos = widget_xsize * pos as u16;
|
||||
let ratios = (0..len).map(|_| 100 / len).collect();
|
||||
Ok(ratios)
|
||||
}
|
||||
|
||||
Coordinates {
|
||||
size: Size((widget_xsize,
|
||||
ysize)),
|
||||
position: Position((widget_xpos,
|
||||
top))
|
||||
}
|
||||
pub fn calculate_coordinates(&self)
|
||||
-> HResult<Vec<Coordinates>> {
|
||||
let box_coords = self.get_coordinates()?;
|
||||
let box_xsize = box_coords.xsize();
|
||||
let box_ysize = box_coords.ysize();
|
||||
let box_top = box_coords.top().y();
|
||||
|
||||
let ratios = match &self.ratios {
|
||||
Some(ratios) => ratios.clone(),
|
||||
None => self.calculate_equal_ratios()?
|
||||
};
|
||||
|
||||
let coords = ratios.iter().fold(Vec::<Coordinates>::new(), |mut coords, ratio| {
|
||||
let ratio = *ratio as u16;
|
||||
let len = coords.len();
|
||||
let gap = if len == 0 { 0 } else { 1 };
|
||||
|
||||
let widget_xsize = box_xsize * ratio / 100;
|
||||
let widget_xpos = if len == 0 {
|
||||
box_coords.top().x()
|
||||
} else {
|
||||
let prev_coords = coords.last().unwrap();
|
||||
let prev_xsize = prev_coords.xsize();
|
||||
let prev_xpos = prev_coords.position().x();
|
||||
|
||||
prev_xsize + prev_xpos + gap
|
||||
};
|
||||
|
||||
coords.push(Coordinates {
|
||||
size: Size((widget_xsize,
|
||||
box_ysize)),
|
||||
position: Position((widget_xpos,
|
||||
box_top))
|
||||
});
|
||||
coords
|
||||
});
|
||||
|
||||
Ok(coords)
|
||||
}
|
||||
|
||||
pub fn active_widget(&self) -> &T {
|
||||
|
@ -92,7 +123,7 @@ impl<T> Widget for HBox<T> where T: Widget + PartialEq {
|
|||
}
|
||||
|
||||
fn refresh(&mut self) -> HResult<()> {
|
||||
self.resize_children();
|
||||
self.resize_children().log();
|
||||
for child in &mut self.widgets {
|
||||
child.refresh()?
|
||||
}
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
use termion::event::Key;
|
||||
use failure::Backtrace;
|
||||
|
||||
use crate::coordinates::{Coordinates, Position, Size};
|
||||
use crate::preview::Previewer;
|
||||
use crate::coordinates::{Coordinates};
|
||||
use crate::widget::{Widget, WidgetCore};
|
||||
use crate::hbox::HBox;
|
||||
use crate::fail::{HError, HResult, ErrorLog};
|
||||
|
@ -11,11 +10,6 @@ use crate::fail::{HError, HResult, ErrorLog};
|
|||
pub struct MillerColumns<T> where T: Widget {
|
||||
pub widgets: HBox<T>,
|
||||
pub core: WidgetCore,
|
||||
// pub left: Option<T>,
|
||||
// pub main: Option<T>,
|
||||
//pub preview: AsyncPreviewer,
|
||||
pub preview: Previewer,
|
||||
pub ratio: (u16, u16, u16),
|
||||
}
|
||||
|
||||
impl<T> MillerColumns<T>
|
||||
|
@ -26,8 +20,6 @@ where
|
|||
MillerColumns {
|
||||
widgets: HBox::new(core),
|
||||
core: core.clone(),
|
||||
ratio: (20, 30, 50),
|
||||
preview: Previewer::new(core)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -46,64 +38,45 @@ where
|
|||
self.widgets.prepend_widget(widget);
|
||||
}
|
||||
|
||||
pub fn calculate_coordinates(&self) -> (Coordinates, Coordinates, Coordinates) {
|
||||
let coordinates = self.get_coordinates().unwrap();
|
||||
let xsize = coordinates.xsize();
|
||||
let ysize = coordinates.ysize();
|
||||
let top = coordinates.top().y();
|
||||
let ratio = self.ratio;
|
||||
pub fn set_ratios(&mut self, ratios: Vec<usize>) {
|
||||
self.widgets.set_ratios(ratios);
|
||||
}
|
||||
|
||||
let left_xsize = xsize * ratio.0 / 100;
|
||||
let left_size = Size((left_xsize, ysize));
|
||||
let left_pos = coordinates.top();
|
||||
|
||||
let main_xsize = xsize * ratio.1 / 100;
|
||||
let main_size = Size((main_xsize, ysize));
|
||||
let main_pos = Position((left_xsize + 2, top));
|
||||
|
||||
let preview_xsize = xsize * ratio.2 / 100;
|
||||
let preview_size = Size((preview_xsize - 1, ysize));
|
||||
let preview_pos = Position((left_xsize + main_xsize + 3, top));
|
||||
|
||||
let left_coords = Coordinates {
|
||||
size: left_size,
|
||||
position: left_pos,
|
||||
};
|
||||
|
||||
let main_coords = Coordinates {
|
||||
size: main_size,
|
||||
position: main_pos,
|
||||
};
|
||||
|
||||
let preview_coords = Coordinates {
|
||||
size: preview_size,
|
||||
position: preview_pos,
|
||||
};
|
||||
|
||||
(left_coords, main_coords, preview_coords)
|
||||
pub fn calculate_coordinates(&self) -> HResult<Vec<Coordinates>> {
|
||||
self.widgets.calculate_coordinates()
|
||||
}
|
||||
|
||||
pub fn get_left_widget(&self) -> HResult<&T> {
|
||||
let len = self.widgets.widgets.len();
|
||||
if len < 2 {
|
||||
if len < 3 {
|
||||
return Err(HError::NoWidgetError(Backtrace::new()));
|
||||
}
|
||||
let widget = self.widgets.widgets.get(len - 2)?;
|
||||
let widget = self.widgets.widgets.get(len - 3)?;
|
||||
Ok(widget)
|
||||
}
|
||||
pub fn get_left_widget_mut(&mut self) -> HResult<&mut T> {
|
||||
let len = self.widgets.widgets.len();
|
||||
if len < 2 {
|
||||
if len < 3 {
|
||||
return Err(HError::NoWidgetError(Backtrace::new()));
|
||||
}
|
||||
let widget = self.widgets.widgets.get_mut(len - 2)?;
|
||||
let widget = self.widgets.widgets.get_mut(len - 3)?;
|
||||
Ok(widget)
|
||||
}
|
||||
pub fn get_main_widget(&self) -> HResult<&T> {
|
||||
let widget = self.widgets.widgets.last()?;
|
||||
let len = self.widgets.widgets.len();
|
||||
let widget = self.widgets.widgets.get(len-2)?;
|
||||
Ok(widget)
|
||||
}
|
||||
pub fn get_main_widget_mut(&mut self) -> HResult<&mut T> {
|
||||
let len = self.widgets.widgets.len();
|
||||
let widget = self.widgets.widgets.get_mut(len-2)?;
|
||||
Ok(widget)
|
||||
}
|
||||
pub fn get_right_widget(&self) -> HResult<&T> {
|
||||
let widget = self.widgets.widgets.last()?;
|
||||
Ok(widget)
|
||||
}
|
||||
pub fn get_right_widget_mut(&mut self) -> HResult<&mut T> {
|
||||
let widget = self.widgets.widgets.last_mut()?;
|
||||
Ok(widget)
|
||||
}
|
||||
|
@ -121,29 +94,18 @@ where
|
|||
Ok(&mut self.core)
|
||||
}
|
||||
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).log();
|
||||
}
|
||||
|
||||
if let Ok(main_widget) = self.get_main_widget_mut() {
|
||||
main_widget.set_coordinates(&main_coords).log();
|
||||
}
|
||||
|
||||
let preview_widget = &mut self.preview;
|
||||
preview_widget.set_coordinates(&preview_coords)?;
|
||||
self.widgets.refresh().log();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn get_drawlist(&self) -> HResult<String> {
|
||||
let left_widget = self.get_left_widget()?;
|
||||
let main_widget = self.get_main_widget()?;
|
||||
let preview = self.preview.get_drawlist()?;
|
||||
let right_widget = self.get_right_widget()?;
|
||||
Ok(format!("{}{}{}",
|
||||
main_widget.get_drawlist()?,
|
||||
left_widget.get_drawlist()?,
|
||||
preview))
|
||||
right_widget.get_drawlist()?))
|
||||
}
|
||||
|
||||
fn on_key(&mut self, key: Key) -> HResult<()> {
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
use std::io::Write;
|
||||
|
||||
use termion::event::Key;
|
||||
|
||||
use crate::coordinates::{Coordinates};
|
||||
|
|
|
@ -11,6 +11,7 @@ use crate::fail::{HResult, HError, ErrorLog};
|
|||
|
||||
|
||||
type HClosure<T> = Box<Fn(Arc<Mutex<bool>>) -> Result<T, HError> + Send>;
|
||||
type HCClosure<T> = Box<Fn(Arc<Mutex<bool>>, WidgetCore) -> Result<T, HError> + Send>;
|
||||
type WidgetO = Box<dyn Widget + Send>;
|
||||
|
||||
lazy_static! {
|
||||
|
@ -111,7 +112,7 @@ impl<W: Widget + Send + 'static> PartialEq for WillBeWidget<W> {
|
|||
}
|
||||
}
|
||||
|
||||
pub struct WillBeWidget<T: Widget + Send> {
|
||||
pub struct WillBeWidget<T: Widget + Send + 'static> {
|
||||
willbe: WillBe<T>,
|
||||
core: WidgetCore
|
||||
}
|
||||
|
@ -129,6 +130,24 @@ impl<T: Widget + Send + 'static> WillBeWidget<T> {
|
|||
core: core.clone()
|
||||
}
|
||||
}
|
||||
pub fn change_to(&mut self, closure: HCClosure<T>) -> HResult<()> {
|
||||
self.set_stale().log();
|
||||
|
||||
let sender = self.get_core()?.get_sender();
|
||||
let core = self.get_core()?.clone();
|
||||
|
||||
let mut willbe = WillBe::new_become(Box::new(move |stale| {
|
||||
let core = core.clone();
|
||||
closure(stale, core)
|
||||
}));
|
||||
willbe.on_ready(Box::new(move |_| {
|
||||
sender.send(crate::widget::Events::WidgetReady)?;
|
||||
Ok(())
|
||||
}))?;
|
||||
|
||||
self.willbe = willbe;
|
||||
Ok(())
|
||||
}
|
||||
pub fn set_stale(&mut self) -> HResult<()> {
|
||||
self.willbe.set_stale()
|
||||
}
|
||||
|
@ -136,6 +155,12 @@ impl<T: Widget + Send + 'static> WillBeWidget<T> {
|
|||
self.willbe.check()?;
|
||||
Ok(self.willbe.thing.clone())
|
||||
}
|
||||
pub fn ready(&self) -> bool {
|
||||
match self.willbe.check() {
|
||||
Ok(_) => true,
|
||||
_ => false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// impl<T: Widget + Send> WillBeWidget<T> {
|
||||
|
@ -157,11 +182,13 @@ impl<T: Widget + Send + 'static> Widget for WillBeWidget<T> {
|
|||
Ok(&mut self.core)
|
||||
}
|
||||
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()
|
||||
if let Ok(widget) = self.widget() {
|
||||
let mut widget = widget.lock()?;
|
||||
let widget = widget.as_mut()?;
|
||||
widget.set_coordinates(self.get_coordinates()?).log();
|
||||
widget.refresh().log();
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
fn get_drawlist(&self) -> HResult<String> {
|
||||
if self.willbe.check().is_err() {
|
||||
|
@ -170,6 +197,9 @@ impl<T: Widget + Send + 'static> Widget for WillBeWidget<T> {
|
|||
let pos = crate::term::goto_xy(xpos, ypos);
|
||||
return Ok(clear + &pos + "...")
|
||||
}
|
||||
if is_stale(&self.willbe.stale)? {
|
||||
return self.get_clearlist()
|
||||
}
|
||||
let widget = self.widget()?;
|
||||
let widget = widget.lock()?;
|
||||
let widget = widget.as_ref()?;
|
||||
|
@ -199,7 +229,8 @@ impl PartialEq for Previewer {
|
|||
pub struct Previewer {
|
||||
widget: WillBeWidget<Box<dyn Widget + Send>>,
|
||||
core: WidgetCore,
|
||||
file: Option<File>
|
||||
file: Option<File>,
|
||||
selection: Option<File>
|
||||
}
|
||||
|
||||
|
||||
|
@ -212,7 +243,8 @@ impl Previewer {
|
|||
}));
|
||||
Previewer { widget: willbe,
|
||||
core: core.clone(),
|
||||
file: None}
|
||||
file: None,
|
||||
selection: None }
|
||||
}
|
||||
|
||||
fn become_preview(&mut self,
|
||||
|
@ -222,9 +254,10 @@ impl Previewer {
|
|||
self.widget.set_coordinates(&coordinates).ok();
|
||||
}
|
||||
|
||||
pub fn set_file(&mut self, file: &File) {
|
||||
pub fn set_file(&mut self, file: &File, selection: Option<File>) {
|
||||
if Some(file) == self.file.as_ref() { return }
|
||||
self.file = Some(file.clone());
|
||||
self.selection = selection.clone();
|
||||
|
||||
let coordinates = self.get_coordinates().unwrap().clone();
|
||||
let file = file.clone();
|
||||
|
@ -236,9 +269,13 @@ impl Previewer {
|
|||
kill_proc().unwrap();
|
||||
|
||||
let file = file.clone();
|
||||
let selection = selection.clone();
|
||||
|
||||
if file.kind == Kind::Directory {
|
||||
let preview = Previewer::preview_dir(&file, &core, stale.clone());
|
||||
let preview = Previewer::preview_dir(&file,
|
||||
selection,
|
||||
&core,
|
||||
stale.clone());
|
||||
return preview;
|
||||
}
|
||||
|
||||
|
@ -261,7 +298,7 @@ impl Previewer {
|
|||
pub fn reload(&mut self) {
|
||||
if let Some(file) = self.file.clone() {
|
||||
self.file = None;
|
||||
self.set_file(&file);
|
||||
self.set_file(&file, self.selection.clone());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -269,15 +306,21 @@ impl Previewer {
|
|||
Err(HError::PreviewFailed { file: file.name.clone() })
|
||||
}
|
||||
|
||||
fn preview_dir(file: &File, core: &WidgetCore, stale: Arc<Mutex<bool>>)
|
||||
fn preview_dir(file: &File,
|
||||
selection: Option<File>,
|
||||
core: &WidgetCore,
|
||||
stale: Arc<Mutex<bool>>)
|
||||
-> Result<WidgetO, HError> {
|
||||
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(&core, files);
|
||||
if let Some(selection) = selection {
|
||||
file_list.select_file(&selection);
|
||||
}
|
||||
file_list.set_coordinates(&core.coordinates)?;
|
||||
file_list.refresh()?;
|
||||
if is_stale(&stale)? { return Previewer::preview_failed(&file) }
|
||||
|
@ -529,6 +572,9 @@ impl<T> Widget for Box<T> where T: Widget + ?Sized {
|
|||
fn get_core(&self) -> HResult<&WidgetCore> {
|
||||
Ok((**self).get_core()?)
|
||||
}
|
||||
fn get_core_mut(&mut self) -> HResult<&mut WidgetCore> {
|
||||
Ok((**self).get_core_mut()?)
|
||||
}
|
||||
fn render_header(&self) -> HResult<String> {
|
||||
(**self).render_header()
|
||||
}
|
||||
|
|
154
src/proclist.rs
154
src/proclist.rs
|
@ -7,10 +7,10 @@ use std::io::{BufRead, BufReader};
|
|||
use termion::event::Key;
|
||||
use unicode_width::UnicodeWidthStr;
|
||||
|
||||
use crate::coordinates::{Coordinates, Size, Position};
|
||||
use crate::listview::{Listable, ListView};
|
||||
use crate::textview::TextView;
|
||||
use crate::widget::{Widget, Events, WidgetCore};
|
||||
use crate::hbox::HBox;
|
||||
use crate::preview::WillBeWidget;
|
||||
use crate::fail::{HResult, HError, ErrorLog};
|
||||
use crate::term;
|
||||
|
@ -26,6 +26,12 @@ struct Process {
|
|||
|
||||
}
|
||||
|
||||
impl PartialEq for Process {
|
||||
fn eq(&self, other: &Process) -> bool {
|
||||
self.cmd == other.cmd
|
||||
}
|
||||
}
|
||||
|
||||
impl Process {
|
||||
fn read_proc(&mut self) -> HResult<()> {
|
||||
let handle = self.handle.clone();
|
||||
|
@ -46,7 +52,8 @@ impl Process {
|
|||
sender.send(Events::WidgetReady).unwrap();
|
||||
}
|
||||
Err(err) => {
|
||||
dbg!(err);
|
||||
let err: HResult<()> = Err(HError::from(err));
|
||||
err.log();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -143,96 +150,117 @@ impl ListView<Vec<Process>> {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(PartialEq)]
|
||||
enum ProcViewWidgets {
|
||||
List(ListView<Vec<Process>>),
|
||||
TextView(WillBeWidget<TextView>),
|
||||
}
|
||||
|
||||
impl Widget for ProcViewWidgets {
|
||||
fn get_core(&self) -> HResult<&WidgetCore> {
|
||||
match self {
|
||||
ProcViewWidgets::List(widget) => widget.get_core(),
|
||||
ProcViewWidgets::TextView(widget) => widget.get_core()
|
||||
}
|
||||
}
|
||||
fn get_core_mut(&mut self) -> HResult<&mut WidgetCore> {
|
||||
match self {
|
||||
ProcViewWidgets::List(widget) => widget.get_core_mut(),
|
||||
ProcViewWidgets::TextView(widget) => widget.get_core_mut()
|
||||
}
|
||||
}
|
||||
fn refresh(&mut self) -> HResult<()> {
|
||||
match self {
|
||||
ProcViewWidgets::List(widget) => widget.refresh(),
|
||||
ProcViewWidgets::TextView(widget) => widget.refresh()
|
||||
}
|
||||
}
|
||||
fn get_drawlist(&self) -> HResult<String> {
|
||||
match self {
|
||||
ProcViewWidgets::List(widget) => widget.get_drawlist(),
|
||||
ProcViewWidgets::TextView(widget) => widget.get_drawlist()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ProcView {
|
||||
core: WidgetCore,
|
||||
proc_list: ListView<Vec<Process>>,
|
||||
textview: WillBeWidget<TextView>,
|
||||
hbox: HBox<ProcViewWidgets>,
|
||||
viewing: Option<usize>
|
||||
}
|
||||
|
||||
impl HBox<ProcViewWidgets> {
|
||||
fn get_listview(&mut self) -> &mut ListView<Vec<Process>> {
|
||||
match &mut self.widgets[0] {
|
||||
ProcViewWidgets::List(listview) => listview,
|
||||
_ => unreachable!()
|
||||
}
|
||||
}
|
||||
fn get_textview(&mut self) -> &mut WillBeWidget<TextView> {
|
||||
match &mut self.widgets[1] {
|
||||
ProcViewWidgets::TextView(textview) => textview,
|
||||
_ => unreachable!()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ProcView {
|
||||
pub fn new(core: &WidgetCore) -> ProcView {
|
||||
let tcore = core.clone();
|
||||
let listview = ListView::new(&core, vec![]);
|
||||
let textview = Box::new(move |_| Ok(TextView::new_blank(&tcore)));
|
||||
let textview = WillBeWidget::new(&core, textview);
|
||||
let mut hbox = HBox::new(&core);
|
||||
hbox.push_widget(ProcViewWidgets::List(listview));
|
||||
hbox.push_widget(ProcViewWidgets::TextView(textview));
|
||||
hbox.set_ratios(vec![33, 66]);
|
||||
hbox.refresh().log();
|
||||
ProcView {
|
||||
core: core.clone(),
|
||||
proc_list: ListView::new(&core, vec![]),
|
||||
textview: WillBeWidget::new(&core, textview),
|
||||
hbox: hbox,
|
||||
viewing: None
|
||||
}
|
||||
}
|
||||
|
||||
fn get_listview(&mut self) -> &mut ListView<Vec<Process>> {
|
||||
self.hbox.get_listview()
|
||||
}
|
||||
|
||||
fn get_textview(&mut self) -> &mut WillBeWidget<TextView> {
|
||||
self.hbox.get_textview()
|
||||
}
|
||||
|
||||
pub fn run_proc(&mut self, cmd: &str) -> HResult<()> {
|
||||
self.proc_list.run_proc(cmd)?;
|
||||
self.get_listview().run_proc(cmd)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
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 = WillBeWidget::new(&core.clone(), Box::new(move |_| {
|
||||
self.get_listview().remove_proc()?;
|
||||
self.get_textview().change_to(Box::new(move |_, core| {
|
||||
let mut textview = TextView::new_blank(&core);
|
||||
textview.refresh().log();
|
||||
textview.animate_slide_up().log();
|
||||
Ok(textview)
|
||||
}));
|
||||
self.textview.set_coordinates(&coords2).log();
|
||||
})).log();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn show_output(&mut self) -> HResult<()> {
|
||||
if Some(self.proc_list.get_selection()) == self.viewing {
|
||||
if Some(self.get_listview().get_selection()) == self.viewing {
|
||||
return Ok(());
|
||||
}
|
||||
let output = self.proc_list.selected_proc()?.output.lock()?.clone();
|
||||
let (_, coords) = self.calculate_coordinates();
|
||||
let mut core = self.core.clone();
|
||||
core.coordinates = coords;
|
||||
let output = self.get_listview().selected_proc()?.output.lock()?.clone();
|
||||
|
||||
self.textview = WillBeWidget::new(&core.clone(), Box::new(move |_| {
|
||||
self.get_textview().change_to(Box::new(move |_, core| {
|
||||
let mut textview = TextView::new_blank(&core);
|
||||
textview.set_text(&output).log();
|
||||
textview.animate_slide_up().log();
|
||||
Ok(textview)
|
||||
}));
|
||||
self.viewing = Some(self.proc_list.get_selection());
|
||||
})).log();
|
||||
self.viewing = Some(self.get_listview().get_selection());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn calculate_coordinates(&self) -> (Coordinates, Coordinates) {
|
||||
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 = coordinates.top();
|
||||
|
||||
let main_xsize = xsize * ratio.1 / 100;
|
||||
let main_size = Size((main_xsize, ysize));
|
||||
let main_pos = Position((left_xsize + 2, top));
|
||||
|
||||
|
||||
|
||||
let left_coords = Coordinates {
|
||||
size: left_size,
|
||||
position: left_pos,
|
||||
};
|
||||
|
||||
let main_coords = Coordinates {
|
||||
size: main_size,
|
||||
position: main_pos,
|
||||
};
|
||||
(left_coords, main_coords)
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
impl Widget for ProcView {
|
||||
|
@ -243,29 +271,27 @@ impl Widget for ProcView {
|
|||
Ok(&mut self.core)
|
||||
}
|
||||
fn refresh(&mut self) -> HResult<()> {
|
||||
let (lcoord, rcoord) = self.calculate_coordinates();
|
||||
self.proc_list.set_coordinates(&lcoord).log();
|
||||
self.textview.set_coordinates(&rcoord).log();
|
||||
self.hbox.refresh().log();
|
||||
|
||||
self.show_output().log();
|
||||
self.proc_list.refresh().log();
|
||||
self.textview.refresh().log();
|
||||
self.get_listview().refresh().log();
|
||||
self.get_textview().refresh().log();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
fn get_drawlist(&self) -> HResult<String> {
|
||||
Ok(self.proc_list.get_drawlist()? + &self.textview.get_drawlist()?)
|
||||
self.hbox.get_drawlist()
|
||||
}
|
||||
fn on_key(&mut self, key: Key) -> HResult<()> {
|
||||
match key {
|
||||
Key::Char('w') => { return Err(HError::PopupFinnished) }
|
||||
Key::Char('d') => { self.remove_proc()? }
|
||||
Key::Char('k') => { self.proc_list.kill_proc()? }
|
||||
Key::Char('k') => { self.get_listview().kill_proc()? }
|
||||
Key::Up | Key::Char('p') => {
|
||||
self.proc_list.move_up();
|
||||
self.get_listview().move_up();
|
||||
}
|
||||
Key::Down | Key::Char('n') => {
|
||||
self.proc_list.move_down();
|
||||
self.get_listview().move_down();
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
|
|
@ -80,6 +80,9 @@ impl<T> Widget for TabView<T> where T: Widget, TabView<T>: Tabbable {
|
|||
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 header = self.active_tab_().render_header()?;
|
||||
|
|
|
@ -4,7 +4,6 @@ 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};
|
||||
|
@ -81,15 +80,12 @@ impl WidgetCore {
|
|||
}
|
||||
|
||||
pub trait Widget {
|
||||
fn get_widget(&self) -> Box<dyn Widget> {
|
||||
Box::new(crate::textview::TextView::new_blank(self.get_core().unwrap()))
|
||||
}
|
||||
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_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)
|
||||
}
|
||||
|
@ -205,6 +201,7 @@ pub trait Widget {
|
|||
|
||||
fn popup(&mut self) -> HResult<()> {
|
||||
self.run_widget().log();
|
||||
self.clear().log();
|
||||
self.get_core()?.get_sender().send(Events::ExclusiveEvent(None))?;
|
||||
Ok(())
|
||||
}
|
||||
|
@ -355,9 +352,9 @@ fn dispatch_events(rx: Receiver<Events>, tx: Sender<Events>) {
|
|||
_ => {}
|
||||
}
|
||||
if let Some(tx_event) = &tx_exclusive_event {
|
||||
tx_event.send(event).unwrap();
|
||||
tx_event.send(event).ok();
|
||||
} else {
|
||||
tx.send(event).unwrap();
|
||||
tx.send(event).ok();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue