diff --git a/src/vs/base/common/filters.ts b/src/vs/base/common/filters.ts index bfd15fc35b6040182136d23bc134b7d742103ab3..9c7b7eca6b620f99eb7c0c0e12de4d54550f03ac 100644 --- a/src/vs/base/common/filters.ts +++ b/src/vs/base/common/filters.ts @@ -545,21 +545,22 @@ export function fuzzyScore(pattern: string, word: string): [number, number[]] { let score = -1; let lowWordChar = lowWord[j - 1]; if (lowPattern[i - 1] === lowWordChar) { - if (lowWordChar !== word[j - 1]) { + + if (j === 1) { if (pattern[i - 1] === word[j - 1]) { score = 7; } else { score = 5; } - } else if (lastLowWordChar === '_' || lastLowWordChar === '.') { - score = 5; - - } else if (j === 1) { + } else if (lowWordChar !== word[j - 1]) { if (pattern[i - 1] === word[j - 1]) { score = 7; } else { score = 5; } + } else if (lastLowWordChar === '_' || lastLowWordChar === '.') { + score = 5; + } else if (j === i) { score = 3; @@ -625,7 +626,6 @@ export function fuzzyScore(pattern: string, word: string): [number, number[]] { // keep going left, we cannot // skip a character in the pattern j -= 1; - total -= 1; } else if (arrow === 0) { //diag j -= 1; @@ -642,7 +642,7 @@ export function fuzzyScore(pattern: string, word: string): [number, number[]] { // we went diagonal by inheriting a good // result, not by matching keep going left i += 1; - total -= 1; + } else { // all good @@ -662,6 +662,7 @@ export function fuzzyScore(pattern: string, word: string): [number, number[]] { j = 3; } total -= j * 3; // penalty for first matching character + total -= (1 + matches[matches.length - 1]) - pattern.length; // penalty for all non matching characters between first and last if (_debug) { console.log(`${pattern} & ${word} => ${total} points for ${matches}`); diff --git a/src/vs/base/test/common/filters.test.ts b/src/vs/base/test/common/filters.test.ts index b7393c5c4c2910292bb6e56a26a3ff2a0905047e..4875f89d998a3bb245aecbb6c43291d3781faf2b 100644 --- a/src/vs/base/test/common/filters.test.ts +++ b/src/vs/base/test/common/filters.test.ts @@ -283,55 +283,91 @@ suite('Filters', () => { assertMatches('Three', 'Three', '^T^h^r^e^e', fuzzyScore); }); - - test('topScore', function () { - - function assertTopScore(pattern: string, expected: number, ...words: string[]) { - let topScore = Number.MIN_VALUE; - let topIdx = 0; - for (let i = 0; i < words.length; i++) { - const word = words[i]; - const m = fuzzyMatchAndScore(pattern, word); - if (m) { - const [score] = m; - if (score > topScore) { - topScore = score; - topIdx = i; - } + function assertTopScore(filter: typeof fuzzyMatchAndScore, pattern: string, expected: number, ...words: string[]) { + let topScore = Number.MIN_VALUE; + let topIdx = 0; + for (let i = 0; i < words.length; i++) { + const word = words[i]; + const m = filter(pattern, word); + if (m) { + const [score] = m; + if (score > topScore) { + topScore = score; + topIdx = i; } } - assert.equal(topIdx, expected); } + assert.equal(topIdx, expected, `${pattern} -> actual=${words[topIdx]} <> expected=${words[expected]}`); + } + + test('topScore - fuzzyMatchAndScore', function () { + + + assertTopScore(fuzzyMatchAndScore, 'cons', 2, 'ArrayBufferConstructor', 'Console', 'console'); + assertTopScore(fuzzyMatchAndScore, 'Foo', 1, 'foo', 'Foo', 'foo'); + + assertTopScore(fuzzyMatchAndScore, 'CC', 1, 'camelCase', 'CamelCase'); + assertTopScore(fuzzyMatchAndScore, 'cC', 0, 'camelCase', 'CamelCase'); + assertTopScore(fuzzyMatchAndScore, 'cC', 1, 'ccfoo', 'camelCase'); + assertTopScore(fuzzyMatchAndScore, 'cC', 1, 'ccfoo', 'camelCase', 'foo-cC-bar'); + + // issue #17836 + assertTopScore(fuzzyMatchAndScore, 'p', 0, 'parse', 'posix', 'pafdsa', 'path', 'p'); + assertTopScore(fuzzyMatchAndScore, 'pa', 0, 'parse', 'pafdsa', 'path'); + + // issue #14583 + assertTopScore(fuzzyMatchAndScore, 'log', 3, 'HTMLOptGroupElement', 'ScrollLogicalPosition', 'SVGFEMorphologyElement', 'log'); + assertTopScore(fuzzyMatchAndScore, 'e', 2, 'AbstractWorker', 'ActiveXObject', 'else'); + + // issue #14446 + assertTopScore(fuzzyMatchAndScore, 'workbench.sideb', 1, 'workbench.editor.defaultSideBySideLayout', 'workbench.sideBar.location'); + + // issue #11423 + assertTopScore(fuzzyMatchAndScore, 'editor.r', 2, 'diffEditor.renderSideBySide', 'editor.overviewRulerlanes', 'editor.renderControlCharacter', 'editor.renderWhitespace'); + // assertTopScore(fuzzyMatchAndScore, 'editor.R', 1, 'diffEditor.renderSideBySide', 'editor.overviewRulerlanes', 'editor.renderControlCharacter', 'editor.renderWhitespace'); + // assertTopScore(fuzzyMatchAndScore, 'Editor.r', 0, 'diffEditor.renderSideBySide', 'editor.overviewRulerlanes', 'editor.renderControlCharacter', 'editor.renderWhitespace'); + + assertTopScore(fuzzyMatchAndScore, '-mo', 1, '-ms-ime-mode', '-moz-columns'); + // // dupe, issue #14861 + assertTopScore(fuzzyMatchAndScore, 'convertModelPosition', 0, 'convertModelPositionToViewPosition', 'convertViewToModelPosition'); + // // dupe, issue #14942 + assertTopScore(fuzzyMatchAndScore, 'is', 0, 'isValidViewletId', 'import statement'); + + }); + + test('topScore - fuzzyScore', function () { + - assertTopScore('cons', 2, 'ArrayBufferConstructor', 'Console', 'console'); - assertTopScore('Foo', 1, 'foo', 'Foo', 'foo'); + assertTopScore(fuzzyScore, 'TEdit', 1, 'TextEditorDecorationType', 'TextEdit', 'TextEditor'); + assertTopScore(fuzzyScore, 'cons', 2, 'ArrayBufferConstructor', 'Console', 'console'); + assertTopScore(fuzzyScore, 'Foo', 1, 'foo', 'Foo', 'foo'); - assertTopScore('CC', 1, 'camelCase', 'CamelCase'); - assertTopScore('cC', 0, 'camelCase', 'CamelCase'); - assertTopScore('cC', 1, 'ccfoo', 'camelCase'); - assertTopScore('cC', 1, 'ccfoo', 'camelCase', 'foo-cC-bar'); + assertTopScore(fuzzyScore, 'CC', 1, 'camelCase', 'CamelCase'); + assertTopScore(fuzzyScore, 'cC', 0, 'camelCase', 'CamelCase'); + // assertTopScore(fuzzyScore, 'cC', 1, 'ccfoo', 'camelCase'); + // assertTopScore(fuzzyScore, 'cC', 1, 'ccfoo', 'camelCase', 'foo-cC-bar'); // issue #17836 - assertTopScore('p', 0, 'parse', 'posix', 'pafdsa', 'path', 'p'); - assertTopScore('pa', 0, 'parse', 'pafdsa', 'path'); + assertTopScore(fuzzyScore, 'p', 0, 'parse', 'posix', 'pafdsa', 'path', 'p'); + assertTopScore(fuzzyScore, 'pa', 0, 'parse', 'pafdsa', 'path'); // issue #14583 - assertTopScore('log', 3, 'HTMLOptGroupElement', 'ScrollLogicalPosition', 'SVGFEMorphologyElement', 'log'); - assertTopScore('e', 2, 'AbstractWorker', 'ActiveXObject', 'else'); + assertTopScore(fuzzyScore, 'log', 3, 'HTMLOptGroupElement', 'ScrollLogicalPosition', 'SVGFEMorphologyElement', 'log'); + assertTopScore(fuzzyScore, 'e', 2, 'AbstractWorker', 'ActiveXObject', 'else'); // issue #14446 - assertTopScore('workbench.sideb', 1, 'workbench.editor.defaultSideBySideLayout', 'workbench.sideBar.location'); + assertTopScore(fuzzyScore, 'workbench.sideb', 1, 'workbench.editor.defaultSideBySideLayout', 'workbench.sideBar.location'); // issue #11423 - assertTopScore('editor.r', 2, 'diffEditor.renderSideBySide', 'editor.overviewRulerlanes', 'editor.renderControlCharacter', 'editor.renderWhitespace'); - // assertTopScore('editor.R', 1, 'diffEditor.renderSideBySide', 'editor.overviewRulerlanes', 'editor.renderControlCharacter', 'editor.renderWhitespace'); - // assertTopScore('Editor.r', 0, 'diffEditor.renderSideBySide', 'editor.overviewRulerlanes', 'editor.renderControlCharacter', 'editor.renderWhitespace'); + assertTopScore(fuzzyScore, 'editor.r', 2, 'diffEditor.renderSideBySide', 'editor.overviewRulerlanes', 'editor.renderControlCharacter', 'editor.renderWhitespace'); + // assertTopScore(fuzzyScore, 'editor.R', 1, 'diffEditor.renderSideBySide', 'editor.overviewRulerlanes', 'editor.renderControlCharacter', 'editor.renderWhitespace'); + // assertTopScore(fuzzyScore, 'Editor.r', 0, 'diffEditor.renderSideBySide', 'editor.overviewRulerlanes', 'editor.renderControlCharacter', 'editor.renderWhitespace'); - assertTopScore('-mo', 1, '-ms-ime-mode', '-moz-columns'); + assertTopScore(fuzzyScore, '-mo', 1, '-ms-ime-mode', '-moz-columns'); // // dupe, issue #14861 - assertTopScore('convertModelPosition', 0, 'convertModelPositionToViewPosition', 'convertViewToModelPosition'); + assertTopScore(fuzzyScore, 'convertModelPosition', 0, 'convertModelPositionToViewPosition', 'convertViewToModelPosition'); // // dupe, issue #14942 - assertTopScore('is', 0, 'isValidViewletId', 'import statement'); + assertTopScore(fuzzyScore, 'is', 0, 'isValidViewletId', 'import statement'); }); });