Skip to content

Commit d96d203

Browse files
committed
feat: no delimiter bonus for delimiter chars
Previously, we would give a bonus for delimiter characters if they came after a delimiter character. But this caused cases such as `nvim__buf_debug` matching against `nvim_buf` to win out against the `nvim_buf_*` options. Related to saghen/blink.cmp#1530
1 parent 74ff035 commit d96d203

File tree

3 files changed

+27
-9
lines changed

3 files changed

+27
-9
lines changed

src/incremental/matcher.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -192,8 +192,13 @@ mod tests {
192192
assert_eq!(get_score("b", "a--b"), CHAR_SCORE + DELIMITER_BONUS);
193193
assert_eq!(get_score("c", "a--bc"), CHAR_SCORE);
194194
assert_eq!(get_score("a", "-a--bc"), CHAR_SCORE);
195+
}
196+
197+
#[test]
198+
fn test_score_no_delimiter_for_delimiter_chars() {
195199
assert_eq!(get_score("-", "a-bc"), CHAR_SCORE);
196-
assert_eq!(get_score("-", "a--bc"), CHAR_SCORE + DELIMITER_BONUS);
200+
assert_eq!(get_score("-", "a--bc"), CHAR_SCORE);
201+
assert!(get_score("a_b", "a_bb") > get_score("a_b", "a__b"));
197202
}
198203

199204
#[test]

src/smith_waterman/reference.rs

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ pub fn smith_waterman<const W: usize>(needle: &str, haystack: &str) -> (u16, u16
2525

2626
let mut left_gap_penalty_mask = true;
2727
let mut delimiter_bonus_enabled_mask = false;
28-
let mut is_delimiter_mask = false;
28+
let mut prev_is_delimiter_mask = false;
2929

3030
for j in 0..haystack.len() {
3131
let is_prefix = j == 0;
@@ -35,6 +35,7 @@ pub fn smith_waterman<const W: usize>(needle: &str, haystack: &str) -> (u16, u16
3535
let capital_mask = cased_haystack_simd.is_ascii_uppercase();
3636
let haystack_simd = cased_haystack_simd.to_ascii_lowercase();
3737

38+
let is_delimiter_mask = [b' ', b'/', b',', b'_', b'-', b':'].contains(&haystack_simd);
3839
let matched_casing_mask = needle_cased_mask == capital_mask;
3940

4041
// Give a bonus for prefix matches
@@ -49,7 +50,7 @@ pub fn smith_waterman<const W: usize>(needle: &str, haystack: &str) -> (u16, u16
4950
let match_mask = needle_char == haystack_simd;
5051
let diag_score = if match_mask {
5152
diag + match_score
52-
+ if is_delimiter_mask && delimiter_bonus_enabled_mask { DELIMITER_BONUS } else { 0 }
53+
+ if prev_is_delimiter_mask && delimiter_bonus_enabled_mask && !is_delimiter_mask { DELIMITER_BONUS } else { 0 }
5354
// ignore capitalization on the prefix
5455
+ if !is_prefix && capital_mask { CAPITALIZATION_BONUS } else { 0 }
5556
+ if matched_casing_mask { MATCHING_CASE_BONUS } else { 0 }
@@ -83,9 +84,9 @@ pub fn smith_waterman<const W: usize>(needle: &str, haystack: &str) -> (u16, u16
8384
left_gap_penalty_mask = max_score != left_score || diag_mask;
8485

8586
// Update delimiter mask
86-
is_delimiter_mask = [b' ', b'/', b',', b'_', b'-', b':'].contains(&haystack_simd);
87+
prev_is_delimiter_mask = is_delimiter_mask;
8788
// Only enable delimiter bonus if we've seen a non-delimiter char
88-
delimiter_bonus_enabled_mask |= !is_delimiter_mask;
89+
delimiter_bonus_enabled_mask |= !prev_is_delimiter_mask;
8990

9091
// Store the scores for the next iterations
9192
up_score_simd = max_score;
@@ -235,8 +236,13 @@ mod tests {
235236
assert_eq!(get_score("b", "a--b"), CHAR_SCORE + DELIMITER_BONUS);
236237
assert_eq!(get_score("c", "a--bc"), CHAR_SCORE);
237238
assert_eq!(get_score("a", "-a--bc"), CHAR_SCORE);
239+
}
240+
241+
#[test]
242+
fn test_score_no_delimiter_for_delimiter_chars() {
238243
assert_eq!(get_score("-", "a-bc"), CHAR_SCORE);
239-
assert_eq!(get_score("-", "a--bc"), CHAR_SCORE + DELIMITER_BONUS);
244+
assert_eq!(get_score("-", "a--bc"), CHAR_SCORE);
245+
assert!(get_score("a_b", "a_bb") > get_score("a_b", "a__b"));
240246
}
241247

242248
#[test]

src/smith_waterman/simd.rs

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -267,8 +267,10 @@ pub(crate) fn smith_waterman_inner<N, const L: usize>(
267267
let capitalization_bonus =
268268
capitalization_bonus_mask.select(N::CAPITALIZATION_BONUS, N::ZERO_VEC);
269269

270-
let delimiter_bonus_mask: Mask<N::Mask, L> =
271-
prev_haystack_char.is_delimiter_mask & delimiter_bonus_enabled_mask;
270+
let delimiter_bonus_mask: Mask<N::Mask, L> = prev_haystack_char
271+
.is_delimiter_mask
272+
& delimiter_bonus_enabled_mask
273+
& !haystack_char.is_delimiter_mask;
272274
let delimiter_bonus =
273275
delimiter_bonus_mask.select(N::DELIMITER_BONUS, N::ZERO_VEC);
274276

@@ -500,8 +502,13 @@ mod tests {
500502
assert_eq!(get_score("b", "a--b"), CHAR_SCORE + DELIMITER_BONUS);
501503
assert_eq!(get_score("c", "a--bc"), CHAR_SCORE);
502504
assert_eq!(get_score("a", "-a--bc"), CHAR_SCORE);
505+
}
506+
507+
#[test]
508+
fn test_score_no_delimiter_for_delimiter_chars() {
503509
assert_eq!(get_score("-", "a-bc"), CHAR_SCORE);
504-
assert_eq!(get_score("-", "a--bc"), CHAR_SCORE + DELIMITER_BONUS);
510+
assert_eq!(get_score("-", "a--bc"), CHAR_SCORE);
511+
assert!(get_score("a_b", "a_bb") > get_score("a_b", "a__b"));
505512
}
506513

507514
#[test]

0 commit comments

Comments
 (0)