mirror of https://github.com/bobwen-dev/hunter
configurable hidden files/animation
This commit is contained in:
parent
8bfc707a59
commit
10d9a5462c
|
@ -0,0 +1,58 @@
|
|||
use crate::paths;
|
||||
use crate::fail::{HError, HResult, ErrorLog};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Config {
|
||||
pub animation: bool,
|
||||
pub show_hidden: bool,
|
||||
}
|
||||
|
||||
|
||||
impl Config {
|
||||
pub fn new() -> Config {
|
||||
Config {
|
||||
animation: true,
|
||||
show_hidden: false
|
||||
}
|
||||
}
|
||||
|
||||
pub fn load() -> HResult<Config> {
|
||||
let config_path = paths::config_path()?;
|
||||
|
||||
if !config_path.exists() {
|
||||
return Ok(Config::new());
|
||||
}
|
||||
|
||||
let config_string = std::fs::read_to_string(config_path)?;
|
||||
|
||||
let config = config_string.lines().fold(Config::new(), |mut config, line| {
|
||||
match Config::prep_line(line) {
|
||||
Ok(("animation", "on")) => { config.animation = true; },
|
||||
Ok(("animation", "off")) => { config.animation = false; },
|
||||
Ok(("show_hidden", "on")) => { config.show_hidden = true; },
|
||||
Ok(("show_hidden", "off")) => { config.show_hidden = false; },
|
||||
_ => { HError::config_error::<Config>(line.to_string()).log(); }
|
||||
}
|
||||
config
|
||||
});
|
||||
Ok(config)
|
||||
}
|
||||
|
||||
fn prep_line<'a>(line: &'a str) -> HResult<(&'a str, &'a str)> {
|
||||
let setting = line.split("=").collect::<Vec<&str>>();
|
||||
if setting.len() == 2 {
|
||||
Ok((setting[0], setting[1]))
|
||||
} else {
|
||||
HError::config_error(line.to_string())
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
pub fn animate(&self) -> bool {
|
||||
self.animation
|
||||
}
|
||||
|
||||
pub fn show_hidden(&self) -> bool {
|
||||
self.show_hidden
|
||||
}
|
||||
}
|
|
@ -89,6 +89,8 @@ pub enum HError {
|
|||
MetadataProcessedError,
|
||||
#[fail(display = "No files to take from widget")]
|
||||
WidgetNoFilesError,
|
||||
#[fail(display = "Invalid line in settings file: {}", _0)]
|
||||
ConfigLineError(String),
|
||||
}
|
||||
|
||||
impl HError {
|
||||
|
@ -147,6 +149,10 @@ impl HError {
|
|||
Err(HError::StaleError)
|
||||
}
|
||||
|
||||
pub fn config_error<T>(line: String) -> HResult<T> {
|
||||
Err(HError::ConfigLineError(line))
|
||||
}
|
||||
|
||||
pub fn async_not_ready<T>() -> HResult<T> {
|
||||
Err(HError::AsyncNotReadyError)
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@ use crate::term;
|
|||
use crate::term::ScreenExt;
|
||||
use crate::foldview::LogView;
|
||||
use crate::coordinates::Coordinates;
|
||||
use crate::dirty::Dirtyable;
|
||||
|
||||
#[derive(PartialEq)]
|
||||
pub enum FileBrowserWidgets {
|
||||
|
@ -188,6 +189,20 @@ impl Tabbable for TabView<FileBrowser> {
|
|||
self.active_tab_mut_().fs_cache.watch_only(open_dirs).log();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn on_config_loaded(&mut self) -> HResult<()> {
|
||||
let show_hidden = self.config().show_hidden();
|
||||
for tab in self.widgets.iter_mut() {
|
||||
tab.left_widget_mut().map(|w| {
|
||||
w.content.show_hidden = show_hidden;
|
||||
w.content.dirty_meta.set_dirty();
|
||||
w.refresh().log();
|
||||
}).ok();
|
||||
tab.main_widget_mut().map(|w| w.content.show_hidden = show_hidden).ok();
|
||||
tab.preview_widget_mut().map(|w| w.config_loaded()).ok();
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
19
src/files.rs
19
src/files.rs
|
@ -229,6 +229,19 @@ impl Files {
|
|||
Ok(files)
|
||||
}
|
||||
|
||||
pub fn get_file_mut(&mut self, index: usize) -> Option<&mut File> {
|
||||
let filter = self.filter.clone();
|
||||
let show_hidden = self.show_hidden;
|
||||
|
||||
let file = self.files
|
||||
.iter_mut()
|
||||
.filter(|f| !(filter.is_some() &&
|
||||
!f.name.contains(filter.as_ref().unwrap())))
|
||||
.filter(|f| !(!show_hidden && f.name.starts_with(".")))
|
||||
.nth(index);
|
||||
file
|
||||
}
|
||||
|
||||
pub fn get_files(&self) -> Vec<&File> {
|
||||
self.files
|
||||
.iter()
|
||||
|
@ -406,8 +419,12 @@ impl Files {
|
|||
self.dirty_meta.set_clean();
|
||||
|
||||
let meta_pool = make_pool(sender.clone());
|
||||
let show_hidden = self.show_hidden;
|
||||
|
||||
for file in self.files.iter_mut().take(meta_files) {
|
||||
for file in self.files
|
||||
.iter_mut()
|
||||
.filter(|f| !(!show_hidden && f.name.starts_with(".")))
|
||||
.take(meta_files) {
|
||||
if !file.meta_processed {
|
||||
file.take_meta(&meta_pool, &mut self.meta_updated).ok();
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@ pub trait Listable {
|
|||
fn render(&self) -> Vec<String>;
|
||||
fn render_header(&self) -> HResult<String> { Ok("".to_string()) }
|
||||
fn render_footer(&self) -> HResult<String> { Ok("".to_string()) }
|
||||
fn on_new(&mut self) -> HResult<()> { Ok(()) }
|
||||
fn on_refresh(&mut self) -> HResult<()> { Ok(()) }
|
||||
fn on_key(&mut self, _key: Key) -> HResult<()> { Ok(()) }
|
||||
}
|
||||
|
@ -27,6 +28,12 @@ impl Listable for ListView<Files> {
|
|||
self.render()
|
||||
}
|
||||
|
||||
fn on_new(&mut self) -> HResult<()> {
|
||||
let show_hidden = self.config().show_hidden();
|
||||
self.content.show_hidden = show_hidden;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn on_refresh(&mut self) -> HResult<()> {
|
||||
let sender = self.core.get_sender();
|
||||
|
||||
|
@ -97,7 +104,7 @@ where
|
|||
ListView<T>: Listable
|
||||
{
|
||||
pub fn new(core: &WidgetCore, content: T) -> ListView<T> {
|
||||
let view = ListView::<T> {
|
||||
let mut view = ListView::<T> {
|
||||
content: content,
|
||||
lines: 0,
|
||||
selection: 0,
|
||||
|
@ -107,6 +114,7 @@ where
|
|||
seeking: false,
|
||||
searching: None
|
||||
};
|
||||
view.on_new().log();
|
||||
view
|
||||
}
|
||||
|
||||
|
@ -161,19 +169,18 @@ impl ListView<Files>
|
|||
{
|
||||
pub fn selected_file(&self) -> &File {
|
||||
let selection = self.selection;
|
||||
let file = &self.content[selection];
|
||||
let file = &self.content.get_files()[selection];
|
||||
file
|
||||
}
|
||||
|
||||
pub fn selected_file_mut(&mut self) -> &mut File {
|
||||
let selection = self.selection;
|
||||
let file = &mut self.content.files[selection];
|
||||
file
|
||||
let mut file = self.content.get_file_mut(selection);
|
||||
file.unwrap()
|
||||
}
|
||||
|
||||
pub fn clone_selected_file(&self) -> File {
|
||||
let selection = self.selection;
|
||||
let file = self.content[selection].clone();
|
||||
let file = self.selected_file().clone();
|
||||
file
|
||||
}
|
||||
|
||||
|
@ -211,9 +218,9 @@ impl ListView<Files>
|
|||
pub fn select_file(&mut self, file: &File) {
|
||||
let pos = self
|
||||
.content
|
||||
.files
|
||||
.get_files()
|
||||
.iter()
|
||||
.position(|item| item == file)
|
||||
.position(|item| item == &file)
|
||||
.unwrap_or(0);
|
||||
self.set_selection(pos);
|
||||
}
|
||||
|
@ -291,10 +298,9 @@ impl ListView<Files>
|
|||
self.refresh().log();
|
||||
}
|
||||
|
||||
fn toggle_hidden(&mut self) {
|
||||
pub fn toggle_hidden(&mut self) {
|
||||
let file = self.clone_selected_file();
|
||||
self.content.toggle_hidden();
|
||||
//self.content.reload_files();
|
||||
self.select_file(&file);
|
||||
self.refresh().log();
|
||||
}
|
||||
|
|
|
@ -49,8 +49,7 @@ mod paths;
|
|||
mod foldview;
|
||||
mod dirty;
|
||||
mod fscache;
|
||||
|
||||
|
||||
mod config;
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@ use crate::textview::TextView;
|
|||
use crate::widget::{Widget, WidgetCore};
|
||||
use crate::coordinates::Coordinates;
|
||||
use crate::fail::{HResult, HError, ErrorLog};
|
||||
use crate::dirty::Dirtyable;
|
||||
|
||||
|
||||
pub type AsyncValueFn<T> = Box<dyn FnBox(Stale) -> HResult<T> + Send + Sync>;
|
||||
|
@ -682,6 +683,15 @@ impl Widget for Previewer {
|
|||
Ok(&mut self.core)
|
||||
}
|
||||
|
||||
fn config_loaded(&mut self) -> HResult<()> {
|
||||
let show_hidden = self.config().show_hidden();
|
||||
if let PreviewWidget::FileList(filelist) = self.widget.widget_mut()? {
|
||||
filelist.content.show_hidden = show_hidden;
|
||||
filelist.content.dirty_meta.set_dirty();
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn set_coordinates(&mut self, coordinates: &Coordinates) -> HResult<()> {
|
||||
self.core.coordinates = coordinates.clone();
|
||||
self.widget.set_coordinates(&coordinates)
|
||||
|
|
|
@ -26,6 +26,9 @@ pub trait Tabbable {
|
|||
}
|
||||
}
|
||||
fn on_refresh(&mut self) -> HResult<()> { Ok(()) }
|
||||
fn on_config_loaded(&mut self) -> HResult<()> { Ok(()) }
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -108,6 +111,10 @@ impl<T> Widget for TabView<T> where T: Widget, TabView<T>: Tabbable {
|
|||
Ok(&mut self.core)
|
||||
}
|
||||
|
||||
fn config_loaded(&mut self) -> HResult<()> {
|
||||
self.on_config_loaded()
|
||||
}
|
||||
|
||||
fn set_coordinates(&mut self, coordinates: &Coordinates) -> HResult<()> {
|
||||
self.core.coordinates = coordinates.clone();
|
||||
for widget in &mut self.widgets {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use std::sync::{Arc, Mutex};
|
||||
use std::sync::{Arc, Mutex, RwLock};
|
||||
use std::sync::mpsc::{Sender, Receiver, channel};
|
||||
use std::io::{Write, stdin};
|
||||
|
||||
|
@ -13,6 +13,8 @@ use crate::term::{Screen, ScreenExt};
|
|||
use crate::dirty::{Dirtyable, DirtyBit};
|
||||
use crate::preview::Stale;
|
||||
use crate::signal_notify::{notify, Signal};
|
||||
use crate::config::Config;
|
||||
use crate::preview::Async;
|
||||
|
||||
|
||||
|
||||
|
@ -24,7 +26,8 @@ pub enum Events {
|
|||
ExclusiveEvent(Option<Mutex<Option<Sender<Events>>>>),
|
||||
InputEnabled(bool),
|
||||
RequestInput,
|
||||
Status(String)
|
||||
Status(String),
|
||||
ConfigLoaded,
|
||||
}
|
||||
|
||||
impl PartialEq for WidgetCore {
|
||||
|
@ -56,7 +59,8 @@ pub struct WidgetCore {
|
|||
event_receiver: Arc<Mutex<Option<Receiver<Events>>>>,
|
||||
pub status_bar_content: Arc<Mutex<Option<String>>>,
|
||||
term_size: (usize, usize),
|
||||
dirty: DirtyBit
|
||||
dirty: DirtyBit,
|
||||
pub config: Arc<RwLock<Async<Config>>>
|
||||
}
|
||||
|
||||
impl WidgetCore {
|
||||
|
@ -70,6 +74,14 @@ impl WidgetCore {
|
|||
let (sender, receiver) = channel();
|
||||
let status_bar_content = Arc::new(Mutex::new(None));
|
||||
|
||||
let mut config = Async::new(Box::new(|_| Config::load()));
|
||||
let confsender = Arc::new(Mutex::new(sender.clone()));
|
||||
config.on_ready(Box::new(move || {
|
||||
confsender.lock()?.send(Events::ConfigLoaded).ok();
|
||||
Ok(())
|
||||
}));
|
||||
config.run().log();
|
||||
|
||||
let core = WidgetCore {
|
||||
screen: screen,
|
||||
coordinates: coords,
|
||||
|
@ -78,7 +90,8 @@ impl WidgetCore {
|
|||
event_receiver: Arc::new(Mutex::new(Some(receiver))),
|
||||
status_bar_content: status_bar_content,
|
||||
term_size: (xsize, ysize),
|
||||
dirty: DirtyBit::new() };
|
||||
dirty: DirtyBit::new(),
|
||||
config: Arc::new(RwLock::new(config)) };
|
||||
|
||||
let minibuffer = MiniBuffer::new(&core);
|
||||
*core.minibuffer.lock().unwrap() = Some(minibuffer);
|
||||
|
@ -130,6 +143,7 @@ pub trait Widget {
|
|||
fn refresh(&mut self) -> HResult<()>;
|
||||
fn get_drawlist(&self) -> HResult<String>;
|
||||
fn after_draw(&self) -> HResult<()> { Ok(()) }
|
||||
fn config_loaded(&mut self) -> HResult<()> { Ok(()) }
|
||||
|
||||
|
||||
|
||||
|
@ -277,6 +291,9 @@ pub trait Widget {
|
|||
_ => {}
|
||||
}
|
||||
}
|
||||
Events::ConfigLoaded => {
|
||||
self.get_core_mut()?.config.write()?.take_async().log();
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
self.refresh().log();
|
||||
|
@ -291,7 +308,19 @@ pub trait Widget {
|
|||
self.write_to_screen(&clearlist)
|
||||
}
|
||||
|
||||
fn config(&self) -> Config {
|
||||
self.get_core()
|
||||
.unwrap()
|
||||
.config.read().unwrap().get()
|
||||
.map(|config| config.clone())
|
||||
.unwrap_or(Config::new())
|
||||
}
|
||||
|
||||
fn animate_slide_up(&mut self, animator: Option<Stale>) -> HResult<()> {
|
||||
if !self.config().animate() { return Ok(()); }
|
||||
|
||||
self.config();
|
||||
|
||||
let coords = self.get_coordinates()?.clone();
|
||||
let xpos = coords.position().x();
|
||||
let ypos = coords.position().y();
|
||||
|
@ -361,6 +390,10 @@ pub trait Widget {
|
|||
Events::TerminalResized => {
|
||||
self.screen()?.clear().log();
|
||||
}
|
||||
Events::ConfigLoaded => {
|
||||
self.get_core_mut()?.config.write()?.take_async().log();
|
||||
self.config_loaded();
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
self.resize().log();
|
||||
|
|
Loading…
Reference in New Issue