Skip to content

Commit

Permalink
feat: Display directory size
Browse files Browse the repository at this point in the history
add option to display lazily loaded directory sizes
  • Loading branch information
krivahtoo committed Jun 11, 2023
1 parent f5edffc commit 7485ae9
Show file tree
Hide file tree
Showing 10 changed files with 137 additions and 17 deletions.
2 changes: 2 additions & 0 deletions config/joshuto.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ show_icons = true
tilde_in_titlebar = true
# none, absolute, relative
line_number_style = "none"
# count, size
size_mode = "count"

[display.sort]
# lexical, mtime, natural
Expand Down
5 changes: 5 additions & 0 deletions docs/configuration/joshuto.toml.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,11 @@ tilde_in_titlebar = true
# - relative
line_number_style = "none"

# Options include:
# - count (use number of items in directory)
# - size (use the total size of items in a directory)
size_mode = "count"

# Configurations related to file sorting
[display.sort]
# Options include
Expand Down
26 changes: 26 additions & 0 deletions src/commands/cursor_move.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,32 @@ pub fn lazy_load_directory_size(context: &mut AppContext) {
curr_entry.metadata.update_directory_size(s);
}
}

if let Some(curr_entry) = context
.tab_context_ref()
.curr_tab_ref()
.curr_list_ref()
.and_then(|l| l.curr_entry_ref())
{
let old_len = curr_entry.metadata.len();
let history = context.tab_context_ref().curr_tab_ref().history_ref();
match history
.get(curr_entry.file_path())
.map(|d| d.contents.iter().map(|e| e.metadata.len()).sum())
{
Some(len) if old_len != len => {
if let Some(curr_entry) = context
.tab_context_mut()
.curr_tab_mut()
.curr_list_mut()
.and_then(|l| l.curr_entry_mut())
{
curr_entry.metadata.update_len(len);
}
}
_ => (),
}
}
}

pub fn cursor_move(context: &mut AppContext, new_index: usize) {
Expand Down
7 changes: 6 additions & 1 deletion src/config/general/display_raw.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use serde_derive::Deserialize;
use tui::layout::Constraint;

use crate::config::option::{
DisplayMode, DisplayOption, LineMode, LineNumberStyle, TabDisplayOption,
DisplayMode, DisplayOption, LineMode, LineNumberStyle, SizeMode, TabDisplayOption,
};

use super::sort_raw::SortOptionRaw;
Expand Down Expand Up @@ -59,6 +59,9 @@ pub struct DisplayOptionRaw {

#[serde(default)]
pub line_number_style: String,

#[serde(default)]
pub size_mode: String,
}

impl std::default::Default for DisplayOptionRaw {
Expand All @@ -75,6 +78,7 @@ impl std::default::Default for DisplayOptionRaw {
sort_options: SortOptionRaw::default(),
tilde_in_titlebar: true,
line_number_style: "none".to_string(),
size_mode: "count".to_string(),
}
}
}
Expand Down Expand Up @@ -126,6 +130,7 @@ impl From<DisplayOptionRaw> for DisplayOption {
sort_options: raw.sort_options.into(),
// todo: make default line mode configurable
linemode: LineMode::Size,
size_mode: SizeMode::from_str(&raw.size_mode),
..Default::default()
},
}
Expand Down
17 changes: 17 additions & 0 deletions src/config/option/display_option.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ pub struct TabDisplayOption {
pub dirlist_options: HashMap<PathBuf, DirListDisplayOptions>,
pub sort_options: SortOption,
pub linemode: LineMode,
pub size_mode: SizeMode,
}

#[derive(Clone, Copy, Debug)]
Expand All @@ -55,6 +56,13 @@ pub enum LineNumberStyle {
Absolute,
}

#[derive(Clone, Debug, Default)]
pub enum SizeMode {
#[default]
Count,
ContentSize,
}

impl LineNumberStyle {
pub fn from_str(s: &str) -> Option<Self> {
match s {
Expand All @@ -66,6 +74,15 @@ impl LineNumberStyle {
}
}

impl SizeMode {
pub fn from_str(s: &str) -> Self {
match s {
"size" => SizeMode::ContentSize,
_ => SizeMode::Count,
}
}
}

impl DirListDisplayOptions {
pub fn set_filter_string(&mut self, pattern: &str) {
self.filter_string = pattern.to_owned();
Expand Down
22 changes: 20 additions & 2 deletions src/fs/dirlist.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,10 @@ impl JoshutoDirList {
index: Option<usize>,
viewport_index: usize,
visual_mode_anchor_index: Option<usize>,
metadata: JoshutoMetadata,
mut metadata: JoshutoMetadata,
) -> Self {
let len: u64 = contents.iter().map(|e| e.metadata.len()).sum();
metadata.update_len(len);
Self {
path,
contents,
Expand All @@ -51,7 +53,18 @@ impl JoshutoDirList {
contents.sort_by(|f1, f2| tab_options.sort_options_ref().compare(f1, f2));

let index = if contents.is_empty() { None } else { Some(0) };
let metadata = JoshutoMetadata::from(&path)?;
let mut metadata = JoshutoMetadata::from(&path)?;
let len: u64 = contents
.iter()
.map(|e| {
if !e.metadata.is_dir() {
e.metadata.len()
} else {
0
}
})
.sum();
metadata.update_len(len);

Ok(Self {
path,
Expand Down Expand Up @@ -183,6 +196,11 @@ impl JoshutoDirList {
self.contents.len()
}

/// get size of directory in bytes
pub fn size(&self) -> u64 {
self.metadata.len()
}

pub fn is_empty(&self) -> bool {
self.contents.is_empty()
}
Expand Down
20 changes: 20 additions & 0 deletions src/fs/entry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ impl JoshutoDirEntry {
let mut metadata = JoshutoMetadata::from(&path)?;

if options.automatically_count_files() && metadata.file_type().is_dir() {
if let Ok(len) = get_directory_len(path.as_path()) {
metadata.update_len(len);
}
if let Ok(size) = get_directory_size(path.as_path()) {
metadata.update_directory_size(size);
}
Expand Down Expand Up @@ -162,3 +165,20 @@ fn create_icon_label(name: &str, metadata: &JoshutoMetadata) -> String {
fn get_directory_size(path: &path::Path) -> io::Result<usize> {
fs::read_dir(path).map(|s| s.count())
}

fn get_directory_len(path: &path::Path) -> io::Result<u64> {
fs::read_dir(path).map(|s| {
s.map(|e| {
if let Ok(entry) = e {
if let Ok(meta) = entry.metadata() {
meta.len()
} else {
0
}
} else {
0
}
})
.sum()
})
}
10 changes: 9 additions & 1 deletion src/fs/metadata.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,11 @@ impl JoshutoMetadata {
let symlink_metadata = fs::symlink_metadata(path)?;
let metadata = fs::metadata(path);
let (_len, _modified, _permissions) = match metadata.as_ref() {
Ok(m) => (m.len(), m.modified()?, m.permissions()),
Ok(m) => (
if m.is_dir() { 0 } else { m.len() },
m.modified()?,
m.permissions(),
),
Err(_) => (
symlink_metadata.len(),
symlink_metadata.modified()?,
Expand Down Expand Up @@ -104,6 +108,10 @@ impl JoshutoMetadata {
self._len
}

pub fn update_len(&mut self, len: u64) {
self._len = len;
}

pub fn directory_size(&self) -> Option<usize> {
self._directory_size
}
Expand Down
18 changes: 17 additions & 1 deletion src/history.rs
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,20 @@ pub fn create_dirlist_with_history(
if entry.metadata.is_dir() {
if let Some(lst) = history.get(entry.file_path()) {
entry.metadata.update_directory_size(lst.len());
let len: u64 = lst
.contents
.iter()
.map(|e| {
if let Some(l) = history.get(e.file_path()) {
l.size()
} else {
0
}
})
.sum();
entry
.metadata
.update_len(if len > lst.size() { len } else { lst.size() });
}
}
}
Expand Down Expand Up @@ -231,7 +245,9 @@ pub fn create_dirlist_with_history(
}
};

let metadata = JoshutoMetadata::from(path)?;
let mut metadata = JoshutoMetadata::from(path)?;
let len: u64 = contents.iter().map(|e| e.metadata.len()).sum();
metadata.update_len(len);
let dirlist = JoshutoDirList::new(
path.to_path_buf(),
contents,
Expand Down
27 changes: 15 additions & 12 deletions src/ui/widgets/tui_dirlist_detailed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use tui::layout::Rect;
use tui::style::{Color, Modifier, Style};
use tui::widgets::Widget;

use crate::config::option::{DisplayOption, LineMode, LineNumberStyle, TabDisplayOption};
use crate::config::option::{DisplayOption, LineMode, LineNumberStyle, SizeMode, TabDisplayOption};
use crate::fs::{FileType, JoshutoDirEntry, JoshutoDirList, LinkType};
use crate::util::format;
use crate::util::string::UnicodeTruncate;
Expand Down Expand Up @@ -108,21 +108,24 @@ impl<'a> Widget for TuiDirListDetailed<'a> {
entry,
style,
(x + 1, y + i as u16),
self.tab_display_options.linemode,
self.tab_display_options,
drawing_width - 1,
&prefix,
);
});
}
}

fn get_entry_size_string(entry: &JoshutoDirEntry) -> String {
fn get_entry_size_string(entry: &JoshutoDirEntry, mode: &SizeMode) -> String {
match entry.metadata.file_type() {
FileType::Directory => entry
.metadata
.directory_size()
.map(|n| n.to_string())
.unwrap_or_else(|| "".to_string()),
FileType::Directory => match mode {
SizeMode::Count => entry
.metadata
.directory_size()
.map(|n| n.to_string())
.unwrap_or_else(|| "".to_string()),
SizeMode::ContentSize => format::file_size_to_string(entry.metadata.len()),
},
FileType::File => format::file_size_to_string(entry.metadata.len()),
}
}
Expand All @@ -132,7 +135,7 @@ fn print_entry(
entry: &JoshutoDirEntry,
style: Style,
(x, y): (u16, u16),
linemode: LineMode,
tab_opts: &TabDisplayOption,
drawing_width: usize,
prefix: &str,
) {
Expand All @@ -144,12 +147,12 @@ fn print_entry(
let right_label_original = format!(
" {}{} ",
symlink_string,
match linemode {
LineMode::Size => get_entry_size_string(entry),
match tab_opts.linemode {
LineMode::Size => get_entry_size_string(entry, &tab_opts.size_mode),
LineMode::MTime => format::mtime_to_string(entry.metadata.modified()),
LineMode::SizeMTime => format!(
"{} {}",
get_entry_size_string(entry),
get_entry_size_string(entry, &tab_opts.size_mode),
format::mtime_to_string(entry.metadata.modified())
),
}
Expand Down

0 comments on commit 7485ae9

Please sign in to comment.