vim-patch:9.1.0963: fuzzy-matching does not prefer full match (#31741)

Problem:  fuzzy-matching does not prefer full match
          (Maxim Kim)
Solution: add additional score for a full match
          (glepnir)

fixes: vim/vim#15654
closes: vim/vim#16300

5a04999a74
This commit is contained in:
glepnir
2024-12-27 14:23:06 +08:00
committed by GitHub
parent 557f2d9700
commit 46c7faa00b
3 changed files with 14 additions and 2 deletions

View File

@@ -1485,6 +1485,7 @@ criteria:
- Matches at a camel case character (e.g. Case in CamelCase) - Matches at a camel case character (e.g. Case in CamelCase)
- Matches after a path separator or a hyphen. - Matches after a path separator or a hyphen.
- The number of unmatched characters in a string. - The number of unmatched characters in a string.
- A full/exact match is preferred.
The matching string with the highest score is returned first. The matching string with the highest score is returned first.
For example, when you search for the "get pat" string using fuzzy matching, it For example, when you search for the "get pat" string using fuzzy matching, it

View File

@@ -2995,6 +2995,7 @@ static int fuzzy_match_compute_score(const char *const str, const int strSz,
assert(numMatches > 0); // suppress clang "result of operation is garbage" assert(numMatches > 0); // suppress clang "result of operation is garbage"
// Initialize score // Initialize score
int score = 100; int score = 100;
bool is_exact_match = true;
// Apply leading letter penalty // Apply leading letter penalty
int penalty = LEADING_LETTER_PENALTY * (int)matches[0]; int penalty = LEADING_LETTER_PENALTY * (int)matches[0];
@@ -3048,6 +3049,14 @@ static int fuzzy_match_compute_score(const char *const str, const int strSz,
// First letter // First letter
score += FIRST_LETTER_BONUS; score += FIRST_LETTER_BONUS;
} }
// Check exact match condition
if (currIdx != (uint32_t)i) {
is_exact_match = false;
}
}
// Boost score for exact matches
if (is_exact_match && numMatches == strSz) {
score += 100;
} }
return score; return score;
} }

View File

@@ -23,6 +23,8 @@ func Test_matchfuzzy()
call assert_equal(['aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'], matchfuzzy(['aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'], 'aa')) call assert_equal(['aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'], matchfuzzy(['aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'], 'aa'))
call assert_equal(256, matchfuzzy([repeat('a', 256)], repeat('a', 256))[0]->len()) call assert_equal(256, matchfuzzy([repeat('a', 256)], repeat('a', 256))[0]->len())
call assert_equal([], matchfuzzy([repeat('a', 300)], repeat('a', 257))) call assert_equal([], matchfuzzy([repeat('a', 300)], repeat('a', 257)))
" full match has highest score
call assert_equal(['Cursor', 'lCursor'], matchfuzzy(["hello", "lCursor", "Cursor"], "Cursor"))
" matches with same score should not be reordered " matches with same score should not be reordered
let l = ['abc1', 'abc2', 'abc3'] let l = ['abc1', 'abc2', 'abc3']
call assert_equal(l, l->matchfuzzy('abc')) call assert_equal(l, l->matchfuzzy('abc'))
@@ -101,7 +103,7 @@ func Test_matchfuzzypos()
call assert_equal([['curl', 'world'], [[2,3], [2,3]], [128, 127]], matchfuzzypos(['world', 'curl'], 'rl')) call assert_equal([['curl', 'world'], [[2,3], [2,3]], [128, 127]], matchfuzzypos(['world', 'curl'], 'rl'))
call assert_equal([['curl', 'world'], [[2,3], [2,3]], [128, 127]], matchfuzzypos(['world', 'one', 'curl'], 'rl')) call assert_equal([['curl', 'world'], [[2,3], [2,3]], [128, 127]], matchfuzzypos(['world', 'one', 'curl'], 'rl'))
call assert_equal([['hello', 'hello world hello world'], call assert_equal([['hello', 'hello world hello world'],
\ [[0, 1, 2, 3, 4], [0, 1, 2, 3, 4]], [275, 257]], \ [[0, 1, 2, 3, 4], [0, 1, 2, 3, 4]], [375, 257]],
\ matchfuzzypos(['hello world hello world', 'hello', 'world'], 'hello')) \ matchfuzzypos(['hello world hello world', 'hello', 'world'], 'hello'))
call assert_equal([['aaaaaaa'], [[0, 1, 2]], [191]], matchfuzzypos(['aaaaaaa'], 'aaa')) call assert_equal([['aaaaaaa'], [[0, 1, 2]], [191]], matchfuzzypos(['aaaaaaa'], 'aaa'))
call assert_equal([['a b'], [[0, 3]], [219]], matchfuzzypos(['a b'], 'a b')) call assert_equal([['a b'], [[0, 3]], [219]], matchfuzzypos(['a b'], 'a b'))
@@ -136,7 +138,7 @@ func Test_matchfuzzypos()
call assert_equal([['foo bar baz'], [[0, 1, 2, 3, 4, 5, 10]], [326]], ['foo bar baz', 'foo', 'foo bar', 'baz bar']->matchfuzzypos('foo baz', {'matchseq': 1})) call assert_equal([['foo bar baz'], [[0, 1, 2, 3, 4, 5, 10]], [326]], ['foo bar baz', 'foo', 'foo bar', 'baz bar']->matchfuzzypos('foo baz', {'matchseq': 1}))
call assert_equal([[], [], []], ['foo bar baz', 'foo', 'foo bar', 'baz bar']->matchfuzzypos('one two')) call assert_equal([[], [], []], ['foo bar baz', 'foo', 'foo bar', 'baz bar']->matchfuzzypos('one two'))
call assert_equal([[], [], []], ['foo bar']->matchfuzzypos(" \t ")) call assert_equal([[], [], []], ['foo bar']->matchfuzzypos(" \t "))
call assert_equal([['grace'], [[1, 2, 3, 4, 2, 3, 4, 0, 1, 2, 3, 4]], [657]], ['grace']->matchfuzzypos('race ace grace')) call assert_equal([['grace'], [[1, 2, 3, 4, 2, 3, 4, 0, 1, 2, 3, 4]], [757]], ['grace']->matchfuzzypos('race ace grace'))
let l = [{'id' : 5, 'val' : 'crayon'}, {'id' : 6, 'val' : 'camera'}] let l = [{'id' : 5, 'val' : 'crayon'}, {'id' : 6, 'val' : 'camera'}]
call assert_equal([[{'id' : 6, 'val' : 'camera'}], [[0, 1, 2]], [192]], call assert_equal([[{'id' : 6, 'val' : 'camera'}], [[0, 1, 2]], [192]],