mirror of https://github.com/bobwen-dev/hunter
the fastest file manager in the galaxy
This commit is contained in:
parent
800592338d
commit
74e43ee965
|
@ -34,6 +34,14 @@ dependencies = [
|
|||
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ansi_term"
|
||||
version = "0.12.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "argon2rs"
|
||||
version = "0.2.5"
|
||||
|
@ -63,7 +71,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
|
||||
[[package]]
|
||||
name = "async_value"
|
||||
version = "0.2.6"
|
||||
version = "0.2.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
@ -580,7 +588,7 @@ name = "hunter"
|
|||
version = "1.3.5"
|
||||
dependencies = [
|
||||
"alphanumeric-sort 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"async_value 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"async_value 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"chrono 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
@ -597,7 +605,7 @@ dependencies = [
|
|||
"itertools 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lscolors 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lscolors 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"mime 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"mime_guess 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"notify 4.0.15 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
@ -726,10 +734,10 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "lscolors"
|
||||
version = "0.5.0"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ansi_term 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1553,11 +1561,12 @@ dependencies = [
|
|||
"checksum aho-corasick 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)" = "58fb5e95d83b38284460a5fda7d6470aa0b8844d283a0b614b8535e880800d2d"
|
||||
"checksum alphanumeric-sort 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)" = "f37ce94154d73f6961f87571a3ab7814e1608f373bd55a933e3e771b6dd59fc4"
|
||||
"checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
|
||||
"checksum ansi_term 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2"
|
||||
"checksum argon2rs 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "3f67b0b6a86dae6e67ff4ca2b6201396074996379fba2b92ff649126f37cb392"
|
||||
"checksum arrayref 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "0d382e583f07208808f6b1249e60848879ba3543f57c32277bf52d69c2f0f0ee"
|
||||
"checksum arrayvec 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)" = "cd9fd44efafa8690358b7408d253adf110036b88f55672a933f01d616ad9b1b9"
|
||||
"checksum arrayvec 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cff77d8686867eceff3105329d4698d96c2391c176d5d03adc90c7389162b5b8"
|
||||
"checksum async_value 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "35a62a04436ffd962e78a3301658eac900480d425ea36ec42553aadc572742be"
|
||||
"checksum async_value 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "82d81baa3badf6d557265cedafc6fc83b4b79567360bbadcfc5ea6eb934885ae"
|
||||
"checksum atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
|
||||
"checksum autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2"
|
||||
"checksum autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d"
|
||||
|
@ -1625,7 +1634,7 @@ dependencies = [
|
|||
"checksum lazycell 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b294d6fa9ee409a054354afc4352b0b9ef7ca222c69b8812cbea9e7d2bf3783f"
|
||||
"checksum libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)" = "d515b1f41455adea1313a4a2ac8a8a477634fbae63cc6100e3aebb207ce61558"
|
||||
"checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7"
|
||||
"checksum lscolors 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e9938fd8c379393454f73ec4c9c5b40f3d8332d80b25a29da05e41ee0ecbb559"
|
||||
"checksum lscolors 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ea3b3414b2d015c4fd689815f2551797f3c2296bb241dd709c7da233ec7cba4b"
|
||||
"checksum lzw 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7d947cbb889ed21c2a84be6ffbaebf5b4e0f4340638cba0444907e38b56be084"
|
||||
"checksum make-cmd 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a8ca8afbe8af1785e09636acb5a41e08a765f5f0340568716c18a8700ba3c0d3"
|
||||
"checksum maybe-uninit 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00"
|
||||
|
|
|
@ -17,8 +17,8 @@ default-run = "hunter"
|
|||
termion = "1.5"
|
||||
unicode-width = "0.1.5"
|
||||
lazy_static = "1"
|
||||
alphanumeric-sort = "1.0.6"
|
||||
lscolors = { version = "0.5.0", features = [ "ansi_term" ] }
|
||||
alphanumeric-sort = "1.0.11"
|
||||
lscolors = { version = "0.6.0", features = [ "ansi_term" ] }
|
||||
tree_magic = "0.2.1"
|
||||
rayon = "1.3"
|
||||
dirs-2 = "1.1.0"
|
||||
|
@ -32,7 +32,7 @@ parse-ansi = "0.1.6"
|
|||
signal-notify = "0.1.3"
|
||||
systemstat = "0.1.5"
|
||||
mime_guess = "2.0"
|
||||
async_value = "0.2.6"
|
||||
async_value = "0.2.7"
|
||||
osstrtools = "0.2"
|
||||
pathbuftools = "0.1"
|
||||
clap = "2.33"
|
||||
|
|
10
src/fail.rs
10
src/fail.rs
|
@ -103,7 +103,9 @@ pub enum HError {
|
|||
#[fail(display = "{}", _0)]
|
||||
KeyBind(KeyBindError),
|
||||
#[fail(display = "FileBrowser needs to know about all tab's files to run exec!")]
|
||||
FileBrowserNeedTabFiles
|
||||
FileBrowserNeedTabFiles,
|
||||
#[fail(display = "{}", _0)]
|
||||
FileError(crate::files::FileError)
|
||||
}
|
||||
|
||||
impl HError {
|
||||
|
@ -425,3 +427,9 @@ impl From<ini::ini::Error> for KeyBindError {
|
|||
KeyBindError::IniError(Arc::new(err))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<crate::files::FileError> for HError {
|
||||
fn from(err: crate::files::FileError) -> Self {
|
||||
HError::FileError(err)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -197,7 +197,7 @@ impl Tabbable for TabView<FileBrowser> {
|
|||
tab.left_async_widget_mut().map(|async_w| {
|
||||
async_w.widget.on_ready(move |mut w, _| {
|
||||
w.as_mut()
|
||||
.map(|mut w| {
|
||||
.map(|w| {
|
||||
if w.content.show_hidden != show_hidden {
|
||||
w.content.show_hidden = show_hidden;
|
||||
w.content.recalculate_len();
|
||||
|
@ -211,7 +211,7 @@ impl Tabbable for TabView<FileBrowser> {
|
|||
tab.main_async_widget_mut().map(|async_w| {
|
||||
async_w.widget.on_ready(move |mut w, _| {
|
||||
w.as_mut()
|
||||
.map(|mut w| {
|
||||
.map(|w| {
|
||||
if w.content.show_hidden != show_hidden {
|
||||
w.content.show_hidden = show_hidden;
|
||||
w.content.recalculate_len();
|
||||
|
@ -262,11 +262,9 @@ impl FileBrowser {
|
|||
|
||||
let cache = fs_cache.clone();
|
||||
let main_widget = AsyncWidget::new(&core, move |stale| {
|
||||
let dir = File::new_from_path(&main_path, None)?;
|
||||
let dir = File::new_from_path(&main_path)?;
|
||||
let source = FileSource::Path(dir);
|
||||
ListView::builder(core_m, source)
|
||||
.meta_all()
|
||||
// .prerender()
|
||||
.with_cache(cache)
|
||||
.with_stale(stale.clone())
|
||||
.build()
|
||||
|
@ -275,11 +273,9 @@ impl FileBrowser {
|
|||
let cache = fs_cache.clone();
|
||||
if let Some(left_path) = left_path {
|
||||
let left_widget = AsyncWidget::new(&core_l.clone(), move |stale| {
|
||||
let dir = File::new_from_path(&left_path, None)?;
|
||||
let dir = File::new_from_path(&left_path)?;
|
||||
let source = FileSource::Path(dir);
|
||||
ListView::builder(core_l, source)
|
||||
// .meta_all()
|
||||
// .prerender()
|
||||
.with_cache(cache)
|
||||
.with_stale(stale.clone())
|
||||
.build()
|
||||
|
@ -311,7 +307,7 @@ impl FileBrowser {
|
|||
columns.refresh().log();
|
||||
|
||||
|
||||
let cwd = File::new_from_path(&cwd, None).unwrap();
|
||||
let cwd = File::new_from_path(&cwd).unwrap();
|
||||
|
||||
let proc_view = ProcView::new(&core);
|
||||
let bookmarks = BMPopup::new(&core);
|
||||
|
@ -363,8 +359,6 @@ impl FileBrowser {
|
|||
};
|
||||
|
||||
ListView::builder(core, source)
|
||||
.meta_all()
|
||||
// .prerender()
|
||||
.with_cache(cache)
|
||||
.with_stale(stale.clone())
|
||||
.build()
|
||||
|
@ -380,7 +374,6 @@ impl FileBrowser {
|
|||
};
|
||||
|
||||
ListView::builder(core, source)
|
||||
.prerender()
|
||||
.with_cache(cache)
|
||||
.with_stale(stale.clone())
|
||||
.build()
|
||||
|
@ -479,6 +472,10 @@ impl FileBrowser {
|
|||
}
|
||||
|
||||
pub fn main_widget_goto(&mut self, dir: &File) -> HResult<()> {
|
||||
self.preview_widget_mut()
|
||||
.map(|p| p.set_stale())
|
||||
.ok();
|
||||
|
||||
let dir = dir.clone();
|
||||
let cache = self.fs_cache.clone();
|
||||
|
||||
|
@ -489,8 +486,6 @@ impl FileBrowser {
|
|||
let main_async_widget = self.main_async_widget_mut()?;
|
||||
main_async_widget.change_to(move |stale: &Stale, core| {
|
||||
let view = ListView::builder(core, file_source)
|
||||
.meta_all()
|
||||
// .prerender()
|
||||
.with_cache(cache)
|
||||
.with_stale(stale.clone())
|
||||
.build()?;
|
||||
|
@ -507,9 +502,7 @@ impl FileBrowser {
|
|||
}).log();
|
||||
}
|
||||
|
||||
self.preview_widget_mut()
|
||||
.map(|p| p.set_stale())
|
||||
.ok();
|
||||
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -527,8 +520,6 @@ impl FileBrowser {
|
|||
let left_async_widget = self.left_async_widget_mut()?;
|
||||
left_async_widget.change_to(move |stale, core| {
|
||||
let view = ListView::builder(core, file_source)
|
||||
// .meta_all()
|
||||
// .prerender()
|
||||
.with_cache(cache)
|
||||
.with_stale(stale.clone())
|
||||
.build()?;
|
||||
|
@ -559,8 +550,6 @@ impl FileBrowser {
|
|||
self.main_async_widget_mut()?.change_to(move |stale, core| {
|
||||
ListView::builder(core, file_source)
|
||||
.select(main_selection)
|
||||
.meta_all()
|
||||
// .prerender()
|
||||
.with_cache(cache)
|
||||
.with_stale(stale.clone())
|
||||
.build()
|
||||
|
@ -571,7 +560,6 @@ impl FileBrowser {
|
|||
let cache = self.fs_cache.clone();
|
||||
self.left_async_widget_mut()?.change_to(move |stale, core| {
|
||||
ListView::builder(core, file_source)
|
||||
// .prerender()
|
||||
.with_cache(cache)
|
||||
.with_stale(stale.clone())
|
||||
.build()
|
||||
|
@ -612,7 +600,7 @@ impl FileBrowser {
|
|||
|
||||
pub fn go_home(&mut self) -> HResult<()> {
|
||||
let home = crate::paths::home_path().unwrap_or(PathBuf::from("~/"));
|
||||
let home = File::new_from_path(&home, None)?;
|
||||
let home = File::new_from_path(&home)?;
|
||||
self.main_widget_goto(&home)
|
||||
}
|
||||
|
||||
|
@ -649,7 +637,7 @@ impl FileBrowser {
|
|||
|
||||
pub fn goto_bookmark(&mut self) -> HResult<()> {
|
||||
let path = self.get_boomark()?;
|
||||
let path = File::new_from_path(&PathBuf::from(path), None)?;
|
||||
let path = File::new_from_path(&PathBuf::from(path))?;
|
||||
self.main_widget_goto(&path)?;
|
||||
Ok(())
|
||||
}
|
||||
|
@ -700,23 +688,35 @@ impl FileBrowser {
|
|||
|
||||
let selection = self.cwd()?.clone();
|
||||
|
||||
self.cwd.parent_as_file()
|
||||
.map(|dir| self.fs_cache
|
||||
.set_selection(dir.clone(), selection.clone())).log();
|
||||
// Saves doing iteration to find file's position
|
||||
if let Some(ref current_selection) = self.left_widget()?.current_item {
|
||||
if current_selection.name == selection.name {
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
|
||||
self.left_widget_mut()?.select_file(&selection);
|
||||
|
||||
let selected_file = self.left_widget()?.selected_file();
|
||||
self.cwd.parent_as_file()
|
||||
.map(|dir| {
|
||||
self.fs_cache
|
||||
.set_selection(dir.clone(), selected_file.clone())
|
||||
}).log();
|
||||
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn take_main_files(&mut self) -> HResult<Files> {
|
||||
let mut w = self.main_widget_mut()?;
|
||||
let w = self.main_widget_mut()?;
|
||||
let files = std::mem::take(&mut w.content);
|
||||
w.content.len = 0;
|
||||
Ok(files)
|
||||
}
|
||||
|
||||
pub fn take_left_files(&mut self) -> HResult<Files> {
|
||||
let mut w = self.left_widget_mut()?;
|
||||
let w = self.left_widget_mut()?;
|
||||
let files = std::mem::take(&mut w.content);
|
||||
w.content.len = 0;
|
||||
Ok(files)
|
||||
|
@ -879,7 +879,7 @@ impl FileBrowser {
|
|||
let dir = self.core.minibuffer("cd")?;
|
||||
|
||||
let path = std::path::PathBuf::from(&dir);
|
||||
let dir = File::new_from_path(&path.canonicalize()?, None)?;
|
||||
let dir = File::new_from_path(&path.canonicalize()?)?;
|
||||
self.main_widget_goto(&dir)?;
|
||||
|
||||
Ok(())
|
||||
|
@ -931,11 +931,11 @@ impl FileBrowser {
|
|||
let path = &paths[0];
|
||||
if path.exists() {
|
||||
if path.is_dir() {
|
||||
let dir = File::new_from_path(&path, None)?;
|
||||
let dir = File::new_from_path(&path)?;
|
||||
|
||||
self.main_widget_goto(&dir).log();
|
||||
} else if path.is_file() {
|
||||
let file = File::new_from_path(&path, None)?;
|
||||
let file = File::new_from_path(&path)?;
|
||||
let dir = file.parent_as_file()?;
|
||||
|
||||
self.main_widget_goto(&dir).log();
|
||||
|
@ -964,7 +964,7 @@ impl FileBrowser {
|
|||
|
||||
let dir_path = file_path.parent()?;
|
||||
if self.cwd.path != dir_path {
|
||||
let file_dir = File::new_from_path(&dir_path, None);
|
||||
let file_dir = File::new_from_path(&dir_path);
|
||||
|
||||
self.main_widget_goto_wait(&file_dir?).log();
|
||||
}
|
||||
|
@ -1033,7 +1033,7 @@ impl FileBrowser {
|
|||
|
||||
if path.exists() {
|
||||
if path.is_dir() {
|
||||
let dir = File::new_from_path(&path, None)?;
|
||||
let dir = File::new_from_path(&path)?;
|
||||
self.main_widget_goto(&dir).log();
|
||||
}
|
||||
else {
|
||||
|
@ -1231,12 +1231,15 @@ impl Widget for FileBrowser {
|
|||
let file = self.selected_file()?;
|
||||
let name = &file.name;
|
||||
|
||||
let fcolor = file.get_color();
|
||||
|
||||
let color = if file.is_dir() {
|
||||
crate::term::highlight_color() }
|
||||
else if file.color.is_none() {
|
||||
crate::term::normal_color()
|
||||
} else {
|
||||
crate::term::from_lscolor(file.color.as_ref().unwrap())
|
||||
else {
|
||||
match fcolor {
|
||||
Some(color) => color,
|
||||
None => crate::term::normal_color()
|
||||
}
|
||||
};
|
||||
|
||||
let path = self.cwd.short_string();
|
||||
|
|
832
src/files.rs
832
src/files.rs
File diff suppressed because it is too large
Load Diff
|
@ -6,7 +6,7 @@ use std::sync::{Arc, RwLock, Weak};
|
|||
use std::sync::mpsc::{channel, Sender, Receiver};
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::time::Duration;
|
||||
use std::path::PathBuf;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
use crate::files::{Files, File, SortBy};
|
||||
use crate::widget::Events;
|
||||
|
@ -123,10 +123,12 @@ impl FsEventDispatcher {
|
|||
|
||||
// fn remove_unnecessary
|
||||
}
|
||||
|
||||
use std::sync::atomic::{AtomicBool, AtomicUsize};
|
||||
#[derive(Clone)]
|
||||
pub struct FsCache {
|
||||
files: Arc<RwLock<HashMap<File, Files>>>,
|
||||
dirsizes: Arc<RwLock<HashMap<PathBuf, HashMap<PathBuf,
|
||||
Arc<(AtomicBool, AtomicUsize)>>>>>,
|
||||
pub tab_settings: Arc<RwLock<HashMap<File, TabSettings>>>,
|
||||
watched_dirs: Arc<RwLock<HashSet<File>>>,
|
||||
watcher: Arc<RwLock<RecommendedWatcher>>,
|
||||
|
@ -142,6 +144,7 @@ impl FsCache {
|
|||
|
||||
let fs_cache = FsCache {
|
||||
files: Arc::new(RwLock::new(HashMap::new())),
|
||||
dirsizes: Arc::new(RwLock::new(HashMap::new())),
|
||||
tab_settings: Arc::new(RwLock::new(HashMap::new())),
|
||||
watched_dirs: Arc::new(RwLock::new(HashSet::new())),
|
||||
watcher: Arc::new(RwLock::new(watcher)),
|
||||
|
@ -176,7 +179,6 @@ impl FsCache {
|
|||
cache.fs_event_dispatcher.add_target(&dir,
|
||||
&files.pending_events).log();
|
||||
FsCache::apply_settingss(&cache, &mut files).ok();
|
||||
files.sort();
|
||||
Ok(files)
|
||||
});
|
||||
Ok((selection, files))
|
||||
|
@ -227,6 +229,67 @@ impl FsCache {
|
|||
Ok(self.files.read()?.contains_key(dir))
|
||||
}
|
||||
|
||||
pub fn get_dirsize(&self, dir: &File) -> Option<Arc<(AtomicBool, AtomicUsize)>> {
|
||||
let parent_dir = dir.parent()
|
||||
.unwrap_or_else(|| Path::new("/"));
|
||||
|
||||
self.dirsizes
|
||||
.read()
|
||||
.unwrap()
|
||||
.get(parent_dir)
|
||||
.map(|parent_map| {
|
||||
parent_map.get(&dir.path)
|
||||
})
|
||||
.flatten()
|
||||
.cloned()
|
||||
}
|
||||
|
||||
pub fn make_dirsize(&self, dir: &File) -> Arc<(AtomicBool, AtomicUsize)> {
|
||||
let parent_dir = dir.parent()
|
||||
.unwrap_or_else(|| Path::new("/"));
|
||||
let dir = dir.path.as_path();
|
||||
|
||||
let mut dirsizes = self.dirsizes
|
||||
.write()
|
||||
.unwrap();
|
||||
|
||||
match dirsizes.contains_key(parent_dir) {
|
||||
false => {
|
||||
let mut dir_map = HashMap::new();
|
||||
let ready = AtomicBool::new(false);
|
||||
let size = AtomicUsize::default();
|
||||
let dirsize = Arc::new((ready, size));
|
||||
dir_map.insert(dir.to_path_buf(),
|
||||
dirsize);
|
||||
dirsizes.insert(parent_dir.to_path_buf(),
|
||||
dir_map);
|
||||
|
||||
return dirsizes.get(parent_dir)
|
||||
.unwrap()
|
||||
.get(dir)
|
||||
.unwrap()
|
||||
.clone();
|
||||
}
|
||||
true => {
|
||||
let pmap = dirsizes.get_mut(parent_dir).unwrap();
|
||||
|
||||
match pmap.get(dir) {
|
||||
Some(dirsize) => dirsize.clone(),
|
||||
None => {
|
||||
let ready = AtomicBool::new(false);
|
||||
let size = AtomicUsize::default();
|
||||
let dirsize = Arc::new((ready, size));
|
||||
pmap.insert(dir.to_path_buf(), dirsize);
|
||||
|
||||
return pmap.get(dir)
|
||||
.unwrap()
|
||||
.clone()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn watch_only(&self, open_dirs: HashSet<File>) -> HResult<()> {
|
||||
let removable = self.watched_dirs
|
||||
.read()?
|
||||
|
@ -399,18 +462,18 @@ impl TryFrom<DebouncedEvent> for FsEvent {
|
|||
fn try_from(event: DebouncedEvent) -> HResult<Self> {
|
||||
let event = match event {
|
||||
DebouncedEvent::Create(path)
|
||||
=> FsEvent::Create(File::new_from_path(&path, None)?),
|
||||
=> FsEvent::Create(File::new_from_path(&path)?),
|
||||
|
||||
DebouncedEvent::Remove(path)
|
||||
=> FsEvent::Remove(File::new_from_path(&path, None)?),
|
||||
=> FsEvent::Remove(File::new_from_path(&path)?),
|
||||
|
||||
DebouncedEvent::Write(path) |
|
||||
DebouncedEvent::Chmod(path)
|
||||
=> FsEvent::Change(File::new_from_path(&path, None)?),
|
||||
=> FsEvent::Change(File::new_from_path(&path)?),
|
||||
|
||||
DebouncedEvent::Rename(old_path, new_path)
|
||||
=> FsEvent::Rename(File::new_from_path(&old_path, None)?,
|
||||
File::new_from_path(&new_path, None)?),
|
||||
=> FsEvent::Rename(File::new_from_path(&old_path)?,
|
||||
File::new_from_path(&new_path)?),
|
||||
|
||||
DebouncedEvent::Error(err, path)
|
||||
=> Err(HError::INotifyError(format!("{}, {:?}", err, path)))?,
|
||||
|
@ -435,7 +498,7 @@ fn watch_fs(rx_fs_events: Receiver<DebouncedEvent>,
|
|||
let dirpath = path.parent()
|
||||
.map(|path| path)
|
||||
.unwrap_or(std::path::Path::new("/"));
|
||||
let dir = File::new_from_path(&dirpath, None)?;
|
||||
let dir = File::new_from_path(&dirpath)?;
|
||||
let event = FsEvent::try_from(event)?;
|
||||
Ok((dir, event))
|
||||
};
|
||||
|
|
292
src/listview.rs
292
src/listview.rs
|
@ -1,11 +1,11 @@
|
|||
use std::fmt::Debug;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::path::PathBuf;
|
||||
|
||||
use termion::event::Key;
|
||||
use unicode_width::UnicodeWidthStr;
|
||||
use rayon::prelude::*;
|
||||
|
||||
use async_value::{Stale, StopIter};
|
||||
use async_value::Stale;
|
||||
|
||||
use crate::files::{File, Files};
|
||||
use crate::fail::{HResult, HError, ErrorLog};
|
||||
|
@ -103,17 +103,6 @@ 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 mut file = self.content
|
||||
.iter_files()
|
||||
.nth(0)
|
||||
.cloned()
|
||||
.unwrap_or_default();
|
||||
|
||||
if file.meta.is_none() {
|
||||
file.meta_sync().log();
|
||||
}
|
||||
|
||||
self.current_item = Some(file);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -125,6 +114,17 @@ impl Listable for ListView<Files> {
|
|||
self.content.len = 1;
|
||||
}
|
||||
|
||||
let meta_upto = self.content.meta_upto.unwrap_or(0);
|
||||
let ysize = self.core.coordinates.ysize_u();
|
||||
|
||||
if self.offset + ysize >= meta_upto {
|
||||
let sender = self.core.get_sender();
|
||||
let njobs = self.offset + ysize;
|
||||
|
||||
self.content.enqueue_jobs(njobs);
|
||||
self.content.run_jobs(sender);
|
||||
}
|
||||
|
||||
self.refresh_files().log();
|
||||
|
||||
if self.content.is_dirty() {
|
||||
|
@ -147,10 +147,8 @@ where
|
|||
{
|
||||
pub content: T,
|
||||
pub current_item: Option<<ListView<T> as Listable>::Item>,
|
||||
// pub lines: usize,
|
||||
selection: usize,
|
||||
pub offset: usize,
|
||||
//pub buffer: Vec<String>,
|
||||
pub core: WidgetCore,
|
||||
seeking: bool,
|
||||
searching: Option<String>,
|
||||
|
@ -165,10 +163,8 @@ where
|
|||
let mut view = ListView::<T> {
|
||||
content: content,
|
||||
current_item: None,
|
||||
// lines: 0,
|
||||
selection: 0,
|
||||
offset: 0,
|
||||
// buffer: Vec::new(),
|
||||
core: core.clone(),
|
||||
seeking: false,
|
||||
searching: None
|
||||
|
@ -248,6 +244,7 @@ where
|
|||
|
||||
}
|
||||
|
||||
#[derive(PartialEq)]
|
||||
pub enum FileSource {
|
||||
Path(File),
|
||||
Files(Files)
|
||||
|
@ -262,7 +259,6 @@ pub struct FileListBuilder {
|
|||
stale: Option<Stale>,
|
||||
meta_upto: usize,
|
||||
meta_all: bool,
|
||||
prerender: bool
|
||||
}
|
||||
|
||||
impl FileListBuilder {
|
||||
|
@ -275,7 +271,6 @@ impl FileListBuilder {
|
|||
stale: None,
|
||||
meta_upto: 0,
|
||||
meta_all: false,
|
||||
prerender: false
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -304,77 +299,58 @@ impl FileListBuilder {
|
|||
self
|
||||
}
|
||||
|
||||
pub fn prerender(mut self) -> Self {
|
||||
self.prerender = true;
|
||||
self
|
||||
}
|
||||
pub fn build(mut self) -> HResult<ListView<Files>> {
|
||||
// Create new IO pool to not block the main render pool, or other busy IO pools
|
||||
let pool = crate::files::get_pool();
|
||||
|
||||
pub fn build(self) -> HResult<ListView<Files>> {
|
||||
let c = &self.cache;
|
||||
let s = self.stale.clone();
|
||||
let files = match self.source {
|
||||
FileSource::Files(f) => Ok(f),
|
||||
FileSource::Path(f) => {
|
||||
c.as_ref()
|
||||
.map_or_else(| | Files::new_from_path(&f.path),
|
||||
|c| s.map_or_else(| | c.get_files_sync(&f),
|
||||
|s| c.get_files_sync_stale(&f, s)))
|
||||
}
|
||||
}?;
|
||||
let core = self.core;
|
||||
let cfg = core.config();
|
||||
let source = self.source;
|
||||
let selected_file = self.selected_file.take();
|
||||
|
||||
let mut view = ListView::new(&self.core, files);
|
||||
|
||||
let selected_file = match self.selected_file {
|
||||
Some(f) => Some(f),
|
||||
None => {
|
||||
c.as_ref()
|
||||
.map(|c| c.get_selection(&view.content.directory).ok())
|
||||
.flatten()
|
||||
}
|
||||
// Already sorted
|
||||
let nosort = match source {
|
||||
FileSource::Files(_) => true,
|
||||
_ => false
|
||||
};
|
||||
|
||||
selected_file.map(|mut f| {
|
||||
f.meta_sync().log();
|
||||
view.select_file(&f);
|
||||
});
|
||||
|
||||
let from = match self.meta_all {
|
||||
true => 0,
|
||||
false => view.offset,
|
||||
};
|
||||
|
||||
let ysize = view.core.coordinates.ysize_u();
|
||||
let upto = match self.meta_all {
|
||||
true => view.content.len,
|
||||
false => from + ysize + 1
|
||||
};
|
||||
|
||||
view.content
|
||||
.iter_files_mut()
|
||||
.skip(from)
|
||||
.take(upto)
|
||||
.par_bridge()
|
||||
.for_each(|f| {
|
||||
f.meta_sync().log();
|
||||
if f.is_dir() {
|
||||
f.run_dirsize();
|
||||
let files = pool.install(|| -> HResult<Files> {
|
||||
let mut files = match source {
|
||||
FileSource::Files(f) => Ok(f),
|
||||
FileSource::Path(f) => {
|
||||
c.as_ref()
|
||||
.map_or_else(| | unreachable!(),
|
||||
|c| s.map_or_else(| | c.get_files_sync(&f),
|
||||
|s| c.get_files_sync_stale(&f, s)))
|
||||
}
|
||||
});
|
||||
view.content.meta_upto = Some(upto);
|
||||
}?;
|
||||
|
||||
// if self.prerender {
|
||||
// match self.stale {
|
||||
// Some(s) => view.render_buffer_stale(s)?,
|
||||
// None => view.render_buffer()?
|
||||
// }
|
||||
// Check/set hidden flag and recalculate number of files if it's different
|
||||
if !files.show_hidden == cfg.show_hidden() {
|
||||
files.show_hidden = cfg.show_hidden();
|
||||
files.recalculate_len();
|
||||
}
|
||||
|
||||
// if view.buffer.len() > 0 {
|
||||
// view.lines = view.buffer.len() - 1;
|
||||
// }
|
||||
// };
|
||||
// TODO: Fix sorting so it works with lazy/partial sorting
|
||||
if !nosort {
|
||||
files.sort();
|
||||
}
|
||||
|
||||
Ok(files)
|
||||
})?;
|
||||
|
||||
let mut view = ListView::new(&core, files);
|
||||
|
||||
selected_file
|
||||
.or_else(|| c.as_ref()
|
||||
.and_then(|c| c.get_selection(&view.content.directory).ok()))
|
||||
.map(|f| view.select_file(&f));
|
||||
|
||||
self.stale.map(|s| view.content.stale = Some(s));
|
||||
self.cache.map(|c| view.content.cache = Some(c));
|
||||
view.content.set_clean();
|
||||
// view.content.dirty_meta.set_clean();
|
||||
view.core.set_clean();
|
||||
|
||||
Ok(view)
|
||||
|
@ -386,6 +362,7 @@ impl ListView<Files>
|
|||
pub fn builder(core: WidgetCore, source: FileSource) -> FileListBuilder {
|
||||
FileListBuilder::new(core, source)
|
||||
}
|
||||
|
||||
pub fn update_selected_file(&mut self) {
|
||||
let pos = self.selection;
|
||||
|
||||
|
@ -398,7 +375,10 @@ impl ListView<Files>
|
|||
}
|
||||
|
||||
pub fn selected_file(&self) -> &File {
|
||||
self.current_item.as_ref().unwrap()
|
||||
self.current_item
|
||||
.as_ref()
|
||||
.or_else(|| self.content.iter_files().nth(0))
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
pub fn selected_file_mut(&mut self) -> &mut File {
|
||||
|
@ -430,43 +410,39 @@ impl ListView<Files>
|
|||
self.selected_file().grand_parent()
|
||||
}
|
||||
|
||||
pub fn goto_grand_parent(&mut self) -> HResult<()> {
|
||||
match self.grand_parent() {
|
||||
Some(grand_parent) => self.goto_path(&grand_parent),
|
||||
None => { self.core.show_status("Can't go further!") },
|
||||
}
|
||||
}
|
||||
|
||||
fn goto_selected(&mut self) -> HResult<()> {
|
||||
let path = self.selected_file().path();
|
||||
|
||||
self.goto_path(&path)
|
||||
}
|
||||
|
||||
pub fn goto_path(&mut self, path: &Path) -> HResult<()> {
|
||||
match crate::files::Files::new_from_path(path) {
|
||||
Ok(files) => {
|
||||
self.content = files;
|
||||
self.selection = 0;
|
||||
self.offset = 0;
|
||||
self.refresh()
|
||||
}
|
||||
Err(err) => {
|
||||
self.core.show_status(&format!("Can't open this path: {}", err))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn select_file(&mut self, file: &File) {
|
||||
let file = file.clone();
|
||||
self.current_item = Some(file);
|
||||
|
||||
let pos = self
|
||||
let posfile = self
|
||||
.content
|
||||
.iter_files()
|
||||
.position(|item| item == self.selected_file())
|
||||
.unwrap_or(0);
|
||||
self.set_selection(pos);
|
||||
.collect::<Vec<&File>>()
|
||||
.into_par_iter()
|
||||
.enumerate()
|
||||
.find_any(|(_, item)| item == &&file);
|
||||
|
||||
match posfile {
|
||||
Some((i, file)) => {
|
||||
self.current_item = Some(file.clone());
|
||||
self.set_selection(i);
|
||||
}
|
||||
// Something went wrong?
|
||||
None => {
|
||||
let dir = &self.content.directory.path;
|
||||
let file = file.path;
|
||||
|
||||
HError::wrong_directory::<()>(dir.clone(),
|
||||
file.clone()).log();
|
||||
let file = self.content
|
||||
.iter_files()
|
||||
.nth(0)
|
||||
.cloned()
|
||||
.or_else(|| File::new_placeholder(dir).ok())
|
||||
.unwrap();
|
||||
self.current_item = Some(file);
|
||||
self.set_selection(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn cycle_sort(&mut self) {
|
||||
|
@ -570,10 +546,6 @@ impl ListView<Files>
|
|||
file.toggle_selection();
|
||||
|
||||
if !self.content.filter_selected {
|
||||
//let selection = self.get_selection();
|
||||
//let line = self.render_line(&file);
|
||||
//self.buffer[selection] = line;
|
||||
|
||||
self.move_down();
|
||||
} else {
|
||||
if self.content.filter_selected && self.content.len() == 0 {
|
||||
|
@ -610,15 +582,6 @@ 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();
|
||||
// self.buffer[selection] = line;
|
||||
|
||||
self.move_down();
|
||||
Ok(())
|
||||
}
|
||||
|
@ -773,6 +736,8 @@ impl ListView<Files>
|
|||
#[allow(trivial_bounds)]
|
||||
fn render_line_fn(&self) -> impl Fn(&File) -> String {
|
||||
use std::fmt::Write;
|
||||
use crate::files::FileError;
|
||||
|
||||
let xsize = self.get_coordinates().unwrap().xsize();
|
||||
let icons = self.core.config().icons;
|
||||
|
||||
|
@ -788,8 +753,13 @@ impl ListView<Files>
|
|||
|
||||
let size = file.calculate_size();
|
||||
let (size, unit) = match size {
|
||||
Ok((size, unit)) => (size, unit),
|
||||
Err(_) => (0 as u32, "")
|
||||
Ok((size, unit)) => (size.to_string(), unit),
|
||||
Err(HError::FileError(FileError::MetaPending)) => {
|
||||
// Using mod 5 explicitly here for that nice nonlinear look
|
||||
let ticks = crate::files::tick_str();
|
||||
(String::from(ticks), "")
|
||||
},
|
||||
Err(_) => (String::from("ERR"), "")
|
||||
};
|
||||
|
||||
let (tag, tag_len) = match file.is_tagged() {
|
||||
|
@ -834,18 +804,18 @@ impl ListView<Files>
|
|||
|
||||
write!(&mut line, "{}", termion::cursor::Save).unwrap();
|
||||
|
||||
match &file.color {
|
||||
match file.get_color() {
|
||||
Some(color) => write!(&mut line,
|
||||
"{}{}{}{}{}{:padding$}{}",
|
||||
tag,
|
||||
term::from_lscolor(color),
|
||||
&color,
|
||||
selection_color,
|
||||
selection_gap,
|
||||
icon,
|
||||
&sized_string,
|
||||
term::normal_color(),
|
||||
padding = padding as usize),
|
||||
None => write!(&mut line,
|
||||
_ => write!(&mut line,
|
||||
"{}{}{}{}{}{:padding$}{}",
|
||||
tag,
|
||||
term::normal_color(),
|
||||
|
@ -885,55 +855,17 @@ impl ListView<Files>
|
|||
.collect()
|
||||
}
|
||||
|
||||
fn render_buffer(&mut self) -> HResult<()> {
|
||||
// let render_fn = self.render_line_fn();
|
||||
// self.buffer = self.content
|
||||
// .iter_files()
|
||||
// .enumerate()
|
||||
// .map(|(_, file)| {
|
||||
// render_fn(file)
|
||||
// })
|
||||
// .collect();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn render_buffer_stale(&mut self, stale: Stale) -> HResult<()> {
|
||||
// let render_fn = self.render_line_fn();
|
||||
// let buffer = self.content
|
||||
// .iter_files()
|
||||
// .stop_stale(stale.clone())
|
||||
// .enumerate()
|
||||
// .map(|(_, file)| {
|
||||
// render_fn(file)
|
||||
// })
|
||||
// .collect();
|
||||
|
||||
// if stale.is_stale()
|
||||
// .unwrap_or(true) {
|
||||
// return HError::stale();
|
||||
// } else {
|
||||
// self.buffer = buffer;
|
||||
// return Ok(())
|
||||
// }
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn refresh_files(&mut self) -> HResult<()> {
|
||||
// if let Ok(Some(mut refresh)) = self.content.get_refresh() {
|
||||
// let file = self.clone_selected_file();
|
||||
let file = self.clone_selected_file();
|
||||
|
||||
// self.buffer = refresh.new_buffer.take()?;
|
||||
// self.lines = self.buffer.len() - 1;
|
||||
if let Ok(Some(_)) = self.content.get_refresh() {
|
||||
self.select_file(&file);
|
||||
self.content.run_jobs(self.core.get_sender());
|
||||
}
|
||||
|
||||
// self.select_file(&file);
|
||||
// }
|
||||
|
||||
// if self.content.ready_to_refresh()? {
|
||||
// let render_fn = self.render_line_fn();
|
||||
// self.content.process_fs_events(self.buffer.clone(),
|
||||
// self.core.get_sender(),
|
||||
// render_fn)?;
|
||||
// }
|
||||
if self.content.ready_to_refresh()? {
|
||||
self.content.process_fs_events(self.core.get_sender())?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -953,18 +885,10 @@ where
|
|||
fn refresh(&mut self) -> HResult<()> {
|
||||
self.on_refresh().log();
|
||||
|
||||
// let buffer_len = self.buffer.len();
|
||||
|
||||
// self.lines = buffer_len;
|
||||
|
||||
if self.selection >= self.len() && self.len() != 0 {
|
||||
self.selection = self.len() - 1;
|
||||
}
|
||||
|
||||
// if self.core.is_dirty() {
|
||||
// self.buffer = self.render();
|
||||
// self.core.set_clean();
|
||||
// }
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
|
@ -460,10 +460,9 @@ impl Previewer {
|
|||
let source = FileSource::Path(file.clone());
|
||||
|
||||
let mut file_list = ListView::builder(core.clone(), source)
|
||||
// .prerender()
|
||||
.with_cache(cache)
|
||||
.with_stale(stale.clone())
|
||||
.build()?;
|
||||
.with_cache(cache)
|
||||
.with_stale(stale.clone())
|
||||
.build()?;
|
||||
|
||||
if stale.is_stale()? { return Previewer::preview_failed(&file) }
|
||||
|
||||
|
|
|
@ -33,11 +33,8 @@ pub trait PathBufMime {
|
|||
|
||||
impl PathBufMime for PathBuf {
|
||||
fn get_mime(&self) -> HResult<String> {
|
||||
let mut file = File::new_from_path(&self, None)
|
||||
let file = File::new_from_path(&self)
|
||||
.map_err(|e| MimeError::AccessFailed(Box::new(e)))?;
|
||||
file.meta_sync()
|
||||
.map_err(|e| MimeError::AccessFailed(Box::new(e)))?;
|
||||
|
||||
|
||||
file.get_mime()
|
||||
.map(|mime| {
|
||||
|
|
Loading…
Reference in New Issue