use async_value library

This commit is contained in:
rabite 2019-05-11 13:29:00 +02:00
parent 01d0c1d338
commit 99980ace6c
11 changed files with 261 additions and 431 deletions

20
Cargo.lock generated
View File

@ -38,6 +38,18 @@ dependencies = [
"nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "async_value"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
"failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
"objekt 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"rayon 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "autocfg"
version = "0.1.2"
@ -254,6 +266,7 @@ name = "hunter"
version = "1.1.3"
dependencies = [
"alphanumeric-sort 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
"async_value 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"dirs-2 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
@ -476,6 +489,11 @@ name = "numtoa"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "objekt"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "ordermap"
version = "0.3.5"
@ -891,6 +909,7 @@ dependencies = [
"checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
"checksum argon2rs 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "3f67b0b6a86dae6e67ff4ca2b6201396074996379fba2b92ff649126f37cb392"
"checksum arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "92c7fb76bc8826a8b33b4ee5bb07a247a81e76764ab4d55e8f73e3a4d8808c71"
"checksum async_value 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1c4cd683ef2421e8767b2a0c02b105707812a98a4e1eb0559f615a15e3a80183"
"checksum autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a6d640bee2da49f60a4068a7fae53acde8982514ab7bae8b8cea9e88cbcfd799"
"checksum backtrace 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "f106c02a3604afcdc0df5d36cc47b44b55917dbaf3d808f71c163a0ddba64637"
"checksum backtrace-sys 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)" = "797c830ac25ccc92a7f8a7b9862bde440715531514594a6154e3d4a54dd769b6"
@ -943,6 +962,7 @@ dependencies = [
"checksum num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0b3a5d7cc97d6d30d8b9bc8fa19bf45349ffe46241e8816f50f62f6d6aaabee1"
"checksum num_cpus 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1a23f0ed30a54abaa0c7e83b1d2d87ada7c3c23078d1d87815af3e3b6385fbba"
"checksum numtoa 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b8f8bdf33df195859076e54ab11ee78a1b208382d3a26ec40d142ffc1ecc49ef"
"checksum objekt 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2069a3ae3dad97a4ae47754e8f47e5d2f1fd32ab7ad8a84bb31d051faa59cc3c"
"checksum ordermap 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "a86ed3f5f244b372d6b1a00b72ef7f8876d0bc6a78a4c9985c53614041512063"
"checksum osstrtools 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "63557d11f265b66ffcda9cc624d5f92315cfeebb7ee01c76257f890f7d730f5b"
"checksum owning_ref 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "cdf84f41639e037b484f93433aa3897863b561ed65c6e59c7073d7c561710f37"

View File

@ -31,6 +31,7 @@ signal-notify = "0.1.3"
systemstat = "0.1.4"
osstrtools = "0.1"
pathbuftools = "0.1"
async_value = "0.2.2"
[patch.crates-io]
systemstat = { git = 'https://github.com/myfreeweb/systemstat' }

View File

@ -1 +1 @@
nightly-2019-03-15
nightly-2019-04-28

View File

@ -1,6 +1,8 @@
use failure;
use failure::Fail;
//use failure::Backtrace;
use async_value::AError;
use termion::event::Key;
@ -47,6 +49,8 @@ pub enum HError {
AsyncAlreadyStartedError,
#[fail(display = "Async Error: {}", _0)]
AsyncError(String),
#[fail(display = "Async Error: {}", _0)]
AError(async_value::AError),
#[fail(display = "No widget found")]
NoWidgetError,
#[fail(display = "Path: {:?} not in this directory: {:?}", path, dir)]
@ -209,7 +213,6 @@ pub trait ErrorLog where Self: Sized {
impl<T> ErrorLog for HResult<T> {
fn log(self) {
if let Err(err) = self {
// eprintln!("{:?}", err);
put_log(&err).ok();
}
}
@ -223,101 +226,97 @@ impl<T> ErrorLog for HResult<T> {
}
impl<T> ErrorLog for Result<T, AError> {
fn log(self) {
if let Err(err) = self {
put_log(&err.into()).ok();
}
}
fn log_and(self) -> Self {
if let Err(err) = &self {
put_log(&err.clone().into()).ok();
}
self
}
}
// impl From<&HError> for HError {
// fn from(error: &HError) -> Self {
// dbg!(&error);
// (error.clone())
// }
// }
impl From<std::io::Error> for HError {
fn from(error: std::io::Error) -> Self {
// dbg!(&error);
let err = HError::IoError(format!("{}", error));
put_log(&err).ok();
err
}
}
impl From<failure::Error> for HError {
fn from(error: failure::Error) -> Self {
// dbg!(&error);
let err = HError::Error(format!("{}", error));
put_log(&err).ok();
err
}
}
impl From<std::sync::mpsc::TryRecvError> for HError {
fn from(error: std::sync::mpsc::TryRecvError) -> Self {
// dbg!(&error);
let err = HError::ChannelTryRecvError { error: error };
put_log(&err).ok();
err
}
}
impl From<std::sync::mpsc::RecvError> for HError {
fn from(error: std::sync::mpsc::RecvError) -> Self {
// dbg!(&error);
let err = HError::ChannelRecvError { error: error };
put_log(&err).ok();
err
}
}
impl<T> From<std::sync::mpsc::SendError<T>> for HError {
fn from(error: std::sync::mpsc::SendError<T>) -> Self {
dbg!(&error);
fn from(_error: std::sync::mpsc::SendError<T>) -> Self {
let err = HError::ChannelSendError;
put_log(&err).ok();
err
}
}
impl<T> From<std::sync::PoisonError<T>> for HError {
fn from(_: std::sync::PoisonError<T>) -> Self {
// dbg!("Poisoned Mutex");
let err = HError::MutexError;
put_log(&err).ok();
err
}
}
impl<T> From<std::sync::TryLockError<T>> for HError {
fn from(_error: std::sync::TryLockError<T>) -> Self {
// dbg!(&error);
let err = HError::TryLockError;
put_log(&err).ok();
err
}
}
impl From<std::option::NoneError> for HError {
fn from(_error: std::option::NoneError) -> Self {
//dbg!(&error);
let err = HError::NoneError;
//put_log(&err).ok();
err
}
}
impl From<std::path::StripPrefixError> for HError {
fn from(error: std::path::StripPrefixError) -> Self {
// dbg!(&error);
let err = HError::StripPrefixError{error: error };
put_log(&err).ok();
err
}
}
impl From<notify::Error> for HError {
fn from(error: notify::Error) -> Self {
// dbg!(&error);
let err = HError::INotifyError(format!("{}", error));
put_log(&err).ok();
err
}
}
impl From<async_value::AError> for HError {
fn from(error: async_value::AError) -> Self {
let err = HError::AError(error);
err
}
}

View File

@ -1,6 +1,7 @@
use termion::event::Key;
use pathbuftools::PathBufTools;
use osstrtools::OsStrTools;
use async_value::Stale;
use std::io::Write;
use std::sync::{Arc, Mutex, RwLock};
@ -196,24 +197,33 @@ impl Tabbable for TabView<FileBrowser> {
}
fn on_config_loaded(&mut self) -> HResult<()> {
// hack: wait a bit for widget readyness...
let duration = std::time::Duration::from_millis(100);
std::thread::sleep(duration);
let show_hidden = self.config().show_hidden();
for tab in self.widgets.iter_mut() {
tab.left_widget_mut().map(|w| {
w.content.show_hidden = show_hidden;
w.content.dirty_meta.set_dirty();
w.refresh().log();
}).ok();
tab.main_widget_mut().map(|w| {
w.content.show_hidden = show_hidden;
w.content.dirty_meta.set_dirty();
w.content.sort();
w.refresh().log();
}).ok();
for tab in self.widgets.iter_mut() {
tab.left_async_widget_mut().map(|async_w| {
async_w.widget.on_ready(move |mut w, _| {
w.as_mut()
.map(|mut w| {
w.content.show_hidden = show_hidden;
w.content.dirty_meta.set_dirty();
w.refresh().log();
}).ok();
Ok(())
}).log();
}).log();
tab.main_async_widget_mut().map(|async_w| {
async_w.widget.on_ready(move |mut w, _| {
w.as_mut()
.map(|mut w| {
w.content.show_hidden = show_hidden;
w.content.dirty_meta.set_dirty();
w.content.sort();
w.refresh().log();
}).ok();
Ok(())
}).log()
}).log();
tab.preview_widget_mut().map(|w| w.config_loaded()).ok();
}
@ -252,7 +262,7 @@ impl FileBrowser {
let left_path = main_path.parent().map(|p| p.to_path_buf());
let cache = fs_cache.clone();
let main_widget = AsyncWidget::new(&core, Box::new(move |_| {
let main_widget = AsyncWidget::new(&core, move |_| {
let name = if main_path.parent().is_none() {
"root".to_string()
} else {
@ -277,11 +287,11 @@ impl FileBrowser {
list.refresh().log();
Ok(list)
}));
});
let cache = fs_cache.clone();
if let Some(left_path) = left_path {
let left_widget = AsyncWidget::new(&core, Box::new(move |_| {
let left_widget = AsyncWidget::new(&core, move |_| {
let name = if left_path.parent().is_none() {
"root".to_string()
} else {
@ -303,14 +313,14 @@ impl FileBrowser {
list.refresh().log();
Ok(list)
}));
});
let left_widget = FileBrowserWidgets::FileList(left_widget);
columns.push_widget(left_widget);
} else {
let left_widget = AsyncWidget::new(&core, Box::new(move |_| {
let left_widget = AsyncWidget::new(&core, move |_| {
let blank = TextView::new_blank(&core_l);
Ok(blank)
}));
});
let left_widget = FileBrowserWidgets::Blank(left_widget);
columns.push_widget(left_widget);
@ -372,7 +382,7 @@ impl FileBrowser {
let core = self.core.clone();
let cache = self.fs_cache.clone();
let main_widget = AsyncWidget::new(&core.clone(), Box::new(move |_| {
let main_widget = AsyncWidget::new(&core.clone(), move |_| {
let files = match previewer_files {
Some(files) => files,
None => cache.get_files_sync(&dir)?
@ -389,7 +399,7 @@ impl FileBrowser {
list.content.meta_all();
Ok(list)
}));
});
let main_widget = FileBrowserWidgets::FileList(main_widget);
self.columns.insert_widget(1, main_widget);
@ -492,9 +502,9 @@ impl FileBrowser {
self.cwd = dir.clone();
let main_async_widget = self.main_async_widget_mut()?;
main_async_widget.change_to(Box::new(move |stale, core| {
let (selected_file, files) = cache.get_files(&dir, stale)?;
let files = files.wait()?;
main_async_widget.change_to(move |stale: &Stale, core| {
let (selected_file, files) = cache.get_files(&dir, stale.clone())?;
let files = files.run_sync()?;
let mut list = ListView::new(&core, files);
@ -505,14 +515,14 @@ impl FileBrowser {
list.select_file(&file);
}
Ok(list)
})).log();
}).log();
if let Ok(grand_parent) = self.cwd()?.parent_as_file() {
self.left_widget_goto(&grand_parent).log();
} else {
self.left_async_widget_mut()?.change_to(Box::new(move |_,_| {
self.left_async_widget_mut()?.change_to(move |_,_| {
HError::stale()?
})).log();
}).log();
}
Ok(())
@ -530,15 +540,15 @@ impl FileBrowser {
let dir = dir.clone();
let left_async_widget = self.left_async_widget_mut()?;
left_async_widget.change_to(Box::new(move |stale, core| {
let cached_files = cache.get_files(&dir, stale)?;
left_async_widget.change_to(move |stale, core| {
let cached_files = cache.get_files(&dir, stale.clone())?;
let (_, files) = cached_files;
let files = files.wait()?;
let files = files.run_sync()?;
let list = ListView::new(&core, files);
Ok(list)
}))?;
})?;
Ok(())
}
@ -552,19 +562,19 @@ impl FileBrowser {
if let Ok(left_dir) = new_cwd.parent_as_file() {
let cache = self.fs_cache.clone();
let left_widget = AsyncWidget::new(&core.clone(), Box::new(move |_| {
let left_widget = AsyncWidget::new(&core.clone(), move |_| {
let files = cache.get_files_sync(&left_dir)?;
let list = ListView::new(&core, files);
Ok(list)
}));
});
let left_widget = FileBrowserWidgets::FileList(left_widget);
self.columns.prepend_widget(left_widget);
} else {
let left_widget = AsyncWidget::new(&core.clone(), Box::new(move |_| {
let left_widget = AsyncWidget::new(&core.clone(), move |_| {
let blank = TextView::new_blank(&core);
Ok(blank)
}));
});
let left_widget = FileBrowserWidgets::Blank(left_widget);
self.columns.prepend_widget(left_widget);
@ -669,9 +679,9 @@ impl FileBrowser {
pub fn take_main_files(&mut self) -> HResult<Files> {
let core = self.core.clone();
let blank = AsyncWidget::new(&core.clone(), Box::new(move |_| {
let blank = AsyncWidget::new(&core.clone(), move |_| {
HError::no_files()
}));
});
let blank = FileBrowserWidgets::Blank(blank);
let old_widget = self.columns.replace_widget(1, blank);
@ -685,9 +695,9 @@ impl FileBrowser {
pub fn take_left_files(&mut self) -> HResult<Files> {
let core = self.core.clone();
let blank = AsyncWidget::new(&core.clone(), Box::new(move |_| {
let blank = AsyncWidget::new(&core.clone(), move |_| {
HError::no_files()
}));
});
let blank = FileBrowserWidgets::FileList(blank);
let old_widget = self.columns.replace_widget(0, blank);
@ -930,9 +940,14 @@ impl FileBrowser {
let file = File::new_from_path(&path, None)?;
let dir = file.parent_as_file()?;
self.main_widget_goto_wait(&dir).log();
self.main_widget_goto(&dir).log();
self.main_widget_mut()?.select_file(&file);
self.main_async_widget_mut()?
.widget
.on_ready(move |w, _| {
w?.select_file(&file);
Ok(())
})?;
}
} else {
let msg = format!("Can't access path: {}!",

View File

@ -19,10 +19,10 @@ use notify::DebouncedEvent;
use rayon::{ThreadPool, ThreadPoolBuilder};
use alphanumeric_sort::compare_str;
use pathbuftools::PathBufTools;
use async_value::{Async, Stale};
use crate::fail::{HResult, HError, ErrorLog};
use crate::dirty::{AsyncDirtyBit, DirtyBit, Dirtyable};
use crate::preview::{Async, Stale};
use crate::widget::Events;
use crate::icon::Icons;
@ -186,7 +186,7 @@ impl Files {
let files: Vec<_> = direntries?
.iter()
.map(|file| {
if crate::preview::is_stale(&stale).unwrap() {
if stale.is_stale().ok()? {
None
} else {
let name = file.file_name();
@ -202,7 +202,7 @@ impl Files {
.flatten()
.collect();
if crate::preview::is_stale(&stale).unwrap() {
if stale.is_stale()? {
return Err(crate::fail::HError::StalePreviewError {
file: path.to_string_lossy().to_string()
})?;
@ -580,8 +580,15 @@ impl Hash for File {
impl Eq for File {}
impl std::fmt::Debug for File {
fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
write!(formatter, "{:?}", self.path)
}
}
#[derive(Clone, Debug)]
#[derive(Clone)]
pub struct File {
pub name: String,
pub path: PathBuf,
@ -682,23 +689,20 @@ impl File {
stale_preview: Option<Stale>) -> Async<Metadata> {
let path = path.clone();
let meta_closure = Box::new(move |stale: Stale| {
let mut meta = Async::new(move |stale: &Stale| {
if stale.is_stale()? { HError::stale()? }
Ok(std::fs::symlink_metadata(&path)?)
});
let mut meta = match stale_preview {
Some(stale) => Async::new_with_stale(meta_closure, stale),
None => Async::new(meta_closure)
};
if let Some(dirty_meta) = dirty_meta {
meta.on_ready(Box::new(move || {
let mut dirty_meta = dirty_meta.clone();
dirty_meta.set_dirty();
stale_preview.map(|s| meta.put_stale(s));
dirty_meta.map(|mut d|
meta.on_ready(move |_,_| {
d.set_dirty();
Ok(())
}));
}
}).log()
);
meta
}
@ -707,29 +711,25 @@ impl File {
stale_preview: Option<Stale>) -> Async<usize> {
let path = path.clone();
let dirsize_closure = Box::new(move |stale: Stale| {
let mut dirsize = Async::new(move |stale: &Stale| {
if stale.is_stale()? { HError::stale()? }
Ok(std::fs::read_dir(&path)?.count())
});
let mut dirsize = match stale_preview {
Some(stale) => Async::new_with_stale(dirsize_closure, stale),
None => Async::new(dirsize_closure)
};
stale_preview.map(|s| dirsize.put_stale(s));
if let Some(dirty_meta) = dirty_meta {
dirsize.on_ready(Box::new(move || {
let mut dirty_meta = dirty_meta.clone();
dirty_meta.set_dirty();
dirty_meta.map(|mut d|
dirsize.on_ready(move |_,_| {
d.set_dirty();
Ok(())
}));
}
}).log()
);
dirsize
}
pub fn meta(&self) -> HResult<&Metadata> {
self.meta.get()
Ok(self.meta.get()?)
}
fn take_dirsize(&mut self,
@ -738,13 +738,15 @@ impl File {
let dirsize = self.dirsize.as_mut()?;
if let Ok(_) = dirsize.value { return Ok(()) }
match dirsize.take_async() {
Ok(_) => { *meta_updated = true; },
Err(HError::AsyncNotReadyError) => { dirsize.run_pooled(&*pool).ok(); },
Err(HError::AsyncAlreadyTakenError) => {},
Err(HError::NoneError) => {},
err @ Err(_) => { err?; }
if !dirsize.is_running() {
dirsize.run_pooled(Some(&*pool))?;
}
if dirsize.is_ready() {
dirsize.pull_async()?;
*meta_updated = true;
}
Ok(())
}
@ -753,15 +755,15 @@ impl File {
meta_updated: &mut bool) -> HResult<()> {
if self.meta_processed { return Ok(()) }
match self.meta.take_async() {
Ok(_) => { *meta_updated = true; },
Err(HError::AsyncNotReadyError) => { self.meta.run_pooled(&*pool).ok(); },
Err(HError::AsyncAlreadyTakenError) => {},
Err(HError::NoneError) => {},
err @ Err(_) => { err?; }
if !self.meta.is_running() {
self.meta.run_pooled(Some(&*pool))?;
}
self.process_meta()?;
if self.meta.is_ready() {
self.meta.pull_async()?;
self.process_meta()?;
*meta_updated = true;
}
Ok(())
}
@ -785,12 +787,13 @@ impl File {
self.meta = File::make_async_meta(&self.path,
self.dirty_meta.clone(),
None);
self.meta.run().log();
self.meta.run()?;
if self.dirsize.is_some() {
self.dirsize
= Some(File::make_async_dirsize(&self.path, self.dirty_meta.clone(), None));
self.dirsize.as_mut()?.run().log();
self.dirsize = Some(File::make_async_dirsize(&self.path,
self.dirty_meta.clone(),
None));
self.dirsize.as_mut()?.run()?;
}
Ok(())
}

View File

@ -1,12 +1,13 @@
use notify::{RecommendedWatcher, Watcher, DebouncedEvent, RecursiveMode};
use async_value::{Async, Stale};
use std::sync::{Arc, RwLock};
use std::sync::mpsc::{channel, Sender, Receiver};
use std::collections::{HashMap, HashSet};
use std::time::Duration;
use std::path::PathBuf;
use crate::preview::{Async, Stale};
use crate::files::{Files, File, SortBy};
use crate::widget::Events;
use crate::fail::{HResult, HError, ErrorLog};
@ -116,11 +117,11 @@ impl FsCache {
let dir = dir.clone();
let selection = self.get_selection(&dir).ok();
let cache = self.clone();
let files = Async::new(Box::new(move |_| {
let files = Async::new(move |_| {
let mut files = Files::new_from_path_cancellable(&dir.path, stale)?;
FsCache::apply_settingss(&cache, &mut files).ok();
Ok(files)
}));
});
Ok((selection, files))
}
}
@ -128,7 +129,7 @@ impl FsCache {
pub fn get_files_sync(&self, dir: &File) -> HResult<Files> {
self.add_watch(&dir).log();
let files = self.get_files(&dir, Stale::new())?.1;
let mut files = files.wait()?;
let mut files = files.run_sync()?;
FsCache::apply_settingss(&self, &mut files).ok();
let files = FsCache::ensure_not_empty(files)?;
Ok(files)
@ -210,8 +211,12 @@ impl FsCache {
let file_cache = self.files.clone();
let dir = dir.clone();
let files = Async::new(Box::new(move |_| {
let mut files = file_cache.read()?.get(&dir)?.clone();
let files = Async::new(move |_| {
let mut files = file_cache.read()
.map_err(|e| HError::from(e))?
.get(&dir)
.ok_or(HError::NoneError)?
.clone();
let tab_settings = &tab_settings;
files.sort = tab_settings.dir_settings.sort;
@ -233,7 +238,7 @@ impl FsCache {
files.sort();
let files = FsCache::ensure_not_empty(files)?;
Ok(files)
}));
});
Ok((selection, files))
}
@ -301,7 +306,7 @@ fn watch_fs(rx_fs_events: Receiver<DebouncedEvent>,
for event in rx_fs_events.iter() {
apply_event(&fs_cache, &fs_changes, event).log();
Ok(sender.send(Events::WidgetReady)?).log();
sender.send(Events::WidgetReady).ok();
}
Ok(())
});

View File

@ -1,7 +1,6 @@
#![feature(vec_remove_item)]
#![feature(trivial_bounds)]
#![feature(try_trait)]
#![feature(fnbox)]
#![allow(dead_code)]
extern crate termion;
@ -24,6 +23,7 @@ extern crate tree_magic;
extern crate systemstat;
extern crate osstrtools;
extern crate pathbuftools;
extern crate async_value;
use failure::Fail;

View File

@ -1,7 +1,6 @@
use std::sync::{Arc, Mutex, RwLock};
use std::boxed::FnBox;
use std::sync::{Arc, Mutex};
use rayon::ThreadPool;
use async_value::{Async, Stale};
use crate::files::{File, Files, Kind};
use crate::fscache::FsCache;
@ -13,14 +12,8 @@ use crate::fail::{HResult, HError, ErrorLog};
use crate::dirty::Dirtyable;
pub type AsyncValueFn<T> = Box<dyn FnBox(Stale) -> HResult<T> + Send + Sync>;
pub type AsyncValue<T> = Arc<Mutex<Option<HResult<T>>>>;
pub type AsyncReadyFn = Box<dyn FnBox() -> HResult<()> + Send + Sync>;
pub type AsyncWidgetFn<W> = Box<dyn FnBox(Stale, WidgetCore)
-> HResult<W> + Send + Sync>;
type WidgetO = Box<dyn Widget + Send>;
pub type AsyncWidgetFn<W> = FnOnce(&Stale, WidgetCore)
-> HResult<W> + Send + Sync;
lazy_static! {
static ref SUBPROC: Arc<Mutex<Option<u32>>> = { Arc::new(Mutex::new(None)) };
@ -35,232 +28,9 @@ fn kill_proc() -> HResult<()> {
Ok(())
}
#[derive(Clone, Debug)]
pub struct Stale(Arc<RwLock<bool>>);
impl Stale {
pub fn new() -> Stale {
Stale(Arc::new(RwLock::new(false)))
}
pub fn is_stale(&self) -> HResult<bool> {
Ok(*self.0.read()?)
}
pub fn set_stale(&self) -> HResult<()> {
*self.0.write()? = true;
Ok(())
}
pub fn set_fresh(&self) -> HResult<()> {
*self.0.write()? = false;
Ok(())
}
}
pub fn is_stale(stale: &Stale) -> HResult<bool> {
let stale = stale.is_stale()?;
Ok(stale)
}
use std::fmt::{Debug, Formatter};
impl<T: Send + Debug> Debug for Async<T> {
fn fmt(&self, formatter: &mut Formatter) -> Result<(), std::fmt::Error> {
write!(formatter,
"{:?}, {:?} {:?}",
self.value,
self.async_value,
self.stale)
}
}
#[derive(Clone)]
pub struct Async<T: Send> {
pub value: HResult<T>,
async_value: AsyncValue<T>,
async_closure: Arc<Mutex<Option<AsyncValueFn<T>>>>,
on_ready: Arc<Mutex<Option<AsyncReadyFn>>>,
started: bool,
stale: Stale,
}
impl<T: Send + 'static> Async<T> {
pub fn new(closure: AsyncValueFn<T>)
-> Async<T> {
let async_value = Async {
value: HError::async_not_ready(),
async_value: Arc::new(Mutex::new(None)),
async_closure: Arc::new(Mutex::new(Some(closure))),
on_ready: Arc::new(Mutex::new(None)),
started: false,
stale: Stale::new() };
async_value
}
pub fn new_with_stale(closure: AsyncValueFn<T>,
stale: Stale)
-> Async<T> {
let async_value = Async {
value: HError::async_not_ready(),
async_value: Arc::new(Mutex::new(None)),
async_closure: Arc::new(Mutex::new(Some(closure))),
on_ready: Arc::new(Mutex::new(None)),
started: false,
stale: stale };
async_value
}
pub fn new_with_value(val: T) -> Async<T> {
Async {
value: Ok(val),
async_value: Arc::new(Mutex::new(None)),
async_closure: Arc::new(Mutex::new(None)),
on_ready: Arc::new(Mutex::new(None)),
started: false,
stale: Stale::new()
}
}
pub fn run_async(async_fn: Arc<Mutex<Option<AsyncValueFn<T>>>>,
async_value: AsyncValue<T>,
on_ready_fn: Arc<Mutex<Option<AsyncReadyFn>>>,
stale: Stale) -> HResult<()> {
let value_fn = async_fn.lock()?.take()?;
let value = value_fn.call_box((stale.clone(),));
async_value.lock()?.replace(value);
on_ready_fn.lock()?
.take()
.map(|on_ready| on_ready.call_box(()).log());
Ok(())
}
pub fn run(&mut self) -> HResult<()> {
if self.started {
HError::async_started()?
}
let closure = self.async_closure.clone();
let async_value = self.async_value.clone();
let stale = self.stale.clone();
let on_ready_fn = self.on_ready.clone();
self.started = true;
std::thread::spawn(move || {
Async::run_async(closure,
async_value,
on_ready_fn,
stale).log();
});
Ok(())
}
pub fn run_pooled(&mut self, pool: &ThreadPool) -> HResult<()> {
if self.started {
HError::async_started()?
}
let closure = self.async_closure.clone();
let async_value = self.async_value.clone();
let stale = self.stale.clone();
let on_ready_fn = self.on_ready.clone();
self.started = true;
pool.spawn(move || {
Async::run_async(closure,
async_value,
on_ready_fn,
stale).log();
});
Ok(())
}
pub fn wait(self) -> HResult<T> {
Async::run_async(self.async_closure,
self.async_value.clone(),
self.on_ready,
self.stale).log();
let value = self.async_value.lock()?.take()?;
value
}
pub fn set_stale(&mut self) -> HResult<()> {
self.stale.set_stale()?;
Ok(())
}
pub fn set_fresh(&self) -> HResult<()> {
self.stale.set_fresh()?;
Ok(())
}
pub fn is_stale(&self) -> HResult<bool> {
self.stale.is_stale()
}
pub fn get_stale(&self) -> Stale {
self.stale.clone()
}
pub fn put_stale(&mut self, stale: Stale) {
self.stale = stale;
}
pub fn is_started(&self) -> bool {
self.started
}
pub fn set_unstarted(&mut self) {
self.started = false;
}
pub fn take_async(&mut self) -> HResult<()> {
if self.value.is_ok() { HError::async_taken()? }
let mut async_value = self.async_value.lock()?;
match async_value.as_ref() {
Some(Ok(_)) => {
let value = async_value.take()?;
self.value = value;
}
Some(Err(HError::AsyncAlreadyTakenError)) => HError::async_taken()?,
Some(Err(_)) => {
let value = async_value.take()?;
self.value = value;
}
None => HError::async_not_ready()?,
}
Ok(())
}
pub fn get(&self) -> HResult<&T> {
match self.value {
Ok(ref value) => Ok(value),
Err(ref err) => HError::async_error(err)
}
}
pub fn get_mut(&mut self) -> HResult<&mut T> {
self.take_async().ok();
match self.value {
Ok(ref mut value) => Ok(value),
Err(ref err) => HError::async_error(err)
}
}
pub fn on_ready(&mut self,
fun: AsyncReadyFn) {
*self.on_ready.lock().unwrap() = Some(fun);
}
}
impl<W: Widget + Send + 'static> PartialEq for AsyncWidget<W> {
fn eq(&self, other: &AsyncWidget<W>) -> bool {
if self.get_coordinates().unwrap() ==
@ -274,19 +44,21 @@ impl<W: Widget + Send + 'static> PartialEq for AsyncWidget<W> {
pub struct AsyncWidget<W: Widget + Send + 'static> {
widget: Async<W>,
pub widget: Async<W>,
core: WidgetCore
}
impl<W: Widget + Send + 'static> AsyncWidget<W> {
pub fn new(core: &WidgetCore, closure: AsyncValueFn<W>) -> AsyncWidget<W> {
let sender = Mutex::new(core.get_sender());
let mut widget = Async::new(Box::new(move |stale|
closure.call_box((stale,))));
widget.on_ready(Box::new(move || {
sender.lock()?.send(crate::widget::Events::WidgetReady)?;
pub fn new(core: &WidgetCore,
closure: impl FnOnce(&Stale) -> HResult<W> + Send + Sync + 'static)
-> AsyncWidget<W> {
let sender = Arc::new(Mutex::new(core.get_sender()));
let mut widget = Async::new(move |stale|
closure(stale).map_err(|e| e.into()));
widget.on_ready(move |_, _| {
sender.lock().map(|s| s.send(crate::widget::Events::WidgetReady)).ok();
Ok(())
}));
}).log();
widget.run().log();
AsyncWidget {
@ -294,20 +66,24 @@ impl<W: Widget + Send + 'static> AsyncWidget<W> {
core: core.clone()
}
}
pub fn change_to(&mut self, closure: AsyncWidgetFn<W>) -> HResult<()> {
pub fn change_to(&mut self,
closure: impl FnOnce(&Stale,
WidgetCore)
-> HResult<W> + Send + Sync + 'static)
-> HResult<()> {
self.set_stale().log();
let sender = Mutex::new(self.get_core()?.get_sender());
let core = self.get_core()?.clone();
let mut widget = Async::new(Box::new(move |stale| {
closure.call_box((stale, core.clone(),))
}));
let mut widget = Async::new(move |stale| {
Ok(closure(stale, core.clone())?)
});
widget.on_ready(Box::new(move || {
sender.lock()?.send(crate::widget::Events::WidgetReady)?;
widget.on_ready(move |_, _| {
sender.lock().map(|s| s.send(crate::widget::Events::WidgetReady)).ok();
Ok(())
}));
}).log();
widget.run().log();
@ -316,11 +92,11 @@ impl<W: Widget + Send + 'static> AsyncWidget<W> {
}
pub fn set_stale(&mut self) -> HResult<()> {
self.widget.set_stale()
Ok(self.widget.set_stale()?)
}
pub fn is_stale(&self) -> HResult<bool> {
self.widget.is_stale()
Ok(self.widget.is_stale()?)
}
pub fn get_stale(&self) -> Stale {
@ -328,11 +104,11 @@ impl<W: Widget + Send + 'static> AsyncWidget<W> {
}
pub fn widget(&self) -> HResult<&W> {
self.widget.get()
Ok(self.widget.get()?)
}
pub fn widget_mut(&mut self) -> HResult<&mut W> {
self.widget.get_mut()
Ok(self.widget.get_mut()?)
}
pub fn take_widget(self) -> HResult<W> {
@ -363,7 +139,7 @@ impl<T: Widget + Send + 'static> Widget for AsyncWidget<T> {
}
fn refresh(&mut self) -> HResult<()> {
self.widget.take_async().ok();
self.widget.pull_async().ok();
let coords = self.get_coordinates()?.clone();
if let Ok(widget) = self.widget_mut() {
@ -415,7 +191,6 @@ enum PreviewWidget {
}
pub struct Previewer {
widget: AsyncWidget<PreviewWidget>,
core: WidgetCore,
@ -428,11 +203,12 @@ pub struct Previewer {
impl Previewer {
pub fn new(core: &WidgetCore, cache: FsCache) -> Previewer {
let core_ = core.clone();
let widget = AsyncWidget::new(&core, Box::new(move |_| {
let widget = AsyncWidget::new(&core, move |_| {
let blank = TextView::new_blank(&core_);
let blank = PreviewWidget::TextView(blank);
Ok(blank)
}));
});
Previewer { widget: widget,
core: core.clone(),
file: None,
@ -457,16 +233,16 @@ impl Previewer {
}
pub fn cancel_animation(&self) -> HResult<()> {
self.animator.set_stale()
Ok(self.animator.set_stale()?)
}
pub fn take_files(&mut self) -> HResult<Files> {
let core = self.core.clone();
let mut widget = AsyncWidget::new(&core.clone(), Box::new(move |_| {
let mut widget = AsyncWidget::new(&core.clone(), move |_| {
let widget = TextView::new_blank(&core);
let widget = PreviewWidget::TextView(widget);
Ok(widget)
}));
});
std::mem::swap(&mut self.widget, &mut widget);
match widget.take_widget() {
@ -501,19 +277,24 @@ impl Previewer {
let cache = self.cache.clone();
self.file = Some(dir);
self.widget = AsyncWidget::new(&self.core, Box::new(move |_| {
self.widget = AsyncWidget::new(&self.core, move |_| {
let selected_file = cache.get_selection(&files.directory);
let mut filelist = ListView::new(&core, files);
selected_file.map(|file| filelist.select_file(&file)).log();
Ok(PreviewWidget::FileList(filelist))
}));
});
}
pub fn set_file(&mut self,
file: &File) -> HResult<()> {
if Some(file) == self.file.as_ref() && !self.widget.is_stale()? { return Ok(()) }
let same_dir = self.file
.as_ref()
.map(|f| f.path.parent() == file.path.parent())
.unwrap_or(true);
self.file = Some(file.clone());
let coordinates = self.get_coordinates().unwrap().clone();
@ -523,41 +304,46 @@ impl Previewer {
let animator = self.animator.clone();
self.widget.set_stale().ok();
self.animator.set_fresh().log();
if same_dir {
self.animator.set_fresh().ok();
} else {
self.animator.set_stale().ok();
}
self.become_preview(Ok(AsyncWidget::new(&self.core,
Box::new(move |stale: Stale| {
move |stale: &Stale| {
kill_proc().unwrap();
if file.kind == Kind::Directory {
let preview = Previewer::preview_dir(&file,
cache,
&core,
stale,
animator);
return preview;
&stale,
&animator);
return Ok(preview?);
}
if file.is_text() {
return Previewer::preview_text(&file,
return Ok(Previewer::preview_text(&file,
&core,
stale,
animator);
&stale,
&animator)?);
}
let preview = Previewer::preview_external(&file,
&core,
stale,
animator.clone());
if preview.is_ok() { return preview; }
&stale,
&animator);
if preview.is_ok() { return Ok(preview?); }
else {
let mut blank = TextView::new_blank(&core);
blank.set_coordinates(&coordinates).log();
blank.refresh().log();
blank.animate_slide_up(Some(animator)).log();
blank.animate_slide_up(Some(&animator)).log();
return Ok(PreviewWidget::TextView(blank))
}
}))))
})))
}
pub fn reload(&mut self) {
@ -576,14 +362,14 @@ impl Previewer {
fn preview_dir(file: &File,
cache: FsCache,
core: &WidgetCore,
stale: Stale,
animator: Stale)
stale: &Stale,
animator: &Stale)
-> HResult<PreviewWidget> {
let (selection, cached_files) = cache.get_files(&file, stale.clone())?;
let files = cached_files.wait()?;
let files = cached_files.run_sync()?;
if is_stale(&stale)? { return Previewer::preview_failed(&file) }
if stale.is_stale()? { return Previewer::preview_failed(&file) }
let mut file_list = ListView::new(&core, files);
if let Some(selection) = selection {
@ -591,27 +377,27 @@ impl Previewer {
}
file_list.set_coordinates(&core.coordinates)?;
file_list.refresh()?;
if is_stale(&stale)? { return Previewer::preview_failed(&file) }
if stale.is_stale()? { return Previewer::preview_failed(&file) }
file_list.animate_slide_up(Some(animator))?;
Ok(PreviewWidget::FileList(file_list))
}
fn preview_text(file: &File,
core: &WidgetCore,
stale: Stale,
animator: Stale)
stale: &Stale,
animator: &Stale)
-> HResult<PreviewWidget> {
let lines = core.coordinates.ysize() as usize;
let mut textview
= TextView::new_from_file_limit_lines(&core,
&file,
lines)?;
if is_stale(&stale)? { return Previewer::preview_failed(&file) }
if stale.is_stale()? { return Previewer::preview_failed(&file) }
textview.set_coordinates(&core.coordinates)?;
textview.refresh()?;
if is_stale(&stale)? { return Previewer::preview_failed(&file) }
if stale.is_stale()? { return Previewer::preview_failed(&file) }
textview.animate_slide_up(Some(animator))?;
Ok(PreviewWidget::TextView(textview))
@ -619,8 +405,8 @@ impl Previewer {
fn preview_external(file: &File,
core: &WidgetCore,
stale: Stale,
animator: Stale)
stale: &Stale,
animator: &Stale)
-> HResult<PreviewWidget> {
let process =
std::process::Command::new("scope.sh")
@ -640,11 +426,11 @@ impl Previewer {
*pid_ = Some(pid);
}
if is_stale(&stale)? { return Previewer::preview_failed(&file) }
if stale.is_stale()? { return Previewer::preview_failed(&file) }
let output = process.wait_with_output()?;
if is_stale(&stale)? { return Previewer::preview_failed(&file) }
if stale.is_stale()? { return Previewer::preview_failed(&file) }
{
let mut pid_ = SUBPROC.lock()?;
*pid_ = None;
@ -652,7 +438,7 @@ impl Previewer {
//let status = output.status.code()?;
if !is_stale(&stale)? {
if stale.is_stale()? {
let output = std::str::from_utf8(&output.stdout)
.unwrap()
.to_string();

View File

@ -9,12 +9,13 @@ use std::os::unix::ffi::OsStringExt;
use termion::event::Key;
use unicode_width::UnicodeWidthStr;
use osstrtools::OsStrTools;
use async_value::Stale;
use crate::listview::{Listable, ListView};
use crate::textview::TextView;
use crate::widget::{Widget, Events, WidgetCore};
use crate::coordinates::Coordinates;
use crate::preview::{AsyncWidget, Stale};
use crate::preview::AsyncWidget;
use crate::dirty::Dirtyable;
use crate::hbox::HBox;
use crate::fail::{HResult, HError, ErrorLog};
@ -368,10 +369,10 @@ impl ProcView {
pub fn new(core: &WidgetCore) -> ProcView {
let tcore = core.clone();
let listview = ListView::new(&core, vec![]);
let textview = AsyncWidget::new(&core, Box::new(move |_| {
let textview = AsyncWidget::new(&core, move |_| {
let textview = TextView::new_blank(&tcore);
Ok(textview)
}));
});
let mut hbox = HBox::new(&core);
hbox.push_widget(ProcViewWidgets::List(listview));
hbox.push_widget(ProcViewWidgets::TextView(textview));
@ -425,12 +426,12 @@ impl ProcView {
let animator = self.animator.clone();
animator.set_fresh().log();
self.get_textview().change_to(Box::new(move |_, core| {
self.get_textview().change_to(move |_, core| {
let mut textview = TextView::new_blank(&core);
textview.set_text(&output).log();
textview.animate_slide_up(Some(animator)).log();
textview.animate_slide_up(Some(&animator)).log();
Ok(textview)
})).log();
}).log();
self.viewing = Some(self.get_listview_mut().get_selection());
Ok(())

View File

@ -4,6 +4,8 @@ use std::io::{Write, stdin};
use termion::event::{Event, Key, MouseEvent};
use termion::input::TermRead;
use async_value::{Async, Stale};
use crate::coordinates::{Coordinates, Position, Size};
use crate::fail::{HResult, HError, ErrorLog};
@ -11,10 +13,8 @@ use crate::minibuffer::MiniBuffer;
use crate::term;
use crate::term::{Screen, ScreenExt};
use crate::dirty::{Dirtyable, DirtyBit};
use crate::preview::Stale;
use crate::signal_notify::{notify, Signal};
use crate::config::Config;
use crate::preview::Async;
@ -75,12 +75,12 @@ impl WidgetCore {
let (sender, receiver) = channel();
let status_bar_content = Arc::new(Mutex::new(None));
let mut config = Async::new(Box::new(|_| Config::load()));
let mut config = Async::new(|_| Ok(Config::load()?));
let confsender = Arc::new(Mutex::new(sender.clone()));
config.on_ready(Box::new(move || {
confsender.lock()?.send(Events::ConfigLoaded).ok();
config.on_ready(move |_, _| {
confsender.lock().map(|s| s.send(Events::ConfigLoaded)).ok();
Ok(())
}));
}).log();
config.run().log();
let core = WidgetCore {
@ -296,7 +296,7 @@ pub trait Widget {
HError::input_updated(input)?
}
Events::ConfigLoaded => {
self.get_core_mut()?.config.write()?.take_async().log();
self.get_core_mut()?.config.write()?.pull_async()?;
}
_ => {}
}
@ -320,7 +320,7 @@ pub trait Widget {
.unwrap_or(Config::new())
}
fn animate_slide_up(&mut self, animator: Option<Stale>) -> HResult<()> {
fn animate_slide_up(&mut self, animator: Option<&Stale>) -> HResult<()> {
if !self.config().animate() { return Ok(()); }
self.config();
@ -398,7 +398,7 @@ pub trait Widget {
self.screen()?.clear().log();
}
Events::ConfigLoaded => {
self.get_core_mut()?.config.write()?.take_async().log();
self.get_core_mut()?.config.write()?.pull_async()?;
self.config_loaded().log();
}
_ => {}
@ -555,7 +555,7 @@ fn input_thread(tx: Sender<Events>, rx_input_request: Receiver<()>) {
input.map(|input| {
tx.send(Events::InputEvent(input)).unwrap();
rx_input_request.recv().unwrap();
}).map_err(|e| e.into()).log();
}).map_err(|e| HError::from(e)).log();
}
});
}