mirror of
https://github.com/bobwen-dev/hunter
synced 2025-04-12 00:55:41 +02:00
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)]
|
#[fail(display = "{}", _0)]
|
||||||
Log(String),
|
Log(String),
|
||||||
#[fail(display = "Metadata already processed")]
|
#[fail(display = "Metadata already processed")]
|
||||||
MetadataProcessedError
|
MetadataProcessedError,
|
||||||
|
#[fail(display = "No files to take from widget")]
|
||||||
|
WidgetNoFilesError,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl HError {
|
impl HError {
|
||||||
@ -158,6 +160,10 @@ impl HError {
|
|||||||
pub fn metadata_processed<T>() -> HResult<T> {
|
pub fn metadata_processed<T>() -> HResult<T> {
|
||||||
Err(HError::MetadataProcessedError)
|
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::sync::{Arc, Mutex};
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::ffi::OsString;
|
use std::ffi::OsString;
|
||||||
|
use std::collections::HashSet;
|
||||||
|
|
||||||
use crate::files::{File, Files, PathBufExt};
|
use crate::files::{File, Files, PathBufExt};
|
||||||
use crate::fscache::FsCache;
|
use crate::fscache::FsCache;
|
||||||
@ -12,6 +13,7 @@ use crate::hbox::HBox;
|
|||||||
use crate::widget::Widget;
|
use crate::widget::Widget;
|
||||||
use crate::tabview::{TabView, Tabbable};
|
use crate::tabview::{TabView, Tabbable};
|
||||||
use crate::preview::{Previewer, AsyncWidget};
|
use crate::preview::{Previewer, AsyncWidget};
|
||||||
|
use crate::textview::TextView;
|
||||||
use crate::fail::{HResult, HError, ErrorLog};
|
use crate::fail::{HResult, HError, ErrorLog};
|
||||||
use crate::widget::{Events, WidgetCore};
|
use crate::widget::{Events, WidgetCore};
|
||||||
use crate::proclist::ProcView;
|
use crate::proclist::ProcView;
|
||||||
@ -25,37 +27,43 @@ use crate::coordinates::Coordinates;
|
|||||||
pub enum FileBrowserWidgets {
|
pub enum FileBrowserWidgets {
|
||||||
FileList(AsyncWidget<ListView<Files>>),
|
FileList(AsyncWidget<ListView<Files>>),
|
||||||
Previewer(Previewer),
|
Previewer(Previewer),
|
||||||
|
Blank(AsyncWidget<TextView>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Widget for FileBrowserWidgets {
|
impl Widget for FileBrowserWidgets {
|
||||||
fn get_core(&self) -> HResult<&WidgetCore> {
|
fn get_core(&self) -> HResult<&WidgetCore> {
|
||||||
match self {
|
match self {
|
||||||
FileBrowserWidgets::FileList(widget) => widget.get_core(),
|
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> {
|
fn get_core_mut(&mut self) -> HResult<&mut WidgetCore> {
|
||||||
match self {
|
match self {
|
||||||
FileBrowserWidgets::FileList(widget) => widget.get_core_mut(),
|
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<()> {
|
fn set_coordinates(&mut self, coordinates: &Coordinates) -> HResult<()> {
|
||||||
match self {
|
match self {
|
||||||
FileBrowserWidgets::FileList(widget) => widget.set_coordinates(coordinates),
|
FileBrowserWidgets::FileList(widget) => widget.set_coordinates(coordinates),
|
||||||
FileBrowserWidgets::Previewer(widget) => widget.set_coordinates(coordinates),
|
FileBrowserWidgets::Previewer(widget) => widget.set_coordinates(coordinates),
|
||||||
|
FileBrowserWidgets::Blank(widget) => widget.set_coordinates(coordinates),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn refresh(&mut self) -> HResult<()> {
|
fn refresh(&mut self) -> HResult<()> {
|
||||||
match self {
|
match self {
|
||||||
FileBrowserWidgets::FileList(widget) => widget.refresh(),
|
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> {
|
fn get_drawlist(&self) -> HResult<String> {
|
||||||
match self {
|
match self {
|
||||||
FileBrowserWidgets::FileList(widget) => widget.get_drawlist(),
|
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()
|
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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -199,9 +223,14 @@ impl FileBrowser {
|
|||||||
|
|
||||||
let cache = fs_cache.clone();
|
let cache = fs_cache.clone();
|
||||||
let main_widget = AsyncWidget::new(&core, Box::new(move |_| {
|
let main_widget = AsyncWidget::new(&core, Box::new(move |_| {
|
||||||
let main_dir = File::new(&main_path.file_name()?
|
let name = if main_path.parent().is_none() {
|
||||||
.to_string_lossy()
|
"root".to_string()
|
||||||
.to_string(),
|
} else {
|
||||||
|
main_path.file_name()?
|
||||||
|
.to_string_lossy()
|
||||||
|
.to_string()
|
||||||
|
};
|
||||||
|
let main_dir = File::new(&name,
|
||||||
main_path.clone(),
|
main_path.clone(),
|
||||||
None);
|
None);
|
||||||
let files = cache.get_files_sync(&main_dir)?;
|
let files = cache.get_files_sync(&main_dir)?;
|
||||||
@ -225,9 +254,14 @@ impl FileBrowser {
|
|||||||
let cache = fs_cache.clone();
|
let cache = fs_cache.clone();
|
||||||
if let Some(left_path) = left_path {
|
if let Some(left_path) = left_path {
|
||||||
let left_widget = AsyncWidget::new(&core, Box::new(move |_| {
|
let left_widget = AsyncWidget::new(&core, Box::new(move |_| {
|
||||||
let left_dir = File::new(&left_path.file_name()?
|
let name = if left_path.parent().is_none() {
|
||||||
.to_string_lossy()
|
"root".to_string()
|
||||||
.to_string(),
|
} else {
|
||||||
|
left_path.file_name()?
|
||||||
|
.to_string_lossy()
|
||||||
|
.to_string()
|
||||||
|
};
|
||||||
|
let left_dir = File::new(&name,
|
||||||
left_path.clone(),
|
left_path.clone(),
|
||||||
None);
|
None);
|
||||||
let files = cache.get_files_sync(&left_dir)?;
|
let files = cache.get_files_sync(&left_dir)?;
|
||||||
@ -248,6 +282,14 @@ impl FileBrowser {
|
|||||||
}));
|
}));
|
||||||
let left_widget = FileBrowserWidgets::FileList(left_widget);
|
let left_widget = FileBrowserWidgets::FileList(left_widget);
|
||||||
columns.push_widget(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());
|
let previewer = Previewer::new(&core_p, fs_cache.clone());
|
||||||
@ -281,7 +323,8 @@ impl FileBrowser {
|
|||||||
let file = self.selected_file()?;
|
let file = self.selected_file()?;
|
||||||
|
|
||||||
if file.is_dir() {
|
if file.is_dir() {
|
||||||
match file.is_readable() {
|
let dir = file;
|
||||||
|
match dir.is_readable() {
|
||||||
Ok(true) => {},
|
Ok(true) => {},
|
||||||
Ok(false) => {
|
Ok(false) => {
|
||||||
let status =
|
let status =
|
||||||
@ -293,7 +336,38 @@ impl FileBrowser {
|
|||||||
err @ Err(_) => err.log()
|
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 {
|
} else {
|
||||||
self.core.get_sender().send(Events::InputEnabled(false))?;
|
self.core.get_sender().send(Events::InputEnabled(false))?;
|
||||||
|
|
||||||
@ -392,9 +466,42 @@ impl FileBrowser {
|
|||||||
|
|
||||||
pub fn go_back(&mut self) -> HResult<()> {
|
pub fn go_back(&mut self) -> HResult<()> {
|
||||||
if let Ok(new_cwd) = self.cwd.parent_as_file() {
|
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()
|
self.refresh()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -459,8 +566,8 @@ impl FileBrowser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_left_selection(&mut self) -> HResult<()> {
|
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.cwd.parent().is_none() { return Ok(()) }
|
||||||
|
if !self.left_async_widget_mut()?.ready() { return Ok(()) }
|
||||||
|
|
||||||
let selection = self.cwd()?.clone();
|
let selection = self.cwd()?.clone();
|
||||||
|
|
||||||
@ -469,6 +576,63 @@ impl FileBrowser {
|
|||||||
Ok(())
|
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> {
|
pub fn get_files(&self) -> HResult<&Files> {
|
||||||
Ok(&self.main_widget()?.content)
|
Ok(&self.main_widget()?.content)
|
||||||
}
|
}
|
||||||
@ -484,10 +648,12 @@ impl FileBrowser {
|
|||||||
self.main_widget_mut()?.content.meta_updated = false;
|
self.main_widget_mut()?.content.meta_updated = false;
|
||||||
|
|
||||||
|
|
||||||
let left_selection = self.left_widget()?.clone_selected_file();
|
if self.cwd.parent().is_some() {
|
||||||
let left_files = self.get_left_files()?;
|
let left_selection = self.left_widget()?.clone_selected_file();
|
||||||
self.fs_cache.put_files(left_files, Some(left_selection)).log();
|
let left_files = self.get_left_files()?;
|
||||||
self.left_widget_mut()?.content.meta_updated = false;
|
self.fs_cache.put_files(left_files, Some(left_selection)).log();
|
||||||
|
self.left_widget_mut()?.content.meta_updated = false;
|
||||||
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -516,6 +682,9 @@ impl FileBrowser {
|
|||||||
if &self.cwd == dir {
|
if &self.cwd == dir {
|
||||||
self.main_widget_mut()?.content.replace_file(old, new.cloned()).log();
|
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 {
|
if &self.left_dir()? == &dir {
|
||||||
self.left_widget_mut()?.content.replace_file(old, new.cloned()).log();
|
self.left_widget_mut()?.content.replace_file(old, new.cloned()).log();
|
||||||
}
|
}
|
||||||
@ -590,6 +759,13 @@ impl FileBrowser {
|
|||||||
widget
|
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> {
|
pub fn preview_widget_mut(&mut self) -> HResult<&mut Previewer> {
|
||||||
match self.columns.widgets.get_mut(2)? {
|
match self.columns.widgets.get_mut(2)? {
|
||||||
FileBrowserWidgets::Previewer(previewer) => Ok(previewer),
|
FileBrowserWidgets::Previewer(previewer) => Ok(previewer),
|
||||||
|
@ -464,7 +464,6 @@ impl Hash for File {
|
|||||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||||
self.name.hash(state);
|
self.name.hash(state);
|
||||||
self.path.hash(state);
|
self.path.hash(state);
|
||||||
self.selected.hash(state);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -114,15 +114,17 @@ impl FsCache {
|
|||||||
} else {
|
} else {
|
||||||
self.add_watch(&dir).log();
|
self.add_watch(&dir).log();
|
||||||
let dir = dir.clone();
|
let dir = dir.clone();
|
||||||
|
let selection = self.get_selection(&dir).ok();
|
||||||
let files = Async::new(Box::new(move |_| {
|
let files = Async::new(Box::new(move |_| {
|
||||||
let files = Files::new_from_path_cancellable(&dir.path, stale)?;
|
let files = Files::new_from_path_cancellable(&dir.path, stale)?;
|
||||||
Ok(files)
|
Ok(files)
|
||||||
}));
|
}));
|
||||||
Ok((None, files))
|
Ok((selection, files))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_files_sync(&self, dir: &File) -> HResult<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;
|
let files = self.get_files(&dir, Stale::new())?.1;
|
||||||
files.wait()
|
files.wait()
|
||||||
}
|
}
|
||||||
@ -145,17 +147,17 @@ impl FsCache {
|
|||||||
|
|
||||||
self.tab_settings.write()?.insert(dir.clone(), tab_settings);
|
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 file_cache.contains_key(&files.directory) {
|
||||||
if files.meta_updated {
|
// if files.meta_updated {
|
||||||
let mut files = files.clone();
|
// let mut files = files.clone();
|
||||||
files.meta_updated = false;
|
// files.meta_updated = false;
|
||||||
file_cache.insert(dir, files);
|
// file_cache.insert(dir, files);
|
||||||
}
|
// }
|
||||||
} else {
|
// } else {
|
||||||
file_cache.insert(dir, files.clone());
|
// file_cache.insert(dir, files.clone());
|
||||||
}
|
// }
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -164,8 +166,23 @@ impl FsCache {
|
|||||||
Ok(self.files.read()?.contains_key(dir))
|
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<()> {
|
fn add_watch(&self, dir: &File) -> HResult<()> {
|
||||||
if !self.watched_dirs.read()?.contains(&dir) {
|
if !self.watched_dirs.read()?.contains(&dir) {
|
||||||
|
self.watched_dirs.write()?.insert(dir.clone());
|
||||||
self.watcher.write()?.watch(&dir.path, RecursiveMode::NonRecursive)?
|
self.watcher.write()?.watch(&dir.path, RecursiveMode::NonRecursive)?
|
||||||
}
|
}
|
||||||
Ok(())
|
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>)>>>,
|
fs_changes: &Arc<RwLock<Vec<(File, Option<File>, Option<File>)>>>,
|
||||||
event: DebouncedEvent)
|
event: DebouncedEvent)
|
||||||
-> HResult<()> {
|
-> HResult<()> {
|
||||||
let path = &event.get_source_path()?;
|
let path = &event.get_source_path()?;
|
||||||
|
|
||||||
for dir in fs_cache.write()?.values_mut() {
|
let dirpath = path.parent()
|
||||||
if dir.path_in_here(&path).unwrap_or(false) {
|
.map(|path| path.to_path_buf())
|
||||||
let old_file = dir.find_file_with_path(&path).cloned();
|
.unwrap_or_else(|| PathBuf::from("/"));
|
||||||
let dirty_meta = old_file
|
let dir = File::new_from_path(&dirpath, None)?;
|
||||||
.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());
|
let old_file = File::new_from_path(&path, None)?;
|
||||||
dir.replace_file(old_file.as_ref(), new_file.clone()).log();
|
let mut new_file = match event {
|
||||||
|
DebouncedEvent::Remove(_) => None,
|
||||||
|
_ => Some(File::new_from_path(&path, None)?)
|
||||||
|
};
|
||||||
|
|
||||||
fs_changes.write()?.push((dir.directory.clone(),
|
new_file.as_mut().map(|file| file.meta_sync());
|
||||||
old_file,
|
|
||||||
new_file));
|
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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -66,6 +66,11 @@ impl<T> HBox<T> where T: Widget + PartialEq {
|
|||||||
self.widgets.insert(index, widget);
|
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<()> {
|
pub fn toggle_zoom(&mut self) -> HResult<()> {
|
||||||
self.clear().log();
|
self.clear().log();
|
||||||
self.zoom_active = !self.zoom_active;
|
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 rayon::ThreadPool;
|
||||||
|
|
||||||
use crate::files::{File, Kind};
|
use crate::files::{File, Files, Kind};
|
||||||
|
use crate::fscache::FsCache;
|
||||||
use crate::listview::ListView;
|
use crate::listview::ListView;
|
||||||
use crate::textview::TextView;
|
use crate::textview::TextView;
|
||||||
use crate::widget::{Widget, WidgetCore};
|
use crate::widget::{Widget, WidgetCore};
|
||||||
@ -131,7 +132,9 @@ impl<T: Send + 'static> Async<T> {
|
|||||||
let value_fn = async_fn.lock()?.take()?;
|
let value_fn = async_fn.lock()?.take()?;
|
||||||
let value = value_fn.call_box((stale.clone(),));
|
let value = value_fn.call_box((stale.clone(),));
|
||||||
async_value.lock()?.replace(value);
|
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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -331,6 +334,10 @@ impl<W: Widget + Send + 'static> AsyncWidget<W> {
|
|||||||
self.widget.get_mut()
|
self.widget.get_mut()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn take_widget(self) -> HResult<W> {
|
||||||
|
Ok(self.widget.value?)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn ready(&self) -> bool {
|
pub fn ready(&self) -> bool {
|
||||||
self.widget().is_ok()
|
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 {
|
pub struct Previewer {
|
||||||
widget: AsyncWidget<Box<dyn Widget + Send>>,
|
widget: AsyncWidget<PreviewWidget>,
|
||||||
core: WidgetCore,
|
core: WidgetCore,
|
||||||
file: Option<File>,
|
file: Option<File>,
|
||||||
pub cache: FsCache,
|
pub cache: FsCache,
|
||||||
@ -414,7 +427,9 @@ impl Previewer {
|
|||||||
pub fn new(core: &WidgetCore, cache: FsCache) -> Previewer {
|
pub fn new(core: &WidgetCore, cache: FsCache) -> Previewer {
|
||||||
let core_ = core.clone();
|
let core_ = core.clone();
|
||||||
let widget = AsyncWidget::new(&core, Box::new(move |_| {
|
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,
|
Previewer { widget: widget,
|
||||||
core: core.clone(),
|
core: core.clone(),
|
||||||
@ -423,7 +438,7 @@ impl Previewer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn become_preview(&mut self,
|
fn become_preview(&mut self,
|
||||||
widget: HResult<AsyncWidget<WidgetO>>) -> HResult<()> {
|
widget: HResult<AsyncWidget<PreviewWidget>>) -> HResult<()> {
|
||||||
let coordinates = self.get_coordinates()?.clone();
|
let coordinates = self.get_coordinates()?.clone();
|
||||||
self.widget = widget?;
|
self.widget = widget?;
|
||||||
self.widget.set_coordinates(&coordinates)?;
|
self.widget.set_coordinates(&coordinates)?;
|
||||||
@ -438,6 +453,57 @@ impl Previewer {
|
|||||||
self.file.as_ref()
|
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,
|
pub fn set_file(&mut self,
|
||||||
file: &File) -> HResult<()> {
|
file: &File) -> HResult<()> {
|
||||||
if Some(file) == self.file.as_ref() && !self.widget.is_stale()? { return Ok(()) }
|
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);
|
let preview = Previewer::preview_external(&file, &core, stale);
|
||||||
if preview.is_ok() { return preview; }
|
if preview.is_ok() { return preview; }
|
||||||
else {
|
else {
|
||||||
let mut blank = Box::new(TextView::new_blank(&core));
|
let mut blank = TextView::new_blank(&core);
|
||||||
blank.set_coordinates(&coordinates).log();
|
blank.set_coordinates(&coordinates).log();
|
||||||
blank.refresh().log();
|
blank.refresh().log();
|
||||||
blank.animate_slide_up().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)
|
HError::preview_failed(file)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -493,7 +561,7 @@ impl Previewer {
|
|||||||
cache: FsCache,
|
cache: FsCache,
|
||||||
core: &WidgetCore,
|
core: &WidgetCore,
|
||||||
stale: Stale)
|
stale: Stale)
|
||||||
-> Result<WidgetO, HError> {
|
-> HResult<PreviewWidget> {
|
||||||
let (selection, cached_files) = cache.get_files(&file, stale.clone())?;
|
let (selection, cached_files) = cache.get_files(&file, stale.clone())?;
|
||||||
|
|
||||||
let files = cached_files.wait()?;
|
let files = cached_files.wait()?;
|
||||||
@ -510,11 +578,11 @@ impl Previewer {
|
|||||||
file_list.refresh()?;
|
file_list.refresh()?;
|
||||||
if is_stale(&stale)? { return Previewer::preview_failed(&file) }
|
if is_stale(&stale)? { return Previewer::preview_failed(&file) }
|
||||||
file_list.animate_slide_up()?;
|
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)
|
fn preview_text(file: &File, core: &WidgetCore, stale: Stale)
|
||||||
-> HResult<WidgetO> {
|
-> HResult<PreviewWidget> {
|
||||||
let lines = core.coordinates.ysize() as usize;
|
let lines = core.coordinates.ysize() as usize;
|
||||||
let mut textview
|
let mut textview
|
||||||
= TextView::new_from_file_limit_lines(&core,
|
= TextView::new_from_file_limit_lines(&core,
|
||||||
@ -528,13 +596,13 @@ impl Previewer {
|
|||||||
if is_stale(&stale)? { return Previewer::preview_failed(&file) }
|
if is_stale(&stale)? { return Previewer::preview_failed(&file) }
|
||||||
|
|
||||||
textview.animate_slide_up()?;
|
textview.animate_slide_up()?;
|
||||||
Ok(Box::new(textview))
|
Ok(PreviewWidget::TextView(textview))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn preview_external(file: &File,
|
fn preview_external(file: &File,
|
||||||
core: &WidgetCore,
|
core: &WidgetCore,
|
||||||
stale: Stale)
|
stale: Stale)
|
||||||
-> Result<Box<dyn Widget + Send>, HError> {
|
-> HResult<PreviewWidget> {
|
||||||
let process =
|
let process =
|
||||||
std::process::Command::new("scope.sh")
|
std::process::Command::new("scope.sh")
|
||||||
.arg(&file.path)
|
.arg(&file.path)
|
||||||
@ -577,7 +645,7 @@ impl Previewer {
|
|||||||
textview.set_coordinates(&core.coordinates).log();
|
textview.set_coordinates(&core.coordinates).log();
|
||||||
textview.refresh().log();
|
textview.refresh().log();
|
||||||
textview.animate_slide_up().log();
|
textview.animate_slide_up().log();
|
||||||
return Ok(Box::new(textview))
|
return Ok(PreviewWidget::TextView(textview))
|
||||||
}
|
}
|
||||||
HError::preview_failed(file)
|
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 {
|
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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_resized(&self) -> HResult<(usize, usize)> {
|
pub fn is_resized(&self) -> HResult<bool> {
|
||||||
Ok(self.size.read()?.clone()?)
|
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)> {
|
pub fn take_size(&self) -> HResult<(usize, usize)> {
|
||||||
|
@ -348,7 +348,9 @@ pub trait Widget {
|
|||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
self.resize().log();
|
self.resize().log();
|
||||||
self.screen()?.take_size().ok();
|
if self.screen()?.is_resized()? {
|
||||||
|
self.screen()?.take_size().ok();
|
||||||
|
}
|
||||||
self.refresh().ok();
|
self.refresh().ok();
|
||||||
self.draw().ok();
|
self.draw().ok();
|
||||||
}
|
}
|
||||||
@ -408,7 +410,8 @@ pub trait Widget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn resize(&mut self) -> HResult<()> {
|
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();
|
let mut coords = self.get_core()?.coordinates.clone();
|
||||||
coords.set_size_u(xsize, ysize-2);
|
coords.set_size_u(xsize, ysize-2);
|
||||||
self.set_coordinates(&coords)?;
|
self.set_coordinates(&coords)?;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user