speedup: make hunter handle directories with 1M files

This commit is contained in:
rabite 2020-01-23 20:44:10 +01:00
parent cd773727eb
commit 8fc070b71b
7 changed files with 115 additions and 29 deletions

View File

@ -87,9 +87,12 @@ pub struct FileBrowser {
}
impl Tabbable for TabView<FileBrowser> {
fn new_tab(&mut self) -> HResult<()> {
let cur_tab = self.active_tab_();
type Tab = FileBrowser;
fn new_tab(&mut self) -> HResult<()> {
self.active_tab_mut().save_tab_settings().log();
let cur_tab = self.active_tab();
let settings = cur_tab.fs_cache.tab_settings.read()?.clone();
let cache = cur_tab.fs_cache.new_client(settings).ok();
@ -136,11 +139,11 @@ impl Tabbable for TabView<FileBrowser> {
}).collect()
}
fn active_tab(& self) -> & dyn Widget {
fn active_tab(& self) -> &Self::Tab {
self.active_tab_()
}
fn active_tab_mut(&mut self) -> &mut dyn Widget {
fn active_tab_mut(&mut self) -> &mut Self::Tab {
self.active_tab_mut_()
}
@ -274,6 +277,7 @@ impl FileBrowser {
let mut list = ListView::new(&core_m.clone(),
files);
selected_file.map(|f| list.select_file(&f));
@ -342,8 +346,7 @@ impl FileBrowser {
bookmarks: Arc::new(Mutex::new(bookmarks)),
log_view: Arc::new(Mutex::new(log_view)),
fs_cache: fs_cache,
fs_stat: Arc::new(RwLock::new(fs_stat))
})
fs_stat: Arc::new(RwLock::new(fs_stat)) })
}
pub fn enter_dir(&mut self) -> HResult<()> {
@ -486,8 +489,6 @@ impl FileBrowser {
}
pub fn main_widget_goto(&mut self, dir: &File) -> HResult<()> {
self.save_tab_settings().log();
let dir = dir.clone();
let cache = self.fs_cache.clone();
@ -730,6 +731,12 @@ impl FileBrowser {
Ok(&self.left_widget()?.content)
}
pub fn save_selected_file(&self) -> HResult<()> {
self.selected_file()
.map(|f| self.fs_cache.set_selection(self.cwd.clone(),
f))?
}
pub fn save_tab_settings(&mut self) -> HResult<()> {
if !self.main_async_widget_mut()?.ready() { return Ok(()) }
@ -1144,11 +1151,8 @@ impl FileBrowser {
pub fn get_footer(&self) -> HResult<String> {
let xsize = self.get_coordinates()?.xsize();
let ypos = self.get_coordinates()?.position().y();
let pos = self.main_widget()?.get_selection();
let file = self.main_widget()?
.content
.iter_files()
.nth(pos)?;
let file = self.selected_file()?;
let permissions = file.pretty_print_permissions().unwrap_or("NOPERMS".into());
let user = file.pretty_user().unwrap_or("NOUSER".into());
@ -1262,7 +1266,6 @@ impl Widget for FileBrowser {
self.set_cwd().log();
if !self.columns.zoom_active { self.update_preview().log(); }
self.columns.refresh().log();
self.save_tab_settings().log();
Ok(())
}
@ -1274,6 +1277,9 @@ impl Widget for FileBrowser {
match self.do_key(key) {
Err(HError::WidgetUndefinedKeyError{..}) => {
match self.main_widget_mut()?.on_key(key) {
Ok(_) => {
self.save_tab_settings()?;
}
Err(HError::WidgetUndefinedKeyError{..}) => {
self.preview_widget_mut()?.on_key(key)?
}
@ -1303,7 +1309,11 @@ impl Acting for FileBrowser {
match movement {
Left => self.go_back(),
Right => self.enter_dir(),
_ => self.main_widget_mut()?.movement(movement)
_ => {
self.main_widget_mut()?.movement(movement)?;
self.save_selected_file()?;
Ok(())
}
}
}

View File

@ -401,7 +401,7 @@ impl Files {
!(filter.is_some() &&
!f.name.contains(filter.as_ref().unwrap())) &&
(!filter_selected || f.selected))
.filter(move |f| !(!show_hidden && f.name.starts_with(".")))
.filter(move |f| !(!show_hidden && f.hidden))
}
pub fn iter_files_mut(&mut self) -> impl Iterator<Item=&mut File> {
@ -416,7 +416,7 @@ impl Files {
!(filter.is_some() &&
!f.name.contains(filter.as_ref().unwrap())) &&
(!filter_selected || f.selected))
.filter(move |f| !(!show_hidden && f.name.starts_with(".")))
.filter(move |f| !(!show_hidden && f.hidden))
}
#[allow(trivial_bounds)]
@ -750,12 +750,18 @@ impl std::fmt::Debug for File {
}
}
impl std::default::Default for File {
fn default() -> File {
File::new_placeholder(Path::new("")).unwrap()
}
}
#[derive(Clone)]
pub struct File {
pub name: String,
pub path: PathBuf,
pub hidden: bool,
pub kind: Kind,
pub dirsize: Option<Async<usize>>,
pub target: Option<PathBuf>,
@ -772,6 +778,7 @@ impl File {
name: &str,
path: PathBuf,
dirty_meta: Option<AsyncDirtyBit>) -> File {
let hidden = name.starts_with(".");
let tag = check_tag(&path).ok();
let meta = File::make_async_meta(&path, dirty_meta.clone(), None);
let dirsize = if path.is_dir() {
@ -780,6 +787,7 @@ impl File {
File {
name: name.to_string(),
hidden: hidden,
kind: if path.is_dir() { Kind::Directory } else { Kind::File },
path: path,
dirsize: dirsize,
@ -797,6 +805,7 @@ impl File {
path: PathBuf,
dirty_meta: Option<AsyncDirtyBit>,
stale: Stale) -> File {
let hidden = name.starts_with(".");
let tag = check_tag(&path).ok();
let meta = File::make_async_meta(&path,
dirty_meta.clone(),
@ -809,6 +818,7 @@ impl File {
File {
name: name.to_string(),
hidden: hidden,
kind: if path.is_dir() { Kind::Directory } else { Kind::File },
path: path,
dirsize: dirsize,

View File

@ -326,6 +326,7 @@ where
ListView<Vec<F>>: FoldableWidgetExt,
Bindings<<ListView<Vec<F>> as ActingExt>::Action>: Default
{
type Item = ();
fn len(&self) -> usize {
self.content.iter().map(|f| f.lines()).sum()

View File

@ -191,7 +191,22 @@ impl FsCache {
}
pub fn get_selection(&self, dir: &File) -> HResult<File> {
Ok(self.tab_settings.read()?.get(&dir).as_ref()?.selection.as_ref()?.clone())
Ok(self.tab_settings
.read()?
.get(&dir)
.as_ref()?
.selection
.as_ref()?
.clone())
}
pub fn set_selection(&self, dir: File, selection: File) -> HResult<()> {
self.tab_settings.write()
.map(|mut settings| {
let setting = settings.entry(dir).or_insert(TabSettings::new());
setting.selection = Some(selection);
})?;
Ok(())
}
pub fn save_settings(&self, files: &Files, selection: Option<File>) -> HResult<()> {

View File

@ -1,3 +1,4 @@
use std::fmt::Debug;
use termion::event::Key;
use unicode_width::UnicodeWidthStr;
@ -10,6 +11,7 @@ use crate::widget::{Widget, WidgetCore};
use crate::dirty::Dirtyable;
pub trait Listable {
type Item: Debug + PartialEq + Default;
fn len(&self) -> usize;
fn render(&self) -> Vec<String>;
fn render_header(&self) -> HResult<String> { Ok("".to_string()) }
@ -32,6 +34,8 @@ impl Acting for ListView<Files> {
fn movement(&mut self, movement: &Movement) -> HResult<()> {
use Movement::*;
let pos = self.get_selection();
match movement {
Up(n) => { for _ in 0..*n { self.move_up(); }; self.refresh()?; }
Down(n) => { for _ in 0..*n { self.move_down(); }; self.refresh()?; }
@ -42,12 +46,18 @@ impl Acting for ListView<Files> {
Left | Right => {}
}
if pos != self.get_selection() {
self.update_selected_file();
}
Ok(())
}
fn do_action(&mut self, action: &Self::Action) -> HResult<()> {
use FileListAction::*;
let pos = self.get_selection();
match action {
Search => self.search_file()?,
SearchNext => self.search_next()?,
@ -65,11 +75,18 @@ impl Acting for ListView<Files> {
ToPrevMtime => self.select_prev_mtime(),
ToggleDirsFirst => self.toggle_dirs_first(),
}
if pos != self.get_selection() {
self.update_selected_file();
}
Ok(())
}
}
impl Listable for ListView<Files> {
type Item = File;
fn len(&self) -> usize {
self.content.len()
}
@ -81,6 +98,12 @@ impl Listable for ListView<Files> {
fn on_new(&mut self) -> HResult<()> {
let show_hidden = self.core.config().show_hidden();
self.content.show_hidden = show_hidden;
let file = self.content
.iter_files()
.nth(0)
.cloned()
.unwrap_or_default();
self.current_item = Some(file);
Ok(())
}
@ -117,9 +140,12 @@ impl Listable for ListView<Files> {
}
#[derive(Debug, PartialEq)]
pub struct ListView<T> where ListView<T>: Listable
pub struct ListView<T>
where
ListView<T>: Listable
{
pub content: T,
pub current_item: Option<<ListView<T> as Listable>::Item>,
pub lines: usize,
selection: usize,
pub offset: usize,
@ -137,6 +163,7 @@ where
pub fn new(core: &WidgetCore, content: T) -> ListView<T> {
let mut view = ListView::<T> {
content: content,
current_item: None,
lines: 0,
selection: 0,
offset: 0,
@ -222,13 +249,19 @@ where
impl ListView<Files>
{
pub fn selected_file(&self) -> &File {
let selection = self.selection;
pub fn update_selected_file(&mut self) {
let pos = self.selection;
&self.content
let file = self.content
.iter_files()
.nth(selection)
.unwrap_or(&self.content.directory)
.nth(pos)
.map(|f| f.clone());
self.current_item = file;
}
pub fn selected_file(&self) -> &File {
self.current_item.as_ref().unwrap()
}
pub fn selected_file_mut(&mut self) -> &mut File {
@ -288,6 +321,8 @@ impl ListView<Files>
}
pub fn select_file(&mut self, file: &File) {
self.current_item = Some(file.clone());
let pos = self
.content
.iter_files()
@ -375,6 +410,8 @@ impl ListView<Files>
self.content.toggle_hidden();
self.select_file(&file);
self.refresh().log();
self.core.show_status(&format!("Showing hidden files: {}",
self.content.show_hidden)).log();
}
fn toggle_dirs_first(&mut self) {
@ -390,9 +427,13 @@ impl ListView<Files>
fn multi_select_file(&mut self) {
self.selected_file_mut().toggle_selection();
// Create mutable clone to render change
let mut file = self.clone_selected_file();
file.toggle_selection();
if !self.content.filter_selected {
let selection = self.get_selection();
let line = self.render_line(self.selected_file());
let line = self.render_line(&file);
self.buffer[selection] = line;
self.move_down();
@ -432,8 +473,12 @@ impl ListView<Files>
fn toggle_tag(&mut self) -> HResult<()> {
self.selected_file_mut().toggle_tag()?;
// Create a mutable clone to render changes into buffer
let mut file = self.clone_selected_file();
file.toggle_tag()?;
let line = self.render_line(&file);
let selection = self.get_selection();
let line = self.render_line(self.selected_file());
self.buffer[selection] = line;
self.move_down();
@ -689,7 +734,10 @@ impl ListView<Files>
}
impl<T> Widget for ListView<T> where ListView<T>: Listable {
impl<T> Widget for ListView<T>
where
ListView<T>: Listable
{
fn get_core(&self) -> HResult<&WidgetCore> {
Ok(&self.core)
}

View File

@ -199,6 +199,7 @@ impl Process {
}
impl Listable for ListView<Vec<Process>> {
type Item = ();
fn len(&self) -> usize { self.content.len() }
fn render(&self) -> Vec<String> {
self.content.iter().map(|proc| {

View File

@ -5,6 +5,7 @@ use crate::fail::{HResult, HError, ErrorLog};
use crate::coordinates::Coordinates;
pub trait Tabbable {
type Tab: Widget;
fn new_tab(&mut self) -> HResult<()>;
fn close_tab(&mut self) -> HResult<()>;
fn next_tab(&mut self) -> HResult<()>;
@ -14,8 +15,8 @@ pub trait Tabbable {
Ok(())
}
fn get_tab_names(&self) -> Vec<Option<String>>;
fn active_tab(&self) -> &dyn Widget;
fn active_tab_mut(&mut self) -> &mut dyn Widget;
fn active_tab(&self) -> &Self::Tab;
fn active_tab_mut(&mut self) -> &mut Self::Tab;
fn on_key_sub(&mut self, key: Key) -> HResult<()>;
fn on_key(&mut self, key: Key) -> HResult<()> {
self.on_key_sub(key)