mirror of https://github.com/bobwen-dev/hunter
speedup: make hunter handle directories with 1M files
This commit is contained in:
parent
cd773727eb
commit
8fc070b71b
|
@ -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(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
14
src/files.rs
14
src/files.rs
|
@ -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,
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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<()> {
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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| {
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue