show fs space usage and too much other stuff

This commit is contained in:
rabite 2019-04-04 00:31:01 +02:00
parent 343dd6deda
commit d5ccfb0d74
10 changed files with 251 additions and 58 deletions

View File

@ -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

View File

@ -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<Mutex<BMPopup>>,
log_view: Arc<Mutex<LogView>>,
fs_cache: FsCache,
fs_stat: Arc<RwLock<FsStat>>
}
impl Tabbable for TabView<FileBrowser> {
@ -95,6 +97,7 @@ impl Tabbable for TabView<FileBrowser> {
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<FileBrowser> {
});
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<FileBrowser> {
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<Files> {
// let widget = self.columns.remove_widget(2);
// if let Filxx
// }
// pub fn take_files_from_widget(&self,
// widget: FileBrowserWidgets) -> HResult<Files> {
// 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();

View File

@ -329,8 +329,21 @@ impl Files {
pub fn replace_file(&mut self,
old: Option<&File>,
new: Option<File>) -> 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()))
}

View File

@ -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<Files> {
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<File> {
@ -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<File>) -> TabSettings {
TabSettings {
selection: selection,

View File

@ -65,6 +65,8 @@ impl Listable for ListView<Files> {
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<Files> {
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<Files>
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<Files>
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()?;

View File

@ -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;

View File

@ -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)

84
src/stats.rs Normal file
View File

@ -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<PathBuf, Filesystem>
}
impl FsStat {
pub fn new() -> HResult<FsStat> {
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::<Vec<&PathBuf>>();
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)
}
}

View File

@ -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()),
}
}

View File

@ -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();
}
_ => {}
}