From 1e3b17e58c492fef139c00d3857d2a3584b76792 Mon Sep 17 00:00:00 2001 From: Yifan Song <41675306+Eric-Song-Nop@users.noreply.github.com> Date: Sat, 12 Aug 2023 23:08:39 +0800 Subject: [PATCH] feat: add `sort_dir_first` option (#49) --- app/src/executor.rs | 5 ++-- config/docs/yazi.md | 5 ++++ config/preset/yazi.toml | 7 +++-- config/src/manager/manager.rs | 5 ++-- core/src/files/files.rs | 53 ++++++++++++++++++++++++----------- 5 files changed, 52 insertions(+), 23 deletions(-) diff --git a/app/src/executor.rs b/app/src/executor.rs index 78414152..038c67a1 100644 --- a/app/src/executor.rs +++ b/app/src/executor.rs @@ -126,9 +126,10 @@ impl Executor { // Sorting "sort" => { let b = cx.manager.current_mut().files.set_sort(FilesSort { - by: SortBy::try_from(exec.args.get(0).cloned().unwrap_or_default()) + by: SortBy::try_from(exec.args.get(0).cloned().unwrap_or_default()) .unwrap_or_default(), - reverse: exec.named.contains_key("reverse"), + reverse: exec.named.contains_key("reverse"), + dir_first: exec.named.contains_key("dir_first"), }); cx.tasks.precache_size(&cx.manager.current().files); b diff --git a/config/docs/yazi.md b/config/docs/yazi.md index a7b414b9..95a94a66 100644 --- a/config/docs/yazi.md +++ b/config/docs/yazi.md @@ -14,6 +14,11 @@ - `true`: Reverse order - `false`: Normal order +- sort_dir_first: Display directories first + + - `true`: Directories first + - `false`: Respects `sort_by` and `sort_reverse` only + - show_hidden: Show hidden files - `true`: Show diff --git a/config/preset/yazi.toml b/config/preset/yazi.toml index 4d91f538..55ebca59 100644 --- a/config/preset/yazi.toml +++ b/config/preset/yazi.toml @@ -1,7 +1,8 @@ [manager] -sort_by = "modified" -sort_reverse = true -show_hidden = false +sort_by = "modified" +sort_reverse = true +sort_dir_first = true +show_hidden = false [preview] tab_size = 2 diff --git a/config/src/manager/manager.rs b/config/src/manager/manager.rs index 319ef7bd..3995d302 100644 --- a/config/src/manager/manager.rs +++ b/config/src/manager/manager.rs @@ -6,8 +6,9 @@ use crate::MERGED_YAZI; #[derive(Debug, Deserialize)] pub struct Manager { // Sorting - pub sort_by: SortBy, - pub sort_reverse: bool, + pub sort_by: SortBy, + pub sort_reverse: bool, + pub sort_dir_first: bool, // Display pub show_hidden: bool, diff --git a/core/src/files/files.rs b/core/src/files/files.rs index d2c39eb6..8af98a90 100644 --- a/core/src/files/files.rs +++ b/core/src/files/files.rs @@ -1,4 +1,4 @@ -use std::{collections::BTreeMap, ops::{Deref, DerefMut}, path::{Path, PathBuf}}; +use std::{cmp::Ordering, collections::BTreeMap, ops::{Deref, DerefMut}, path::{Path, PathBuf}}; use anyhow::Result; use config::{manager::SortBy, MANAGER}; @@ -116,28 +116,42 @@ impl Files { return false; } - fn cmp(a: T, b: T, reverse: bool) -> std::cmp::Ordering { - if reverse { b.cmp(&a) } else { a.cmp(&b) } + #[inline] + #[allow(clippy::collapsible_else_if)] + fn cmp(a: T, b: T, reverse: bool, promote: Ordering) -> Ordering { + if promote != Ordering::Equal { + promote + } else { + if reverse { b.cmp(&a) } else { a.cmp(&b) } + } + } + + #[inline] + fn promote(a: &File, b: &File, dir_first: bool) -> Ordering { + if dir_first { b.meta.is_dir().cmp(&a.meta.is_dir()) } else { Ordering::Equal } } let reverse = self.sort.reverse; + let dir_first = self.sort.dir_first; match self.sort.by { - SortBy::Alphabetical => self.items.sort_by(|_, a, _, b| cmp(&a.path, &b.path, reverse)), + SortBy::Alphabetical => { + self.items.sort_by(|_, a, _, b| cmp(&a.path, &b.path, reverse, promote(a, b, dir_first))) + } SortBy::Created => self.items.sort_by(|_, a, _, b| { - if let (Ok(a), Ok(b)) = (a.meta.created(), b.meta.created()) { - return cmp(a, b, reverse); + if let (Ok(aa), Ok(bb)) = (a.meta.created(), b.meta.created()) { + return cmp(aa, bb, reverse, promote(a, b, dir_first)); } - std::cmp::Ordering::Equal + Ordering::Equal }), SortBy::Modified => self.items.sort_by(|_, a, _, b| { - if let (Ok(a), Ok(b)) = (a.meta.modified(), b.meta.modified()) { - return cmp(a, b, reverse); + if let (Ok(aa), Ok(bb)) = (a.meta.modified(), b.meta.modified()) { + return cmp(aa, bb, reverse, promote(a, b, dir_first)); } - std::cmp::Ordering::Equal + Ordering::Equal + }), + SortBy::Size => self.items.sort_by(|_, a, _, b| { + cmp(a.length.unwrap_or(0), b.length.unwrap_or(0), reverse, promote(a, b, dir_first)) }), - SortBy::Size => { - self.items.sort_by(|_, a, _, b| cmp(a.length.unwrap_or(0), b.length.unwrap_or(0), reverse)) - } } true } @@ -155,12 +169,19 @@ impl DerefMut for Files { #[derive(PartialEq)] pub struct FilesSort { - pub by: SortBy, - pub reverse: bool, + pub by: SortBy, + pub reverse: bool, + pub dir_first: bool, } impl Default for FilesSort { - fn default() -> Self { Self { by: MANAGER.sort_by, reverse: MANAGER.sort_reverse } } + fn default() -> Self { + Self { + by: MANAGER.sort_by, + reverse: MANAGER.sort_reverse, + dir_first: MANAGER.sort_dir_first, + } + } } #[derive(Debug)]