From f6b4c923b4480cce18c8f7da3c555586d8c5ca13 Mon Sep 17 00:00:00 2001 From: coolabhays Date: Sun, 11 Feb 2024 18:43:06 +0530 Subject: [PATCH] feat: Enable the ability to sort the which key * sort "which" window in following way: - sort_by: "key|desc|none" - sort_sensitive: true|false - sort_reverse: true|false --- yazi-config/preset/yazi.toml | 5 ++++ yazi-config/src/keymap/control.rs | 1 + yazi-config/src/lib.rs | 3 ++ yazi-config/src/which/mod.rs | 5 ++++ yazi-config/src/which/sorting.rs | 44 ++++++++++++++++++++++++++++ yazi-config/src/which/which.rs | 27 +++++++++++++++++ yazi-core/src/which/commands/show.rs | 29 ++++++++++-------- yazi-core/src/which/config.rs | 41 ++++++++++++++++++++++++++ yazi-core/src/which/mod.rs | 4 +++ yazi-core/src/which/sorter.rs | 39 ++++++++++++++++++++++++ yazi-core/src/which/which.rs | 6 +++- 11 files changed, 190 insertions(+), 14 deletions(-) create mode 100644 yazi-config/src/which/mod.rs create mode 100644 yazi-config/src/which/sorting.rs create mode 100644 yazi-config/src/which/which.rs create mode 100644 yazi-core/src/which/config.rs create mode 100644 yazi-core/src/which/sorter.rs diff --git a/yazi-config/preset/yazi.toml b/yazi-config/preset/yazi.toml index 789263cc..53005265 100644 --- a/yazi-config/preset/yazi.toml +++ b/yazi-config/preset/yazi.toml @@ -2,6 +2,11 @@ # If you encounter any issues, please make an issue at https://github.com/yazi-rs/schemas. "$schema" = "https://yazi-rs.github.io/schemas/yazi.json" +[which] +sort_by = "none" +sort_sensitive = false +sort_reverse = false + [manager] ratio = [ 1, 4, 3 ] sort_by = "alphabetical" diff --git a/yazi-config/src/keymap/control.rs b/yazi-config/src/keymap/control.rs index 5fae5900..23ae3cf7 100644 --- a/yazi-config/src/keymap/control.rs +++ b/yazi-config/src/keymap/control.rs @@ -43,6 +43,7 @@ impl Control { } } +#[derive(Debug)] pub enum ControlCow { Owned(Control), Borrowed(&'static Control), diff --git a/yazi-config/src/lib.rs b/yazi-config/src/lib.rs index 3347986c..6ef59ed8 100644 --- a/yazi-config/src/lib.rs +++ b/yazi-config/src/lib.rs @@ -18,6 +18,7 @@ mod tasks; pub mod theme; mod validation; mod xdg; +pub mod which; pub use layout::*; pub(crate) use pattern::*; @@ -43,6 +44,7 @@ pub static TASKS: RoCell = RoCell::new(); pub static THEME: RoCell = RoCell::new(); pub static INPUT: RoCell = RoCell::new(); pub static SELECT: RoCell = RoCell::new(); +pub static WHICH: RoCell = RoCell::new(); pub fn init() { ARGS.with(Default::default); @@ -63,4 +65,5 @@ pub fn init() { THEME.with(Default::default); INPUT.with(Default::default); SELECT.with(Default::default); + WHICH.with(Default::default); } diff --git a/yazi-config/src/which/mod.rs b/yazi-config/src/which/mod.rs new file mode 100644 index 00000000..2033591b --- /dev/null +++ b/yazi-config/src/which/mod.rs @@ -0,0 +1,5 @@ +mod sorting; +mod which; + +pub use sorting::*; +pub use which::*; diff --git a/yazi-config/src/which/sorting.rs b/yazi-config/src/which/sorting.rs new file mode 100644 index 00000000..d9a0566f --- /dev/null +++ b/yazi-config/src/which/sorting.rs @@ -0,0 +1,44 @@ +use std::str::FromStr; + +use anyhow::bail; +use serde::{Deserialize, Serialize}; + +#[derive(Clone, Copy, Debug, Default, Deserialize, Serialize, PartialEq, Eq)] +#[serde(try_from = "String")] +pub enum SortBy { + #[default] + None, + Key, + Desc, +} + +impl FromStr for SortBy { + type Err = anyhow::Error; + + fn from_str(s: &str) -> Result { + Ok(match s { + "none" => Self::None, + "key" => Self::Key, + "desc" => Self::Desc, + _ => bail!("Invalid sort option: {s}") + }) + } +} + +impl TryFrom for SortBy { + type Error = anyhow::Error; + + fn try_from(value: String) -> Result { + Self::from_str(&value) + } +} + +impl ToString for SortBy { + fn to_string(&self) -> String { + match self { + Self::None => "none", + Self::Key => "key", + Self::Desc => "desc", + }.to_string() + } +} diff --git a/yazi-config/src/which/which.rs b/yazi-config/src/which/which.rs new file mode 100644 index 00000000..96caccc8 --- /dev/null +++ b/yazi-config/src/which/which.rs @@ -0,0 +1,27 @@ +use serde::{Deserialize, Serialize}; +use validator::Validate; + +use super::SortBy; +use crate::{validation::check_validation, MERGED_YAZI}; + +#[derive(Debug, Deserialize, Serialize, Validate)] +pub struct Which { + // Sorting + pub sort_by: SortBy, + pub sort_sensitive: bool, + pub sort_reverse: bool, +} + +impl Default for Which { + fn default() -> Self { + #[derive(Deserialize)] + struct Outer { + which: Which, + } + + let which = toml::from_str::(&MERGED_YAZI).unwrap().which; + + check_validation(which.validate()); + which + } +} diff --git a/yazi-core/src/which/commands/show.rs b/yazi-core/src/which/commands/show.rs index 63970462..092eb5d4 100644 --- a/yazi-core/src/which/commands/show.rs +++ b/yazi-core/src/which/commands/show.rs @@ -42,18 +42,21 @@ impl Which { render!(); } - pub fn show_with(&mut self, key: &Key, layer: Layer) { - self.layer = layer; - self.times = 1; - self.cands = KEYMAP - .get(layer) - .iter() - .filter(|c| c.on.len() > 1 && &c.on[0] == key) - .map(|c| c.into()) - .collect(); + pub fn show_with(&mut self, key: &Key, layer: Layer) { + self.layer = layer; + self.times = 1; + self.cands = KEYMAP + .get(layer) + .iter() + .filter(|c| c.on.len() > 1 && &c.on[0] == key) + .map(|c| c.into()) + .collect(); - self.visible = true; - self.silent = false; - render!(); - } + // sort "which" + self.conf.sorter().sort(&mut self.cands); + + self.visible = true; + self.silent = false; + render!(); + } } diff --git a/yazi-core/src/which/config.rs b/yazi-core/src/which/config.rs new file mode 100644 index 00000000..986eb3a5 --- /dev/null +++ b/yazi-core/src/which/config.rs @@ -0,0 +1,41 @@ +use yazi_config::{which::SortBy, WHICH}; + +use crate::which::WhichSorter; + +#[derive(Clone, PartialEq, Debug)] +pub struct Config { + // Sorting + pub sort_by: SortBy, + pub sort_sensitive: bool, + pub sort_reverse: bool, +} + +impl Default for Config { + fn default() -> Self { + Self { + // Sorting + sort_by: WHICH.sort_by, + sort_sensitive: WHICH.sort_sensitive, + sort_reverse: WHICH.sort_reverse, + } + } +} + +impl Config { + #[allow(unused)] + pub(super) fn patch(&mut self, f: F) -> bool { + let old = self.clone(); + f(self); + *self != old + } + + #[inline] + pub(super) fn sorter(&self) -> WhichSorter { + WhichSorter { + by: self.sort_by, + sensitive: self.sort_sensitive, + reverse: self.sort_reverse, + } + } +} + diff --git a/yazi-core/src/which/mod.rs b/yazi-core/src/which/mod.rs index b2098e80..824b99b8 100644 --- a/yazi-core/src/which/mod.rs +++ b/yazi-core/src/which/mod.rs @@ -1,4 +1,8 @@ mod commands; mod which; +mod config; +mod sorter; pub use which::*; +pub use config::*; +pub use sorter::*; diff --git a/yazi-core/src/which/sorter.rs b/yazi-core/src/which/sorter.rs new file mode 100644 index 00000000..d73d9f91 --- /dev/null +++ b/yazi-core/src/which/sorter.rs @@ -0,0 +1,39 @@ +use yazi_config::{which::SortBy, keymap::ControlCow}; +use yazi_shared::natsort; + +#[derive(Clone, Copy, Default, PartialEq)] +pub struct WhichSorter { + pub by: SortBy, + pub sensitive: bool, + pub reverse: bool, +} + +impl WhichSorter { + pub(super) fn sort(&self, items: &mut Vec) -> bool { + if items.is_empty() { + return false; + } + + let by_alphabetical = |a: &str, b: &str| { + let ordering = natsort(a.as_bytes(), b.as_bytes(), !self.sensitive); + if self.reverse { ordering.reverse() } else { ordering } + }; + + match self.by { + SortBy::None => return false, + SortBy::Key => items.sort_unstable_by(|a, b| { + let a = a.on.iter().map(|c| c.to_string()).collect::(); + let b = b.on.iter().map(|c| c.to_string()).collect::(); + by_alphabetical(&a, &b) + }), + SortBy::Desc => items.sort_unstable_by(|a, b| { + // what if description isn't present (need to check if it's mandatory or not) + // in case if it is not present, should I just panic ? + by_alphabetical(a.desc.as_ref().unwrap(), b.desc.as_ref().unwrap()) + }) + } + + true + } + +} diff --git a/yazi-core/src/which/which.rs b/yazi-core/src/which/which.rs index 8cc627c8..b5e69aaa 100644 --- a/yazi-core/src/which/which.rs +++ b/yazi-core/src/which/which.rs @@ -1,12 +1,16 @@ use yazi_config::keymap::{ControlCow, Key}; use yazi_shared::{emit, render, Layer}; -#[derive(Default)] +use crate::which::Config; + +#[derive(Default, Debug)] pub struct Which { pub(super) layer: Layer, pub times: usize, pub cands: Vec, + pub conf: Config, + pub visible: bool, pub silent: bool, }