summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorrabite <rabite@posteo.de>2019-03-26 02:15:25 +0100
committerrabite <rabite@posteo.de>2019-03-26 02:15:25 +0100
commit90e626d16902f2dfcaf50121325913c579583bca (patch)
treeefdd822e86a5a54b20e5ab441ee2be318d51a352
parent153bf24238c5e11c12cbc848228c94cfa7334174 (diff)
some bugfixes and stuff
-rw-r--r--src/file_browser.rs34
-rw-r--r--src/files.rs102
-rw-r--r--src/preview.rs165
-rw-r--r--src/widget.rs1
4 files changed, 228 insertions, 74 deletions
diff --git a/src/file_browser.rs b/src/file_browser.rs
index 3a55f14..3cf05e7 100644
--- a/src/file_browser.rs
+++ b/src/file_browser.rs
@@ -13,6 +13,7 @@ use crate::files::{File, Files, PathBufExt};
use crate::listview::ListView;
use crate::hbox::HBox;
use crate::widget::Widget;
+use crate::dirty::Dirtyable;
use crate::tabview::{TabView, Tabbable};
use crate::preview::{Previewer, AsyncWidget};
use crate::fail::{HResult, HError, ErrorLog};
@@ -248,6 +249,18 @@ impl FileBrowser {
let file = self.selected_file()?;
if file.is_dir() {
+ match file.is_readable() {
+ Ok(true) => {},
+ Ok(false) => {
+ let status =
+ format!("{}Stop right there, cowboy! Check your permisions!",
+ term::color_red());
+ self.show_status(&status).log();
+ return Ok(());
+ }
+ err @ Err(_) => err.log()
+ }
+
self.main_widget_goto(&file).log();
} else {
self.core.get_sender().send(Events::InputEnabled(false))?;
@@ -293,22 +306,13 @@ impl FileBrowser {
}
pub fn main_widget_goto(&mut self, dir: &File) -> HResult<()> {
- match dir.is_readable() {
- Ok(true) => {},
- Ok(false) => {
- let status =
- format!("{}Stop right there, cowboy! Check your permisions!",
- term::color_red());
- self.show_status(&status).log();
- return Ok(());
- }
- err @ Err(_) => err.log()
- }
+
let dir = dir.clone();
let selected_file = self.get_selection(&dir).ok().cloned();
self.get_files().and_then(|files| self.cache_files(files)).log();
+ self.get_left_files().and_then(|files| self.cache_files(files)).log();
let cached_files = self.get_cached_files(&dir).ok();
self.prev_cwd = Some(self.cwd.clone());
@@ -320,11 +324,12 @@ impl FileBrowser {
let cached_files = cached_files.clone();
let files = cached_files.or_else(|| {
- Files::new_from_path_cancellable(&path, stale).ok()
+ Files::new_from_path_cancellable(&path, stale.clone()).ok()
})?;
let mut list = ListView::new(&core, files);
- list.content.meta_all();
+
+ list.content.meta_set_fresh().log();
if let Some(file) = &selected_file {
list.select_file(file);
@@ -335,6 +340,8 @@ impl FileBrowser {
if let Ok(grand_parent) = self.cwd()?.parent_as_file() {
self.left_widget_goto(&grand_parent).log();
} else {
+ self.left_async_widget_mut()?.clear().log();
+ self.screen()?.flush();
self.left_async_widget_mut()?.set_stale().log();
}
@@ -342,7 +349,6 @@ impl FileBrowser {
}
pub fn left_widget_goto(&mut self, dir: &File) -> HResult<()> {
- self.get_left_files().and_then(|files| self.cache_files(files)).log();
let cached_files = self.get_cached_files(&dir).ok();
let dir = dir.clone();
diff --git a/src/files.rs b/src/files.rs
index 424b648..90646ba 100644
--- a/src/files.rs
+++ b/src/files.rs
@@ -3,7 +3,7 @@ use std::ops::Index;
use std::fs::Metadata;
use std::os::unix::fs::MetadataExt;
use std::path::{Path, PathBuf};
-use std::sync::{Arc, Mutex};
+use std::sync::{Arc, Mutex, RwLock};
use std::sync::mpsc::Sender;
use std::hash::{Hash, Hasher};
use std::os::unix::ffi::{OsStringExt, OsStrExt};
@@ -23,13 +23,13 @@ use rayon::{ThreadPool, ThreadPoolBuilder};
use crate::fail::{HResult, HError, ErrorLog};
use crate::dirty::{AsyncDirtyBit, DirtyBit, Dirtyable};
-use crate::preview::Async;
+use crate::preview::{Async, Stale};
use crate::widget::Events;
lazy_static! {
static ref COLORS: LsColors = LsColors::from_env().unwrap();
- static ref TAGS: Mutex<(bool, Vec<PathBuf>)> = Mutex::new((false, vec![]));
+ static ref TAGS: RwLock<(bool, Vec<PathBuf>)> = RwLock::new((false, vec![]));
}
fn make_pool(sender: Option<Sender<Events>>) -> ThreadPool {
@@ -54,7 +54,7 @@ pub fn load_tags() -> HResult<()> {
let tag_path = crate::paths::tagfile_path()?;
let tags = std::fs::read_to_string(tag_path)?;
let mut tags = tags.lines().map(|f| PathBuf::from(f)).collect::<Vec<PathBuf>>();
- let mut tag_lock = TAGS.lock()?;
+ let mut tag_lock = TAGS.write()?;
tag_lock.0 = true;
tag_lock.1.append(&mut tags);
Ok(())
@@ -64,12 +64,12 @@ pub fn load_tags() -> HResult<()> {
pub fn check_tag(path: &PathBuf) -> HResult<bool> {
tags_loaded()?;
- let tagged = TAGS.lock()?.1.contains(path);
+ let tagged = TAGS.read()?.1.contains(path);
Ok(tagged)
}
pub fn tags_loaded() -> HResult<()> {
- let loaded = TAGS.lock()?.0;
+ let loaded = TAGS.read()?.0;
if loaded { Ok(()) }
else { HError::tags_not_loaded() }
}
@@ -155,7 +155,7 @@ impl Files {
}
pub fn new_from_path_cancellable(path: &Path,
- stale: Arc<Mutex<bool>>)
+ stale: Stale)
-> Result<Files, Error> {
let direntries: Result<Vec<_>, _> = std::fs::read_dir(&path)?.collect();
let dirty = DirtyBit::new();
@@ -170,9 +170,10 @@ impl Files {
let name = file.file_name();
let name = name.to_string_lossy();
let path = file.path();
- Some(File::new(&name,
- path,
- Some(dirty_meta.clone())))
+ Some(File::new_with_stale(&name,
+ path,
+ Some(dirty_meta.clone()),
+ stale.clone()))
}
})
.fuse()
@@ -392,6 +393,11 @@ impl Files {
self.meta_upto = Some(meta_files);
}
+ pub fn meta_set_fresh(&self) -> HResult<()> {
+ self.files.get(0)?.meta.set_fresh()?;
+ Ok(())
+ }
+
pub fn set_filter(&mut self, filter: Option<String>) {
self.filter = filter;
@@ -480,9 +486,38 @@ impl File {
path: PathBuf,
dirty_meta: Option<AsyncDirtyBit>) -> File {
let tag = check_tag(&path).ok();
- let meta = File::make_async_meta(&path, dirty_meta.clone());
+ let meta = File::make_async_meta(&path, dirty_meta.clone(), None);
let dirsize = if path.is_dir() {
- Some(File::make_async_dirsize(&path, dirty_meta.clone()))
+ Some(File::make_async_dirsize(&path, dirty_meta.clone(), None))
+ } else { None };
+
+ File {
+ name: name.to_string(),
+ kind: if path.is_dir() { Kind::Directory } else { Kind::File },
+ path: path,
+ dirsize: dirsize,
+ target: None,
+ meta: meta,
+ meta_processed: false,
+ dirty_meta: dirty_meta,
+ color: None,
+ selected: false,
+ tag: tag,
+ }
+ }
+
+ pub fn new_with_stale(name: &str,
+ path: PathBuf,
+ dirty_meta: Option<AsyncDirtyBit>,
+ stale: Stale) -> File {
+ let tag = check_tag(&path).ok();
+ let meta = File::make_async_meta(&path,
+ dirty_meta.clone(),
+ Some(stale.clone()));
+ let dirsize = if path.is_dir() {
+ Some(File::make_async_dirsize(&path,
+ dirty_meta.clone(),
+ Some(stale)))
} else { None };
File {
@@ -519,13 +554,19 @@ impl File {
}
pub fn make_async_meta(path: &PathBuf,
- dirty_meta: Option<AsyncDirtyBit>) -> Async<Metadata> {
+ dirty_meta: Option<AsyncDirtyBit>,
+ stale_preview: Option<Stale>) -> Async<Metadata> {
let path = path.clone();
- let mut meta = Async::new(Box::new(move |stale| {
- if *stale.lock()? { HError::stale()? }
- Ok(std::fs::symlink_metadata(&path).unwrap())
- }));
+ let meta_closure = Box::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();
@@ -538,13 +579,20 @@ impl File {
}
pub fn make_async_dirsize(path: &PathBuf,
- dirty_meta: Option<AsyncDirtyBit>) -> Async<usize> {
+ dirty_meta: Option<AsyncDirtyBit>,
+ stale_preview: Option<Stale>) -> Async<usize> {
let path = path.clone();
- let mut dirsize = Async::new(Box::new(move |stale| {
- if *stale.lock()? { HError::stale()? }
+ let dirsize_closure = Box::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)
+ };
+
if let Some(dirty_meta) = dirty_meta {
dirsize.on_ready(Box::new(move |_| {
let mut dirty_meta = dirty_meta.clone();
@@ -604,10 +652,12 @@ impl File {
pub fn reload_meta(&mut self) -> HResult<()> {
self.dirty_meta.as_mut()?.set_dirty();
self.meta_processed = false;
- self.meta = File::make_async_meta(&self.path, self.dirty_meta.clone());
+ self.meta = File::make_async_meta(&self.path,
+ self.dirty_meta.clone(),
+ None);
if self.dirsize.is_some() {
self.dirsize
- = Some(File::make_async_dirsize(&self.path, self.dirty_meta.clone()));
+ = Some(File::make_async_dirsize(&self.path, self.dirty_meta.clone(), None));
}
Ok(())
}
@@ -720,8 +770,8 @@ impl File {
self.tag = Some(new_state);
match new_state {
- true => TAGS.lock()?.1.push(self.path.clone()),
- false => { TAGS.lock()?.1.remove_item(&self.path); },
+ true => TAGS.write()?.1.push(self.path.clone()),
+ false => { TAGS.write()?.1.remove_item(&self.path); },
}
self.save_tags()?;
Ok(())
@@ -730,7 +780,7 @@ impl File {
pub fn save_tags(&self) -> HResult<()> {
std::thread::spawn(|| -> HResult<()> {
let tagfile_path = crate::paths::tagfile_path()?;
- let tags = TAGS.lock()?.clone();
+ let tags = TAGS.read()?.clone();
let tags_str = tags.1.iter().map(|p| {
let path = p.to_string_lossy().to_string();
format!("{}\n", path)
diff --git a/src/preview.rs b/src/preview.rs
index da2a90a..d70b011 100644
--- a/src/preview.rs
+++ b/src/preview.rs
@@ -1,4 +1,4 @@
-use std::sync::{Arc, Mutex};
+use std::sync::{Arc, Mutex, RwLock};
use rayon::ThreadPool;
@@ -10,8 +10,6 @@ use crate::coordinates::Coordinates;
use crate::fail::{HResult, HError, ErrorLog};
-pub type Stale = Arc<Mutex<bool>>;
-
pub type AsyncValueFn<T> = Box<Fn(Stale) -> HResult<T> + Send>;
pub type AsyncValue<T> = Arc<Mutex<Option<HResult<T>>>>;
pub type AsyncReadyFn<T> = Box<Fn(&mut T) -> HResult<()> + Send>;
@@ -33,8 +31,30 @@ fn kill_proc() -> HResult<()> {
Ok(())
}
-pub fn is_stale(stale: &Arc<Mutex<bool>>) -> HResult<bool> {
- let stale = *(stale.lock().unwrap());
+#[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)
}
@@ -68,7 +88,20 @@ impl<T: Send + 'static> Async<T> {
async_value: Arc::new(Mutex::new(None)),
async_closure: Arc::new(Mutex::new(Some(closure))),
on_ready: Arc::new(Mutex::new(None)),
- stale: Arc::new(Mutex::new(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)),
+ stale: stale };
async_value
}
@@ -79,53 +112,104 @@ impl<T: Send + 'static> Async<T> {
async_value: Arc::new(Mutex::new(None)),
async_closure: Arc::new(Mutex::new(None)),
on_ready: Arc::new(Mutex::new(None)),
- stale: Arc::new(Mutex::new(false))
+ stale: Stale::new()
}
}
pub fn run(&mut self) -> HResult<()> {
- let closure = self.async_closure.lock()?.take()?;
+ 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.lock()?.take();
+ let on_ready_fn = self.on_ready.clone();
std::thread::spawn(move|| -> HResult<()> {
- let mut value = closure(stale);
-
- if let Ok(ref mut value) = value {
- if let Some(on_ready_fn) = on_ready_fn {
- on_ready_fn(value);
+ let value = closure.lock().map(|closure|
+ closure.as_ref().map(|closure|
+ closure(stale)));
+
+ if let Ok(value) = value {
+ if let Some(value) = value {
+ match value {
+ Ok(mut value) => {
+ if let Ok(mut on_ready_fn) = on_ready_fn.lock() {
+ if let Some(on_ready_fn) = on_ready_fn.as_ref() {
+ on_ready_fn(&mut value).log();
+ }
+ on_ready_fn.take();
+ }
+ async_value
+ .lock()
+ .map(|mut async_value|
+ async_value.replace(Ok(value))).ok();
+ closure.lock().map(|mut closure|
+ closure.take()).ok();
+ },
+ Err(err) => {
+ async_value
+ .lock()
+ .map(|mut async_value|
+ async_value.replace(Err(err))).ok();
+ }
+ }
}
+ } else {
+ async_value
+ .lock()
+ .map(|mut async_value|
+ async_value.replace(Err(HError::MutexError))).ok();
}
-
- async_value.lock()?.replace(value);
Ok(())
});
Ok(())
}
pub fn run_pooled(&mut self, pool: &ThreadPool) -> HResult<()> {
- let closure = self.async_closure.lock()?.take()?;
+ 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.lock()?.take();
+ let on_ready_fn = self.on_ready.clone();
pool.spawn(move || {
- let mut value = closure(stale);
-
- if let Ok(ref mut value) = value {
- if let Some(on_ready_fn) = on_ready_fn {
- on_ready_fn(value);
+ let value = closure.lock().map(|closure|
+ closure.as_ref().map(|closure|
+ closure(stale)));
+
+ if let Ok(value) = value {
+ if let Some(value) = value {
+ match value {
+ Ok(mut value) => {
+ if let Ok(mut on_ready_fn) = on_ready_fn.lock() {
+ if let Some(on_ready_fn) = on_ready_fn.as_ref() {
+ on_ready_fn(&mut value).log();
+ }
+ on_ready_fn.take();
+ }
+ async_value
+ .lock()
+ .map(|mut async_value|
+ async_value.replace(Ok(value))).ok();
+ closure.lock().map(|mut closure|
+ closure.take()).ok();
+ },
+ Err(err) => {
+ async_value
+ .lock()
+ .map(|mut async_value|
+ async_value.replace(Err(err))).ok();
+ }
+ }
}
+ } else {
+ async_value
+ .lock()
+ .map(|mut async_value|
+ async_value.replace(Err(HError::MutexError))).ok();
}
-
- async_value
- .lock()
- .map(|mut async_value| async_value.replace(value));
});
Ok(())
}
+
pub fn wait(&mut self) -> HResult<()> {
let closure = self.async_closure.lock()?.take()?;
let mut value = closure(self.stale.clone());
@@ -141,12 +225,21 @@ impl<T: Send + 'static> Async<T> {
}
pub fn set_stale(&mut self) -> HResult<()> {
- *self.stale.lock()? = true;
+ self.stale.set_stale()?;
+ Ok(())
+ }
+
+ pub fn set_fresh(&self) -> HResult<()> {
+ self.stale.set_fresh()?;
Ok(())
}
pub fn is_stale(&self) -> HResult<bool> {
- is_stale(&self.stale)
+ self.stale.is_stale()
+ }
+
+ pub fn get_stale(&self) -> Stale {
+ self.stale.clone()
}
pub fn take_async(&mut self) -> HResult<()> {
@@ -251,6 +344,10 @@ impl<W: Widget + Send + 'static> AsyncWidget<W> {
self.widget.is_stale()
}
+ pub fn get_stale(&self) -> Stale {
+ self.widget.get_stale()
+ }
+
pub fn widget(&self) -> HResult<&W> {
self.widget.get()
}
@@ -292,7 +389,7 @@ impl<T: Widget + Send + 'static> Widget for AsyncWidget<T> {
}
fn refresh(&mut self) -> HResult<()> {
- self.widget.take_async().log();
+ self.widget.take_async().ok();
let coords = self.get_coordinates()?.clone();
if let Ok(widget) = self.widget_mut() {
@@ -342,7 +439,7 @@ pub struct Previewer {
core: WidgetCore,
file: Option<File>,
selection: Option<File>,
- cached_files: Option<Files>
+ cached_files: Option<Files>,
}
@@ -435,7 +532,7 @@ impl Previewer {
selection: Option<File>,
cached_files: Option<Files>,
core: &WidgetCore,
- stale: Arc<Mutex<bool>>)
+ stale: Stale)
-> Result<WidgetO, HError> {
let files = cached_files.or_else(|| {
Files::new_from_path_cancellable(&file.path,
@@ -456,7 +553,7 @@ impl Previewer {
Ok(Box::new(file_list) as Box<dyn Widget + Send>)
}
- fn preview_text(file: &File, core: &WidgetCore, stale: Arc<Mutex<bool>>)
+ fn preview_text(file: &File, core: &WidgetCore, stale: Stale)
-> HResult<WidgetO> {
let lines = core.coordinates.ysize() as usize;
let mut textview
@@ -476,7 +573,7 @@ impl Previewer {
fn preview_external(file: &File,
core: &WidgetCore,
- stale: Arc<Mutex<bool>>)
+ stale: Stale)
-> Result<Box<dyn Widget + Send>, HError> {
let process =
std::process::Command::new("scope.sh")
diff --git a/src/widget.rs b/src/widget.rs
index 2093d2d..9c0fe43 100644
--- a/src/widget.rs
+++ b/src/widget.rs
@@ -11,6 +11,7 @@ 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 std::io::stdin;