Skip to content

Commit

Permalink
Adds keybinding 'm' to toggle sorting by modified time
Browse files Browse the repository at this point in the history
  • Loading branch information
piotrwach committed Nov 24, 2023
1 parent adebd00 commit 2bd06be
Show file tree
Hide file tree
Showing 13 changed files with 169 additions and 35 deletions.
19 changes: 19 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ num_cpus = "1.10.0"
filesize = "0.2.0"
anyhow = "1.0.31"
trash = { version = "3.0.0", optional = true, default-features = false, features = ["coinit_apartmentthreaded"] }
chrono = { version = "0.4.31", default-features = false, features = ["std"] }

# 'tui' related
unicode-segmentation = { version = "1.3.0", optional = true }
Expand Down
6 changes: 3 additions & 3 deletions src/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -192,9 +192,7 @@ impl WalkOptions {
if let Ok(dir_entry) = dir_entry_result {
let metadata = dir_entry.metadata();

if dir_entry.file_type.is_file() || dir_entry.file_type().is_symlink() {
dir_entry.client_state = Some(metadata);
} else if dir_entry.file_type.is_dir() {
if dir_entry.file_type.is_dir() {
let ok_for_fs = cross_filesystems
|| metadata
.as_ref()
Expand All @@ -204,6 +202,8 @@ impl WalkOptions {
dir_entry.read_children_path = None;
}
}

dir_entry.client_state = Some(metadata);
}
})
}
Expand Down
18 changes: 17 additions & 1 deletion src/interactive/app/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,28 @@ pub enum SortMode {
#[default]
SizeDescending,
SizeAscending,
MTimeAscending,
MTimeDescending,
}

impl SortMode {
pub fn toggle_size(&mut self) {
use SortMode::*;
*self = match self {
SizeAscending => SizeDescending,
SizeDescending => SizeAscending,
SizeAscending => SizeDescending,
MTimeAscending => SizeAscending,
MTimeDescending => SizeDescending,
}
}

pub fn toggle_mtime(&mut self) {
use SortMode::*;
*self = match self {
SizeDescending => MTimeDescending,
SizeAscending => MTimeAscending,
MTimeAscending => MTimeDescending,
MTimeDescending => MTimeAscending,
}
}
}
Expand Down Expand Up @@ -46,6 +60,8 @@ pub fn sorted_entries(tree: &Tree, node_idx: TreeIndex, sorting: SortMode) -> Ve
.sorted_by(|l, r| match sorting {
SizeDescending => r.data.size.cmp(&l.data.size),
SizeAscending => l.data.size.cmp(&r.data.size),
MTimeAscending => l.data.mtime.cmp(&r.data.mtime),
MTimeDescending => r.data.mtime.cmp(&l.data.mtime),
})
.collect()
}
Expand Down
1 change: 1 addition & 0 deletions src/interactive/app/eventloop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@ impl AppState {
Char('j') | Down => self.change_entry_selection(CursorDirection::Down),
Ctrl('d') | PageDown => self.change_entry_selection(CursorDirection::PageDown),
Char('s') => self.cycle_sorting(traversal),
Char('m') => self.cycle_mtime_sorting(traversal),
Char('g') => display.byte_vis.cycle(),
_ => {}
},
Expand Down
5 changes: 5 additions & 0 deletions src/interactive/app/handlers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,11 @@ impl AppState {
self.entries = sorted_entries(&traversal.tree, self.root, self.sorting);
}

pub fn cycle_mtime_sorting(&mut self, traversal: &Traversal) {
self.sorting.toggle_mtime();
self.entries = sorted_entries(&traversal.tree, self.root, self.sorting);
}

pub fn reset_message(&mut self) {
if self.is_scanning {
self.message = Some("-> scanning <-".into());
Expand Down
14 changes: 14 additions & 0 deletions src/interactive/app/tests/journeys_readonly.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,20 @@ fn simple_user_journey_read_only() -> Result<()> {

// SORTING
{
// when hitting the M key
app.process_events(&mut terminal, into_keys(b"m".iter()))?;
assert_eq!(
app.state.sorting,
SortMode::MTimeDescending,
"it sets the sort mode to descending by mtime"
);
// when hitting the M key again
app.process_events(&mut terminal, into_keys(b"m".iter()))?;
assert_eq!(
app.state.sorting,
SortMode::MTimeAscending,
"it sets the sort mode to ascending by mtime"
);
// when hitting the S key
app.process_events(&mut terminal, into_keys(b"s".iter()))?;
assert_eq!(
Expand Down
2 changes: 2 additions & 0 deletions src/interactive/app/tests/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ use std::{
fs::{copy, create_dir_all, remove_dir, remove_file},
io::ErrorKind,
path::{Path, PathBuf},
time::UNIX_EPOCH,
};
use tui::backend::TestBackend;
use tui_react::Terminal;
Expand Down Expand Up @@ -294,6 +295,7 @@ pub fn make_add_node(t: &mut Tree) -> impl FnMut(&str, u128, Option<NodeIndex>)
let n = t.add_node(EntryData {
name: PathBuf::from(name),
size,
mtime: UNIX_EPOCH,
metadata_io_error: false,
});
if let Some(from) = maybe_from_idx {
Expand Down
46 changes: 36 additions & 10 deletions src/interactive/widgets/entries.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
use crate::interactive::{
path_of,
widgets::{entry_color, EntryMarkMap},
DisplayOptions, EntryDataBundle,
DisplayOptions, EntryDataBundle, SortMode,
};
use chrono::DateTime;
use dua::traverse::{Tree, TreeIndex};
use itertools::Itertools;
use std::{borrow::Borrow, path::Path};
Expand All @@ -29,6 +30,7 @@ pub struct EntriesProps<'a> {
pub marked: Option<&'a EntryMarkMap>,
pub border_style: Style,
pub is_focussed: bool,
pub sort_mode: SortMode,
}

#[derive(Default)]
Expand All @@ -52,6 +54,7 @@ impl Entries {
marked,
border_style,
is_focussed,
sort_mode,
} = props.borrow();
let list = &mut self.list;

Expand Down Expand Up @@ -114,24 +117,47 @@ impl Entries {
style.add_modifier.insert(Modifier::BOLD);
}

let fraction = w.size as f32 / total as f32;
let should_avoid_showing_a_big_reversed_bar = fraction > 0.9;
let local_style = if should_avoid_showing_a_big_reversed_bar {
style.remove_modifier(Modifier::REVERSED)
} else {
style
};

let datetime = DateTime::<chrono::Utc>::from(w.mtime);
let formatted_time = datetime.format("%d/%m/%Y %H:%M:%S").to_string();
let mtime = Span::styled(
format!("{:>20}", formatted_time),
Style {
fg: match sort_mode {
SortMode::SizeAscending | SortMode::SizeDescending => style.fg,
SortMode::MTimeAscending | SortMode::MTimeDescending => {
Color::Green.into()
}
},
..style
},
);

let bar = Span::styled(" | ", local_style);

let bytes = Span::styled(
format!(
"{:>byte_column_width$}",
display.byte_format.display(w.size).to_string(), // we would have to impl alignment/padding ourselves otherwise...
byte_column_width = display.byte_format.width()
),
Style {
fg: Color::Green.into(),
fg: match sort_mode {
SortMode::SizeAscending | SortMode::SizeDescending => {
Color::Green.into()
}
SortMode::MTimeAscending | SortMode::MTimeDescending => style.fg,
},
..style
},
);
let fraction = w.size as f32 / total as f32;
let should_avoid_showing_a_big_reversed_bar = fraction > 0.9;
let local_style = if should_avoid_showing_a_big_reversed_bar {
style.remove_modifier(Modifier::REVERSED)
} else {
style
};

let left_bar = Span::styled(" |", local_style);
let percentage = Span::styled(
Expand Down Expand Up @@ -160,7 +186,7 @@ impl Entries {
Style { fg, ..style }
},
);
vec![bytes, left_bar, percentage, right_bar, name]
vec![mtime, bar, bytes, left_bar, percentage, right_bar, name]
},
);

Expand Down
12 changes: 11 additions & 1 deletion src/interactive/widgets/footer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ use tui::{
widgets::{Paragraph, Widget},
};

use crate::interactive::SortMode;

pub struct Footer;

pub struct FooterProps {
Expand All @@ -18,6 +20,7 @@ pub struct FooterProps {
pub elapsed: Option<std::time::Duration>,
pub format: ByteFormat,
pub message: Option<String>,
pub sort_mode: SortMode,
}

impl Footer {
Expand All @@ -29,11 +32,18 @@ impl Footer {
traversal_start,
format,
message,
sort_mode,
} = props.borrow();

let spans = vec![
Span::from(format!(
" Total disk usage: {} Entries: {} {progress} ",
"Sort mode: {} Total disk usage: {} Entries: {} {progress} ",
match sort_mode {
SortMode::SizeAscending => "size ascending",
SortMode::SizeDescending => "size descending",
SortMode::MTimeAscending => "modified ascending",
SortMode::MTimeDescending => "modified descending",
},
match total_bytes {
Some(b) => format!("{}", format.display(*b)),
None => "-".to_owned(),
Expand Down
1 change: 1 addition & 0 deletions src/interactive/widgets/help.rs
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ impl HelpPane {
title("Keys for display");
{
hotkey("s", "toggle sort by size ascending/descending", None);
hotkey("m", "toggle sort by mtime ascending/descending", None);
hotkey(
"g",
"cycle through percentage display and bar options",
Expand Down
2 changes: 2 additions & 0 deletions src/interactive/widgets/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@ impl MainWindow {
selected: state.selected,
border_style: entries_style,
is_focussed: matches!(state.focussed, Main),
sort_mode: state.sorting,
};
self.entries_pane.render(props, entries_area, buf);

Expand All @@ -142,6 +143,7 @@ impl MainWindow {
message: state.message.clone(),
traversal_start: *start,
elapsed: *elapsed,
sort_mode: state.sorting,
},
footer_area,
buf,
Expand Down

0 comments on commit 2bd06be

Please sign in to comment.