diff options
author | Jiayi Zhao <jeff.no.zhao@gmail.com> | 2020-02-16 22:01:27 -0500 |
---|---|---|
committer | Jiayi Zhao <jeff.no.zhao@gmail.com> | 2020-02-16 22:01:27 -0500 |
commit | 686033bfcf6d34bfb180e0b0f64ae4493340bf38 (patch) | |
tree | f9318e77aaa6dd317d084676faf4eeb0d99d09d0 /src/ui/widgets | |
parent | 88da91c0f97dcb40e7e4cab54941af92a46d2e1a (diff) |
move topbar functionality into widget
- add ability to show file sizes in the main column
Diffstat (limited to 'src/ui/widgets')
-rw-r--r-- | src/ui/widgets/mod.rs | 4 | ||||
-rw-r--r-- | src/ui/widgets/tui_dirlist.rs | 181 | ||||
-rw-r--r-- | src/ui/widgets/tui_topbar.rs | 41 |
3 files changed, 175 insertions, 51 deletions
diff --git a/src/ui/widgets/mod.rs b/src/ui/widgets/mod.rs index 9ace2b7..e619450 100644 --- a/src/ui/widgets/mod.rs +++ b/src/ui/widgets/mod.rs @@ -1,3 +1,5 @@ +pub mod tui_topbar; pub mod tui_dirlist; -pub use self::tui_dirlist::TuiDirList; +pub use self::tui_dirlist::{TuiDirList, TuiDirListDetailed}; +pub use self::tui_topbar::TuiTopBar; diff --git a/src/ui/widgets/tui_dirlist.rs b/src/ui/widgets/tui_dirlist.rs index cda2da9..73425c4 100644 --- a/src/ui/widgets/tui_dirlist.rs +++ b/src/ui/widgets/tui_dirlist.rs @@ -1,88 +1,109 @@ -use std::io::{self, Write}; - use tui::buffer::Buffer; use tui::layout::Rect; use tui::style::{Color, Modifier, Style}; use tui::widgets::Widget; +use unicode_width::UnicodeWidthStr; +use unicode_width::UnicodeWidthChar; use crate::fs::JoshutoDirList; -/* -pub struct TermionWindow<'a> { - rect: Rect, + +pub struct TuiDirList<'a> { dirlist: &'a JoshutoDirList, } -impl<'a> TermionWindow<'a> { - pub fn new(rect: &Rect, dirlist: &'a JoshutoDirList) -> Self { - Self { - rect: rect.clone(), - dirlist - } - } - - pub fn update_rect(&mut self, rect: &Rect) { - self.rect = rect.clone(); +impl<'a> TuiDirList<'a> { + pub fn new(dirlist: &'a JoshutoDirList) -> Self { + Self { dirlist } } +} - pub fn clear<W: Write>(&self, terminal: &mut W) { - for i in 1..self.rect.height + 1 { - write!(terminal, "{}{}", Goto(self.rect.width, i as u16), clear::BeforeCursor); +impl<'a> Widget for TuiDirList<'a> { + fn draw(&mut self, area: Rect, buf: &mut Buffer) { + if area.width < 1 || area.height < 1 { + return; } - } - pub fn draw<W: Write>(&self, terminal: &mut W) { - if self.rect.height < 4 { + if area.width < 4 { return; } + + let x = area.left(); + let y = area.top(); + let dir_len = self.dirlist.contents.len(); if dir_len == 0 { - write!(terminal, "{}EMPTY", Goto(self.rect.x, self.rect.y)); + let style = Style::default().bg(Color::Red).fg(Color::White); + buf.set_stringn(x, y, "empty", area.width as usize, style); return; } let curr_index = self.dirlist.index.unwrap(); + let skip_dist = curr_index / area.height as usize * area.height as usize; + + let screen_index = if skip_dist > 0 { + curr_index % skip_dist + } else { + curr_index + }; - let height = self.rect.height as usize; + let area_width = area.width as usize - 1; + for (i, entry) in self + .dirlist + .contents + .iter() + .skip(skip_dist) + .enumerate() + .take(area.height as usize) + { + let name = entry.file_name(); + let mut style = entry.get_style(); - for (i, entry) in self.dirlist.contents.iter().enumerate() { - let goto_i = i + 1; - if goto_i > height { - break; + if i == screen_index { + style = style.modifier(Modifier::REVERSED); } - let fg = entry.get_fg_color(); - let bg = entry.get_bg_color(); - let file_ansi_text = entry.as_ansi_text(); - - if i == curr_index { - write!(terminal, "{}{}{}{}{}", - Goto(self.rect.x, goto_i as u16), - style::Invert, - bg.bg_str(), - fg.fg_str(), - file_ansi_text); + let name_width = name.width(); + if name_width < area_width { + buf.set_stringn(x, y + i as u16, + name, + area_width, style); } else { - write!(terminal, "{}{}{}{}{}", - Goto(self.rect.x, goto_i as u16), - style::Reset, - bg.bg_str(), - fg.fg_str(), - file_ansi_text); + match name.rfind('.') { + None => { + buf.set_stringn(x, y + i as u16, + name, + area_width, style); + } + Some(p_ind) => { + let ext_width = name[p_ind..].width(); + let file_name_width = area_width - ext_width - 1; + + buf.set_stringn(x, y + i as u16, + &name[..p_ind], + file_name_width, style); + buf.set_string(x + file_name_width as u16, y + i as u16, + "…", style); + buf.set_string(x + file_name_width as u16 + 1, y + i as u16, + &name[p_ind..], style); + } + } } } } } -*/ -pub struct TuiDirList<'a> { + +const FILE_SIZE_WIDTH: usize = 8; + +pub struct TuiDirListDetailed<'a> { dirlist: &'a JoshutoDirList, } -impl<'a> TuiDirList<'a> { +impl<'a> TuiDirListDetailed<'a> { pub fn new(dirlist: &'a JoshutoDirList) -> Self { Self { dirlist } } } -impl<'a> Widget for TuiDirList<'a> { +impl<'a> Widget for TuiDirListDetailed<'a> { fn draw(&mut self, area: Rect, buf: &mut Buffer) { if area.width < 1 || area.height < 1 { return; @@ -97,7 +118,9 @@ impl<'a> Widget for TuiDirList<'a> { let dir_len = self.dirlist.contents.len(); if dir_len == 0 { - let style = Style::default().bg(Color::Red).fg(Color::White); + let style = Style::default() + .bg(Color::Red) + .fg(Color::White); buf.set_stringn(x, y, "empty", area.width as usize, style); return; } @@ -110,6 +133,8 @@ impl<'a> Widget for TuiDirList<'a> { } else { curr_index }; + + let area_width = area.width as usize; for (i, entry) in self .dirlist .contents @@ -124,7 +149,63 @@ impl<'a> Widget for TuiDirList<'a> { if i == screen_index { style = style.modifier(Modifier::REVERSED); } - buf.set_stringn(x, y + i as u16, name, area.width as usize, style); + let file_type = entry.metadata.file_type; + + let name_width = name.width(); + if file_type.is_dir() { + buf.set_stringn(x, y + i as u16, + name, + area_width, style); + continue; + } + + if name_width < area_width - FILE_SIZE_WIDTH { + buf.set_stringn(x, y + i as u16, + name, + area_width - FILE_SIZE_WIDTH, style); + } else { + match name.rfind('.') { + None => { + buf.set_stringn(x, y + i as u16, + name, + area_width - FILE_SIZE_WIDTH, style); + } + Some(p_ind) => { + let ext_width = name[p_ind..].width(); + let file_name_width = area_width - FILE_SIZE_WIDTH - ext_width - 1; + + buf.set_stringn(x, y + i as u16, + &name[..p_ind], + file_name_width, style); + buf.set_string(x + file_name_width as u16, y + i as u16, + "…", style); + buf.set_string(x + file_name_width as u16 + 1, y + i as u16, + &name[p_ind..], style); + } + } + } + let file_size_string = file_size_to_string(entry.metadata.len as f64); + buf.set_string(x + (area_width - FILE_SIZE_WIDTH) as u16, y + i as u16, + file_size_string, style); } } } + +fn file_size_to_string(mut file_size: f64) -> String { + const FILE_UNITS: [&str; 6] = ["B", "K", "M", "G", "T", "E"]; + const CONV_RATE: f64 = 1024.0; + + let mut index = 0; + while file_size > CONV_RATE { + file_size /= CONV_RATE; + index += 1; + } + + if file_size >= 100.0 { + format!("{:>4.0} {}", file_size, FILE_UNITS[index]) + } else if file_size >= 10.0 { + format!("{:>4.1} {}", file_size, FILE_UNITS[index]) + } else { + format!("{:>4.2} {}", file_size, FILE_UNITS[index]) + } +} diff --git a/src/ui/widgets/tui_topbar.rs b/src/ui/widgets/tui_topbar.rs new file mode 100644 index 0000000..6ff46b7 --- /dev/null +++ b/src/ui/widgets/tui_topbar.rs @@ -0,0 +1,41 @@ +use std::path::Path; + +use tui::buffer::Buffer; +use tui::layout::Rect; +use tui::style::{Color, Modifier, Style}; +use tui::widgets::{Paragraph, Text, Widget}; + +use crate::{HOSTNAME, USERNAME}; + +pub struct TuiTopBar<'a> { + path: &'a Path, +} + +impl<'a> TuiTopBar<'a> { + pub fn new(path: &'a Path) -> Self { + Self { path } + } +} + +impl<'a> Widget for TuiTopBar<'a> { + fn draw(&mut self, area: Rect, buf: &mut Buffer) { + let username_style = Style::default() + .fg(Color::LightGreen) + .modifier(Modifier::BOLD); + + let path_style = Style::default() + .fg(Color::LightBlue) + .modifier(Modifier::BOLD); + + let curr_path_str = self.path.to_string_lossy(); + + let text = [ + Text::styled(format!("{}@{} ", *USERNAME, *HOSTNAME), username_style), + Text::styled(curr_path_str, path_style), + ]; + + Paragraph::new(text.iter()) + .wrap(true) + .draw(area, buf); + } +} |