Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Display total size of current directory #334

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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