From 99980ace6c0935d2ebf4ddda21499702dfacde76 Mon Sep 17 00:00:00 2001 From: rabite Date: Sat, 11 May 2019 13:29:00 +0200 Subject: [PATCH] use async_value library --- Cargo.lock | 20 +++ Cargo.toml | 1 + rust-toolchain | 2 +- src/fail.rs | 55 ++++--- src/file_browser.rs | 103 +++++++------ src/files.rs | 91 +++++------ src/fscache.rs | 21 ++- src/main.rs | 2 +- src/preview.rs | 364 +++++++++----------------------------------- src/proclist.rs | 13 +- src/widget.rs | 20 +-- 11 files changed, 261 insertions(+), 431 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ece9cca..4e93349 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -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" diff --git a/Cargo.toml b/Cargo.toml index ba3a4ae..4866532 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -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' } diff --git a/rust-toolchain b/rust-toolchain index 11e142a..d8d61dd 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1 +1 @@ -nightly-2019-03-15 +nightly-2019-04-28 diff --git a/src/fail.rs b/src/fail.rs index d34ed76..c8b4e70 100644 --- a/src/fail.rs +++ b/src/fail.rs @@ -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 ErrorLog for HResult { fn log(self) { if let Err(err) = self { - // eprintln!("{:?}", err); put_log(&err).ok(); } } @@ -223,101 +226,97 @@ impl ErrorLog for HResult { } +impl ErrorLog for Result { + 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 for HError { fn from(error: std::io::Error) -> Self { - // dbg!(&error); let err = HError::IoError(format!("{}", error)); - put_log(&err).ok(); err } } impl From for HError { fn from(error: failure::Error) -> Self { - // dbg!(&error); let err = HError::Error(format!("{}", error)); - put_log(&err).ok(); err } } impl From 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 for HError { fn from(error: std::sync::mpsc::RecvError) -> Self { - // dbg!(&error); let err = HError::ChannelRecvError { error: error }; - put_log(&err).ok(); err } } impl From> for HError { - fn from(error: std::sync::mpsc::SendError) -> Self { - dbg!(&error); + fn from(_error: std::sync::mpsc::SendError) -> Self { let err = HError::ChannelSendError; - put_log(&err).ok(); err } } impl From> for HError { fn from(_: std::sync::PoisonError) -> Self { - // dbg!("Poisoned Mutex"); let err = HError::MutexError; - put_log(&err).ok(); err } } impl From> for HError { fn from(_error: std::sync::TryLockError) -> Self { - // dbg!(&error); let err = HError::TryLockError; - put_log(&err).ok(); err } } impl From for HError { fn from(_error: std::option::NoneError) -> Self { - //dbg!(&error); let err = HError::NoneError; - //put_log(&err).ok(); err } } impl From for HError { fn from(error: std::path::StripPrefixError) -> Self { - // dbg!(&error); let err = HError::StripPrefixError{error: error }; - put_log(&err).ok(); err } } impl From for HError { fn from(error: notify::Error) -> Self { - // dbg!(&error); let err = HError::INotifyError(format!("{}", error)); - put_log(&err).ok(); + err + } +} + +impl From for HError { + fn from(error: async_value::AError) -> Self { + let err = HError::AError(error); err } } diff --git a/src/file_browser.rs b/src/file_browser.rs index 34ab2a6..cdd2284 100644 --- a/src/file_browser.rs +++ b/src/file_browser.rs @@ -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 { } 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 { 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 { 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: {}!", diff --git a/src/files.rs b/src/files.rs index a5b9b46..17b2612 100644 --- a/src/files.rs +++ b/src/files.rs @@ -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) -> Async { 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) -> Async { 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(()) } diff --git a/src/fscache.rs b/src/fscache.rs index 1c5ab17..d92caab 100644 --- a/src/fscache.rs +++ b/src/fscache.rs @@ -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 { 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, 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(()) }); diff --git a/src/main.rs b/src/main.rs index 1a06eb0..4df39ab 100644 --- a/src/main.rs +++ b/src/main.rs @@ -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; diff --git a/src/preview.rs b/src/preview.rs index b833c00..08e10c3 100644 --- a/src/preview.rs +++ b/src/preview.rs @@ -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 = Box HResult + Send + Sync>; -pub type AsyncValue = Arc>>>; -pub type AsyncReadyFn = Box HResult<()> + Send + Sync>; -pub type AsyncWidgetFn = Box HResult + Send + Sync>; - - -type WidgetO = Box; +pub type AsyncWidgetFn = FnOnce(&Stale, WidgetCore) + -> HResult + Send + Sync; lazy_static! { static ref SUBPROC: Arc>> = { Arc::new(Mutex::new(None)) }; @@ -35,232 +28,9 @@ fn kill_proc() -> HResult<()> { Ok(()) } -#[derive(Clone, Debug)] -pub struct Stale(Arc>); - -impl Stale { - pub fn new() -> Stale { - Stale(Arc::new(RwLock::new(false))) - } - pub fn is_stale(&self) -> HResult { - 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 { - let stale = stale.is_stale()?; - Ok(stale) -} - -use std::fmt::{Debug, Formatter}; - -impl Debug for Async { - fn fmt(&self, formatter: &mut Formatter) -> Result<(), std::fmt::Error> { - write!(formatter, - "{:?}, {:?} {:?}", - self.value, - self.async_value, - self.stale) - } -} - - -#[derive(Clone)] -pub struct Async { - pub value: HResult, - async_value: AsyncValue, - async_closure: Arc>>>, - on_ready: Arc>>, - started: bool, - stale: Stale, -} - - - -impl Async { - pub fn new(closure: AsyncValueFn) - -> Async { - 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, - stale: Stale) - -> Async { - 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 { - 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>>>, - async_value: AsyncValue, - on_ready_fn: Arc>>, - 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 { - 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 { - 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 PartialEq for AsyncWidget { fn eq(&self, other: &AsyncWidget) -> bool { if self.get_coordinates().unwrap() == @@ -274,19 +44,21 @@ impl PartialEq for AsyncWidget { pub struct AsyncWidget { - widget: Async, + pub widget: Async, core: WidgetCore } impl AsyncWidget { - pub fn new(core: &WidgetCore, closure: AsyncValueFn) -> AsyncWidget { - 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 + Send + Sync + 'static) + -> AsyncWidget { + 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 AsyncWidget { core: core.clone() } } - pub fn change_to(&mut self, closure: AsyncWidgetFn) -> HResult<()> { + pub fn change_to(&mut self, + closure: impl FnOnce(&Stale, + WidgetCore) + -> HResult + 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 AsyncWidget { } pub fn set_stale(&mut self) -> HResult<()> { - self.widget.set_stale() + Ok(self.widget.set_stale()?) } pub fn is_stale(&self) -> HResult { - self.widget.is_stale() + Ok(self.widget.is_stale()?) } pub fn get_stale(&self) -> Stale { @@ -328,11 +104,11 @@ impl AsyncWidget { } 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 { @@ -363,7 +139,7 @@ impl Widget for AsyncWidget { } 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, 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 { 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 { 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 { 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 { 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(); diff --git a/src/proclist.rs b/src/proclist.rs index f40b46d..8895a72 100644 --- a/src/proclist.rs +++ b/src/proclist.rs @@ -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(()) diff --git a/src/widget.rs b/src/widget.rs index e4e529c..16ae390 100644 --- a/src/widget.rs +++ b/src/widget.rs @@ -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) -> 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, 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(); } }); }