mirror of
https://github.com/sxyazi/yazi.git
synced 2026-07-25 08:41:05 +00:00
支持中文首字母搜索文件
This commit is contained in:
parent
8456d3a7dc
commit
b960aec48c
3 changed files with 109 additions and 3 deletions
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
34
yazi-config/src/userdic.rs
Normal file
34
yazi-config/src/userdic.rs
Normal 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
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue