init
This commit is contained in:
105
src/matcher.rs
Normal file
105
src/matcher.rs
Normal file
@@ -0,0 +1,105 @@
|
||||
use nucleo_matcher::{
|
||||
Config, Matcher,
|
||||
pattern::{AtomKind, CaseMatching, Normalization, Pattern},
|
||||
};
|
||||
use std::sync::{Mutex, OnceLock};
|
||||
|
||||
static MATCHER: OnceLock<Mutex<Matcher>> = OnceLock::new();
|
||||
|
||||
pub fn match_lines(code: &str, start: &str, end: &str) -> Option<(usize, usize)> {
|
||||
let mut matcher = MATCHER
|
||||
.get_or_init(|| Mutex::new(Matcher::new(Config::DEFAULT)))
|
||||
.lock()
|
||||
.ok()?;
|
||||
|
||||
let lines: Vec<&str> = code.lines().collect();
|
||||
let n = lines.len();
|
||||
|
||||
let start_parts: Vec<&str> = start.split('\n').collect();
|
||||
let end_parts: Vec<&str> = end.split('\n').collect();
|
||||
|
||||
let start_len = start_parts.len();
|
||||
let end_len = end_parts.len();
|
||||
|
||||
if start_len == 0 || end_len == 0 || n == 0 {
|
||||
return None;
|
||||
}
|
||||
|
||||
let non_empty: Vec<bool> = lines.iter().map(|line| !line.trim().is_empty()).collect();
|
||||
let nei: Vec<usize> = (0..n).filter(|&i| non_empty[i]).collect();
|
||||
let m = nei.len();
|
||||
|
||||
if m < start_len || m < end_len {
|
||||
return None;
|
||||
}
|
||||
|
||||
let start_patterns: Vec<Pattern> = start_parts
|
||||
.iter()
|
||||
.map(|&part| {
|
||||
Pattern::new(
|
||||
part,
|
||||
CaseMatching::Ignore,
|
||||
Normalization::Smart,
|
||||
AtomKind::Fuzzy,
|
||||
)
|
||||
})
|
||||
.collect();
|
||||
|
||||
let end_patterns: Vec<Pattern> = end_parts
|
||||
.iter()
|
||||
.map(|&part| {
|
||||
Pattern::new(
|
||||
part,
|
||||
CaseMatching::Ignore,
|
||||
Normalization::Smart,
|
||||
AtomKind::Fuzzy,
|
||||
)
|
||||
})
|
||||
.collect();
|
||||
|
||||
let mut start_candidates: Vec<(usize, usize)> = vec![];
|
||||
|
||||
for p in 0..=m - start_len {
|
||||
let matches_all = (0..start_len).all(|k| {
|
||||
let line = lines[nei[p + k]];
|
||||
!start_patterns[k]
|
||||
.match_list(std::iter::once(line), &mut matcher)
|
||||
.is_empty()
|
||||
});
|
||||
if matches_all {
|
||||
start_candidates.push((nei[p], nei[p + start_len - 1]));
|
||||
}
|
||||
}
|
||||
|
||||
let mut end_candidates: Vec<(usize, usize)> = vec![];
|
||||
|
||||
for p in 0..=m - end_len {
|
||||
let matches_all = (0..end_len).all(|k| {
|
||||
let line = lines[nei[p + k]];
|
||||
!end_patterns[k]
|
||||
.match_list(std::iter::once(line), &mut matcher)
|
||||
.is_empty()
|
||||
});
|
||||
if matches_all {
|
||||
end_candidates.push((nei[p], nei[p + end_len - 1]));
|
||||
}
|
||||
}
|
||||
|
||||
let mut result = None;
|
||||
|
||||
for &(s_start, s_end) in &start_candidates {
|
||||
let pos = end_candidates.partition_point(|&(e_start, _)| e_start <= s_end);
|
||||
|
||||
if end_candidates[pos..].len() == 1 {
|
||||
let (_, e_end) = end_candidates[pos];
|
||||
if result.is_some() {
|
||||
return None;
|
||||
}
|
||||
result = Some((s_start, e_end));
|
||||
} else {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
|
||||
result
|
||||
}
|
||||
Reference in New Issue
Block a user