feat: enable the ability to sort the which key (#662)

This commit is contained in:
AbhaySP 2024-02-13 00:09:36 +05:30 committed by GitHub
parent 3213674dc7
commit 84616bd15f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
11 changed files with 139 additions and 19 deletions

View file

@ -183,5 +183,10 @@ open_title = "Open with:"
open_origin = "hovered" open_origin = "hovered"
open_offset = [ 0, 1, 50, 7 ] open_offset = [ 0, 1, 50, 7 ]
[which]
sort_by = "none"
sort_sensitive = false
sort_reverse = false
[log] [log]
enabled = false enabled = false

View file

@ -5,7 +5,7 @@ use yazi_shared::event::Cmd;
use super::Key; use super::Key;
#[derive(Debug, Deserialize)] #[derive(Debug, Default, Deserialize)]
pub struct Control { pub struct Control {
pub on: Vec<Key>, pub on: Vec<Key>,
#[serde(deserialize_with = "super::exec_deserialize")] #[serde(deserialize_with = "super::exec_deserialize")]
@ -43,6 +43,7 @@ impl Control {
} }
} }
#[derive(Debug)]
pub enum ControlCow { pub enum ControlCow {
Owned(Control), Owned(Control),
Borrowed(&'static Control), Borrowed(&'static Control),
@ -67,6 +68,10 @@ impl Deref for ControlCow {
} }
} }
impl Default for ControlCow {
fn default() -> Self { Self::Owned(Control::default()) }
}
impl ControlCow { impl ControlCow {
pub fn into_seq(self) -> VecDeque<Cmd> { pub fn into_seq(self) -> VecDeque<Cmd> {
match self { match self {

View file

@ -17,6 +17,7 @@ mod priority;
mod tasks; mod tasks;
pub mod theme; pub mod theme;
mod validation; mod validation;
pub mod which;
mod xdg; mod xdg;
pub use layout::*; pub use layout::*;
@ -43,6 +44,7 @@ pub static TASKS: RoCell<tasks::Tasks> = RoCell::new();
pub static THEME: RoCell<theme::Theme> = RoCell::new(); pub static THEME: RoCell<theme::Theme> = RoCell::new();
pub static INPUT: RoCell<popup::Input> = RoCell::new(); pub static INPUT: RoCell<popup::Input> = RoCell::new();
pub static SELECT: RoCell<popup::Select> = RoCell::new(); pub static SELECT: RoCell<popup::Select> = RoCell::new();
pub static WHICH: RoCell<which::Which> = RoCell::new();
pub fn init() { pub fn init() {
ARGS.with(Default::default); ARGS.with(Default::default);
@ -63,4 +65,5 @@ pub fn init() {
THEME.with(Default::default); THEME.with(Default::default);
INPUT.with(Default::default); INPUT.with(Default::default);
SELECT.with(Default::default); SELECT.with(Default::default);
WHICH.with(Default::default);
} }

View file

@ -0,0 +1,5 @@
mod sorting;
mod which;
pub use sorting::*;
pub use which::*;

View file

@ -0,0 +1,32 @@
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<Self, Self::Err> {
Ok(match s {
"none" => Self::None,
"key" => Self::Key,
"desc" => Self::Desc,
_ => bail!("Invalid sort option: {s}"),
})
}
}
impl TryFrom<String> for SortBy {
type Error = anyhow::Error;
fn try_from(value: String) -> Result<Self, Self::Error> { Self::from_str(&value) }
}

View file

@ -0,0 +1,24 @@
use serde::{Deserialize, Serialize};
use validator::Validate;
use super::SortBy;
use crate::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,
}
toml::from_str::<Outer>(&MERGED_YAZI).unwrap().which
}
}

View file

@ -12,9 +12,9 @@ pub struct FilesSorter {
} }
impl FilesSorter { impl FilesSorter {
pub(super) fn sort(&self, items: &mut Vec<File>, sizes: &BTreeMap<Url, u64>) -> bool { pub(super) fn sort(&self, items: &mut Vec<File>, sizes: &BTreeMap<Url, u64>) {
if items.is_empty() { if items.is_empty() {
return false; return;
} }
let by_alphabetical = |a: &File, b: &File| { let by_alphabetical = |a: &File, b: &File| {
@ -30,7 +30,7 @@ impl FilesSorter {
}; };
match self.by { match self.by {
SortBy::None => return false, SortBy::None => {}
SortBy::Modified => items.sort_unstable_by(|a, b| { SortBy::Modified => items.sort_unstable_by(|a, b| {
let ord = self.cmp(a.modified, b.modified, self.promote(a, b)); let ord = self.cmp(a.modified, b.modified, self.promote(a, b));
if ord == Ordering::Equal { by_alphabetical(a, b) } else { ord } if ord == Ordering::Equal { by_alphabetical(a, b) } else { ord }
@ -60,7 +60,6 @@ impl FilesSorter {
if ord == Ordering::Equal { by_alphabetical(a, b) } else { ord } if ord == Ordering::Equal { by_alphabetical(a, b) } else { ord }
}), }),
} }
true
} }
fn sort_naturally(&self, items: &mut Vec<File>) { fn sort_naturally(&self, items: &mut Vec<File>) {
@ -81,11 +80,7 @@ impl FilesSorter {
if self.reverse { ordering.reverse() } else { ordering } if self.reverse { ordering.reverse() } else { ordering }
}); });
let mut new = Vec::with_capacity(indices.len()); *items = indices.into_iter().map(|i| mem::take(&mut items[i])).collect();
for i in indices {
new.push(mem::take(&mut items[i]));
}
*items = new;
} }
#[inline(always)] #[inline(always)]

View file

@ -3,7 +3,7 @@ use std::str::FromStr;
use yazi_config::{keymap::{Control, Key}, KEYMAP}; use yazi_config::{keymap::{Control, Key}, KEYMAP};
use yazi_shared::{event::Cmd, render, Layer}; use yazi_shared::{event::Cmd, render, Layer};
use crate::which::Which; use crate::which::{Which, WhichSorter};
pub struct Opt { pub struct Opt {
cands: Vec<Control>, cands: Vec<Control>,
@ -52,6 +52,7 @@ impl Which {
.map(|c| c.into()) .map(|c| c.into())
.collect(); .collect();
WhichSorter::default().sort(&mut self.cands);
self.visible = true; self.visible = true;
self.silent = false; self.silent = false;
render!(); render!();

View file

@ -1,4 +1,6 @@
mod commands; mod commands;
mod sorter;
mod which; mod which;
pub use sorter::*;
pub use which::*; pub use which::*;

View file

@ -0,0 +1,47 @@
use std::{borrow::Cow, mem};
use yazi_config::{keymap::ControlCow, which::SortBy, WHICH};
use yazi_shared::natsort;
#[derive(Clone, Copy, PartialEq)]
pub struct WhichSorter {
pub by: SortBy,
pub sensitive: bool,
pub reverse: bool,
}
impl Default for WhichSorter {
fn default() -> Self {
Self {
by: WHICH.sort_by,
sensitive: WHICH.sort_sensitive,
reverse: WHICH.sort_reverse,
}
}
}
impl WhichSorter {
pub(super) fn sort(&self, items: &mut Vec<ControlCow>) {
if self.by == SortBy::None || items.is_empty() {
return;
}
let mut indices = Vec::with_capacity(items.len());
let mut entities = Vec::with_capacity(items.len());
for (i, ctrl) in items.iter().enumerate() {
indices.push(i);
entities.push(match self.by {
SortBy::None => unreachable!(),
SortBy::Key => Cow::Owned(ctrl.on()),
SortBy::Desc => ctrl.desc_or_exec(),
});
}
indices.sort_unstable_by(|&a, &b| {
let ordering = natsort(entities[a].as_bytes(), entities[b].as_bytes(), !self.sensitive);
if self.reverse { ordering.reverse() } else { ordering }
});
*items = indices.into_iter().map(|i| mem::take(&mut items[i])).collect();
}
}

View file

@ -7,19 +7,12 @@ pub struct Which {
pub times: usize, pub times: usize,
pub cands: Vec<ControlCow>, pub cands: Vec<ControlCow>,
// Visibility
pub visible: bool, pub visible: bool,
pub silent: bool, pub silent: bool,
} }
impl Which { impl Which {
fn reset(&mut self) {
self.times = 0;
self.cands.clear();
self.visible = false;
self.silent = false;
}
pub fn type_(&mut self, key: Key) -> bool { pub fn type_(&mut self, key: Key) -> bool {
self.cands.retain(|c| c.on.len() > self.times && c.on[self.times] == key); self.cands.retain(|c| c.on.len() > self.times && c.on[self.times] == key);
self.times += 1; self.times += 1;
@ -37,4 +30,12 @@ impl Which {
render!(); render!();
true true
} }
fn reset(&mut self) {
self.times = 0;
self.cands.clear();
self.visible = false;
self.silent = false;
}
} }