Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 8df0b4c

Browse files
committed
Adds keybinding for 'c' to toggle sorting by number of items
1 parent bf4da4e commit 8df0b4c

11 files changed

Lines changed: 184 additions & 84 deletions

File tree

Cargo.lock

Lines changed: 7 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ tui-react = { version = "0.19.0", optional = true }
3838
open = { version = "5.0", optional = true }
3939
wild = "2.0.4"
4040
owo-colors = "3.5.0"
41+
human_format = "1.0.3"
4142

4243
[[bin]]
4344
name="dua"

src/interactive/app/common.rs

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ pub enum SortMode {
1111
SizeAscending,
1212
MTimeAscending,
1313
MTimeDescending,
14+
CountAscending,
15+
CountDescending,
1416
}
1517

1618
impl SortMode {
@@ -19,18 +21,25 @@ impl SortMode {
1921
*self = match self {
2022
SizeDescending => SizeAscending,
2123
SizeAscending => SizeDescending,
22-
MTimeAscending => SizeAscending,
23-
MTimeDescending => SizeDescending,
24+
_ => SizeAscending,
2425
}
2526
}
2627

2728
pub fn toggle_mtime(&mut self) {
2829
use SortMode::*;
2930
*self = match self {
30-
SizeDescending => MTimeDescending,
31-
SizeAscending => MTimeAscending,
3231
MTimeAscending => MTimeDescending,
3332
MTimeDescending => MTimeAscending,
33+
_ => MTimeAscending,
34+
}
35+
}
36+
37+
pub fn toggle_count(&mut self) {
38+
use SortMode::*;
39+
*self = match self {
40+
CountAscending => CountDescending,
41+
CountDescending => CountAscending,
42+
_ => CountAscending,
3443
}
3544
}
3645
}
@@ -62,6 +71,8 @@ pub fn sorted_entries(tree: &Tree, node_idx: TreeIndex, sorting: SortMode) -> Ve
6271
SizeAscending => l.data.size.cmp(&r.data.size),
6372
MTimeAscending => l.data.mtime.cmp(&r.data.mtime),
6473
MTimeDescending => r.data.mtime.cmp(&l.data.mtime),
74+
CountAscending => l.data.entry_count.cmp(&r.data.entry_count),
75+
CountDescending => r.data.entry_count.cmp(&l.data.entry_count),
6576
})
6677
.collect()
6778
}

src/interactive/app/eventloop.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,7 @@ impl AppState {
149149
Ctrl('d') | PageDown => self.change_entry_selection(CursorDirection::PageDown),
150150
Char('s') => self.cycle_sorting(traversal),
151151
Char('m') => self.cycle_mtime_sorting(traversal),
152+
Char('c') => self.cycle_count_sorting(traversal),
152153
Char('g') => display.byte_vis.cycle(),
153154
_ => {}
154155
},

src/interactive/app/handlers.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,11 @@ impl AppState {
161161
self.entries = sorted_entries(&traversal.tree, self.root, self.sorting);
162162
}
163163

164+
pub fn cycle_count_sorting(&mut self, traversal: &Traversal) {
165+
self.sorting.toggle_count();
166+
self.entries = sorted_entries(&traversal.tree, self.root, self.sorting);
167+
}
168+
164169
pub fn reset_message(&mut self) {
165170
if self.is_scanning {
166171
self.message = Some("-> scanning <-".into());

src/interactive/app/tests/journeys_readonly.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,14 +67,14 @@ fn simple_user_journey_read_only() -> Result<()> {
6767
app.process_events(&mut terminal, into_keys(b"m".iter()))?;
6868
assert_eq!(
6969
app.state.sorting,
70-
SortMode::MTimeDescending,
70+
SortMode::MTimeAscending,
7171
"it sets the sort mode to descending by mtime"
7272
);
7373
// when hitting the M key again
7474
app.process_events(&mut terminal, into_keys(b"m".iter()))?;
7575
assert_eq!(
7676
app.state.sorting,
77-
SortMode::MTimeAscending,
77+
SortMode::MTimeDescending,
7878
"it sets the sort mode to ascending by mtime"
7979
);
8080
// when hitting the S key

src/interactive/app/tests/utils.rs

Lines changed: 33 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -224,32 +224,32 @@ pub fn sample_01_tree() -> Tree {
224224
let root_size = 1259070;
225225
#[cfg(windows)]
226226
let root_size = 1259069;
227-
let rn = add_node("", root_size, None);
227+
let rn = add_node("", root_size, 14, None);
228228
{
229-
let sn = add_node(&fixture_str("sample-01"), root_size, Some(rn));
229+
let sn = add_node(&fixture_str("sample-01"), root_size, 13, Some(rn));
230230
{
231-
add_node(".hidden.666", 666, Some(sn));
232-
add_node("a", 256, Some(sn));
233-
add_node("b.empty", 0, Some(sn));
231+
add_node(".hidden.666", 666, 0, Some(sn));
232+
add_node("a", 256, 0, Some(sn));
233+
add_node("b.empty", 0, 0, Some(sn));
234234
#[cfg(not(windows))]
235-
add_node("c.lnk", 1, Some(sn));
235+
add_node("c.lnk", 1, 0, Some(sn));
236236
#[cfg(windows)]
237-
add_node("c.lnk", 0, Some(sn));
238-
let dn = add_node("dir", 1258024, Some(sn));
237+
add_node("c.lnk", 0, 0, Some(sn));
238+
let dn = add_node("dir", 1258024, 7, Some(sn));
239239
{
240-
add_node("1000bytes", 1000, Some(dn));
241-
add_node("dir-a.1mb", 1_000_000, Some(dn));
242-
add_node("dir-a.kb", 1024, Some(dn));
243-
let en = add_node("empty-dir", 0, Some(dn));
240+
add_node("1000bytes", 1000, 0, Some(dn));
241+
add_node("dir-a.1mb", 1_000_000, 0, Some(dn));
242+
add_node("dir-a.kb", 1024, 0, Some(dn));
243+
let en = add_node("empty-dir", 0, 1, Some(dn));
244244
{
245-
add_node(".gitkeep", 0, Some(en));
245+
add_node(".gitkeep", 0, 0, Some(en));
246246
}
247-
let sub = add_node("sub", 256_000, Some(dn));
247+
let sub = add_node("sub", 256_000, 1, Some(dn));
248248
{
249-
add_node("dir-sub-a.256kb", 256_000, Some(sub));
249+
add_node("dir-sub-a.256kb", 256_000, 0, Some(sub));
250250
}
251251
}
252-
add_node("z123.b", 123, Some(sn));
252+
add_node("z123.b", 123, 0, Some(sn));
253253
}
254254
}
255255
}
@@ -261,27 +261,28 @@ pub fn sample_02_tree() -> Tree {
261261
{
262262
let mut add_node = make_add_node(&mut tree);
263263
let root_size = 1540;
264-
let rn = add_node("", root_size, None);
264+
let rn = add_node("", root_size, 10, None);
265265
{
266266
let sn = add_node(
267267
Path::new(FIXTURE_PATH).join("sample-02").to_str().unwrap(),
268268
root_size,
269+
9,
269270
Some(rn),
270271
);
271272
{
272-
add_node("a", 256, Some(sn));
273-
add_node("b", 1, Some(sn));
274-
let dn = add_node("dir", 1283, Some(sn));
273+
add_node("a", 256, 0, Some(sn));
274+
add_node("b", 1, 0, Some(sn));
275+
let dn = add_node("dir", 1283, 6, Some(sn));
275276
{
276-
add_node("c", 257, Some(dn));
277-
add_node("d", 2, Some(dn));
278-
let en = add_node("empty-dir", 0, Some(dn));
277+
add_node("c", 257, 0, Some(dn));
278+
add_node("d", 2, 0, Some(dn));
279+
let en = add_node("empty-dir", 0, 1, Some(dn));
279280
{
280-
add_node(".gitkeep", 0, Some(en));
281+
add_node(".gitkeep", 0, 0, Some(en));
281282
}
282-
let sub = add_node("sub", 1024, Some(dn));
283+
let sub = add_node("sub", 1024, 1, Some(dn));
283284
{
284-
add_node("e", 1024, Some(sub));
285+
add_node("e", 1024, 0, Some(sub));
285286
}
286287
}
287288
}
@@ -290,13 +291,15 @@ pub fn sample_02_tree() -> Tree {
290291
tree
291292
}
292293

293-
pub fn make_add_node(t: &mut Tree) -> impl FnMut(&str, u128, Option<NodeIndex>) -> NodeIndex + '_ {
294-
move |name, size, maybe_from_idx| {
294+
pub fn make_add_node(
295+
t: &mut Tree,
296+
) -> impl FnMut(&str, u128, u64, Option<NodeIndex>) -> NodeIndex + '_ {
297+
move |name, size, entry_count, maybe_from_idx| {
295298
let n = t.add_node(EntryData {
296299
name: PathBuf::from(name),
297300
size,
298-
mtime: UNIX_EPOCH,
299-
metadata_io_error: false,
301+
entry_count,
302+
..Default::default()
300303
});
301304
if let Some(from) = maybe_from_idx {
302305
t.add_edge(from, n, ());

src/interactive/widgets/entries.rs

Lines changed: 61 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use crate::interactive::{
55
};
66
use chrono::DateTime;
77
use dua::traverse::{EntryData, Tree, TreeIndex};
8+
use human_format;
89
use itertools::Itertools;
910
use std::time::SystemTime;
1011
use std::{borrow::Borrow, path::Path};
@@ -89,15 +90,24 @@ impl Entries {
8990

9091
let mut columns = Vec::new();
9192
if should_show_mtime_column(sort_mode) {
92-
columns.push(mtime_column(entry_data.mtime, *sort_mode, text_style));
93+
columns.push(mtime_column(
94+
entry_data.mtime,
95+
column_style(Column::MTime, *sort_mode, text_style),
96+
));
9397
}
9498
columns.push(bytes_column(
9599
*display,
96100
entry_data.size,
97-
*sort_mode,
98-
text_style,
101+
column_style(Column::Bytes, *sort_mode, text_style),
99102
));
100103
columns.push(percentage_column(*display, fraction, percentage_style));
104+
if should_show_count_column(sort_mode) {
105+
columns.push(count_column(
106+
entry_data.entry_count,
107+
*is_dir,
108+
column_style(Column::Count, *sort_mode, text_style),
109+
));
110+
}
101111
columns.push(name_column(
102112
&entry_data.name,
103113
*is_dir,
@@ -229,18 +239,27 @@ fn columns_with_separators(columns: Vec<Span<'_>>, style: Style) -> Vec<Span<'_>
229239
columns_with_separators
230240
}
231241

232-
fn mtime_column(entry_mtime: SystemTime, sort_mode: SortMode, style: Style) -> Span<'static> {
242+
fn mtime_column(entry_mtime: SystemTime, style: Style) -> Span<'static> {
233243
let datetime = DateTime::<chrono::Utc>::from(entry_mtime);
234244
let formatted_time = datetime.format("%d/%m/%Y %H:%M:%S").to_string();
245+
Span::styled(format!("{:>20}", formatted_time), style)
246+
}
247+
248+
fn count_column(entry_count: u64, is_dir: bool, style: Style) -> Span<'static> {
249+
let count_in_units = human_format::Formatter::new()
250+
.with_decimals(0)
251+
.with_separator("")
252+
.format(entry_count as f64);
235253
Span::styled(
236-
format!("{:>20}", formatted_time),
237-
Style {
238-
fg: match sort_mode {
239-
SortMode::SizeAscending | SortMode::SizeDescending => style.fg,
240-
SortMode::MTimeAscending | SortMode::MTimeDescending => Color::Green.into(),
241-
},
242-
..style
243-
},
254+
format!(
255+
"{:>4}",
256+
if is_dir {
257+
count_in_units
258+
} else {
259+
"".to_string()
260+
}
261+
),
262+
style,
244263
)
245264
}
246265

@@ -279,31 +298,48 @@ fn percentage_column(display: DisplayOptions, fraction: f32, style: Style) -> Sp
279298
Span::styled(format!("{}", display.byte_vis.display(fraction)), style)
280299
}
281300

282-
fn bytes_column(
283-
display: DisplayOptions,
284-
entry_size: u128,
285-
sort_mode: SortMode,
286-
style: Style,
287-
) -> Span<'static> {
301+
fn bytes_column(display: DisplayOptions, entry_size: u128, style: Style) -> Span<'static> {
288302
Span::styled(
289303
format!(
290304
"{:>byte_column_width$}",
291305
display.byte_format.display(entry_size).to_string(), // we would have to impl alignment/padding ourselves otherwise...
292306
byte_column_width = display.byte_format.width()
293307
),
294-
Style {
295-
fg: match sort_mode {
296-
SortMode::SizeAscending | SortMode::SizeDescending => Color::Green.into(),
297-
SortMode::MTimeAscending | SortMode::MTimeDescending => style.fg,
298-
},
299-
..style
300-
},
308+
style,
301309
)
302310
}
303311

312+
#[derive(PartialEq)]
313+
enum Column {
314+
Bytes,
315+
MTime,
316+
Count,
317+
}
318+
319+
fn column_style(column: Column, sort_mode: SortMode, style: Style) -> Style {
320+
Style {
321+
fg: match (sort_mode, column) {
322+
(SortMode::SizeAscending | SortMode::SizeDescending, Column::Bytes)
323+
| (SortMode::MTimeAscending | SortMode::MTimeDescending, Column::MTime)
324+
| (SortMode::CountAscending | SortMode::CountDescending, Column::Count) => {
325+
Color::Green.into()
326+
}
327+
_ => style.fg,
328+
},
329+
..style
330+
}
331+
}
332+
304333
fn should_show_mtime_column(sort_mode: &SortMode) -> bool {
305334
matches!(
306335
sort_mode,
307336
SortMode::MTimeAscending | SortMode::MTimeDescending
308337
)
309338
}
339+
340+
fn should_show_count_column(sort_mode: &SortMode) -> bool {
341+
matches!(
342+
sort_mode,
343+
SortMode::CountAscending | SortMode::CountDescending
344+
)
345+
}

src/interactive/widgets/footer.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ impl Footer {
4343
SortMode::SizeDescending => "size descending",
4444
SortMode::MTimeAscending => "modified ascending",
4545
SortMode::MTimeDescending => "modified descending",
46+
SortMode::CountAscending => "items ascending",
47+
SortMode::CountDescending => "items descending",
4648
},
4749
match total_bytes {
4850
Some(b) => format!("{}", format.display(*b)),

src/interactive/widgets/help.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,7 @@ impl HelpPane {
134134
{
135135
hotkey("s", "toggle sort by size ascending/descending", None);
136136
hotkey("m", "toggle sort by mtime ascending/descending", None);
137+
hotkey("c", "toggle sort by items ascending/descending", None);
137138
hotkey(
138139
"g",
139140
"cycle through percentage display and bar options",

0 commit comments

Comments
 (0)