mirror of
https://github.com/sxyazi/yazi.git
synced 2026-07-25 08:41:05 +00:00
feat: enable the ability to sort the which key (#662)
This commit is contained in:
parent
3213674dc7
commit
84616bd15f
11 changed files with 139 additions and 19 deletions
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
5
yazi-config/src/which/mod.rs
Normal file
5
yazi-config/src/which/mod.rs
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
mod sorting;
|
||||||
|
mod which;
|
||||||
|
|
||||||
|
pub use sorting::*;
|
||||||
|
pub use which::*;
|
||||||
32
yazi-config/src/which/sorting.rs
Normal file
32
yazi-config/src/which/sorting.rs
Normal 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) }
|
||||||
|
}
|
||||||
24
yazi-config/src/which/which.rs
Normal file
24
yazi-config/src/which/which.rs
Normal 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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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)]
|
||||||
|
|
|
||||||
|
|
@ -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!();
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,6 @@
|
||||||
mod commands;
|
mod commands;
|
||||||
|
mod sorter;
|
||||||
mod which;
|
mod which;
|
||||||
|
|
||||||
|
pub use sorter::*;
|
||||||
pub use which::*;
|
pub use which::*;
|
||||||
|
|
|
||||||
47
yazi-core/src/which/sorter.rs
Normal file
47
yazi-core/src/which/sorter.rs
Normal 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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue