From b960aec48c0349c4222d9a4e5fcde3083323e2b6 Mon Sep 17 00:00:00 2001 From: fwt Date: Tue, 23 Apr 2024 00:47:15 +0800 Subject: [PATCH] =?UTF-8?q?=E6=94=AF=E6=8C=81=E4=B8=AD=E6=96=87=E9=A6=96?= =?UTF-8?q?=E5=AD=97=E6=AF=8D=E6=90=9C=E7=B4=A2=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- yazi-config/src/lib.rs | 3 ++ yazi-config/src/userdic.rs | 34 +++++++++++++++ yazi-core/src/folder/filter.rs | 75 ++++++++++++++++++++++++++++++++-- 3 files changed, 109 insertions(+), 3 deletions(-) create mode 100644 yazi-config/src/userdic.rs diff --git a/yazi-config/src/lib.rs b/yazi-config/src/lib.rs index 5b6b0798..1429d2be 100644 --- a/yazi-config/src/lib.rs +++ b/yazi-config/src/lib.rs @@ -18,6 +18,7 @@ mod tasks; pub mod theme; mod validation; pub mod which; +mod userdic; pub use layout::*; pub(crate) use pattern::*; @@ -46,12 +47,14 @@ 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 static USER_DIC: RoCell = RoCell::new(); pub fn init() -> anyhow::Result<()> { let config_dir = Xdg::config_dir(); MERGED_YAZI.init(Preset::yazi(&config_dir)?); MERGED_KEYMAP.init(Preset::keymap(&config_dir)?); MERGED_THEME.init(Preset::theme(&config_dir)?); + USER_DIC.init(userdic::read_user_dict(&config_dir)); LAYOUT.with(Default::default); diff --git a/yazi-config/src/userdic.rs b/yazi-config/src/userdic.rs new file mode 100644 index 00000000..af5e7022 --- /dev/null +++ b/yazi-config/src/userdic.rs @@ -0,0 +1,34 @@ +use std::collections::HashMap; +use std::fs::File; +use std::io::{BufRead, BufReader}; +use std::path::Path; + + +pub struct USERDICT { + pub exist: bool, + pub table: HashMap> +} + +pub fn read_user_dict(p:&Path) -> USERDICT { + let mut ret = USERDICT { + exist: false, + table: HashMap::new() + }; + + if let Ok(file) = File::open(p.join("user.dict")) { + let reader = BufReader::new(file); + + for line in reader.lines() { + if let Ok(entry) = line { + let parts: Vec = entry.trim().chars().collect(); + if parts.len() == 3 { + ret.table.entry(parts[0]) + .or_insert_with(Vec::new) + .push(parts[2]); + } + } + } + ret.exist = true; + } + ret +} diff --git a/yazi-core/src/folder/filter.rs b/yazi-core/src/folder/filter.rs index 8d7ca45e..fc289bc0 100644 --- a/yazi-core/src/folder/filter.rs +++ b/yazi-core/src/folder/filter.rs @@ -3,16 +3,58 @@ use std::{ffi::OsStr, ops::Range}; use anyhow::Result; use regex::bytes::{Regex, RegexBuilder}; use yazi_shared::event::Cmd; +use yazi_config::USER_DIC; pub struct Filter { raw: String, regex: Regex, + chars: Vec, } +struct MatchResult { + ismatch: bool, + range: Option> +} + + +fn table_match(needle: &Vec, haystack: Vec, flag:bool) -> MatchResult { + let needle_len = needle.len(); + let haystack_len = haystack.len(); + if needle_len > haystack_len { return MatchResult{ismatch:false, range:None} } + + for i in 0..=(haystack_len - needle_len) { + let mut found = true; + for j in 0..needle_len { + if haystack[i + j] == needle[j] { continue; } + if let Some(value) = USER_DIC.table.get(&haystack[i+j]) { + if !value.contains(&needle[j]) { + found = false; + break; + } + } else { + found = false; + break; + } + } + if found { + if flag { + let start:usize = haystack[0..i].into_iter().collect::().len(); + let end:usize = haystack[0..(i + needle.len())].into_iter().collect::().len(); + return MatchResult{ismatch:true, range:Some(start..end)} + } else { + return MatchResult{ismatch:true, range:None} + } + } + } + MatchResult{ismatch:false, range:None} +} + + impl PartialEq for Filter { fn eq(&self, other: &Self) -> bool { self.raw == other.raw } } + impl Filter { pub fn new(s: &str, case: FilterCase) -> Result { let regex = match case { @@ -23,15 +65,42 @@ impl Filter { FilterCase::Sensitive => Regex::new(s)?, FilterCase::Insensitive => RegexBuilder::new(s).case_insensitive(true).build()?, }; - Ok(Self { raw: s.to_owned(), regex }) + let chars: Vec = if USER_DIC.exist { s.chars().collect()} else { Vec::new() }; + + Ok(Self { raw: s.to_owned(), regex, chars}) } #[inline] - pub fn matches(&self, name: &OsStr) -> bool { self.regex.is_match(name.as_encoded_bytes()) } + pub fn matches(&self, name: &OsStr) -> bool { + if self.regex.is_match(name.as_encoded_bytes()) { + return true + } else if !USER_DIC.exist { + return false + } else { + let name_bytes = name.as_encoded_bytes(); + if let Ok(s) = std::str::from_utf8(name_bytes) { + return table_match(&self.chars, s.chars().collect(), false).ismatch + } + false + } + } #[inline] pub fn highlighted(&self, name: &OsStr) -> Option>> { - self.regex.find(name.as_encoded_bytes()).map(|m| vec![m.range()]) + let m = self.regex.find(name.as_encoded_bytes()); + return match m { + Some(r) => Some(vec![r.range()]), + None => { + let name_bytes = name.as_encoded_bytes(); + return match std::str::from_utf8(name_bytes) { + Ok(s) => return match table_match(&self.chars, s.chars().collect(), true).range { + Some(r) => Some(vec![r]), + None => None + }, + Err(_) => None + } + }, + } } }