mirror of https://github.com/bobwen-dev/hunter
move widgets/files around instead of caching
This commit is contained in:
parent
ed32c83aca
commit
e99a3d993c
|
@ -84,7 +84,9 @@ pub enum HError {
|
|||
#[fail(display = "{}", _0)]
|
||||
Log(String),
|
||||
#[fail(display = "Metadata already processed")]
|
||||
MetadataProcessedError
|
||||
MetadataProcessedError,
|
||||
#[fail(display = "No files to take from widget")]
|
||||
WidgetNoFilesError,
|
||||
}
|
||||
|
||||
impl HError {
|
||||
|
@ -158,6 +160,10 @@ impl HError {
|
|||
pub fn metadata_processed<T>() -> HResult<T> {
|
||||
Err(HError::MetadataProcessedError)
|
||||
}
|
||||
|
||||
pub fn no_files<T>() -> HResult<T> {
|
||||
Err(HError::WidgetNoFilesError)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@ use std::io::Write;
|
|||
use std::sync::{Arc, Mutex};
|
||||
use std::path::PathBuf;
|
||||
use std::ffi::OsString;
|
||||
use std::collections::HashSet;
|
||||
|
||||
use crate::files::{File, Files, PathBufExt};
|
||||
use crate::fscache::FsCache;
|
||||
|
@ -12,6 +13,7 @@ use crate::hbox::HBox;
|
|||
use crate::widget::Widget;
|
||||
use crate::tabview::{TabView, Tabbable};
|
||||
use crate::preview::{Previewer, AsyncWidget};
|
||||
use crate::textview::TextView;
|
||||
use crate::fail::{HResult, HError, ErrorLog};
|
||||
use crate::widget::{Events, WidgetCore};
|
||||
use crate::proclist::ProcView;
|
||||
|
@ -25,37 +27,43 @@ use crate::coordinates::Coordinates;
|
|||
pub enum FileBrowserWidgets {
|
||||
FileList(AsyncWidget<ListView<Files>>),
|
||||
Previewer(Previewer),
|
||||
Blank(AsyncWidget<TextView>),
|
||||
}
|
||||
|
||||
impl Widget for FileBrowserWidgets {
|
||||
fn get_core(&self) -> HResult<&WidgetCore> {
|
||||
match self {
|
||||
FileBrowserWidgets::FileList(widget) => widget.get_core(),
|
||||
FileBrowserWidgets::Previewer(widget) => widget.get_core()
|
||||
FileBrowserWidgets::Previewer(widget) => widget.get_core(),
|
||||
FileBrowserWidgets::Blank(widget) => widget.get_core(),
|
||||
}
|
||||
}
|
||||
fn get_core_mut(&mut self) -> HResult<&mut WidgetCore> {
|
||||
match self {
|
||||
FileBrowserWidgets::FileList(widget) => widget.get_core_mut(),
|
||||
FileBrowserWidgets::Previewer(widget) => widget.get_core_mut()
|
||||
FileBrowserWidgets::Previewer(widget) => widget.get_core_mut(),
|
||||
FileBrowserWidgets::Blank(widget) => widget.get_core_mut(),
|
||||
}
|
||||
}
|
||||
fn set_coordinates(&mut self, coordinates: &Coordinates) -> HResult<()> {
|
||||
match self {
|
||||
FileBrowserWidgets::FileList(widget) => widget.set_coordinates(coordinates),
|
||||
FileBrowserWidgets::Previewer(widget) => widget.set_coordinates(coordinates),
|
||||
FileBrowserWidgets::Blank(widget) => widget.set_coordinates(coordinates),
|
||||
}
|
||||
}
|
||||
fn refresh(&mut self) -> HResult<()> {
|
||||
match self {
|
||||
FileBrowserWidgets::FileList(widget) => widget.refresh(),
|
||||
FileBrowserWidgets::Previewer(widget) => widget.refresh()
|
||||
FileBrowserWidgets::Previewer(widget) => widget.refresh(),
|
||||
FileBrowserWidgets::Blank(widget) => widget.refresh(),
|
||||
}
|
||||
}
|
||||
fn get_drawlist(&self) -> HResult<String> {
|
||||
match self {
|
||||
FileBrowserWidgets::FileList(widget) => widget.get_drawlist(),
|
||||
FileBrowserWidgets::Previewer(widget) => widget.get_drawlist()
|
||||
FileBrowserWidgets::Previewer(widget) => widget.get_drawlist(),
|
||||
FileBrowserWidgets::Blank(widget) => widget.get_drawlist(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -162,6 +170,22 @@ impl Tabbable for TabView<FileBrowser> {
|
|||
new_file.as_ref()).log()
|
||||
}
|
||||
}
|
||||
|
||||
let open_dirs = self.widgets
|
||||
.iter()
|
||||
.fold(HashSet::new(), |mut dirs, tab| {
|
||||
tab.left_dir().map(|dir| dirs.insert(dir.clone())).ok();
|
||||
dirs.insert(tab.cwd.clone());
|
||||
tab.preview_widget()
|
||||
.map(|preview| preview.get_file().map(|file| {
|
||||
if file.is_dir() {
|
||||
dirs.insert(file.clone());
|
||||
}
|
||||
})).ok();
|
||||
dirs
|
||||
});
|
||||
|
||||
self.active_tab_mut_().fs_cache.watch_only(open_dirs).log();
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
@ -199,9 +223,14 @@ impl FileBrowser {
|
|||
|
||||
let cache = fs_cache.clone();
|
||||
let main_widget = AsyncWidget::new(&core, Box::new(move |_| {
|
||||
let main_dir = File::new(&main_path.file_name()?
|
||||
.to_string_lossy()
|
||||
.to_string(),
|
||||
let name = if main_path.parent().is_none() {
|
||||
"root".to_string()
|
||||
} else {
|
||||
main_path.file_name()?
|
||||
.to_string_lossy()
|
||||
.to_string()
|
||||
};
|
||||
let main_dir = File::new(&name,
|
||||
main_path.clone(),
|
||||
None);
|
||||
let files = cache.get_files_sync(&main_dir)?;
|
||||
|
@ -225,9 +254,14 @@ impl FileBrowser {
|
|||
let cache = fs_cache.clone();
|
||||
if let Some(left_path) = left_path {
|
||||
let left_widget = AsyncWidget::new(&core, Box::new(move |_| {
|
||||
let left_dir = File::new(&left_path.file_name()?
|
||||
.to_string_lossy()
|
||||
.to_string(),
|
||||
let name = if left_path.parent().is_none() {
|
||||
"root".to_string()
|
||||
} else {
|
||||
left_path.file_name()?
|
||||
.to_string_lossy()
|
||||
.to_string()
|
||||
};
|
||||
let left_dir = File::new(&name,
|
||||
left_path.clone(),
|
||||
None);
|
||||
let files = cache.get_files_sync(&left_dir)?;
|
||||
|
@ -248,6 +282,14 @@ impl FileBrowser {
|
|||
}));
|
||||
let left_widget = FileBrowserWidgets::FileList(left_widget);
|
||||
columns.push_widget(left_widget);
|
||||
} else {
|
||||
let left_widget = AsyncWidget::new(&core, Box::new(move |_| {
|
||||
let blank = TextView::new_blank(&core_l);
|
||||
Ok(blank)
|
||||
}));
|
||||
|
||||
let left_widget = FileBrowserWidgets::Blank(left_widget);
|
||||
columns.push_widget(left_widget);
|
||||
}
|
||||
|
||||
let previewer = Previewer::new(&core_p, fs_cache.clone());
|
||||
|
@ -281,7 +323,8 @@ impl FileBrowser {
|
|||
let file = self.selected_file()?;
|
||||
|
||||
if file.is_dir() {
|
||||
match file.is_readable() {
|
||||
let dir = file;
|
||||
match dir.is_readable() {
|
||||
Ok(true) => {},
|
||||
Ok(false) => {
|
||||
let status =
|
||||
|
@ -293,7 +336,38 @@ impl FileBrowser {
|
|||
err @ Err(_) => err.log()
|
||||
}
|
||||
|
||||
self.main_widget_goto(&file).log();
|
||||
let previewer_files = self.preview_widget_mut()?.take_files().ok();
|
||||
|
||||
self.columns.remove_widget(0);
|
||||
|
||||
self.prev_cwd = Some(self.cwd.clone());
|
||||
self.cwd = dir.clone();
|
||||
|
||||
let core = self.core.clone();
|
||||
let cache = self.fs_cache.clone();
|
||||
|
||||
let main_widget = AsyncWidget::new(&core.clone(), Box::new(move |_| {
|
||||
let files = match previewer_files {
|
||||
Some(files) => files,
|
||||
None => cache.get_files_sync(&dir)?
|
||||
};
|
||||
|
||||
let selection = cache.get_selection(&dir).ok();
|
||||
|
||||
let mut list = ListView::new(&core, files);
|
||||
|
||||
if let Some(file) = selection {
|
||||
list.select_file(&file);
|
||||
}
|
||||
|
||||
list.content.meta_all();
|
||||
|
||||
Ok(list)
|
||||
}));
|
||||
|
||||
let main_widget = FileBrowserWidgets::FileList(main_widget);
|
||||
self.columns.insert_widget(1, main_widget);
|
||||
|
||||
} else {
|
||||
self.core.get_sender().send(Events::InputEnabled(false))?;
|
||||
|
||||
|
@ -392,9 +466,42 @@ impl FileBrowser {
|
|||
|
||||
pub fn go_back(&mut self) -> HResult<()> {
|
||||
if let Ok(new_cwd) = self.cwd.parent_as_file() {
|
||||
self.main_widget_goto(&new_cwd).log();
|
||||
let core = self.core.clone();
|
||||
let preview_files = self.take_main_files();
|
||||
let old_left = self.columns.remove_widget(0);
|
||||
self.prev_cwd = Some(self.cwd.clone());
|
||||
self.cwd = new_cwd.clone();
|
||||
|
||||
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 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 blank = TextView::new_blank(&core);
|
||||
Ok(blank)
|
||||
}));
|
||||
|
||||
let left_widget = FileBrowserWidgets::Blank(left_widget);
|
||||
self.columns.prepend_widget(left_widget);
|
||||
}
|
||||
self.columns.replace_widget(1, old_left);
|
||||
self.main_widget_mut()?.content.meta_all();
|
||||
|
||||
if let Ok(preview_files) = preview_files {
|
||||
self.preview_widget_mut().map(|preview| {
|
||||
preview.put_preview_files(preview_files)
|
||||
}).ok();
|
||||
}
|
||||
}
|
||||
|
||||
self.columns.resize_children();
|
||||
self.refresh()
|
||||
}
|
||||
|
||||
|
@ -459,8 +566,8 @@ impl FileBrowser {
|
|||
}
|
||||
|
||||
pub fn set_left_selection(&mut self) -> HResult<()> {
|
||||
if !self.left_async_widget_mut()?.ready() { return Ok(()) }
|
||||
if self.cwd.parent().is_none() { return Ok(()) }
|
||||
if !self.left_async_widget_mut()?.ready() { return Ok(()) }
|
||||
|
||||
let selection = self.cwd()?.clone();
|
||||
|
||||
|
@ -469,6 +576,63 @@ impl FileBrowser {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub fn take_main_files(&mut self) -> HResult<Files> {
|
||||
let core = self.core.clone();
|
||||
let blank = AsyncWidget::new(&core.clone(), Box::new(move |_| {
|
||||
HError::no_files()
|
||||
}));
|
||||
let blank = FileBrowserWidgets::Blank(blank);
|
||||
|
||||
let old_widget = self.columns.replace_widget(1, blank);
|
||||
|
||||
if let FileBrowserWidgets::FileList(main_widget) = old_widget {
|
||||
let files = main_widget.take_widget()?.content;
|
||||
return Ok(files)
|
||||
}
|
||||
HError::no_files()
|
||||
}
|
||||
|
||||
pub fn take_left_files(&mut self) -> HResult<Files> {
|
||||
let core = self.core.clone();
|
||||
let blank = AsyncWidget::new(&core.clone(), Box::new(move |_| {
|
||||
HError::no_files()
|
||||
}));
|
||||
let blank = FileBrowserWidgets::FileList(blank);
|
||||
|
||||
let old_widget = self.columns.replace_widget(0, blank);
|
||||
|
||||
if let FileBrowserWidgets::FileList(left_widget) = old_widget {
|
||||
let files = left_widget.take_widget()?.content;
|
||||
return Ok(files)
|
||||
}
|
||||
HError::no_files()
|
||||
}
|
||||
|
||||
// pub fn take_preview_files(&mut self) -> HResult<Files> {
|
||||
// let widget = self.columns.remove_widget(2);
|
||||
// if let Filxx
|
||||
// }
|
||||
|
||||
// pub fn take_files_from_widget(&self,
|
||||
// widget: FileBrowserWidgets) -> HResult<Files> {
|
||||
// match widget {
|
||||
// FileBrowserWidgets::FileList(file_list) => {
|
||||
// match file_list.take_widget() {
|
||||
// Ok(widget) => {
|
||||
// let files = widget.content;
|
||||
// Ok(files)
|
||||
// }
|
||||
// _ => HError::no_files()
|
||||
// }
|
||||
// }
|
||||
// FileBrowserWidgets::Previewer(previewer) => {
|
||||
// let files = previewer.take_files()?;
|
||||
// Ok(files)
|
||||
// }
|
||||
// _ => HError::no_files()
|
||||
// }
|
||||
// }
|
||||
|
||||
pub fn get_files(&self) -> HResult<&Files> {
|
||||
Ok(&self.main_widget()?.content)
|
||||
}
|
||||
|
@ -484,10 +648,12 @@ impl FileBrowser {
|
|||
self.main_widget_mut()?.content.meta_updated = false;
|
||||
|
||||
|
||||
let left_selection = self.left_widget()?.clone_selected_file();
|
||||
let left_files = self.get_left_files()?;
|
||||
self.fs_cache.put_files(left_files, Some(left_selection)).log();
|
||||
self.left_widget_mut()?.content.meta_updated = false;
|
||||
if self.cwd.parent().is_some() {
|
||||
let left_selection = self.left_widget()?.clone_selected_file();
|
||||
let left_files = self.get_left_files()?;
|
||||
self.fs_cache.put_files(left_files, Some(left_selection)).log();
|
||||
self.left_widget_mut()?.content.meta_updated = false;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -516,6 +682,9 @@ impl FileBrowser {
|
|||
if &self.cwd == dir {
|
||||
self.main_widget_mut()?.content.replace_file(old, new.cloned()).log();
|
||||
}
|
||||
|
||||
self.preview_widget_mut()?.replace_file(dir, old, new).ok();
|
||||
|
||||
if &self.left_dir()? == &dir {
|
||||
self.left_widget_mut()?.content.replace_file(old, new.cloned()).log();
|
||||
}
|
||||
|
@ -590,6 +759,13 @@ impl FileBrowser {
|
|||
widget
|
||||
}
|
||||
|
||||
pub fn preview_widget(&self) -> HResult<&Previewer> {
|
||||
match self.columns.widgets.get(2)? {
|
||||
FileBrowserWidgets::Previewer(previewer) => Ok(previewer),
|
||||
_ => { return HError::wrong_widget("filelist", "previewer"); }
|
||||
}
|
||||
}
|
||||
|
||||
pub fn preview_widget_mut(&mut self) -> HResult<&mut Previewer> {
|
||||
match self.columns.widgets.get_mut(2)? {
|
||||
FileBrowserWidgets::Previewer(previewer) => Ok(previewer),
|
||||
|
|
|
@ -464,7 +464,6 @@ impl Hash for File {
|
|||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
self.name.hash(state);
|
||||
self.path.hash(state);
|
||||
self.selected.hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -114,15 +114,17 @@ impl FsCache {
|
|||
} else {
|
||||
self.add_watch(&dir).log();
|
||||
let dir = dir.clone();
|
||||
let selection = self.get_selection(&dir).ok();
|
||||
let files = Async::new(Box::new(move |_| {
|
||||
let files = Files::new_from_path_cancellable(&dir.path, stale)?;
|
||||
Ok(files)
|
||||
}));
|
||||
Ok((None, files))
|
||||
Ok((selection, files))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_files_sync(&self, dir: &File) -> HResult<Files> {
|
||||
self.add_watch(&dir).log();
|
||||
let files = self.get_files(&dir, Stale::new())?.1;
|
||||
files.wait()
|
||||
}
|
||||
|
@ -145,17 +147,17 @@ impl FsCache {
|
|||
|
||||
self.tab_settings.write()?.insert(dir.clone(), tab_settings);
|
||||
|
||||
let mut file_cache = self.files.write()?;
|
||||
// let mut file_cache = self.files.write()?;
|
||||
|
||||
if file_cache.contains_key(&files.directory) {
|
||||
if files.meta_updated {
|
||||
let mut files = files.clone();
|
||||
files.meta_updated = false;
|
||||
file_cache.insert(dir, files);
|
||||
}
|
||||
} else {
|
||||
file_cache.insert(dir, files.clone());
|
||||
}
|
||||
// if file_cache.contains_key(&files.directory) {
|
||||
// if files.meta_updated {
|
||||
// let mut files = files.clone();
|
||||
// files.meta_updated = false;
|
||||
// file_cache.insert(dir, files);
|
||||
// }
|
||||
// } else {
|
||||
// file_cache.insert(dir, files.clone());
|
||||
// }
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -164,8 +166,23 @@ impl FsCache {
|
|||
Ok(self.files.read()?.contains_key(dir))
|
||||
}
|
||||
|
||||
pub fn watch_only(&self, open_dirs: HashSet<File>) -> HResult<()> {
|
||||
let removable = self.watched_dirs
|
||||
.read()?
|
||||
.difference(&open_dirs)
|
||||
.map(|dir| dir.clone())
|
||||
.collect::<Vec<File>>();
|
||||
|
||||
for watch in removable {
|
||||
self.remove_watch(&watch).log();
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn add_watch(&self, dir: &File) -> HResult<()> {
|
||||
if !self.watched_dirs.read()?.contains(&dir) {
|
||||
self.watched_dirs.write()?.insert(dir.clone());
|
||||
self.watcher.write()?.watch(&dir.path, RecursiveMode::NonRecursive)?
|
||||
}
|
||||
Ok(())
|
||||
|
@ -245,32 +262,49 @@ fn watch_fs(rx_fs_events: Receiver<DebouncedEvent>,
|
|||
});
|
||||
}
|
||||
|
||||
fn apply_event(fs_cache: &Arc<RwLock<HashMap<File, Files>>>,
|
||||
fn apply_event(_fs_cache: &Arc<RwLock<HashMap<File, Files>>>,
|
||||
fs_changes: &Arc<RwLock<Vec<(File, Option<File>, Option<File>)>>>,
|
||||
event: DebouncedEvent)
|
||||
-> HResult<()> {
|
||||
let path = &event.get_source_path()?;
|
||||
|
||||
for dir in fs_cache.write()?.values_mut() {
|
||||
if dir.path_in_here(&path).unwrap_or(false) {
|
||||
let old_file = dir.find_file_with_path(&path).cloned();
|
||||
let dirty_meta = old_file
|
||||
.as_ref()
|
||||
.map(|f| f.dirty_meta.clone())
|
||||
.unwrap_or(None);
|
||||
let mut new_file = match event {
|
||||
DebouncedEvent::Remove(_) => None,
|
||||
_ => Some(File::new_from_path(&path, dirty_meta)?)
|
||||
};
|
||||
let dirpath = path.parent()
|
||||
.map(|path| path.to_path_buf())
|
||||
.unwrap_or_else(|| PathBuf::from("/"));
|
||||
let dir = File::new_from_path(&dirpath, None)?;
|
||||
|
||||
new_file.as_mut().map(|file| file.meta_sync());
|
||||
dir.replace_file(old_file.as_ref(), new_file.clone()).log();
|
||||
let old_file = File::new_from_path(&path, None)?;
|
||||
let mut new_file = match event {
|
||||
DebouncedEvent::Remove(_) => None,
|
||||
_ => Some(File::new_from_path(&path, None)?)
|
||||
};
|
||||
|
||||
fs_changes.write()?.push((dir.directory.clone(),
|
||||
old_file,
|
||||
new_file));
|
||||
}
|
||||
}
|
||||
new_file.as_mut().map(|file| file.meta_sync());
|
||||
|
||||
fs_changes.write()?.push((dir,
|
||||
Some(old_file),
|
||||
new_file));
|
||||
|
||||
// for dir in fs_cache.write()?.values_mut() {
|
||||
// if dir.path_in_here(&path).unwrap_or(false) {
|
||||
// let old_file = dir.find_file_with_path(&path).cloned();
|
||||
// let dirty_meta = old_file
|
||||
// .as_ref()
|
||||
// .map(|f| f.dirty_meta.clone())
|
||||
// .unwrap_or(None);
|
||||
// let mut new_file = match event {
|
||||
// DebouncedEvent::Remove(_) => None,
|
||||
// _ => Some(File::new_from_path(&path, dirty_meta)?)
|
||||
// };
|
||||
|
||||
// new_file.as_mut().map(|file| file.meta_sync());
|
||||
// dir.replace_file(old_file.as_ref(), new_file.clone()).log();
|
||||
|
||||
// fs_changes.write()?.push((dir.directory.clone(),
|
||||
// old_file,
|
||||
// new_file));
|
||||
// }
|
||||
// }
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
|
@ -66,6 +66,11 @@ impl<T> HBox<T> where T: Widget + PartialEq {
|
|||
self.widgets.insert(index, widget);
|
||||
}
|
||||
|
||||
pub fn replace_widget(&mut self, index: usize, mut widget: T) -> T {
|
||||
std::mem::swap(&mut self.widgets[index], &mut widget);
|
||||
widget
|
||||
}
|
||||
|
||||
pub fn toggle_zoom(&mut self) -> HResult<()> {
|
||||
self.clear().log();
|
||||
self.zoom_active = !self.zoom_active;
|
||||
|
|
131
src/preview.rs
131
src/preview.rs
|
@ -3,7 +3,8 @@ use std::boxed::FnBox;
|
|||
|
||||
use rayon::ThreadPool;
|
||||
|
||||
use crate::files::{File, Kind};
|
||||
use crate::files::{File, Files, Kind};
|
||||
use crate::fscache::FsCache;
|
||||
use crate::listview::ListView;
|
||||
use crate::textview::TextView;
|
||||
use crate::widget::{Widget, WidgetCore};
|
||||
|
@ -131,7 +132,9 @@ impl<T: Send + 'static> Async<T> {
|
|||
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()?.call_box(()).log();
|
||||
on_ready_fn.lock()?
|
||||
.take()
|
||||
.map(|on_ready| on_ready.call_box(()).log());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -331,6 +334,10 @@ impl<W: Widget + Send + 'static> AsyncWidget<W> {
|
|||
self.widget.get_mut()
|
||||
}
|
||||
|
||||
pub fn take_widget(self) -> HResult<W> {
|
||||
Ok(self.widget.value?)
|
||||
}
|
||||
|
||||
pub fn ready(&self) -> bool {
|
||||
self.widget().is_ok()
|
||||
}
|
||||
|
@ -400,10 +407,16 @@ impl PartialEq for Previewer {
|
|||
}
|
||||
}
|
||||
|
||||
use crate::fscache::FsCache;
|
||||
#[derive(PartialEq)]
|
||||
enum PreviewWidget {
|
||||
FileList(ListView<Files>),
|
||||
TextView(TextView)
|
||||
}
|
||||
|
||||
|
||||
|
||||
pub struct Previewer {
|
||||
widget: AsyncWidget<Box<dyn Widget + Send>>,
|
||||
widget: AsyncWidget<PreviewWidget>,
|
||||
core: WidgetCore,
|
||||
file: Option<File>,
|
||||
pub cache: FsCache,
|
||||
|
@ -414,7 +427,9 @@ impl Previewer {
|
|||
pub fn new(core: &WidgetCore, cache: FsCache) -> Previewer {
|
||||
let core_ = core.clone();
|
||||
let widget = AsyncWidget::new(&core, Box::new(move |_| {
|
||||
Ok(Box::new(TextView::new_blank(&core_)) as Box<dyn Widget + Send>)
|
||||
let blank = TextView::new_blank(&core_);
|
||||
let blank = PreviewWidget::TextView(blank);
|
||||
Ok(blank)
|
||||
}));
|
||||
Previewer { widget: widget,
|
||||
core: core.clone(),
|
||||
|
@ -423,7 +438,7 @@ impl Previewer {
|
|||
}
|
||||
|
||||
fn become_preview(&mut self,
|
||||
widget: HResult<AsyncWidget<WidgetO>>) -> HResult<()> {
|
||||
widget: HResult<AsyncWidget<PreviewWidget>>) -> HResult<()> {
|
||||
let coordinates = self.get_coordinates()?.clone();
|
||||
self.widget = widget?;
|
||||
self.widget.set_coordinates(&coordinates)?;
|
||||
|
@ -438,6 +453,57 @@ impl Previewer {
|
|||
self.file.as_ref()
|
||||
}
|
||||
|
||||
pub fn take_files(&mut self) -> HResult<Files> {
|
||||
let core = self.core.clone();
|
||||
let mut widget = AsyncWidget::new(&core.clone(), Box::new(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() {
|
||||
Ok(PreviewWidget::FileList(file_list)) => {
|
||||
let files = file_list.content;
|
||||
Ok(files)
|
||||
}
|
||||
_ => HError::no_files()?
|
||||
}
|
||||
}
|
||||
|
||||
pub fn replace_file(&mut self, dir: &File,
|
||||
old: Option<&File>,
|
||||
new: Option<&File>) -> HResult<()> {
|
||||
if self.file.as_ref() != Some(dir) { return Ok(()) }
|
||||
self.widget.widget_mut().map(|widget| {
|
||||
match widget {
|
||||
PreviewWidget::FileList(filelist) => {
|
||||
filelist.content.replace_file(old, new.cloned()).map(|_| {
|
||||
filelist.refresh().ok();
|
||||
}).ok();
|
||||
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub fn put_preview_files(&mut self, files: Files) {
|
||||
let core = self.core.clone();
|
||||
let dir = files.directory.clone();
|
||||
let cache = self.cache.clone();
|
||||
self.file = Some(dir);
|
||||
|
||||
self.widget = AsyncWidget::new(&self.core, Box::new(move |_| {
|
||||
let selected_file = cache.get_selection(&files.directory);
|
||||
let mut filelist = ListView::new(&core, files);
|
||||
|
||||
selected_file.map(|file| filelist.select_file(&file));
|
||||
|
||||
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(()) }
|
||||
|
@ -469,11 +535,11 @@ impl Previewer {
|
|||
let preview = Previewer::preview_external(&file, &core, stale);
|
||||
if preview.is_ok() { return preview; }
|
||||
else {
|
||||
let mut blank = Box::new(TextView::new_blank(&core));
|
||||
let mut blank = TextView::new_blank(&core);
|
||||
blank.set_coordinates(&coordinates).log();
|
||||
blank.refresh().log();
|
||||
blank.animate_slide_up().log();
|
||||
return Ok(blank)
|
||||
return Ok(PreviewWidget::TextView(blank))
|
||||
}
|
||||
}))))
|
||||
}
|
||||
|
@ -485,7 +551,9 @@ impl Previewer {
|
|||
}
|
||||
}
|
||||
|
||||
fn preview_failed(file: &File) -> HResult<WidgetO> {
|
||||
|
||||
|
||||
fn preview_failed(file: &File) -> HResult<PreviewWidget> {
|
||||
HError::preview_failed(file)
|
||||
}
|
||||
|
||||
|
@ -493,7 +561,7 @@ impl Previewer {
|
|||
cache: FsCache,
|
||||
core: &WidgetCore,
|
||||
stale: Stale)
|
||||
-> Result<WidgetO, HError> {
|
||||
-> HResult<PreviewWidget> {
|
||||
let (selection, cached_files) = cache.get_files(&file, stale.clone())?;
|
||||
|
||||
let files = cached_files.wait()?;
|
||||
|
@ -510,11 +578,11 @@ impl Previewer {
|
|||
file_list.refresh()?;
|
||||
if is_stale(&stale)? { return Previewer::preview_failed(&file) }
|
||||
file_list.animate_slide_up()?;
|
||||
Ok(Box::new(file_list) as Box<dyn Widget + Send>)
|
||||
Ok(PreviewWidget::FileList(file_list))
|
||||
}
|
||||
|
||||
fn preview_text(file: &File, core: &WidgetCore, stale: Stale)
|
||||
-> HResult<WidgetO> {
|
||||
-> HResult<PreviewWidget> {
|
||||
let lines = core.coordinates.ysize() as usize;
|
||||
let mut textview
|
||||
= TextView::new_from_file_limit_lines(&core,
|
||||
|
@ -528,13 +596,13 @@ impl Previewer {
|
|||
if is_stale(&stale)? { return Previewer::preview_failed(&file) }
|
||||
|
||||
textview.animate_slide_up()?;
|
||||
Ok(Box::new(textview))
|
||||
Ok(PreviewWidget::TextView(textview))
|
||||
}
|
||||
|
||||
fn preview_external(file: &File,
|
||||
core: &WidgetCore,
|
||||
stale: Stale)
|
||||
-> Result<Box<dyn Widget + Send>, HError> {
|
||||
-> HResult<PreviewWidget> {
|
||||
let process =
|
||||
std::process::Command::new("scope.sh")
|
||||
.arg(&file.path)
|
||||
|
@ -577,7 +645,7 @@ impl Previewer {
|
|||
textview.set_coordinates(&core.coordinates).log();
|
||||
textview.refresh().log();
|
||||
textview.animate_slide_up().log();
|
||||
return Ok(Box::new(textview))
|
||||
return Ok(PreviewWidget::TextView(textview))
|
||||
}
|
||||
HError::preview_failed(file)
|
||||
}
|
||||
|
@ -607,7 +675,38 @@ impl Widget for Previewer {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
impl Widget for PreviewWidget {
|
||||
fn get_core(&self) -> HResult<&WidgetCore> {
|
||||
match self {
|
||||
PreviewWidget::FileList(widget) => widget.get_core(),
|
||||
PreviewWidget::TextView(widget) => widget.get_core()
|
||||
}
|
||||
}
|
||||
fn get_core_mut(&mut self) -> HResult<&mut WidgetCore> {
|
||||
match self {
|
||||
PreviewWidget::FileList(widget) => widget.get_core_mut(),
|
||||
PreviewWidget::TextView(widget) => widget.get_core_mut()
|
||||
}
|
||||
}
|
||||
fn set_coordinates(&mut self, coordinates: &Coordinates) -> HResult<()> {
|
||||
match self {
|
||||
PreviewWidget::FileList(widget) => widget.set_coordinates(coordinates),
|
||||
PreviewWidget::TextView(widget) => widget.set_coordinates(coordinates),
|
||||
}
|
||||
}
|
||||
fn refresh(&mut self) -> HResult<()> {
|
||||
match self {
|
||||
PreviewWidget::FileList(widget) => widget.refresh(),
|
||||
PreviewWidget::TextView(widget) => widget.refresh()
|
||||
}
|
||||
}
|
||||
fn get_drawlist(&self) -> HResult<String> {
|
||||
match self {
|
||||
PreviewWidget::FileList(widget) => widget.get_drawlist(),
|
||||
PreviewWidget::TextView(widget) => widget.get_drawlist()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl<T> Widget for Box<T> where T: Widget + ?Sized {
|
||||
|
|
11
src/term.rs
11
src/term.rs
|
@ -54,8 +54,15 @@ impl Screen {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub fn is_resized(&self) -> HResult<(usize, usize)> {
|
||||
Ok(self.size.read()?.clone()?)
|
||||
pub fn is_resized(&self) -> HResult<bool> {
|
||||
Ok(self.size.read()?.is_some())
|
||||
}
|
||||
|
||||
pub fn get_size(&self) -> HResult<(usize, usize)> {
|
||||
match self.size.read()?.clone() {
|
||||
Some((xsize, ysize)) => Ok((xsize, ysize)),
|
||||
None => Ok((self.xsize()?, self.ysize()?))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn take_size(&self) -> HResult<(usize, usize)> {
|
||||
|
|
|
@ -348,7 +348,9 @@ pub trait Widget {
|
|||
_ => {}
|
||||
}
|
||||
self.resize().log();
|
||||
self.screen()?.take_size().ok();
|
||||
if self.screen()?.is_resized()? {
|
||||
self.screen()?.take_size().ok();
|
||||
}
|
||||
self.refresh().ok();
|
||||
self.draw().ok();
|
||||
}
|
||||
|
@ -408,7 +410,8 @@ pub trait Widget {
|
|||
}
|
||||
|
||||
fn resize(&mut self) -> HResult<()> {
|
||||
if let Ok((xsize, ysize)) = self.screen()?.is_resized() {
|
||||
if let Ok(true) = self.screen()?.is_resized() {
|
||||
let (xsize, ysize) = self.screen()?.get_size()?;
|
||||
let mut coords = self.get_core()?.coordinates.clone();
|
||||
coords.set_size_u(xsize, ysize-2);
|
||||
self.set_coordinates(&coords)?;
|
||||
|
|
Loading…
Reference in New Issue