支持中文首字母搜索文件

This commit is contained in:
fwt 2024-04-23 00:47:15 +08:00
parent 8456d3a7dc
commit b960aec48c
3 changed files with 109 additions and 3 deletions

View file

@ -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<theme::Theme> = RoCell::new();
pub static INPUT: RoCell<popup::Input> = RoCell::new();
pub static SELECT: RoCell<popup::Select> = RoCell::new();
pub static WHICH: RoCell<which::Which> = RoCell::new();
pub static USER_DIC: RoCell<userdic::USERDICT> = 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);

View file

@ -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<char, Vec<char>>
}
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<char> = 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
}

View file

@ -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<char>,
}
struct MatchResult {
ismatch: bool,
range: Option<Range<usize>>
}
fn table_match(needle: &Vec<char>, haystack: Vec<char>, 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::<String>().len();
let end:usize = haystack[0..(i + needle.len())].into_iter().collect::<String>().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<Self> {
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<char> = 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<Vec<Range<usize>>> {
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
}
},
}
}
}