mirror of https://github.com/bobwen-dev/hunter
added on_ready support
This commit is contained in:
parent
fe542047c2
commit
3b38143f9b
48
src/fail.rs
48
src/fail.rs
|
@ -1,4 +1,6 @@
|
|||
use failure;
|
||||
use failure::Error;
|
||||
use failure::{Fail, ResultExt};
|
||||
|
||||
pub type HResult<T> = Result<T, HError>;
|
||||
|
||||
|
@ -8,36 +10,80 @@ pub enum HError {
|
|||
IoError{#[cause] error: std::io::Error},
|
||||
#[fail(display = "Mutex failed")]
|
||||
MutexError,
|
||||
#[fail(display = "Can't lock!")]
|
||||
TryLockError,
|
||||
#[fail(display = "Channel failed: {}", error)]
|
||||
ChannelTryRecvError{#[cause] error: std::sync::mpsc::TryRecvError},
|
||||
#[fail(display = "Channel failed: {}", error)]
|
||||
ChannelRecvError{#[cause] error: std::sync::mpsc::RecvError},
|
||||
#[fail(display = "Channel failed")]
|
||||
ChannelSendError,
|
||||
#[fail(display = "Previewer failed on file: {}", file)]
|
||||
PreviewFailed{file: String},
|
||||
#[fail(display = "StalePreviewer for file: {}", file)]
|
||||
StalePreviewError{file: String},
|
||||
#[fail(display = "Failed: {}", error)]
|
||||
Error{#[cause] error: failure::Error }
|
||||
Error{#[cause] error: failure::Error },
|
||||
#[fail(display = "Was None!")]
|
||||
NoneError,
|
||||
#[fail(display = "Not ready yet!")]
|
||||
WillBeNotReady,
|
||||
#[fail(display = "No widget found")]
|
||||
NoWidgetError
|
||||
}
|
||||
|
||||
impl From<std::io::Error> for HError {
|
||||
fn from(error: std::io::Error) -> Self {
|
||||
dbg!(&error);
|
||||
HError::IoError { error: error }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<failure::Error> for HError {
|
||||
fn from(error: failure::Error) -> Self {
|
||||
dbg!(&error);
|
||||
HError::Error { error: error }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<std::sync::mpsc::TryRecvError> for HError {
|
||||
fn from(error: std::sync::mpsc::TryRecvError) -> Self {
|
||||
dbg!(&error);
|
||||
HError::ChannelTryRecvError { error: error }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<std::sync::mpsc::RecvError> for HError {
|
||||
fn from(error: std::sync::mpsc::RecvError) -> Self {
|
||||
dbg!(&error);
|
||||
HError::ChannelRecvError { error: error }
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<std::sync::mpsc::SendError<T>> for HError {
|
||||
fn from(error: std::sync::mpsc::SendError<T>) -> Self {
|
||||
dbg!(&error);
|
||||
HError::ChannelSendError
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<std::sync::PoisonError<T>> for HError {
|
||||
fn from(_: std::sync::PoisonError<T>) -> Self {
|
||||
dbg!("Poisoned Mutex");
|
||||
HError::MutexError
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<std::sync::TryLockError<T>> for HError {
|
||||
fn from(error: std::sync::TryLockError<T>) -> Self {
|
||||
dbg!(&error);
|
||||
HError::TryLockError
|
||||
}
|
||||
}
|
||||
|
||||
impl From<std::option::NoneError> for HError {
|
||||
fn from(error: std::option::NoneError) -> Self {
|
||||
dbg!(&error);
|
||||
HError::NoneError
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ use termion::event::Key;
|
|||
|
||||
use std::error::Error;
|
||||
use std::io::Write;
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
use crate::coordinates::{Coordinates};
|
||||
use crate::files::{File, Files};
|
||||
|
@ -9,10 +10,13 @@ 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::{HError, HResult};
|
||||
|
||||
#[derive(PartialEq)]
|
||||
pub struct FileBrowser {
|
||||
pub columns: MillerColumns<ListView<Files>>,
|
||||
pub columns: MillerColumns<WillBeWidget<ListView<Files>>>,
|
||||
pub cwd: File
|
||||
}
|
||||
|
||||
impl Tabbable for TabView<FileBrowser> {
|
||||
|
@ -55,37 +59,70 @@ impl FileBrowser {
|
|||
miller.set_coordinates(&coords);
|
||||
|
||||
|
||||
let lists: Result<Vec<ListView<Files>>, Box<Error>> = cwd
|
||||
.ancestors()
|
||||
.map(|path| Ok(ListView::new(Files::new_from_path(path)?)))
|
||||
.take(2)
|
||||
.collect();
|
||||
let mut lists = lists?;
|
||||
lists.reverse();
|
||||
// let lists: Result<Vec<ListView<Files>>, Box<Error>> = cwd
|
||||
// .ancestors()
|
||||
// .map(|path| Ok(ListView::new(Files::new_from_path(path)?)))
|
||||
// .take(2)
|
||||
// .collect();
|
||||
// let mut lists = lists?;
|
||||
// lists.reverse();
|
||||
let (left_coords, main_coords, _) = miller.calculate_coordinates();
|
||||
|
||||
for widget in lists {
|
||||
miller.push_widget(widget);
|
||||
}
|
||||
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();
|
||||
Ok(list)
|
||||
}));
|
||||
|
||||
let mut file_browser = FileBrowser { columns: miller };
|
||||
let left_path: std::path::PathBuf = cwd.ancestors().skip(1).take(1).map(|path| std::path::PathBuf::from(path)).collect();
|
||||
let left_widget = WillBeWidget::new(Box::new(move |_| {
|
||||
let mut list = ListView::new(Files::new_from_path(&left_path).unwrap());
|
||||
list.set_coordinates(&left_coords);
|
||||
list.animate_slide_up();
|
||||
Ok(list)
|
||||
}));
|
||||
|
||||
|
||||
file_browser.fix_selection();
|
||||
file_browser.animate_columns();
|
||||
file_browser.update_preview();
|
||||
|
||||
|
||||
miller.push_widget(left_widget);
|
||||
miller.push_widget(main_widget);
|
||||
|
||||
// for widget in lists {
|
||||
// miller.push_widget(widget);
|
||||
// }
|
||||
|
||||
let cwd = File::new_from_path(&cwd).unwrap();
|
||||
|
||||
let mut file_browser = FileBrowser { columns: miller,
|
||||
cwd: cwd };
|
||||
|
||||
|
||||
|
||||
//file_browser.fix_selection();
|
||||
//file_browser.animate_columns();
|
||||
//file_browser.update_preview();
|
||||
|
||||
Ok(file_browser)
|
||||
}
|
||||
|
||||
pub fn enter_dir(&mut self) {
|
||||
let file = self.selected_file();
|
||||
pub fn enter_dir(&mut self) -> HResult<()> {
|
||||
let file = self.selected_file()?;
|
||||
let (_, coords, _) = self.columns.calculate_coordinates();
|
||||
|
||||
match file.read_dir() {
|
||||
Ok(files) => {
|
||||
std::env::set_current_dir(&file.path).unwrap();
|
||||
let view = ListView::new(files);
|
||||
let view = WillBeWidget::new(Box::new(move |_| {
|
||||
let files = files.clone();
|
||||
let mut list = ListView::new(files);
|
||||
list.set_coordinates(&coords);
|
||||
list.animate_slide_up();
|
||||
Ok(list)
|
||||
}));
|
||||
self.columns.push_widget(view);
|
||||
self.update_preview();
|
||||
},
|
||||
_ => {
|
||||
let status = std::process::Command::new("rifle")
|
||||
|
@ -103,102 +140,121 @@ impl FileBrowser {
|
|||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn go_back(&mut self) {
|
||||
if self.columns.get_left_widget().is_none() {
|
||||
return;
|
||||
}
|
||||
let fileview = self.columns.get_main_widget();
|
||||
let path = fileview.selected_file().grand_parent().unwrap();
|
||||
std::env::set_current_dir(path).unwrap();
|
||||
pub fn go_back(&mut self) -> HResult<()> {
|
||||
// if self.left_widget().is_err() {
|
||||
// return None;
|
||||
// }
|
||||
// if self.columns.get_main_widget().is_none() {
|
||||
// return None;
|
||||
// }
|
||||
let fileview = self.main_widget()?;
|
||||
let path = self.selected_file()?.grand_parent()?;
|
||||
std::env::set_current_dir(path)?;
|
||||
self.columns.pop_widget();
|
||||
|
||||
// Make sure there's a directory on the left unless it's /
|
||||
if self.columns.get_left_widget().is_none() {
|
||||
let file = self.columns.get_main_widget().clone_selected_file();
|
||||
if self.left_widget().is_err() {
|
||||
let file = self.selected_file()?.clone();
|
||||
if let Some(grand_parent) = file.grand_parent() {
|
||||
let mut left_view = ListView::new(Files::new_from_path(&grand_parent).unwrap());
|
||||
left_view.select_file(&file);
|
||||
let mut left_view = WillBeWidget::new(Box::new(move |_| {
|
||||
let mut view
|
||||
= ListView::new(Files::new_from_path(&grand_parent)?);
|
||||
Ok(view)
|
||||
}));
|
||||
self.columns.prepend_widget(left_view);
|
||||
}
|
||||
}
|
||||
self.fix_selection();
|
||||
self.columns.refresh();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn update_preview(&mut self) {
|
||||
if self.columns.get_main_widget().content.len() == 0 { return }
|
||||
let file = self.columns.get_main_widget().selected_file().clone();
|
||||
pub fn update_preview(&mut self) -> HResult<()> {
|
||||
let file = self.selected_file()?.clone();
|
||||
let preview = &mut self.columns.preview;
|
||||
preview.set_file(&file);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn fix_selection(&mut self) {
|
||||
let cwd = self.cwd();
|
||||
self.columns.get_left_widget_mut()
|
||||
.map(|w|
|
||||
w.select_file(&cwd));
|
||||
pub fn fix_selection(&mut self) -> HResult<()> {
|
||||
let cwd = self.cwd()?;
|
||||
(*self.left_widget()?.lock()?).as_mut()?.select_file(&cwd);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn cwd(&self) -> File {
|
||||
self.columns.get_main_widget().content.directory.clone()
|
||||
pub fn cwd(&self) -> HResult<File> {
|
||||
//(self.columns.get_main_widget()?.widget()?.content.directory.clone())
|
||||
let widget = self.columns.get_main_widget()?.widget()?;
|
||||
let cwd = (*widget.lock()?).as_ref()?.content.directory.clone();
|
||||
Ok(cwd)
|
||||
}
|
||||
|
||||
pub fn selected_file(&self) -> &File {
|
||||
self.main_column().selected_file()
|
||||
pub fn selected_file(&self) -> HResult<File> {
|
||||
let widget = self.main_widget()?;
|
||||
let file = widget.lock()?.as_ref()?.selected_file().clone();
|
||||
Ok(file)
|
||||
}
|
||||
|
||||
pub fn main_column(&self) -> &ListView<Files> {
|
||||
self.columns.get_main_widget()
|
||||
pub fn main_widget(&self) -> HResult<Arc<Mutex<Option<ListView<Files>>>>> {
|
||||
let widget = self.columns.get_main_widget()?.widget()?;
|
||||
Ok(widget)
|
||||
}
|
||||
|
||||
pub fn quit_with_dir(&self) {
|
||||
let cwd = self.cwd().path;
|
||||
let selected_file = self.selected_file().path.to_string_lossy();
|
||||
pub fn left_widget(&self) -> HResult<Arc<Mutex<Option<ListView<Files>>>>> {
|
||||
let widget = self.columns.get_left_widget()?.widget()?;
|
||||
Ok(widget)
|
||||
}
|
||||
|
||||
let mut filepath = dirs_2::home_dir().unwrap();
|
||||
pub fn quit_with_dir(&self) -> HResult<()> {
|
||||
let cwd = self.cwd()?.path;
|
||||
let selected_file = self.selected_file()?;
|
||||
let selected_file = selected_file.path.to_string_lossy();
|
||||
|
||||
let mut filepath = dirs_2::home_dir()?;
|
||||
filepath.push(".hunter_cwd");
|
||||
|
||||
let output = format!("HUNTER_CWD=\"{}\"\nF=\"{}\"",
|
||||
cwd.to_str().unwrap(),
|
||||
cwd.to_str()?,
|
||||
selected_file);
|
||||
|
||||
let mut file = std::fs::File::create(filepath).unwrap();
|
||||
file.write(output.as_bytes()).unwrap();
|
||||
let mut file = std::fs::File::create(filepath)?;
|
||||
file.write(output.as_bytes())?;
|
||||
panic!("Quitting!");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn animate_columns(&mut self) {
|
||||
self.columns.get_left_widget_mut().map(|w| w.animate_slide_up());
|
||||
self.columns.get_main_widget_mut().animate_slide_up();
|
||||
self.columns.get_main_widget_mut().unwrap().animate_slide_up();
|
||||
}
|
||||
|
||||
pub fn turbo_cd(&mut self) {
|
||||
let dir = self.minibuffer("cd: ");
|
||||
|
||||
match dir {
|
||||
Some(dir) => {
|
||||
Files::new_from_path(&std::path::PathBuf::from(&dir)).and_then(|files| {
|
||||
let cwd = files.directory.clone();
|
||||
self.columns.widgets.widgets.clear();
|
||||
self.columns.push_widget(ListView::new(files));
|
||||
// match dir {
|
||||
// Some(dir) => {
|
||||
// Files::new_from_path(&std::path::PathBuf::from(&dir)).and_then(|files| {
|
||||
// let cwd = files.directory.clone();
|
||||
// self.columns.widgets.widgets.clear();
|
||||
// self.columns.push_widget(ListView::new(files));
|
||||
|
||||
std::env::set_current_dir(&cwd.path).unwrap();
|
||||
// std::env::set_current_dir(&cwd.path).unwrap();
|
||||
|
||||
if let Some(grand_parent) = cwd.path.parent() {
|
||||
let left_view =
|
||||
ListView::new(Files::new_from_path(&grand_parent).unwrap());
|
||||
self.columns.prepend_widget(left_view);
|
||||
}
|
||||
self.fix_selection();
|
||||
self.update_preview();
|
||||
self.refresh();
|
||||
self.columns.refresh();
|
||||
Ok(())
|
||||
}).ok();
|
||||
} None => {}
|
||||
}
|
||||
// if let Some(grand_parent) = cwd.path.parent() {
|
||||
// let left_view =
|
||||
// ListView::new(Files::new_from_path(&grand_parent).unwrap());
|
||||
// self.columns.prepend_widget(left_view);
|
||||
// }
|
||||
// self.fix_selection();
|
||||
// self.update_preview();
|
||||
// self.refresh();
|
||||
// self.columns.refresh();
|
||||
// Ok(())
|
||||
// }).ok();
|
||||
// } None => {}
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -211,8 +267,9 @@ impl Widget for FileBrowser {
|
|||
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();
|
||||
let file = self.selected_file().unwrap();
|
||||
let name = &file.name;
|
||||
|
||||
let color = if file.is_dir() || file.color.is_none() {
|
||||
|
@ -226,9 +283,10 @@ impl Widget for FileBrowser {
|
|||
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();
|
||||
let file = self.selected_file().unwrap();
|
||||
|
||||
let permissions = file.pretty_print_permissions().unwrap_or("NOPERMS".into());
|
||||
let user = file.pretty_user().unwrap_or("NOUSER".into());
|
||||
|
@ -236,8 +294,8 @@ impl Widget for FileBrowser {
|
|||
let mtime = file.pretty_mtime().unwrap_or("NOMTIME".into());
|
||||
|
||||
|
||||
let selection = self.main_column().get_selection();
|
||||
let file_count = self.main_column().content.len();
|
||||
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 file_count = format!("{}", file_count);
|
||||
let digits = file_count.len();
|
||||
let file_count = format!("{:digits$}/{:digits$}",
|
||||
|
@ -251,11 +309,13 @@ impl Widget for FileBrowser {
|
|||
crate::term::goto_xy(count_xpos, count_ypos), file_count)
|
||||
}
|
||||
fn refresh(&mut self) {
|
||||
self.update_preview();
|
||||
self.fix_selection();
|
||||
self.columns.refresh();
|
||||
}
|
||||
|
||||
fn get_drawlist(&self) -> String {
|
||||
if self.columns.get_left_widget().is_none() {
|
||||
if self.columns.get_left_widget().is_err() {
|
||||
self.columns.get_clearlist() + &self.columns.get_drawlist()
|
||||
} else {
|
||||
self.columns.get_drawlist()
|
||||
|
@ -265,10 +325,10 @@ impl Widget for FileBrowser {
|
|||
fn on_key(&mut self, key: Key) {
|
||||
match key {
|
||||
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(),
|
||||
_ => self.columns.get_main_widget_mut().on_key(key),
|
||||
Key::Char('Q') => { self.quit_with_dir(); },
|
||||
Key::Right | Key::Char('f') => { self.enter_dir(); },
|
||||
Key::Left | Key::Char('b') => { self.go_back(); },
|
||||
_ => self.columns.get_main_widget_mut().unwrap().on_key(key),
|
||||
}
|
||||
self.update_preview();
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#![feature(vec_remove_item)]
|
||||
#![feature(trivial_bounds)]
|
||||
#![feature(try_trait)]
|
||||
|
||||
extern crate termion;
|
||||
extern crate unicode_width;
|
||||
|
|
|
@ -1,9 +1,12 @@
|
|||
use termion::event::Key;
|
||||
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
use crate::coordinates::{Coordinates, Position, Size};
|
||||
use crate::preview::Previewer;
|
||||
use crate::widget::Widget;
|
||||
use crate::hbox::HBox;
|
||||
use crate::fail::{HError, HResult};
|
||||
|
||||
#[derive(PartialEq)]
|
||||
pub struct MillerColumns<T> where T: Widget {
|
||||
|
@ -80,25 +83,27 @@ where
|
|||
(left_coords, main_coords, preview_coords)
|
||||
}
|
||||
|
||||
pub fn get_left_widget(&self) -> Option<&T> {
|
||||
pub fn get_left_widget(&self) -> HResult<&T> {
|
||||
let len = self.widgets.widgets.len();
|
||||
if len < 2 {
|
||||
return None;
|
||||
return Err(HError::NoWidgetError);
|
||||
}
|
||||
self.widgets.widgets.get(len - 2)
|
||||
Ok(self.widgets.widgets.get(len - 2)?)
|
||||
}
|
||||
pub fn get_left_widget_mut(&mut self) -> Option<&mut T> {
|
||||
pub fn get_left_widget_mut(&mut self) -> HResult<&mut T> {
|
||||
let len = self.widgets.widgets.len();
|
||||
if len < 2 {
|
||||
return None;
|
||||
return Err(HError::NoWidgetError);
|
||||
}
|
||||
self.widgets.widgets.get_mut(len - 2)
|
||||
Ok(self.widgets.widgets.get_mut(len - 2)?)
|
||||
}
|
||||
pub fn get_main_widget(&self) -> &T {
|
||||
self.widgets.widgets.last().unwrap()
|
||||
pub fn get_main_widget(&self) -> HResult<&T> {
|
||||
let widget = self.widgets.widgets.last()?;
|
||||
Ok(widget)
|
||||
}
|
||||
pub fn get_main_widget_mut(&mut self) -> &mut T {
|
||||
self.widgets.widgets.last_mut().unwrap()
|
||||
pub fn get_main_widget_mut(&mut self) -> HResult<&mut T> {
|
||||
let widget = self.widgets.widgets.last_mut()?;
|
||||
Ok(widget)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -123,11 +128,11 @@ where
|
|||
fn refresh(&mut self) {
|
||||
let (left_coords, main_coords, preview_coords) = self.calculate_coordinates();
|
||||
|
||||
if let Some(left_widget) = self.get_left_widget_mut() {
|
||||
if let Ok(left_widget) = self.get_left_widget_mut() {
|
||||
left_widget.set_coordinates(&left_coords);
|
||||
}
|
||||
|
||||
if let Some(main_widget) = self.widgets.widgets.last_mut() {
|
||||
if let Ok(main_widget) = self.get_main_widget_mut() {
|
||||
main_widget.set_coordinates(&main_coords);
|
||||
}
|
||||
|
||||
|
@ -137,15 +142,20 @@ where
|
|||
|
||||
fn get_drawlist(&self) -> String {
|
||||
let left_widget = match self.get_left_widget() {
|
||||
Some(widget) => widget.get_drawlist(),
|
||||
None => "".into(),
|
||||
Ok(widget) => widget.get_drawlist(),
|
||||
Err(_) => "".into(),
|
||||
};
|
||||
let main_widget = self.get_main_widget().get_drawlist();
|
||||
let preview = self.preview.get_drawlist();
|
||||
format!("{}{}{}", main_widget, left_widget, preview)
|
||||
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 on_key(&mut self, key: Key) {
|
||||
self.get_main_widget_mut().on_key(key);
|
||||
self.get_main_widget_mut().unwrap().on_key(key);
|
||||
}
|
||||
}
|
||||
|
|
133
src/preview.rs
133
src/preview.rs
|
@ -29,19 +29,21 @@ fn kill_proc() -> HResult<()> {
|
|||
}
|
||||
|
||||
pub fn is_stale(stale: &Arc<Mutex<bool>>) -> HResult<bool> {
|
||||
Ok(*(stale.lock()?))
|
||||
let stale = *(stale.try_lock().unwrap());
|
||||
Ok(stale)
|
||||
}
|
||||
|
||||
enum State<T: Send> {
|
||||
Is(T),
|
||||
enum State {
|
||||
Is,
|
||||
Becoming,
|
||||
Taken,
|
||||
Fail
|
||||
}
|
||||
|
||||
struct WillBe<T: Send> {
|
||||
pub state: State<T>,
|
||||
rx: std::sync::mpsc::Receiver<T>,
|
||||
pub state: Arc<Mutex<State>>,
|
||||
pub thing: Arc<Mutex<Option<T>>>,
|
||||
on_ready: Arc<Mutex<Option<Box<Fn(Arc<Mutex<Option<T>>>) -> HResult<()> + Send>>>>,
|
||||
rx: Option<std::sync::mpsc::Receiver<T>>,
|
||||
stale: Arc<Mutex<bool>>
|
||||
}
|
||||
|
||||
|
@ -49,42 +51,58 @@ impl<T: Send + 'static> WillBe<T> where {
|
|||
pub fn new_become(closure: HClosure<T>)
|
||||
-> WillBe<T> {
|
||||
let (tx,rx) = std::sync::mpsc::channel();
|
||||
let mut willbe = WillBe { state: State::Becoming,
|
||||
rx: rx,
|
||||
let mut willbe = WillBe { state: Arc::new(Mutex::new(State::Becoming)),
|
||||
thing: Arc::new(Mutex::new(None)),
|
||||
on_ready: Arc::new(Mutex::new(None)),
|
||||
rx: Some(rx),
|
||||
stale: Arc::new(Mutex::new(false)) };
|
||||
willbe.run(closure, tx);
|
||||
willbe
|
||||
}
|
||||
|
||||
fn run(&mut self, closure: HClosure<T>, tx: std::sync::mpsc::Sender<T>) {
|
||||
let state = self.state.clone();
|
||||
let stale = self.stale.clone();
|
||||
let thing = self.thing.clone();
|
||||
let on_ready_fn = self.on_ready.clone();
|
||||
std::thread::spawn(move|| {
|
||||
let thing = closure(stale);
|
||||
match thing {
|
||||
Ok(thing) => { tx.send(thing).ok(); },
|
||||
let got_thing = closure(stale);
|
||||
match got_thing {
|
||||
Ok(got_thing) => {
|
||||
*thing.try_lock().unwrap() = Some(got_thing);
|
||||
*state.try_lock().unwrap() = State::Is;
|
||||
match *on_ready_fn.lock().unwrap() {
|
||||
Some(ref on_ready) => { on_ready(thing.clone()); },
|
||||
None => {}
|
||||
}
|
||||
},
|
||||
Err(err) => { dbg!(err); }
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
pub fn set_stale(&mut self) -> HResult<()> {
|
||||
*self.stale.lock()? = true;
|
||||
*self.stale.try_lock()? = true;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn check(&mut self) -> Result<(), Error> {
|
||||
match self.state {
|
||||
State::Is(_) => Ok(()),
|
||||
_ => {
|
||||
let thing = self.rx.try_recv()?;
|
||||
self.state = State::Is(thing);
|
||||
Ok(())
|
||||
}
|
||||
pub fn check(&self) -> HResult<()> {
|
||||
match *self.state.try_lock()? {
|
||||
State::Is => Ok(()),
|
||||
_ => Err(HError::WillBeNotReady)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn wait(self) -> Result<T, std::sync::mpsc::RecvError> {
|
||||
self.rx.recv()
|
||||
pub fn on_ready(&mut self,
|
||||
fun: Box<Fn(Arc<Mutex<Option<T>>>) -> HResult<()> + Send>)
|
||||
-> HResult<()> {
|
||||
if self.check().is_ok() {
|
||||
fun(self.thing.clone());
|
||||
//*self.on_ready.try_lock()? = None;
|
||||
} else {
|
||||
*self.on_ready.try_lock()? = Some(fun);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -98,21 +116,30 @@ impl<W: Widget + Send> PartialEq for WillBeWidget<W> {
|
|||
}
|
||||
}
|
||||
|
||||
struct WillBeWidget<T: Widget + Send> {
|
||||
pub struct WillBeWidget<T: Widget + Send> {
|
||||
willbe: WillBe<T>,
|
||||
coordinates: Coordinates
|
||||
}
|
||||
|
||||
impl<T: Widget + Send + 'static> WillBeWidget<T> {
|
||||
fn new(closure: HClosure<T>) -> WillBeWidget<T> {
|
||||
pub fn new(closure: HClosure<T>) -> WillBeWidget<T> {
|
||||
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);
|
||||
Ok(()) }));
|
||||
|
||||
WillBeWidget {
|
||||
willbe: WillBe::new_become(Box::new(move |stale| closure(stale))),
|
||||
willbe: willbe,
|
||||
coordinates: Coordinates::new()
|
||||
}
|
||||
}
|
||||
pub fn set_stale(&mut self) -> HResult<()> {
|
||||
self.willbe.set_stale()
|
||||
}
|
||||
pub fn widget(&self) -> HResult<Arc<Mutex<Option<T>>>> {
|
||||
self.willbe.check()?;
|
||||
Ok(self.willbe.thing.clone())
|
||||
}
|
||||
}
|
||||
|
||||
// impl<T: Widget + Send> WillBeWidget<T> {
|
||||
|
@ -126,41 +153,46 @@ impl<T: Widget + Send + 'static> WillBeWidget<T> {
|
|||
// }
|
||||
//}
|
||||
|
||||
impl<T: Widget + Send> Widget for WillBeWidget<T> {
|
||||
impl<T: Widget + Send + 'static> Widget for WillBeWidget<T> {
|
||||
fn get_coordinates(&self) -> &Coordinates {
|
||||
&self.coordinates
|
||||
}
|
||||
fn set_coordinates(&mut self, coordinates: &Coordinates) {
|
||||
if self.coordinates == *coordinates {
|
||||
return;
|
||||
}
|
||||
self.coordinates = coordinates.clone();
|
||||
match &mut self.willbe.state {
|
||||
State::Is(widget) => {
|
||||
widget.set_coordinates(&coordinates.clone());
|
||||
self.refresh();
|
||||
}
|
||||
_ => {}
|
||||
|
||||
{
|
||||
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 render_header(&self) -> String {
|
||||
"".to_string()
|
||||
}
|
||||
fn refresh(&mut self) {
|
||||
match &mut self.willbe.state {
|
||||
State::Is(widget) => {
|
||||
widget.refresh();
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
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 {
|
||||
match &self.willbe.state {
|
||||
State::Is(widget) => {
|
||||
widget.get_drawlist()
|
||||
},
|
||||
_ => { "".to_string() }
|
||||
}
|
||||
if self.willbe.check().is_err() { return "".to_string() }
|
||||
let widget = self.widget().unwrap();
|
||||
let widget = widget.try_lock().unwrap();
|
||||
let widget = widget.as_ref().unwrap();
|
||||
widget.get_drawlist()
|
||||
}
|
||||
fn on_key(&mut self, key: termion::event::Key) {
|
||||
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.on_key(key);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -177,6 +209,7 @@ impl PartialEq for Previewer {
|
|||
|
||||
pub struct Previewer {
|
||||
widget: WillBeWidget<Box<dyn Widget + Send>>,
|
||||
file: Option<File>
|
||||
}
|
||||
|
||||
|
||||
|
@ -186,7 +219,8 @@ impl Previewer {
|
|||
Ok(Box::new(crate::textview::TextView::new_blank())
|
||||
as Box<dyn Widget + Send>)
|
||||
}));
|
||||
Previewer { widget: willbe }
|
||||
Previewer { widget: willbe,
|
||||
file: None}
|
||||
}
|
||||
|
||||
fn become_preview(&mut self,
|
||||
|
@ -197,6 +231,9 @@ impl Previewer {
|
|||
}
|
||||
|
||||
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 file = file.clone();
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use std::io::{stdin, stdout, Stdout, Write};
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::sync::mpsc::{Sender, Receiver, channel};
|
||||
|
||||
use termion::event::{Event, Key};
|
||||
use termion::input::TermRead;
|
||||
|
@ -10,6 +11,18 @@ use crate::term::ScreenExt;
|
|||
|
||||
use crate::coordinates::{Coordinates, Position, Size};
|
||||
use crate::widget::Widget;
|
||||
use crate::fail::HResult;
|
||||
|
||||
lazy_static! {
|
||||
static ref TX_EVENT: Arc<Mutex<Option<Sender<Events>>>> = { Arc::new(Mutex::new(None)) };
|
||||
}
|
||||
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Events {
|
||||
InputEvent(Event),
|
||||
WidgetReady
|
||||
}
|
||||
|
||||
pub struct Window<T>
|
||||
where
|
||||
|
@ -69,17 +82,58 @@ where
|
|||
// Self::show_status("");
|
||||
// }
|
||||
|
||||
|
||||
pub fn handle_input(&mut self) {
|
||||
for event in stdin().events() {
|
||||
let (tx_event_internal, rx_event_internal) = channel();
|
||||
let (tx_event, rx_event) = channel();
|
||||
*TX_EVENT.try_lock().unwrap() = Some(tx_event);
|
||||
|
||||
event_thread(rx_event, tx_event_internal.clone());
|
||||
input_thread(tx_event_internal);
|
||||
|
||||
for event in rx_event_internal.iter() {
|
||||
//Self::clear_status();
|
||||
let event = event.unwrap();
|
||||
self.widget.on_event(event);
|
||||
self.screen.cursor_hide();
|
||||
self.draw();
|
||||
//let event = event.unwrap();
|
||||
dbg!(&event);
|
||||
match event {
|
||||
Events::InputEvent(event) => {
|
||||
self.widget.on_event(event);
|
||||
self.screen.cursor_hide();
|
||||
self.draw();
|
||||
}
|
||||
_ => {
|
||||
self.widget.refresh();
|
||||
self.draw();
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn event_thread(rx: Receiver<Events>, tx: Sender<Events>) {
|
||||
std::thread::spawn(move || {
|
||||
for event in rx.iter() {
|
||||
dbg!(&event);
|
||||
tx.send(event).unwrap();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
fn input_thread(tx: Sender<Events>) {
|
||||
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(())
|
||||
}
|
||||
|
||||
impl<T> Drop for Window<T>
|
||||
where
|
||||
T: Widget,
|
||||
|
|
Loading…
Reference in New Issue