diff --git a/src/algos/fzf/fzf.rs b/src/algos/fzf/fzf.rs index 0c83a72..081e325 100644 --- a/src/algos/fzf/fzf.rs +++ b/src/algos/fzf/fzf.rs @@ -1,6 +1,7 @@ use core::ops::Range; use super::{query::*, *}; +use crate::utils::CharEq; use crate::*; /// TODO: docs @@ -8,6 +9,9 @@ pub(super) trait Fzf { /// TODO: docs fn alloc_chars<'a>(&mut self, candidate: &str) -> &'a [char]; + /// TODO: docs + fn char_eq(&self, pattern: Pattern) -> CharEq; + /// TODO: docs fn scheme(&self) -> &Scheme; @@ -36,7 +40,25 @@ pub(super) trait Fzf { }, MatchType::Exact => { - todo!(); + let char_eq = self.char_eq(pattern); + + if pattern.is_inverse { + exact_match::( + pattern, + candidate, + char_eq, + self.scheme(), + ranges, + ) + } else { + exact_match::( + pattern, + candidate, + char_eq, + self.scheme(), + ranges, + ) + } }, MatchType::PrefixExact => { @@ -193,12 +215,12 @@ pub(super) fn calculate_score( /// TODO: docs #[inline] -pub(super) fn exact_match( +pub(super) fn exact_match( pattern: Pattern, - candidate: &str, - opts: impl Opts, + candidate: Candidate, + char_eq: CharEq, scheme: &Scheme, - ranges_buf: Option<&mut MatchedRanges>, + ranges: &mut MatchedRanges, ) -> Option { if pattern.is_empty() { return Some(0); @@ -216,30 +238,29 @@ pub(super) fn exact_match( // TODO: docs let mut matched = false; - let mut prev_char_class = scheme.initial_char_class; + let mut prev_class = scheme.initial_char_class; let mut start_offset = 0; 'outer: loop { let current_start_offset = start_offset; - let candidate = &candidate[start_offset..]; let mut bonus_start = 0; let mut current_bonus: Score = 0; let mut pattern_char_idx = 0; - let mut char_indices = candidate.char_indices(); + let mut chars = candidate.chars_from(start_offset).enumerate(); - for (byte_offset, candidate_ch) in char_indices.by_ref() { + for (char_offset, candidate_ch) in chars.by_ref() { let pattern_ch = pattern.char(pattern_char_idx); let char_class = char_class(candidate_ch, scheme); - if opts.char_eq(pattern_ch, candidate_ch) { + if (char_eq)(pattern_ch, candidate_ch) { if pattern_char_idx == 0 { - bonus_start = current_start_offset + byte_offset; - start_offset += byte_offset + candidate_ch.len_utf8(); + bonus_start = current_start_offset + char_offset; + start_offset += char_offset + 1; current_bonus = - compute_bonus(prev_char_class, char_class, scheme); + compute_bonus(prev_class, char_class, scheme); } pattern_char_idx += 1; @@ -252,9 +273,8 @@ pub(super) fn exact_match( best_bonus_start = bonus_start; - best_bonus_end = current_start_offset - + byte_offset - + candidate_ch.len_utf8(); + best_bonus_end = + current_start_offset + char_offset + 1; } if current_bonus >= bonus::BOUNDARY { @@ -267,10 +287,10 @@ pub(super) fn exact_match( break; } - prev_char_class = char_class; + prev_class = char_class; } - if char_indices.next().is_none() { + if chars.next().is_none() { break; } } @@ -281,20 +301,22 @@ pub(super) fn exact_match( let matched_range = best_bonus_start..best_bonus_end; - let score = calculate_score( - pattern, - candidate, - matched_range.clone(), - opts, - scheme, - None, - ); + // let score = calculate_score( + // pattern, + // candidate, + // matched_range.clone(), + // opts, + // scheme, + // None, + // ); - if let Some(ranges) = ranges_buf { + if RANGES { ranges.insert(matched_range); } - Some(score) + todo!(); + + // Some(score) } /// TODO: docs diff --git a/src/algos/fzf/fzf_v1.rs b/src/algos/fzf/fzf_v1.rs index bb6e97b..85c0816 100644 --- a/src/algos/fzf/fzf_v1.rs +++ b/src/algos/fzf/fzf_v1.rs @@ -106,6 +106,17 @@ impl Fzf for FzfV1 { unsafe { core::mem::transmute(self.candidate_slab.alloc(s)) } } + #[inline(always)] + fn char_eq(&self, pattern: Pattern) -> utils::CharEq { + let is_sensitive = match self.case_sensitivity { + CaseSensitivity::Sensitive => true, + CaseSensitivity::Insensitive => false, + CaseSensitivity::Smart => pattern.has_uppercase, + }; + + utils::char_eq(is_sensitive, self.normalization) + } + #[inline(always)] fn scheme(&self) -> &Scheme { &self.scheme diff --git a/src/algos/fzf/fzf_v2.rs b/src/algos/fzf/fzf_v2.rs index 76551fe..9231d9a 100644 --- a/src/algos/fzf/fzf_v2.rs +++ b/src/algos/fzf/fzf_v2.rs @@ -107,6 +107,17 @@ impl Fzf for FzfV2 { unsafe { core::mem::transmute(self.candidate_slab.alloc(s)) } } + #[inline(always)] + fn char_eq(&self, pattern: Pattern) -> utils::CharEq { + let is_sensitive = match self.case_sensitivity { + CaseSensitivity::Sensitive => true, + CaseSensitivity::Insensitive => false, + CaseSensitivity::Smart => pattern.has_uppercase, + }; + + utils::char_eq(is_sensitive, self.normalization) + } + #[inline(always)] fn scheme(&self) -> &Scheme { &self.scheme diff --git a/src/candidate.rs b/src/candidate.rs index 6f5c9fe..82003d5 100644 --- a/src/candidate.rs +++ b/src/candidate.rs @@ -17,6 +17,19 @@ impl<'a> Candidate<'a> { } } + /// TODO: docs + #[inline(always)] + pub fn chars_from(&self, char_offset: usize) -> Chars<'_> { + match self { + Candidate::Ascii(slice) => { + Chars::Ascii(slice[char_offset..].iter()) + }, + Candidate::Unicode(slice) => { + Chars::Unicode(slice[char_offset..].iter()) + }, + } + } + /// TODO: docs #[inline(always)] pub fn char_len(&self) -> usize { @@ -226,36 +239,21 @@ fn find_last_unicode( .find_map(|(idx, &ch)| char_eq(needle, ch).then_some(idx)) } -struct UnicodeMatches<'a> { - needle: char, - haystack: &'a [char], - char_eq: CharEq, - offset: usize, -} - -impl<'a> UnicodeMatches<'a> { - fn new(ch: char, haystack: &'a [char], char_eq: CharEq) -> Self { - Self { needle: ch, haystack, char_eq, offset: 0 } - } +/// TODO: docs +pub(crate) enum Chars<'a> { + Ascii(core::slice::Iter<'a, u8>), + Unicode(core::slice::Iter<'a, char>), } -impl Iterator for UnicodeMatches<'_> { - type Item = usize; +impl Iterator for Chars<'_> { + type Item = char; #[inline(always)] fn next(&mut self) -> Option { - let idx = - self.haystack.iter().enumerate().find_map(|(idx, &ch)| { - (self.char_eq)(self.needle, ch).then_some(idx) - })?; - - self.haystack = &self.haystack[idx + 1..]; - - let offset = self.offset + idx; - - self.offset = offset + 1; - - Some(offset) + match self { + Chars::Ascii(iter) => iter.next().copied().map(char::from), + Chars::Unicode(iter) => iter.next().copied(), + } } } @@ -323,3 +321,36 @@ impl Iterator for CandidateMatches<'_> { .map(|offset| self.start_offset + offset) } } + +struct UnicodeMatches<'a> { + needle: char, + haystack: &'a [char], + char_eq: CharEq, + offset: usize, +} + +impl<'a> UnicodeMatches<'a> { + fn new(ch: char, haystack: &'a [char], char_eq: CharEq) -> Self { + Self { needle: ch, haystack, char_eq, offset: 0 } + } +} + +impl Iterator for UnicodeMatches<'_> { + type Item = usize; + + #[inline(always)] + fn next(&mut self) -> Option { + let idx = + self.haystack.iter().enumerate().find_map(|(idx, &ch)| { + (self.char_eq)(self.needle, ch).then_some(idx) + })?; + + self.haystack = &self.haystack[idx + 1..]; + + let offset = self.offset + idx; + + self.offset = offset + 1; + + Some(offset) + } +}