From d5ccfb0d7403bea77e027a9ca930c81bed5a2314 Mon Sep 17 00:00:00 2001 From: rabite Date: Thu, 4 Apr 2019 00:31:01 +0200 Subject: [PATCH] show fs space usage and too much other stuff --- Cargo.toml | 2 ++ src/file_browser.rs | 88 +++++++++++++++++++++++++-------------------- src/files.rs | 19 ++++++++-- src/fscache.rs | 38 ++++++++++++++++++-- src/listview.rs | 25 +++++++++++-- src/main.rs | 3 +- src/preview.rs | 4 +-- src/stats.rs | 84 +++++++++++++++++++++++++++++++++++++++++++ src/term.rs | 44 ++++++++++++++++++----- src/widget.rs | 2 +- 10 files changed, 251 insertions(+), 58 deletions(-) create mode 100644 src/stats.rs diff --git a/Cargo.toml b/Cargo.toml index 0c02c56..278f2ea 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,6 +23,8 @@ failure_derive = "0.1.1" notify = "4.0.9" parse-ansi = "0.1.6" signal-notify = "0.1.3" +systemstat = "0.1.4" + #[profile.release] #debug = true diff --git a/src/file_browser.rs b/src/file_browser.rs index a7f4b19..cb5e40f 100644 --- a/src/file_browser.rs +++ b/src/file_browser.rs @@ -1,7 +1,7 @@ use termion::event::Key; use std::io::Write; -use std::sync::{Arc, Mutex}; +use std::sync::{Arc, Mutex, RwLock}; use std::path::PathBuf; use std::ffi::OsString; use std::collections::HashSet; @@ -23,6 +23,7 @@ use crate::term::ScreenExt; use crate::foldview::LogView; use crate::coordinates::Coordinates; use crate::dirty::Dirtyable; +use crate::stats::{FsStat, FsExt}; #[derive(PartialEq)] pub enum FileBrowserWidgets { @@ -78,6 +79,7 @@ pub struct FileBrowser { bookmarks: Arc>, log_view: Arc>, fs_cache: FsCache, + fs_stat: Arc> } impl Tabbable for TabView { @@ -95,6 +97,7 @@ impl Tabbable for TabView { tab.proc_view = proc_view; tab.bookmarks = bookmarks; tab.log_view = log_view; + tab.fs_stat = cur_tab.fs_stat.clone(); self.push_widget(tab)?; self.active = self.widgets.len() - 1; @@ -187,10 +190,14 @@ impl Tabbable for TabView { }); self.active_tab_mut_().fs_cache.watch_only(open_dirs).log(); + self.active_tab_mut_().fs_stat.write()?.refresh().log(); Ok(()) } fn on_config_loaded(&mut self) -> HResult<()> { + // hack: wait a bit for widget readyness... + std::thread::sleep_ms(100); + let show_hidden = self.config().show_hidden(); for tab in self.widgets.iter_mut() { tab.left_widget_mut().map(|w| { @@ -198,7 +205,14 @@ impl Tabbable for TabView { w.content.dirty_meta.set_dirty(); w.refresh().log(); }).ok(); - tab.main_widget_mut().map(|w| w.content.show_hidden = show_hidden).ok(); + + tab.main_widget_mut().map(|w| { + w.content.show_hidden = show_hidden; + w.content.dirty_meta.set_dirty(); + w.content.sort(); + w.refresh().log(); + }).ok(); + tab.preview_widget_mut().map(|w| w.config_loaded()).ok(); } Ok(()) @@ -256,6 +270,8 @@ impl FileBrowser { list.select_file(&file); } + list.content.meta_all(); + list.content.dirty_meta.set_dirty(); list.refresh().log(); if startup { @@ -320,6 +336,7 @@ impl FileBrowser { let proc_view = ProcView::new(&core); let bookmarks = BMPopup::new(&core); let log_view = LogView::new(&core, vec![]); + let fs_stat = FsStat::new().unwrap(); @@ -331,6 +348,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)) }) } @@ -636,31 +654,6 @@ impl FileBrowser { HError::no_files() } - // pub fn take_preview_files(&mut self) -> HResult { - // let widget = self.columns.remove_widget(2); - // if let Filxx - // } - - // pub fn take_files_from_widget(&self, - // widget: FileBrowserWidgets) -> HResult { - // 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> { Ok(&self.main_widget()?.content) } @@ -676,12 +669,12 @@ impl FileBrowser { self.main_widget_mut()?.content.meta_updated = false; - if self.cwd.parent().is_some() { - let left_selection = self.left_widget()?.clone_selected_file(); - let left_files = self.get_left_files()?; - self.fs_cache.put_files(left_files, Some(left_selection)).log(); - self.left_widget_mut()?.content.meta_updated = false; - } + // if self.cwd.parent().is_some() { + // let left_selection = self.left_widget()?.clone_selected_file(); + // let left_files = self.get_left_files()?; + // self.fs_cache.put_files(left_files, Some(left_selection)).log(); + // self.left_widget_mut()?.content.meta_updated = false; + // } Ok(()) } @@ -929,6 +922,18 @@ impl FileBrowser { let count_xpos = xsize - file_count.len() as u16; let count_ypos = ypos + self.get_coordinates()?.ysize(); + let fs = self.fs_stat.read()?.find_fs(&file.path)?.clone(); + + let dev = fs.get_dev(); + let free_space = fs.get_free(); + let total_space = fs.get_total(); + let space = format!("{}: {} / {}", + dev, + free_space, + total_space); + + let space_xpos = count_xpos - space.len() as u16 - 5; // - 3; + let status = format!("{} {}:{} {}{} {}{}", permissions, user, @@ -940,10 +945,13 @@ impl FileBrowser { ); let status = crate::term::sized_string_u(&status, (xsize-1) as usize); - let status = format!("{}{}{}{}", + let status = format!("{}{}{}{}{}{} | {}", status, crate::term::header_color(), - crate::term::goto_xy(count_xpos, count_ypos), + crate::term::goto_xy(space_xpos, count_ypos), + crate::term::color_orange(), + space, + crate::term::header_color(), file_count); Ok(status) @@ -972,9 +980,13 @@ impl Widget for FileBrowser { let file = self.selected_file()?; let name = &file.name; - let color = if file.is_dir() || file.color.is_none() { - crate::term::highlight_color() } else { - crate::term::from_lscolor(file.color.as_ref().unwrap()) }; + 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()) + }; let path = self.cwd.short_string(); diff --git a/src/files.rs b/src/files.rs index b3c13e4..637b99a 100644 --- a/src/files.rs +++ b/src/files.rs @@ -329,8 +329,21 @@ impl Files { pub fn replace_file(&mut self, old: Option<&File>, new: Option) -> HResult<()> { + let (tag, selected) = if let Some(old) = old { + if let Some(old) = self.find_file_with_path(&old.path) { + (old.tag, old.selected) + } else { + (None, false) + } + } else { + (None, false) + }; old.map(|old| self.files.remove_item(old)); - new.map(|new| self.files.push(new)); + new.map(|mut new| { + new.tag = tag; + new.selected = selected; + self.files.push(new); + }); self.sort(); Ok(()) } @@ -913,7 +926,7 @@ impl File { if file_user.name() == cur_user { crate::term::color_green() } else { - crate::term::color_yellow() }; + crate::term::color_red() }; Some(format!("{}{}", color, file_user.name().to_string_lossy())) } @@ -926,7 +939,7 @@ impl File { if file_group.name() == cur_group { crate::term::color_green() } else { - crate::term::color_yellow() }; + crate::term::color_red() }; Some(format!("{}{}", color, file_group.name().to_string_lossy())) } diff --git a/src/fscache.rs b/src/fscache.rs index ba0212f..7add081 100644 --- a/src/fscache.rs +++ b/src/fscache.rs @@ -115,8 +115,10 @@ impl FsCache { self.add_watch(&dir).log(); let dir = dir.clone(); let selection = self.get_selection(&dir).ok(); + let cache = self.clone(); let files = Async::new(Box::new(move |_| { - let files = Files::new_from_path_cancellable(&dir.path, stale)?; + let mut files = Files::new_from_path_cancellable(&dir.path, stale)?; + FsCache::apply_settingss(&cache, &mut files).ok(); Ok(files) })); Ok((selection, files)) @@ -126,7 +128,9 @@ impl FsCache { pub fn get_files_sync(&self, dir: &File) -> HResult { self.add_watch(&dir).log(); let files = self.get_files(&dir, Stale::new())?.1; - files.wait() + let mut files = files.wait()?; + FsCache::apply_settingss(&self, &mut files).ok(); + Ok(files) } pub fn get_selection(&self, dir: &File) -> HResult { @@ -232,6 +236,36 @@ impl FsCache { Ok((selection, files)) } + + pub fn apply_settingss(cache: &FsCache, + files: &mut Files) + -> HResult<()> { + let dir = &files.directory; + let tab_settings = cache.tab_settings.read()?.get(&dir).cloned(); + if tab_settings.is_none() { return Ok(()) } + let tab_settings = tab_settings?; + + files.sort = tab_settings.dir_settings.sort; + files.dirs_first = tab_settings.dir_settings.dirs_first; + files.reverse = tab_settings.dir_settings.reverse; + files.show_hidden = tab_settings.dir_settings.show_hidden; + files.filter = tab_settings.dir_settings.filter.clone(); + + if tab_settings.multi_selections.len() > 0 { + for file in &mut files.files { + for selected_files in &tab_settings.multi_selections { + if file.path == selected_files.path { + file.selected = true; + } + } + } + } + + files.sort(); + Ok(()) + } + + fn extract_tab_settings(files: &Files, selection: Option) -> TabSettings { TabSettings { selection: selection, diff --git a/src/listview.rs b/src/listview.rs index ddf8c90..92fac5f 100644 --- a/src/listview.rs +++ b/src/listview.rs @@ -65,6 +65,8 @@ impl Listable for ListView { self.move_down(); self.refresh()?; }, + Key::Char('<') => self.move_top(), + Key::Char('>') => self.move_bottom(), Key::Char('S') => { self.search_file().log(); } Key::Alt('s') => { self.search_next().log(); } Key::Alt('S') => { self.search_prev().log(); } @@ -72,6 +74,7 @@ impl Listable for ListView { Key::Left => self.goto_grand_parent()?, Key::Right => self.goto_selected()?, Key::Char(' ') => self.multi_select_file(), + Key::Char('v') => self.invert_selection(), Key::Char('t') => self.toggle_tag()?, Key::Char('h') => self.toggle_hidden(), Key::Char('r') => self.reverse_sort(), @@ -146,6 +149,15 @@ where self.seeking = false; } + pub fn move_top(&mut self) { + self.set_selection(0); + } + + pub fn move_bottom(&mut self) { + let lines = self.lines; + self.set_selection(lines - 1); + } + pub fn get_selection(&self) -> usize { self.selection } @@ -154,8 +166,7 @@ where let ysize = self.get_coordinates().unwrap().ysize() as usize; let mut offset = 0; - while position + 2 - >= ysize + offset { + while position >= ysize + offset { offset += 1 } @@ -175,7 +186,7 @@ impl ListView pub fn selected_file_mut(&mut self) -> &mut File { let selection = self.selection; - let mut file = self.content.get_file_mut(selection); + let file = self.content.get_file_mut(selection); file.unwrap() } @@ -325,6 +336,14 @@ impl ListView self.move_down(); } + pub fn invert_selection(&mut self) { + for file in self.content.get_files_mut() { + file.toggle_selection(); + } + self.content.set_dirty(); + self.refresh().log(); + } + fn toggle_tag(&mut self) -> HResult<()> { self.selected_file_mut().toggle_tag()?; diff --git a/src/main.rs b/src/main.rs index 4d77667..1d2451c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -21,6 +21,7 @@ extern crate notify; extern crate parse_ansi; extern crate signal_notify; extern crate tree_magic; +extern crate systemstat; use failure::Fail; @@ -50,7 +51,7 @@ mod foldview; mod dirty; mod fscache; mod config; - +mod stats; diff --git a/src/preview.rs b/src/preview.rs index a6a99a7..9aecdbc 100644 --- a/src/preview.rs +++ b/src/preview.rs @@ -644,7 +644,7 @@ impl Previewer { if is_stale(&stale)? { return Previewer::preview_failed(&file) } - let output = dbg!(process.wait_with_output())?; + let output = process.wait_with_output()?; if is_stale(&stale)? { return Previewer::preview_failed(&file) } { @@ -652,7 +652,7 @@ impl Previewer { *pid_ = None; } - let status = output.status.code()?; + //let status = output.status.code()?; if !is_stale(&stale)? { let output = std::str::from_utf8(&output.stdout) diff --git a/src/stats.rs b/src/stats.rs new file mode 100644 index 0000000..10c83b0 --- /dev/null +++ b/src/stats.rs @@ -0,0 +1,84 @@ +use systemstat::{System, Platform}; +use systemstat::data::Filesystem; + +use std::path::{Path, PathBuf, Component}; +use std::collections::HashMap; + +use crate::fail::{HResult, ErrorLog}; + +#[derive(Debug,Clone)] +pub struct FsStat { + pub stats: HashMap +} + +impl FsStat { + pub fn new() -> HResult { + let mut stats = FsStat { stats: HashMap::new() }; + stats.refresh().log(); + + Ok(stats) + } + + pub fn refresh(&mut self) -> HResult<()> { + let sys = System::new(); + let mounts = sys.mounts()?; + + let stats = mounts.into_iter() + .fold(HashMap::new(), |mut stats, mount: Filesystem| { + let path = PathBuf::from(&mount.fs_mounted_on); + stats.insert(path, mount); + stats + }); + + self.stats = stats; + + Ok(()) + } + + pub fn find_fs(&self, path: &Path) -> HResult<&Filesystem> { + let candidates = self + .stats + .keys() + .filter(|mount_point| path.starts_with(&mount_point)) + .collect::>(); + + let deepest_match = candidates.iter() + .fold(PathBuf::new(), |mut deepest, path| { + let curren_path_len = deepest.components().count(); + let candidate_path_len = path.components().count(); + + if candidate_path_len > curren_path_len { + deepest = path.to_path_buf(); + } + deepest + }); + let fs = self.stats.get(&deepest_match)?; + Ok(fs) + } +} + +pub trait FsExt { + fn get_dev(&self) -> String; + fn get_total(&self) -> String; + fn get_free(&self) -> String; +} + +impl FsExt for Filesystem { + fn get_dev(&self) -> String { + let path = PathBuf::from(&self.fs_mounted_from); + let dev = path.components().last().unwrap(); + let dev = match dev { + Component::Normal(dev) => dev.to_string_lossy().to_string(), + _ => "wtf".to_string() + }; + dev + } + + fn get_total(&self) -> String { + self.total.to_string(false) + } + + fn get_free(&self) -> String { + self.free.to_string(false) + } +} diff --git a/src/term.rs b/src/term.rs index bc99c36..f9a3347 100644 --- a/src/term.rs +++ b/src/term.rs @@ -249,16 +249,44 @@ pub fn color_green() -> String { format!("{}", termion::color::Fg(termion::color::Green)) } +pub fn color_light_green() -> String { + format!("{}", termion::color::Fg(termion::color::LightGreen)) +} + +pub fn color_cyan() -> String { + format!("{}", termion::color::Fg(termion::color::Cyan)) +} + +pub fn color_light_yellow() -> String { + format!("{}", termion::color::Fg(termion::color::LightYellow)) +} + +pub fn color_orange() -> String { + let color = termion::color::Fg(termion::color::AnsiValue::rgb(5 as u8 , + 4 as u8, + 0 as u8)); + format!("{}", color) +} + + pub fn from_lscolor(color: &lscolors::Color) -> String { match color { - lscolors::Color::Black => format!("{}", termion::color::Fg(termion::color::Black)), - lscolors::Color::Red => format!("{}", termion::color::Fg(termion::color::Red)), - lscolors::Color::Green => format!("{}", termion::color::Fg(termion::color::Green)), - lscolors::Color::Yellow => format!("{}", termion::color::Fg(termion::color::Yellow)), - lscolors::Color::Blue => format!("{}", termion::color::Fg(termion::color::Blue)), - lscolors::Color::Magenta => format!("{}", termion::color::Fg(termion::color::Magenta)), - lscolors::Color::Cyan => format!("{}", termion::color::Fg(termion::color::Cyan)), - lscolors::Color::White => format!("{}", termion::color::Fg(termion::color::White)), + lscolors::Color::Black + => format!("{}", termion::color::Fg(termion::color::Black)), + lscolors::Color::Red + => format!("{}", termion::color::Fg(termion::color::Red)), + lscolors::Color::Green + => format!("{}", termion::color::Fg(termion::color::Green)), + lscolors::Color::Yellow + => format!("{}", termion::color::Fg(termion::color::Yellow)), + lscolors::Color::Blue + => format!("{}", termion::color::Fg(termion::color::Blue)), + lscolors::Color::Magenta + => format!("{}", termion::color::Fg(termion::color::Magenta)), + lscolors::Color::Cyan + => format!("{}", termion::color::Fg(termion::color::Cyan)), + lscolors::Color::White + => format!("{}", termion::color::Fg(termion::color::White)), _ => format!("{}", normal_color()), } } diff --git a/src/widget.rs b/src/widget.rs index 0d9b72a..8525677 100644 --- a/src/widget.rs +++ b/src/widget.rs @@ -392,7 +392,7 @@ pub trait Widget { } Events::ConfigLoaded => { self.get_core_mut()?.config.write()?.take_async().log(); - self.config_loaded(); + self.config_loaded().log(); } _ => {} }