From b62307dc4a7635eb1f31d3222f65856e5553c36d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=89=E5=92=B2=E9=9B=85=20=C2=B7=20Misaki=20Masa?= Date: Thu, 14 Sep 2023 09:34:07 +0800 Subject: [PATCH 1/2] feat: make the glob expr case insensitive by default, and prepend `\s` to make it sensitive (#156) --- config/docs/yazi.md | 4 ++-- config/src/pattern.rs | 22 ++++++++++++++++------ 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/config/docs/yazi.md b/config/docs/yazi.md index 7e6f4255..0500fde2 100644 --- a/config/docs/yazi.md +++ b/config/docs/yazi.md @@ -81,8 +81,8 @@ rules = [ Available rule parameters are as follows: -- name: Glob expression for matching the file name -- mime: Glob expression for matching the MIME type +- name: Glob expression for matching the file name. Case insensitive by default, add `\s` to the beginning to make it sensitive. +- mime: Glob expression for matching the MIME type. Case insensitive by default, add `\s` to the beginning to make it sensitive. - use: Opener name corresponding to the names in the opener section. ## tasks diff --git a/config/src/pattern.rs b/config/src/pattern.rs index 1b5bdc60..7a9d7c30 100644 --- a/config/src/pattern.rs +++ b/config/src/pattern.rs @@ -1,18 +1,26 @@ use std::path::Path; +use glob::MatchOptions; use serde::Deserialize; #[derive(Debug, Deserialize)] #[serde(try_from = "String")] pub struct Pattern { inner: glob::Pattern, + sensitive: bool, is_folder: bool, full_path: bool, } impl Pattern { #[inline] - pub fn matches(&self, str: impl AsRef) -> bool { self.inner.matches(str.as_ref()) } + pub fn matches(&self, str: impl AsRef) -> bool { + self.inner.matches_with(str.as_ref(), MatchOptions { + case_sensitive: self.sensitive, + require_literal_separator: false, + require_literal_leading_dot: false, + }) + } #[inline] pub fn match_path(&self, path: impl AsRef, is_folder: Option) -> bool { @@ -20,7 +28,7 @@ impl Pattern { let s = if self.full_path { path.to_str() } else { - path.file_name().and_then(|n| n.to_str()).or(path.to_str()) + path.file_name().and_then(|n| n.to_str()).or_else(|| path.to_str()) }; is_folder.map_or(true, |f| f == self.is_folder) && s.map_or(false, |s| self.matches(s)) } @@ -30,11 +38,13 @@ impl TryFrom<&str> for Pattern { type Error = anyhow::Error; fn try_from(s: &str) -> Result { - let new = s.trim_end_matches('/'); + let a = s.trim_start_matches("\\s"); + let b = a.trim_end_matches('/'); Ok(Self { - inner: glob::Pattern::new(new)?, - is_folder: new.len() < s.len(), - full_path: new.contains('/'), + inner: glob::Pattern::new(b)?, + sensitive: a.len() < s.len(), + is_folder: b.len() < a.len(), + full_path: b.contains('/'), }) } } From 902c0942244f2e1753899ed0aa1d4faf5b01c7eb Mon Sep 17 00:00:00 2001 From: Linus <23507341+Linus789@users.noreply.github.com> Date: Thu, 14 Sep 2023 01:56:50 +0000 Subject: [PATCH 2/2] feat: new `sort_sensitive` option, and sort case-insensitively by default (#155) --- app/src/executor.rs | 1 + config/docs/yazi.md | 5 +++++ config/preset/yazi.toml | 1 + config/src/manager/manager.rs | 1 + core/src/files/sorter.rs | 32 +++++++++++++++++++++++--------- 5 files changed, 31 insertions(+), 9 deletions(-) diff --git a/app/src/executor.rs b/app/src/executor.rs index 6c7e41ae..bbc1ffec 100644 --- a/app/src/executor.rs +++ b/app/src/executor.rs @@ -151,6 +151,7 @@ impl Executor { let b = cx.manager.active_mut().set_sorter(FilesSorter { by: SortBy::try_from(exec.args.get(0).cloned().unwrap_or_default()) .unwrap_or_default(), + sensitive: exec.named.contains_key("sensitive"), reverse: exec.named.contains_key("reverse"), dir_first: exec.named.contains_key("dir_first"), }); diff --git a/config/docs/yazi.md b/config/docs/yazi.md index 0500fde2..0c609692 100644 --- a/config/docs/yazi.md +++ b/config/docs/yazi.md @@ -14,6 +14,11 @@ - `"natural"`: Sort naturally, e.g. `1.md` < `2.md` < `10.md` - `"size"`: Sort by file size +- sort_sensitive: Sort case-sensitively + + - `true`: Case-sensitive + - `false`: Case-insensitive + - sort_reverse: Display files in reverse order - `true`: Reverse order diff --git a/config/preset/yazi.toml b/config/preset/yazi.toml index ed101007..0e23f707 100644 --- a/config/preset/yazi.toml +++ b/config/preset/yazi.toml @@ -1,6 +1,7 @@ [manager] layout = [ 1, 4, 3 ] sort_by = "modified" +sort_sensitive = false sort_reverse = true sort_dir_first = true show_hidden = false diff --git a/config/src/manager/manager.rs b/config/src/manager/manager.rs index ddc1627a..f1acf380 100644 --- a/config/src/manager/manager.rs +++ b/config/src/manager/manager.rs @@ -9,6 +9,7 @@ pub struct Manager { // Sorting pub sort_by: SortBy, + pub sort_sensitive: bool, pub sort_reverse: bool, pub sort_dir_first: bool, diff --git a/core/src/files/sorter.rs b/core/src/files/sorter.rs index 36ce4794..5149a9ac 100644 --- a/core/src/files/sorter.rs +++ b/core/src/files/sorter.rs @@ -1,4 +1,4 @@ -use std::{cmp::Ordering, collections::BTreeMap, mem}; +use std::{cmp::Ordering, collections::BTreeMap, mem, ops::Deref}; use config::{manager::SortBy, MANAGER}; use shared::Url; @@ -8,6 +8,7 @@ use super::File; #[derive(Clone, Copy, PartialEq)] pub struct FilesSorter { pub by: SortBy, + pub sensitive: bool, pub reverse: bool, pub dir_first: bool, } @@ -16,6 +17,7 @@ impl Default for FilesSorter { fn default() -> Self { Self { by: MANAGER.sort_by, + sensitive: MANAGER.sort_sensitive, reverse: MANAGER.sort_reverse, dir_first: MANAGER.sort_dir_first, } @@ -29,9 +31,17 @@ impl FilesSorter { } match self.by { - SortBy::Alphabetical => { - items.sort_unstable_by(|a, b| self.cmp(&*a.url, &*b.url, self.promote(a, b))) - } + SortBy::Alphabetical => items.sort_unstable_by(|a, b| { + if self.sensitive { + return self.cmp(&*a.url, &*b.url, self.promote(a, b)); + } + + self.cmp( + a.url.as_os_str().to_ascii_lowercase(), + b.url.as_os_str().to_ascii_lowercase(), + self.promote(a, b), + ) + }), SortBy::Created => items.sort_unstable_by(|a, b| { if let (Ok(aa), Ok(bb)) = (a.meta.created(), b.meta.created()) { return self.cmp(aa, bb, self.promote(a, b)); @@ -65,12 +75,16 @@ impl FilesSorter { indices.sort_unstable_by(|&a, &b| { let promote = self.promote(entities[a].1, entities[b].1); if promote != Ordering::Equal { - promote - } else if self.reverse { - natord::compare(&entities[b].0, &entities[a].0) - } else { - natord::compare(&entities[a].0, &entities[b].0) + return promote; } + + let ordering = if self.sensitive { + natord::compare(&entities[a].0, &entities[b].0) + } else { + natord::compare_ignore_case(&entities[a].0, &entities[b].0) + }; + + if self.reverse { ordering.reverse() } else { ordering } }); let dummy = File {