1
0
mirror of https://github.com/bobwen-dev/hunter synced 2025-04-12 00:55:41 +02:00

added on_ready support

This commit is contained in:
rabite 2019-02-21 21:41:52 +01:00
parent fe542047c2
commit 3b38143f9b
6 changed files with 362 additions and 154 deletions

View File

@ -1,4 +1,6 @@
use failure; use failure;
use failure::Error;
use failure::{Fail, ResultExt};
pub type HResult<T> = Result<T, HError>; pub type HResult<T> = Result<T, HError>;
@ -8,36 +10,80 @@ pub enum HError {
IoError{#[cause] error: std::io::Error}, IoError{#[cause] error: std::io::Error},
#[fail(display = "Mutex failed")] #[fail(display = "Mutex failed")]
MutexError, MutexError,
#[fail(display = "Can't lock!")]
TryLockError,
#[fail(display = "Channel failed: {}", error)] #[fail(display = "Channel failed: {}", error)]
ChannelTryRecvError{#[cause] error: std::sync::mpsc::TryRecvError}, 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)] #[fail(display = "Previewer failed on file: {}", file)]
PreviewFailed{file: String}, PreviewFailed{file: String},
#[fail(display = "StalePreviewer for file: {}", file)] #[fail(display = "StalePreviewer for file: {}", file)]
StalePreviewError{file: String}, StalePreviewError{file: String},
#[fail(display = "Failed: {}", error)] #[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 { impl From<std::io::Error> for HError {
fn from(error: std::io::Error) -> Self { fn from(error: std::io::Error) -> Self {
dbg!(&error);
HError::IoError { error: error } HError::IoError { error: error }
} }
} }
impl From<failure::Error> for HError { impl From<failure::Error> for HError {
fn from(error: failure::Error) -> Self { fn from(error: failure::Error) -> Self {
dbg!(&error);
HError::Error { error: error } HError::Error { error: error }
} }
} }
impl From<std::sync::mpsc::TryRecvError> for HError { impl From<std::sync::mpsc::TryRecvError> for HError {
fn from(error: std::sync::mpsc::TryRecvError) -> Self { fn from(error: std::sync::mpsc::TryRecvError) -> Self {
dbg!(&error);
HError::ChannelTryRecvError { error: 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 { impl<T> From<std::sync::PoisonError<T>> for HError {
fn from(_: std::sync::PoisonError<T>) -> Self { fn from(_: std::sync::PoisonError<T>) -> Self {
dbg!("Poisoned Mutex");
HError::MutexError 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
}
}

View File

@ -2,6 +2,7 @@ use termion::event::Key;
use std::error::Error; use std::error::Error;
use std::io::Write; use std::io::Write;
use std::sync::{Arc, Mutex};
use crate::coordinates::{Coordinates}; use crate::coordinates::{Coordinates};
use crate::files::{File, Files}; use crate::files::{File, Files};
@ -9,10 +10,13 @@ use crate::listview::ListView;
use crate::miller_columns::MillerColumns; use crate::miller_columns::MillerColumns;
use crate::widget::Widget; use crate::widget::Widget;
use crate::tabview::{TabView, Tabbable}; use crate::tabview::{TabView, Tabbable};
use crate::preview::WillBeWidget;
use crate::fail::{HError, HResult};
#[derive(PartialEq)] #[derive(PartialEq)]
pub struct FileBrowser { pub struct FileBrowser {
pub columns: MillerColumns<ListView<Files>>, pub columns: MillerColumns<WillBeWidget<ListView<Files>>>,
pub cwd: File
} }
impl Tabbable for TabView<FileBrowser> { impl Tabbable for TabView<FileBrowser> {
@ -55,37 +59,70 @@ impl FileBrowser {
miller.set_coordinates(&coords); miller.set_coordinates(&coords);
let lists: Result<Vec<ListView<Files>>, Box<Error>> = cwd // let lists: Result<Vec<ListView<Files>>, Box<Error>> = cwd
.ancestors() // .ancestors()
.map(|path| Ok(ListView::new(Files::new_from_path(path)?))) // .map(|path| Ok(ListView::new(Files::new_from_path(path)?)))
.take(2) // .take(2)
.collect(); // .collect();
let mut lists = lists?; // let mut lists = lists?;
lists.reverse(); // lists.reverse();
let (left_coords, main_coords, _) = miller.calculate_coordinates();
for widget in lists { let main_path: std::path::PathBuf = cwd.ancestors().take(1).map(|path| std::path::PathBuf::from(path)).collect();
miller.push_widget(widget); 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) Ok(file_browser)
} }
pub fn enter_dir(&mut self) { pub fn enter_dir(&mut self) -> HResult<()> {
let file = self.selected_file(); let file = self.selected_file()?;
let (_, coords, _) = self.columns.calculate_coordinates();
match file.read_dir() { match file.read_dir() {
Ok(files) => { Ok(files) => {
std::env::set_current_dir(&file.path).unwrap(); 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.columns.push_widget(view);
self.update_preview();
}, },
_ => { _ => {
let status = std::process::Command::new("rifle") let status = std::process::Command::new("rifle")
@ -103,102 +140,121 @@ impl FileBrowser {
} }
} }
} }
Ok(())
} }
pub fn go_back(&mut self) { pub fn go_back(&mut self) -> HResult<()> {
if self.columns.get_left_widget().is_none() { // if self.left_widget().is_err() {
return; // return None;
} // }
let fileview = self.columns.get_main_widget(); // if self.columns.get_main_widget().is_none() {
let path = fileview.selected_file().grand_parent().unwrap(); // return None;
std::env::set_current_dir(path).unwrap(); // }
let fileview = self.main_widget()?;
let path = self.selected_file()?.grand_parent()?;
std::env::set_current_dir(path)?;
self.columns.pop_widget(); self.columns.pop_widget();
// Make sure there's a directory on the left unless it's / // Make sure there's a directory on the left unless it's /
if self.columns.get_left_widget().is_none() { if self.left_widget().is_err() {
let file = self.columns.get_main_widget().clone_selected_file(); let file = self.selected_file()?.clone();
if let Some(grand_parent) = file.grand_parent() { if let Some(grand_parent) = file.grand_parent() {
let mut left_view = ListView::new(Files::new_from_path(&grand_parent).unwrap()); let mut left_view = WillBeWidget::new(Box::new(move |_| {
left_view.select_file(&file); let mut view
= ListView::new(Files::new_from_path(&grand_parent)?);
Ok(view)
}));
self.columns.prepend_widget(left_view); self.columns.prepend_widget(left_view);
} }
} }
self.fix_selection();
self.columns.refresh(); self.columns.refresh();
Ok(())
} }
pub fn update_preview(&mut self) { pub fn update_preview(&mut self) -> HResult<()> {
if self.columns.get_main_widget().content.len() == 0 { return } let file = self.selected_file()?.clone();
let file = self.columns.get_main_widget().selected_file().clone();
let preview = &mut self.columns.preview; let preview = &mut self.columns.preview;
preview.set_file(&file); preview.set_file(&file);
Ok(())
} }
pub fn fix_selection(&mut self) { pub fn fix_selection(&mut self) -> HResult<()> {
let cwd = self.cwd(); let cwd = self.cwd()?;
self.columns.get_left_widget_mut() (*self.left_widget()?.lock()?).as_mut()?.select_file(&cwd);
.map(|w| Ok(())
w.select_file(&cwd));
} }
pub fn cwd(&self) -> File { pub fn cwd(&self) -> HResult<File> {
self.columns.get_main_widget().content.directory.clone() //(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 { pub fn selected_file(&self) -> HResult<File> {
self.main_column().selected_file() let widget = self.main_widget()?;
let file = widget.lock()?.as_ref()?.selected_file().clone();
Ok(file)
} }
pub fn main_column(&self) -> &ListView<Files> { pub fn main_widget(&self) -> HResult<Arc<Mutex<Option<ListView<Files>>>>> {
self.columns.get_main_widget() let widget = self.columns.get_main_widget()?.widget()?;
Ok(widget)
} }
pub fn quit_with_dir(&self) { pub fn left_widget(&self) -> HResult<Arc<Mutex<Option<ListView<Files>>>>> {
let cwd = self.cwd().path; let widget = self.columns.get_left_widget()?.widget()?;
let selected_file = self.selected_file().path.to_string_lossy(); 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"); filepath.push(".hunter_cwd");
let output = format!("HUNTER_CWD=\"{}\"\nF=\"{}\"", let output = format!("HUNTER_CWD=\"{}\"\nF=\"{}\"",
cwd.to_str().unwrap(), cwd.to_str()?,
selected_file); selected_file);
let mut file = std::fs::File::create(filepath).unwrap(); let mut file = std::fs::File::create(filepath)?;
file.write(output.as_bytes()).unwrap(); file.write(output.as_bytes())?;
panic!("Quitting!"); panic!("Quitting!");
Ok(())
} }
pub fn animate_columns(&mut self) { pub fn animate_columns(&mut self) {
self.columns.get_left_widget_mut().map(|w| w.animate_slide_up()); 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) { pub fn turbo_cd(&mut self) {
let dir = self.minibuffer("cd: "); let dir = self.minibuffer("cd: ");
match dir { // match dir {
Some(dir) => { // Some(dir) => {
Files::new_from_path(&std::path::PathBuf::from(&dir)).and_then(|files| { // Files::new_from_path(&std::path::PathBuf::from(&dir)).and_then(|files| {
let cwd = files.directory.clone(); // let cwd = files.directory.clone();
self.columns.widgets.widgets.clear(); // self.columns.widgets.widgets.clear();
self.columns.push_widget(ListView::new(files)); // 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() { // if let Some(grand_parent) = cwd.path.parent() {
let left_view = // let left_view =
ListView::new(Files::new_from_path(&grand_parent).unwrap()); // ListView::new(Files::new_from_path(&grand_parent).unwrap());
self.columns.prepend_widget(left_view); // self.columns.prepend_widget(left_view);
} // }
self.fix_selection(); // self.fix_selection();
self.update_preview(); // self.update_preview();
self.refresh(); // self.refresh();
self.columns.refresh(); // self.columns.refresh();
Ok(()) // Ok(())
}).ok(); // }).ok();
} None => {} // } None => {}
} // }
} }
} }
@ -211,8 +267,9 @@ impl Widget for FileBrowser {
self.refresh(); self.refresh();
} }
fn render_header(&self) -> String { fn render_header(&self) -> String {
if self.main_widget().is_err() { return "".to_string() }
let xsize = self.get_coordinates().xsize(); let xsize = self.get_coordinates().xsize();
let file = self.selected_file(); let file = self.selected_file().unwrap();
let name = &file.name; let name = &file.name;
let color = if file.is_dir() || file.color.is_none() { let color = if file.is_dir() || file.color.is_none() {
@ -226,9 +283,10 @@ impl Widget for FileBrowser {
sized_path sized_path
} }
fn render_footer(&self) -> String { fn render_footer(&self) -> String {
if self.main_widget().is_err() { return "".to_string() }
let xsize = self.get_coordinates().xsize(); let xsize = self.get_coordinates().xsize();
let ypos = self.get_coordinates().position().y(); 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 permissions = file.pretty_print_permissions().unwrap_or("NOPERMS".into());
let user = file.pretty_user().unwrap_or("NOUSER".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 mtime = file.pretty_mtime().unwrap_or("NOMTIME".into());
let selection = self.main_column().get_selection(); let selection = (*self.main_widget().as_ref().unwrap().lock().unwrap()).as_ref().unwrap().get_selection();
let file_count = self.main_column().content.len(); let file_count = (*self.main_widget().unwrap().lock().unwrap()).as_ref().unwrap().content.len();
let file_count = format!("{}", file_count); let file_count = format!("{}", file_count);
let digits = file_count.len(); let digits = file_count.len();
let file_count = format!("{:digits$}/{:digits$}", let file_count = format!("{:digits$}/{:digits$}",
@ -251,11 +309,13 @@ impl Widget for FileBrowser {
crate::term::goto_xy(count_xpos, count_ypos), file_count) crate::term::goto_xy(count_xpos, count_ypos), file_count)
} }
fn refresh(&mut self) { fn refresh(&mut self) {
self.update_preview();
self.fix_selection();
self.columns.refresh(); self.columns.refresh();
} }
fn get_drawlist(&self) -> String { 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() self.columns.get_clearlist() + &self.columns.get_drawlist()
} else { } else {
self.columns.get_drawlist() self.columns.get_drawlist()
@ -265,10 +325,10 @@ impl Widget for FileBrowser {
fn on_key(&mut self, key: Key) { fn on_key(&mut self, key: Key) {
match key { match key {
Key::Char('/') => self.turbo_cd(), Key::Char('/') => self.turbo_cd(),
Key::Char('Q') => self.quit_with_dir(), Key::Char('Q') => { self.quit_with_dir(); },
Key::Right | Key::Char('f') => self.enter_dir(), Key::Right | Key::Char('f') => { self.enter_dir(); },
Key::Left | Key::Char('b') => self.go_back(), Key::Left | Key::Char('b') => { self.go_back(); },
_ => self.columns.get_main_widget_mut().on_key(key), _ => self.columns.get_main_widget_mut().unwrap().on_key(key),
} }
self.update_preview(); self.update_preview();
} }

View File

@ -1,5 +1,6 @@
#![feature(vec_remove_item)] #![feature(vec_remove_item)]
#![feature(trivial_bounds)] #![feature(trivial_bounds)]
#![feature(try_trait)]
extern crate termion; extern crate termion;
extern crate unicode_width; extern crate unicode_width;

View File

@ -1,9 +1,12 @@
use termion::event::Key; use termion::event::Key;
use std::sync::{Arc, Mutex};
use crate::coordinates::{Coordinates, Position, Size}; use crate::coordinates::{Coordinates, Position, Size};
use crate::preview::Previewer; use crate::preview::Previewer;
use crate::widget::Widget; use crate::widget::Widget;
use crate::hbox::HBox; use crate::hbox::HBox;
use crate::fail::{HError, HResult};
#[derive(PartialEq)] #[derive(PartialEq)]
pub struct MillerColumns<T> where T: Widget { pub struct MillerColumns<T> where T: Widget {
@ -80,25 +83,27 @@ where
(left_coords, main_coords, preview_coords) (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(); let len = self.widgets.widgets.len();
if len < 2 { 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(); let len = self.widgets.widgets.len();
if len < 2 { 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 { pub fn get_main_widget(&self) -> HResult<&T> {
self.widgets.widgets.last().unwrap() let widget = self.widgets.widgets.last()?;
Ok(widget)
} }
pub fn get_main_widget_mut(&mut self) -> &mut T { pub fn get_main_widget_mut(&mut self) -> HResult<&mut T> {
self.widgets.widgets.last_mut().unwrap() let widget = self.widgets.widgets.last_mut()?;
Ok(widget)
} }
} }
@ -123,11 +128,11 @@ where
fn refresh(&mut self) { fn refresh(&mut self) {
let (left_coords, main_coords, preview_coords) = self.calculate_coordinates(); 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); 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); main_widget.set_coordinates(&main_coords);
} }
@ -137,15 +142,20 @@ where
fn get_drawlist(&self) -> String { fn get_drawlist(&self) -> String {
let left_widget = match self.get_left_widget() { let left_widget = match self.get_left_widget() {
Some(widget) => widget.get_drawlist(), Ok(widget) => widget.get_drawlist(),
None => "".into(), Err(_) => "".into(),
}; };
let main_widget = self.get_main_widget().get_drawlist(); let main_widget = self.get_main_widget();
match main_widget {
Ok(main_widget) => {
let preview = self.preview.get_drawlist(); let preview = self.preview.get_drawlist();
format!("{}{}{}", main_widget, left_widget, preview) format!("{}{}{}", main_widget.get_drawlist(), left_widget, preview)
}
Err(_) => "".to_string()
}
} }
fn on_key(&mut self, key: Key) { fn on_key(&mut self, key: Key) {
self.get_main_widget_mut().on_key(key); self.get_main_widget_mut().unwrap().on_key(key);
} }
} }

View File

@ -29,19 +29,21 @@ fn kill_proc() -> HResult<()> {
} }
pub fn is_stale(stale: &Arc<Mutex<bool>>) -> HResult<bool> { 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> { enum State {
Is(T), Is,
Becoming, Becoming,
Taken,
Fail Fail
} }
struct WillBe<T: Send> { struct WillBe<T: Send> {
pub state: State<T>, pub state: Arc<Mutex<State>>,
rx: std::sync::mpsc::Receiver<T>, 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>> stale: Arc<Mutex<bool>>
} }
@ -49,42 +51,58 @@ impl<T: Send + 'static> WillBe<T> where {
pub fn new_become(closure: HClosure<T>) pub fn new_become(closure: HClosure<T>)
-> WillBe<T> { -> WillBe<T> {
let (tx,rx) = std::sync::mpsc::channel(); let (tx,rx) = std::sync::mpsc::channel();
let mut willbe = WillBe { state: State::Becoming, let mut willbe = WillBe { state: Arc::new(Mutex::new(State::Becoming)),
rx: rx, thing: Arc::new(Mutex::new(None)),
on_ready: Arc::new(Mutex::new(None)),
rx: Some(rx),
stale: Arc::new(Mutex::new(false)) }; stale: Arc::new(Mutex::new(false)) };
willbe.run(closure, tx); willbe.run(closure, tx);
willbe willbe
} }
fn run(&mut self, closure: HClosure<T>, tx: std::sync::mpsc::Sender<T>) { fn run(&mut self, closure: HClosure<T>, tx: std::sync::mpsc::Sender<T>) {
let state = self.state.clone();
let stale = self.stale.clone(); let stale = self.stale.clone();
let thing = self.thing.clone();
let on_ready_fn = self.on_ready.clone();
std::thread::spawn(move|| { std::thread::spawn(move|| {
let thing = closure(stale); let got_thing = closure(stale);
match thing { match got_thing {
Ok(thing) => { tx.send(thing).ok(); }, 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); } Err(err) => { dbg!(err); }
} }
}); });
} }
pub fn set_stale(&mut self) -> HResult<()> { pub fn set_stale(&mut self) -> HResult<()> {
*self.stale.lock()? = true; *self.stale.try_lock()? = true;
Ok(()) Ok(())
} }
pub fn check(&mut self) -> Result<(), Error> { pub fn check(&self) -> HResult<()> {
match self.state { match *self.state.try_lock()? {
State::Is(_) => Ok(()), State::Is => Ok(()),
_ => { _ => Err(HError::WillBeNotReady)
let thing = self.rx.try_recv()?;
self.state = State::Is(thing);
Ok(())
}
} }
} }
pub fn wait(self) -> Result<T, std::sync::mpsc::RecvError> { pub fn on_ready(&mut self,
self.rx.recv() 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>, willbe: WillBe<T>,
coordinates: Coordinates coordinates: Coordinates
} }
impl<T: Widget + Send + 'static> WillBeWidget<T> { 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 { WillBeWidget {
willbe: WillBe::new_become(Box::new(move |stale| closure(stale))), willbe: willbe,
coordinates: Coordinates::new() coordinates: Coordinates::new()
} }
} }
pub fn set_stale(&mut self) -> HResult<()> { pub fn set_stale(&mut self) -> HResult<()> {
self.willbe.set_stale() 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> { // 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 { fn get_coordinates(&self) -> &Coordinates {
&self.coordinates &self.coordinates
} }
fn set_coordinates(&mut self, coordinates: &Coordinates) { fn set_coordinates(&mut self, coordinates: &Coordinates) {
if self.coordinates == *coordinates {
return;
}
self.coordinates = coordinates.clone(); self.coordinates = coordinates.clone();
match &mut self.willbe.state {
State::Is(widget) => { {
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()); widget.set_coordinates(&coordinates.clone());
}
self.refresh(); self.refresh();
} }
_ => {}
}
}
fn render_header(&self) -> String { fn render_header(&self) -> String {
"".to_string() "".to_string()
} }
fn refresh(&mut self) { fn refresh(&mut self) {
match &mut self.willbe.state { if self.willbe.check().is_err() { return }
State::Is(widget) => { let widget = self.widget().unwrap();
let mut widget = widget.try_lock().unwrap();
let widget = widget.as_mut().unwrap();
widget.refresh(); widget.refresh();
} }
_ => {}
}
}
fn get_drawlist(&self) -> String { fn get_drawlist(&self) -> String {
match &self.willbe.state { if self.willbe.check().is_err() { return "".to_string() }
State::Is(widget) => { let widget = self.widget().unwrap();
let widget = widget.try_lock().unwrap();
let widget = widget.as_ref().unwrap();
widget.get_drawlist() widget.get_drawlist()
},
_ => { "".to_string() }
} }
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 { pub struct Previewer {
widget: WillBeWidget<Box<dyn Widget + Send>>, widget: WillBeWidget<Box<dyn Widget + Send>>,
file: Option<File>
} }
@ -186,7 +219,8 @@ impl Previewer {
Ok(Box::new(crate::textview::TextView::new_blank()) Ok(Box::new(crate::textview::TextView::new_blank())
as Box<dyn Widget + Send>) as Box<dyn Widget + Send>)
})); }));
Previewer { widget: willbe } Previewer { widget: willbe,
file: None}
} }
fn become_preview(&mut self, fn become_preview(&mut self,
@ -197,6 +231,9 @@ impl Previewer {
} }
pub fn set_file(&mut self, file: &File) { 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().clone();
let file = file.clone(); let file = file.clone();

View File

@ -1,5 +1,6 @@
use std::io::{stdin, stdout, Stdout, Write}; use std::io::{stdin, stdout, Stdout, Write};
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
use std::sync::mpsc::{Sender, Receiver, channel};
use termion::event::{Event, Key}; use termion::event::{Event, Key};
use termion::input::TermRead; use termion::input::TermRead;
@ -10,6 +11,18 @@ use crate::term::ScreenExt;
use crate::coordinates::{Coordinates, Position, Size}; use crate::coordinates::{Coordinates, Position, Size};
use crate::widget::Widget; 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> pub struct Window<T>
where where
@ -69,15 +82,56 @@ where
// Self::show_status(""); // Self::show_status("");
// } // }
pub fn handle_input(&mut self) { 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(); //Self::clear_status();
let event = event.unwrap(); //let event = event.unwrap();
dbg!(&event);
match event {
Events::InputEvent(event) => {
self.widget.on_event(event); self.widget.on_event(event);
self.screen.cursor_hide(); self.screen.cursor_hide();
self.draw(); 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> impl<T> Drop for Window<T>