Skip to content

Commit

Permalink
fzf: re-implement exact_match using Candidate
Browse files Browse the repository at this point in the history
  • Loading branch information
noib3 committed Nov 23, 2023
1 parent 21bb609 commit 1c35a4b
Show file tree
Hide file tree
Showing 4 changed files with 128 additions and 53 deletions.
78 changes: 50 additions & 28 deletions src/algos/fzf/fzf.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
use core::ops::Range;

use super::{query::*, *};
use crate::utils::CharEq;
use crate::*;

/// TODO: docs
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;

Expand Down Expand Up @@ -36,7 +40,25 @@ pub(super) trait Fzf {
},

MatchType::Exact => {
todo!();
let char_eq = self.char_eq(pattern);

if pattern.is_inverse {
exact_match::<false>(
pattern,
candidate,
char_eq,
self.scheme(),
ranges,
)
} else {
exact_match::<RANGES>(
pattern,
candidate,
char_eq,
self.scheme(),
ranges,
)
}
},

MatchType::PrefixExact => {
Expand Down Expand Up @@ -193,12 +215,12 @@ pub(super) fn calculate_score(

/// TODO: docs
#[inline]
pub(super) fn exact_match(
pub(super) fn exact_match<const RANGES: bool>(
pattern: Pattern,
candidate: &str,
opts: impl Opts,
candidate: Candidate,
char_eq: CharEq,
scheme: &Scheme,
ranges_buf: Option<&mut MatchedRanges>,
ranges: &mut MatchedRanges,
) -> Option<Score> {
if pattern.is_empty() {
return Some(0);
Expand All @@ -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;
Expand All @@ -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 {
Expand All @@ -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;
}
}
Expand All @@ -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
Expand Down
11 changes: 11 additions & 0 deletions src/algos/fzf/fzf_v1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
11 changes: 11 additions & 0 deletions src/algos/fzf/fzf_v2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
81 changes: 56 additions & 25 deletions src/candidate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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<Self::Item> {
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(),
}
}
}

Expand Down Expand Up @@ -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<Self::Item> {
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)
}
}

0 comments on commit 1c35a4b

Please sign in to comment.