summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJiayi Zhao <jeff.no.zhao@gmail.com>2020-03-21 12:39:54 -0400
committerJiayi Zhao <jeff.no.zhao@gmail.com>2020-03-21 12:39:54 -0400
commitc2de16c1e1d7cc8f5cc40f3ca977e01c6e1a9f2a (patch)
tree7bb04fd08e62f03d34ac500076f4bcd8fbef67a4
parentf2815145cb3da431ebeaf154b8d9964331d6cd4c (diff)
wrap fs::FileType with in-house solution
- This allows for efficient symlink lookup through caching - Theme processing happens upfront rather than recomputing styling over and over
-rw-r--r--src/config/theme.rs54
-rw-r--r--src/fs/dirlist.rs10
-rw-r--r--src/fs/entry.rs119
-rw-r--r--src/fs/metadata.rs51
-rw-r--r--src/fs/mod.rs2
-rw-r--r--src/run.rs3
-rw-r--r--src/ui/widgets/tui_dirlist.rs55
-rw-r--r--src/ui/widgets/tui_dirlist_detailed.rs83
-rw-r--r--src/ui/widgets/tui_footer.rs11
9 files changed, 199 insertions, 189 deletions
diff --git a/src/config/theme.rs b/src/config/theme.rs
index 541c340..02f9a03 100644
--- a/src/config/theme.rs
+++ b/src/config/theme.rs
@@ -1,7 +1,7 @@
use serde_derive::Deserialize;
use std::collections::HashMap;
-use tui::style::Color;
+use tui::style::{Color, Modifier, Style};
use crate::THEME_FILE;
@@ -51,14 +51,21 @@ impl JoshutoStyleThemeRaw {
let bg = Self::str_to_color(self.bg.as_str());
let fg = Self::str_to_color(self.fg.as_str());
- JoshutoStyleTheme {
- bg,
- fg,
- bold: self.bold,
- underline: self.underline,
- invert: self.invert,
- prefix: self.prefix.clone(),
+ let mut modifier = Modifier::empty();
+ if self.bold {
+ modifier.insert(Modifier::BOLD);
}
+ if self.underline {
+ modifier.insert(Modifier::UNDERLINED);
+ }
+ if self.invert {
+ modifier.insert(Modifier::REVERSED);
+ }
+
+ JoshutoStyleTheme::default()
+ .set_fg(fg)
+ .set_bg(bg)
+ .insert(modifier)
}
pub fn str_to_color(s: &str) -> Color {
@@ -162,9 +169,7 @@ impl Flattenable<JoshutoTheme> for JoshutoRawTheme {
pub struct JoshutoStyleTheme {
pub fg: Color,
pub bg: Color,
- pub bold: bool,
- pub underline: bool,
- pub invert: bool,
+ pub modifier: Modifier,
pub prefix: Option<JoshutoPrefix>,
}
@@ -177,16 +182,13 @@ impl JoshutoStyleTheme {
self.fg = fg;
self
}
- pub fn set_bold(mut self, bold: bool) -> Self {
- self.bold = bold;
+ pub fn set_prefix(mut self, prefix: JoshutoPrefix) -> Self {
+ self.prefix = Some(prefix);
self
}
- pub fn set_underline(mut self, bold: bool) -> Self {
- self.bold = bold;
- self
- }
- pub fn set_invert(mut self, bold: bool) -> Self {
- self.bold = bold;
+
+ pub fn insert(mut self, modifier: Modifier) -> Self {
+ self.modifier.insert(modifier);
self
}
}
@@ -196,9 +198,7 @@ impl std::default::Default for JoshutoStyleTheme {
Self {
fg: default_color(),
bg: default_color(),
- bold: false,
- underline: false,
- invert: false,
+ modifier: Modifier::empty(),
prefix: None,
}
}
@@ -226,20 +226,20 @@ impl std::default::Default for JoshutoTheme {
fn default() -> Self {
let selection = JoshutoStyleTheme::default()
.set_fg(Color::LightYellow)
- .set_bold(true);
+ .insert(Modifier::BOLD);
let executable = JoshutoStyleTheme::default()
.set_fg(Color::LightGreen)
- .set_bold(true);
+ .insert(Modifier::BOLD);
let regular = JoshutoStyleTheme::default().set_fg(Color::White);
let directory = JoshutoStyleTheme::default()
.set_fg(Color::LightBlue)
- .set_bold(true);
+ .insert(Modifier::BOLD);
let link = JoshutoStyleTheme::default()
.set_fg(Color::LightCyan)
- .set_bold(true);
+ .insert(Modifier::BOLD);
let socket = JoshutoStyleTheme::default()
.set_fg(Color::LightMagenta)
- .set_bold(true);
+ .insert(Modifier::BOLD);
let ext = HashMap::new();
Self {
diff --git a/src/fs/dirlist.rs b/src/fs/dirlist.rs
index d62664c..d636b2b 100644
--- a/src/fs/dirlist.rs
+++ b/src/fs/dirlist.rs
@@ -139,8 +139,14 @@ fn map_entry_default(result: std::io::Result<fs::DirEntry>) -> Option<JoshutoDir
match result {
Ok(direntry) => match JoshutoDirEntry::from(&direntry) {
Ok(s) => Some(s),
- Err(_) => None,
+ Err(e) => {
+ eprintln!("Entry: {:?}, {:?}", direntry, e);
+ None
+ }
},
- Err(_) => None,
+ Err(e) => {
+ eprintln!("{:?}", e);
+ None
+ }
}
}
diff --git a/src/fs/entry.rs b/src/fs/entry.rs
index 3cba354..80847b4 100644
--- a/src/fs/entry.rs
+++ b/src/fs/entry.rs
@@ -68,7 +68,7 @@ impl JoshutoDirEntry {
pub fn get_fg_color(&self) -> Color {
let metadata = &self.metadata;
- let filetype = metadata.file_type;
+ let filetype = &metadata.file_type;
if self.is_selected() {
THEME_T.selection.fg
@@ -92,7 +92,7 @@ impl JoshutoDirEntry {
pub fn get_bg_color(&self) -> Color {
let metadata = &self.metadata;
- let filetype = metadata.file_type;
+ let filetype = &metadata.file_type;
if self.is_selected() {
THEME_T.selection.bg
@@ -116,119 +116,62 @@ impl JoshutoDirEntry {
pub fn get_modifier(&self) -> Modifier {
let metadata = &self.metadata;
- let filetype = metadata.file_type;
-
- let mut modifier = Modifier::empty();
+ let filetype = &metadata.file_type;
if filetype.is_dir() {
- if THEME_T.directory.bold {
- modifier.insert(Modifier::BOLD);
- }
- if THEME_T.directory.underline {
- modifier.insert(Modifier::UNDERLINED);
- }
+ THEME_T.directory.modifier
} else if filetype.is_symlink() {
- if THEME_T.link.bold {
- modifier.insert(Modifier::BOLD);
- }
- if THEME_T.link.underline {
- modifier.insert(Modifier::UNDERLINED);
- }
+ THEME_T.link.modifier
} else {
match self.file_path().extension() {
- None => {}
+ None => Modifier::empty(),
Some(os_str) => match os_str.to_str() {
- None => {}
+ None => Modifier::empty(),
Some(s) => match THEME_T.ext.get(s) {
- None => {}
- Some(t) => {
- if t.bold {
- modifier.insert(Modifier::BOLD);
- }
- if t.underline {
- modifier.insert(Modifier::UNDERLINED);
- }
- }
+ None => Modifier::empty(),
+ Some(t) => t.modifier,
},
},
- };
+ }
}
- modifier
}
pub fn get_style(&self) -> Style {
let metadata = &self.metadata;
- let filetype = metadata.file_type;
-
- let mut style = Style::default();
+ let filetype = &metadata.file_type;
if self.is_selected() {
- let mut modifier = Modifier::empty();
- if THEME_T.selection.bold {
- modifier.insert(Modifier::BOLD);
- }
- if THEME_T.selection.underline {
- modifier.insert(Modifier::UNDERLINED);
- }
-
- style = style.fg(THEME_T.selection.fg).bg(THEME_T.selection.bg);
- style = style.modifier(modifier);
+ Style::default()
+ .fg(THEME_T.selection.fg)
+ .bg(THEME_T.selection.bg)
+ .modifier(THEME_T.selection.modifier)
} else if filetype.is_dir() {
- let mut modifier = Modifier::empty();
- if THEME_T.directory.bold {
- modifier.insert(Modifier::BOLD);
- }
- if THEME_T.directory.underline {
- modifier.insert(Modifier::UNDERLINED);
- }
-
- style = style.fg(THEME_T.directory.fg).bg(THEME_T.directory.bg);
- style = style.modifier(modifier);
+ Style::default()
+ .fg(THEME_T.directory.fg)
+ .bg(THEME_T.directory.bg)
+ .modifier(THEME_T.directory.modifier)
} else if filetype.is_symlink() {
- let mut modifier = Modifier::empty();
- if THEME_T.link.bold {
- modifier.insert(Modifier::BOLD);
- }
- if THEME_T.link.underline {
- modifier.insert(Modifier::UNDERLINED);
- }
-
- style = style.fg(THEME_T.link.fg).bg(THEME_T.link.bg);
- style = style.modifier(modifier);
+ Style::default()
+ .fg(THEME_T.link.fg)
+ .bg(THEME_T.link.bg)
+ .modifier(THEME_T.link.modifier)
} else if unix::is_executable(metadata.mode) {
- let mut modifier = Modifier::empty();
- if THEME_T.link.bold {
- modifier.insert(Modifier::BOLD);
- }
- if THEME_T.link.underline {
- modifier.insert(Modifier::UNDERLINED);
- }
-
- style = style.fg(THEME_T.executable.fg).bg(THEME_T.executable.bg);
- style = style.modifier(modifier);
+ Style::default()
+ .fg(THEME_T.executable.fg)
+ .bg(THEME_T.executable.bg)
+ .modifier(THEME_T.executable.modifier)
} else {
match self.file_path().extension() {
- None => {}
+ None => Style::default(),
Some(os_str) => match os_str.to_str() {
- None => {}
+ None => Style::default(),
Some(s) => match THEME_T.ext.get(s) {
- None => {}
- Some(t) => {
- let mut modifier = Modifier::empty();
- if t.bold {
- modifier.insert(Modifier::BOLD);
- }
- if t.underline {
- modifier.insert(Modifier::UNDERLINED);
- }
- style = style.fg(t.fg).bg(t.bg);
- style = style.modifier(modifier);
- }
+ None => Style::default(),
+ Some(t) => Style::default().fg(t.fg).bg(t.bg).modifier(t.modifier),
},
},
}
}
- style
}
}
diff --git a/src/fs/metadata.rs b/src/fs/metadata.rs
index 9f3ddd9..9a3fb60 100644
--- a/src/fs/metadata.rs
+++ b/src/fs/metadata.rs
@@ -1,11 +1,41 @@
use std::{fs, path, process, time};
#[derive(Clone, Debug)]
+pub enum FileType {
+ Directory,
+ Symlink(String),
+ File,
+}
+
+impl FileType {
+ pub fn is_dir(&self) -> bool {
+ match *self {
+ Self::Directory => true,
+ _ => false,
+ }
+ }
+
+ pub fn is_symlink(&self) -> bool {
+ match *self {
+ Self::Symlink(_) => true,
+ _ => false,
+ }
+ }
+
+ pub fn is_file(&self) -> bool {
+ match *self {
+ Self::File => true,
+ _ => false,
+ }
+ }
+}
+
+#[derive(Clone, Debug)]
pub struct JoshutoMetadata {
pub len: u64,
pub modified: time::SystemTime,
pub permissions: fs::Permissions,
- pub file_type: fs::FileType,
+ pub file_type: FileType,
pub mimetype: Option<String>,
#[cfg(unix)]
pub uid: u32,
@@ -26,9 +56,24 @@ impl JoshutoMetadata {
let modified = metadata.modified()?;
let permissions = metadata.permissions();
let file_type = metadata.file_type();
- let mut mimetype = None;
- if file_type.is_file() {
+ let file_type = if file_type.is_dir() {
+ FileType::Directory
+ } else if file_type.is_symlink() {
+ let mut link = "".to_string();
+
+ if let Ok(path) = fs::read_link(path) {
+ if let Some(s) = path.to_str() {
+ link = s.to_string();
+ }
+ }
+ FileType::Symlink(link)
+ } else {
+ FileType::File
+ };
+
+ let mut mimetype = None;
+ if let FileType::File = file_type {
#[cfg(feature = "file_mimetype")]
{
mimetype = file_mimetype(path)
diff --git a/src/fs/mod.rs b/src/fs/mod.rs
index 632c2ff..2704bdc 100644
--- a/src/fs/mod.rs
+++ b/src/fs/mod.rs
@@ -4,4 +4,4 @@ mod metadata;
pub use self::dirlist::JoshutoDirList;
pub use self::entry::JoshutoDirEntry;
-pub use self::metadata::JoshutoMetadata;
+pub use self::metadata::{FileType, JoshutoMetadata};
diff --git a/src/run.rs b/src/run.rs
index 65f52c8..23002da 100644
--- a/src/run.rs
+++ b/src/run.rs
@@ -63,7 +63,8 @@ pub fn run(config_t: JoshutoConfig, keymap_t: JoshutoCommandMapping) -> std::io:
let size_string = format::file_size_to_string(s);
format!(
"io_worker completed successfully: {} processed",
- size_string)
+ size_string
+ )
}
Err(e) => format!("io_worker was not completed: {}", e.to_string()),
};
diff --git a/src/ui/widgets/tui_dirlist.rs b/src/ui/widgets/tui_dirlist.rs
index 5eeb23b..8840bda 100644
--- a/src/ui/widgets/tui_dirlist.rs
+++ b/src/ui/widgets/tui_dirlist.rs
@@ -54,12 +54,13 @@ impl<'a> Widget for TuiDirList<'a> {
let name = entry.file_name();
let name_width = name.width();
- let mut style = entry.get_style();
- if i == screen_index {
- style = style.modifier(Modifier::REVERSED);
- }
+ let style = if i == screen_index {
+ entry.get_style().modifier(Modifier::REVERSED)
+ } else {
+ entry.get_style()
+ };
- let file_type = entry.metadata.file_type;
+ let file_type = &entry.metadata.file_type;
if file_type.is_dir() {
if name_width <= area_width {
buf.set_stringn(x, y + i as u16, name, area_width, style);
@@ -67,27 +68,33 @@ impl<'a> Widget for TuiDirList<'a> {
buf.set_stringn(x, y + i as u16, name, area_width - 1, style);
buf.set_string(x + area_width as u16 - 1, y + i as u16, "…", style);
}
- continue;
- }
- if name_width < area_width {
- buf.set_stringn(x, y + i as u16, name, area_width, style);
} else {
- 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;
+ if name_width < area_width {
+ buf.set_stringn(x, y + i as u16, name, area_width, style);
+ } else {
+ 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,
- );
+ 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,
+ );
+ }
}
}
}
diff --git a/src/ui/widgets/tui_dirlist_detailed.rs b/src/ui/widgets/tui_dirlist_detailed.rs
index 5ec8633..ac7da28 100644
--- a/src/ui/widgets/tui_dirlist_detailed.rs
+++ b/src/ui/widgets/tui_dirlist_detailed.rs
@@ -21,11 +21,7 @@ impl<'a> TuiDirListDetailed<'a> {
impl<'a> Widget for TuiDirListDetailed<'a> {
fn draw(&mut self, area: Rect, buf: &mut Buffer) {
- if area.width < 1 || area.height < 1 {
- return;
- }
-
- if area.width < 4 {
+ if area.width < 4 || area.height < 1 {
return;
}
@@ -58,12 +54,13 @@ impl<'a> Widget for TuiDirListDetailed<'a> {
let name = entry.file_name();
let name_width = name.width();
- let mut style = entry.get_style();
- if i == screen_index {
- style = style.modifier(Modifier::REVERSED);
- }
+ let style = if i == screen_index {
+ entry.get_style().modifier(Modifier::REVERSED)
+ } else {
+ entry.get_style()
+ };
- let file_type = entry.metadata.file_type;
+ let file_type = &entry.metadata.file_type;
if file_type.is_dir() {
if name_width <= area_width {
buf.set_stringn(x, y + i as u16, name, area_width, style);
@@ -71,38 +68,50 @@ impl<'a> Widget for TuiDirListDetailed<'a> {
buf.set_stringn(x, y + i as u16, name, area_width - 1, style);
buf.set_string(x + area_width as u16 - 1, y + i as u16, "…", 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 if file_type.is_symlink() {
} 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 - 2;
+ 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 - 2;
- 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,
- );
+ 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 = format::file_size_to_string(entry.metadata.len);
+ buf.set_string(
+ x + (area_width - FILE_SIZE_WIDTH) as u16,
+ y + i as u16,
+ file_size_string,
+ style,
+ );
}
- let file_size_string = format::file_size_to_string(entry.metadata.len);
- buf.set_string(
- x + (area_width - FILE_SIZE_WIDTH) as u16,
- y + i as u16,
- file_size_string,
- style,
- );
}
}
}
diff --git a/src/ui/widgets/tui_footer.rs b/src/ui/widgets/tui_footer.rs
index e957590..83598a2 100644
--- a/src/ui/widgets/tui_footer.rs
+++ b/src/ui/widgets/tui_footer.rs
@@ -5,7 +5,7 @@ use tui::layout::Rect;
use tui::style::{Color, Style};
use tui::widgets::{Paragraph, Text, Widget};
-use crate::fs::JoshutoDirEntry;
+use crate::fs::{FileType, JoshutoDirEntry};
use crate::util::format;
pub struct TuiFooter<'a> {
@@ -51,13 +51,12 @@ impl<'a> Widget for TuiFooter<'a> {
Text::raw(mimetype),
];
- if self.entry.metadata.file_type.is_symlink() {
- if let Ok(path) = fs::read_link(self.entry.file_path()) {
+ match &self.entry.metadata.file_type {
+ FileType::Symlink(s) => {
text.push(Text::styled(" -> ", mode_style));
- if let Some(s) = path.to_str() {
- text.push(Text::styled(s.to_string(), mode_style));
- }
+ text.push(Text::styled(s, mode_style));
}
+ _ => {}
}
Paragraph::new(text.iter()).wrap(true).draw(area, buf);