1use std::cmp::Ordering;
2
3use crate::modes::FileInfo;
4
5#[derive(Debug, Clone, Default, Copy)]
7enum SortBy {
8 #[default]
9 Kind,
11 File,
13 Date,
15 Size,
17 Exte,
19}
20
21impl std::fmt::Display for SortBy {
22 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
23 let sort_by = match &self {
24 Self::Exte => "Exte",
25 Self::Date => "Date",
26 Self::File => "File",
27 Self::Size => "Size",
28 Self::Kind => "Kind",
29 };
30 write!(f, "{sort_by}")
31 }
32}
33
34#[derive(Debug, Clone, Default, Copy)]
36enum Order {
37 #[default]
38 Ascending,
40 Descending,
42}
43
44impl Order {
45 const fn reverse(self) -> Self {
46 match self {
47 Self::Descending => Self::Ascending,
48 Self::Ascending => Self::Descending,
49 }
50 }
51}
52
53#[derive(Debug, Clone, Default, Copy)]
54pub struct SortKind {
56 sort_by: SortBy,
58 order: Order,
60}
61
62impl SortKind {
63 #[must_use]
66 pub const fn tree_default() -> Self {
67 Self {
68 sort_by: SortBy::Kind,
69 order: Order::Descending,
70 }
71 }
72
73 pub fn update_from_char(&mut self, c: char) {
78 match c.to_ascii_uppercase() {
79 'K' => self.sort_by = SortBy::Kind,
80 'N' => self.sort_by = SortBy::File,
81 'M' => self.sort_by = SortBy::Date,
82 'S' => self.sort_by = SortBy::Size,
83 'E' => self.sort_by = SortBy::Exte,
84 'R' => self.order = self.order.reverse(),
85 _ => {
86 return;
87 }
88 }
89 if c != 'r' {
90 if c.is_uppercase() {
91 self.order = Order::Descending;
92 } else {
93 self.order = Order::Ascending;
94 }
95 }
96 }
97 fn sort_by_key_hrtb<T, F, K>(slice: &mut [T], f: F)
102 where
103 F: for<'a> Fn(&'a T) -> &'a K,
104 K: Ord + ?Sized,
105 {
106 slice.sort_unstable_by(|a, b| f(a).cmp(f(b)));
107 }
108
109 fn reversed_sort_by_key_hrtb<T, F, K>(slice: &mut [T], f: F)
115 where
116 F: for<'a> Fn(&'a T) -> &'a K,
117 K: Ord + ?Sized,
118 {
119 slice.sort_unstable_by(|a, b| Ordering::reverse(f(a).cmp(f(b))));
120 }
121
122 #[rustfmt::skip]
128 pub fn sort(&self, files: &mut [FileInfo]) {
129 if matches!(self.order, Order::Ascending) {
130 match self.sort_by {
131 SortBy::Kind => files.sort_unstable_by(|a, b| natord::compare(&a.kind_format(), &b.kind_format())),
132 SortBy::File => files.sort_unstable_by(|a, b| natord::compare(&a.filename, &b.filename)),
133 SortBy::Date => Self::sort_by_key_hrtb(files, |f| &f.system_time),
134 SortBy::Size => Self::sort_by_key_hrtb(files, |f| &f.true_size),
135 SortBy::Exte => Self::sort_by_key_hrtb(files, |f| &f.extension),
136 }
137 } else {
138 match self.sort_by {
139 SortBy::Kind => files.sort_unstable_by(|a, b| natord::compare(&b.kind_format(), &a.kind_format())),
140 SortBy::File => files.sort_unstable_by(|a, b| natord::compare(&b.filename, &a.filename)),
141 SortBy::Date => Self::reversed_sort_by_key_hrtb(files, |f| &f.system_time),
142 SortBy::Size => Self::reversed_sort_by_key_hrtb(files, |f| &f.true_size),
143 SortBy::Exte => Self::reversed_sort_by_key_hrtb(files, |f| &f.extension),
144 }
145 }
146 }
147}
148
149impl std::fmt::Display for SortKind {
150 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
151 let sort_order = match &self.order {
152 Order::Ascending => "↓",
153 Order::Descending => "↑",
154 };
155 write!(f, "{sort_by} {sort_order}", sort_by = &self.sort_by)
156 }
157}