1pub use nucleo_matcher::pattern::{Atom, AtomKind, CaseMatching, Normalization, Pattern};
2use nucleo_matcher::{Matcher, Utf32String};
3
4#[cfg(test)]
5mod tests;
6
7#[derive(Debug, PartialEq, Eq, Clone, Copy, PartialOrd, Ord, Default)]
8pub(crate) enum Status {
9 #[default]
10 Unchanged,
11 Update,
12 Rescore,
13}
14
15#[derive(Debug)]
16pub struct MultiPattern {
17 cols: Vec<(Pattern, Status)>,
18}
19
20impl Clone for MultiPattern {
21 fn clone(&self) -> Self {
22 Self {
23 cols: self.cols.clone(),
24 }
25 }
26
27 fn clone_from(&mut self, source: &Self) {
28 self.cols.clone_from(&source.cols)
29 }
30}
31
32impl MultiPattern {
33 pub fn new(columns: usize) -> Self {
35 Self {
36 cols: vec![Default::default(); columns],
37 }
38 }
39
40 pub fn reparse(
45 &mut self,
46 column: usize,
47 new_text: &str,
48 case_matching: CaseMatching,
49 normalization: Normalization,
50 append: bool,
51 ) {
52 let old_status = self.cols[column].1;
53 if append
54 && old_status != Status::Rescore
55 && self.cols[column]
56 .0
57 .atoms
58 .last()
59 .map_or(true, |last| !last.negative)
60 {
61 self.cols[column].1 = Status::Update;
62 } else {
63 self.cols[column].1 = Status::Rescore;
64 }
65 self.cols[column]
66 .0
67 .reparse(new_text, case_matching, normalization);
68 }
69
70 pub fn column_pattern(&self, column: usize) -> &Pattern {
71 &self.cols[column].0
72 }
73
74 pub(crate) fn status(&self) -> Status {
75 self.cols
76 .iter()
77 .map(|&(_, status)| status)
78 .max()
79 .unwrap_or(Status::Unchanged)
80 }
81
82 pub(crate) fn reset_status(&mut self) {
83 for (_, status) in &mut self.cols {
84 *status = Status::Unchanged
85 }
86 }
87
88 pub fn score(&self, haystack: &[Utf32String], matcher: &mut Matcher) -> Option<u32> {
89 let mut score = 0;
91 for ((pattern, _), haystack) in self.cols.iter().zip(haystack) {
92 score += pattern.score(haystack.slice(..), matcher)?
93 }
94 Some(score)
95 }
96
97 pub fn is_empty(&self) -> bool {
98 self.cols.iter().all(|(pat, _)| pat.atoms.is_empty())
99 }
100}