some bugfixes and stuff

This commit is contained in:
rabite 2019-03-26 02:15:25 +01:00
parent 153bf24238
commit 90e626d169
4 changed files with 226 additions and 72 deletions

View File

@ -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();

View File

@ -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)

View File

@ -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);
let value = closure.lock().map(|closure|
closure.as_ref().map(|closure|
closure(stale)));
if let Ok(ref mut value) = value {
if let Some(on_ready_fn) = on_ready_fn {
on_ready_fn(value);
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);
let value = closure.lock().map(|closure|
closure.as_ref().map(|closure|
closure(stale)));
if let Ok(ref mut value) = value {
if let Some(on_ready_fn) = on_ready_fn {
on_ready_fn(value);
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")

View File

@ -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;