提交 10532246 编写于 作者: J Johannes Rieken

fix #23215

上级 caaa8c49
......@@ -410,6 +410,7 @@ function initTable() {
}
const _table = initTable();
const _scores = initTable();
const _arrows = <Arrow[][]>initTable();
const _debug = false;
......@@ -502,29 +503,41 @@ export function fuzzyScore(pattern: string, word: string): [number, number[]] {
} else {
score = 1;
}
if (i > 1 && j > 1 && _scores[i - 1][j - 1] > score) {
score = _scores[i - 1][j - 1];
}
}
_scores[i][j] = score;
let diag = _table[i - 1][j - 1] + score;
let top = _table[i - 1][j] + -1;
let left = _table[i][j - 1] + -1;
if (left >= top) {
// left or diag
if (left >= diag) {
if (left > diag) {
_table[i][j] = left;
_arrows[i][j] = Arrow.Left;
} else if (left === diag) {
_table[i][j] = left;
_arrows[i][j] = Arrow.Left | Arrow.Diag;
} else {
_table[i][j] = diag;
_arrows[i][j] = Arrow.Diag;
}
} else {
// top or diag
if (diag >= top) {
_table[i][j] = diag;
_arrows[i][j] = Arrow.Diag;
} else {
if (top > diag) {
_table[i][j] = top;
_arrows[i][j] = Arrow.Top;
} else if (top === diag) {
_table[i][j] = top;
_arrows[i][j] = Arrow.Top | Arrow.Diag;
} else {
_table[i][j] = diag;
_arrows[i][j] = Arrow.Diag;
}
}
......@@ -535,52 +548,76 @@ export function fuzzyScore(pattern: string, word: string): [number, number[]] {
if (_debug) {
console.log(printTable(_table, pattern, patternLen, word, wordLen));
console.log(printTable(_arrows, pattern, patternLen, word, wordLen));
console.log(printTable(_scores, pattern, patternLen, word, wordLen));
}
let matches: number[] = [];
let total = 0;
i = patternLen;
j = wordLen;
while (i > 0 && j > 0) {
let value = _table[i][j];
let arrow = _arrows[i][j];
if (arrow === Arrow.Diag) { //diag
j -= 1;
i -= 1;
let score = value - _table[i][j];
if (i === 0 && score === 1) {
// we have reached the first pattern char and now
// test that it has scored properly, like `o -> bbOO`
// and not `o -> foobar`
return undefined;
} else if (score < 1) {
// we went diagonal by inheriting a good
// result, not by matching keep going left
i += 1;
let bucket: [number, number[]][] = [];
findAllMatches(patternLen, patternLen, wordLen, 0, [], bucket);
} else {
// all good
total += value;
matches.unshift(j);
if (bucket.length === 0) {
return undefined;
}
let topMatch = bucket.shift();
for (const match of bucket) {
if (!topMatch || topMatch[0] < match[0]) {
topMatch = match;
}
}
if (_debug) {
console.log(`${pattern} & ${word} => ${topMatch[0]} points for ${topMatch[1]}`);
}
return topMatch;
}
function findAllMatches(patternLen: number, patternPos: number, wordPos: number, total: number, matches: number[], bucket: [number, number[]][]): void {
while (patternPos > 0 && wordPos > 0) {
let value = _table[patternPos][wordPos];
let score = _scores[patternPos][wordPos];
let arrow = _arrows[patternPos][wordPos];
if (arrow === Arrow.Left || score < 0) {
// left
wordPos -= 1;
} else if (arrow === Arrow.Diag) {
// diag
total += value;
patternPos -= 1;
wordPos -= 1;
matches.unshift(wordPos);
} else if (arrow & Arrow.Diag) {
if (arrow & Arrow.Left) {
// left
findAllMatches(patternLen, patternPos, wordPos - 1, total, matches.slice(0), bucket);
}
// diag
total += value;
patternPos -= 1;
wordPos -= 1;
matches.unshift(wordPos);
} else {
// keep going left, we cannot
// skip a character in the pattern
j -= 1;
// undefined
}
}
if (j > 3) {
j = 3;
if (matches.length !== patternLen) {
// doesn't cover whole pattern
return undefined;
}
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}`);
if (_scores[1][matches[0] + 1] === 1) {
// first match is weak
return undefined;
}
return [total, matches];
total -= wordPos >= 3 ? 9 : wordPos * 3; // late start penalty
total -= (1 + matches[matches.length - 1]) - patternLen; // penalty for all non matching characters between first and last
bucket.push([total, matches]);
}
......@@ -208,6 +208,13 @@ suite('Filters', () => {
}
}
test('fuzzyScore, #23215', function () {
assertMatches('tit', 'win.tit', 'win.^t^i^t', fuzzyScore);
assertMatches('title', 'win.title', 'win.^t^i^t^l^e', fuzzyScore);
assertMatches('WordCla', 'WordCharacterClassifier', '^W^o^r^d^CharacterC^l^assifier', fuzzyScore);
assertMatches('WordCCla', 'WordCharacterClassifier', '^W^o^r^d^Character^C^l^assifier', fuzzyScore);
});
test('fuzzyScore', function () {
assertMatches('ab', 'abA', '^a^bA', fuzzyScore);
assertMatches('ccm', 'cacmelCase', '^ca^c^melCase', fuzzyScore);
......@@ -218,13 +225,13 @@ suite('Filters', () => {
assertMatches('LLL', 'SVisualLoggerLogsList', 'SVisual^Logger^Logs^List', fuzzyScore);
assertMatches('LLLL', 'SVilLoLosLi', undefined, fuzzyScore);
assertMatches('LLLL', 'SVisualLoggerLogsList', undefined, fuzzyScore);
assertMatches('TEdit', 'TextEdit', '^Text^E^d^i^t', fuzzyScore);
assertMatches('TEdit', 'TextEditor', '^Text^E^d^i^tor', fuzzyScore);
assertMatches('TEdit', 'TextEdit', '^T^extE^d^i^t', fuzzyScore);
assertMatches('TEdit', 'TextEditor', '^T^extE^d^i^tor', fuzzyScore);
assertMatches('TEdit', 'Textedit', '^T^exte^d^i^t', fuzzyScore);
assertMatches('TEdit', 'text_edit', '^text_^e^d^i^t', fuzzyScore);
assertMatches('TEditDit', 'TextEditorDecorationType', '^Text^E^d^i^tor^Decorat^ion^Type', fuzzyScore);
assertMatches('TEdit', 'TextEditorDecorationType', '^Text^Editor^Decorat^ion^Type', fuzzyScore);
assertMatches('Tedit', 'TextEdit', '^Text^E^d^i^t', fuzzyScore);
assertMatches('TEdit', 'text_edit', '^t^ext_e^d^i^t', fuzzyScore);
assertMatches('TEditDit', 'TextEditorDecorationType', '^T^extE^d^i^tor^Decorat^ion^Type', fuzzyScore);
assertMatches('TEdit', 'TextEditorDecorationType', '^T^extE^d^i^torDecorationType', fuzzyScore);
assertMatches('Tedit', 'TextEdit', '^T^extE^d^i^t', fuzzyScore);
assertMatches('ba', '?AB?', undefined, fuzzyScore);
assertMatches('bkn', 'the_black_knight', 'the_^black_^k^night', fuzzyScore);
assertMatches('bt', 'the_black_knight', 'the_^black_knigh^t', fuzzyScore);
......@@ -242,7 +249,7 @@ suite('Filters', () => {
assertMatches('gp', 'Git_Git_Pull', '^Git_Git_^Pull', fuzzyScore);
assertMatches('is', 'ImportStatement', '^Import^Statement', fuzzyScore);
assertMatches('is', 'isValid', '^i^sValid', fuzzyScore);
assertMatches('lowrd', 'lowWord', '^l^ow^Wo^r^d', fuzzyScore);
assertMatches('lowrd', 'lowWord', '^l^o^wWo^r^d', fuzzyScore);
assertMatches('myvable', 'myvariable', '^m^y^v^aria^b^l^e', fuzzyScore);
assertMatches('no', '', undefined, fuzzyScore);
assertMatches('no', 'match', undefined, fuzzyScore);
......@@ -279,7 +286,6 @@ suite('Filters', () => {
test('topScore - fuzzyScore', function () {
assertTopScore(fuzzyScore, 'TEdit', 1, 'TextEditorDecorationType', 'TextEdit', 'TextEditor');
assertTopScore(fuzzyScore, 'cons', 2, 'ArrayBufferConstructor', 'Console', 'console');
assertTopScore(fuzzyScore, 'Foo', 1, 'foo', 'Foo', 'foo');
......@@ -289,6 +295,7 @@ suite('Filters', () => {
// assertTopScore(fuzzyScore, 'cC', 1, 'ccfoo', 'camelCase', 'foo-cC-bar');
// issue #17836
// assertTopScore(fuzzyScore, 'TEdit', 1, 'TextEditorDecorationType', 'TextEdit', 'TextEditor');
assertTopScore(fuzzyScore, 'p', 0, 'parse', 'posix', 'pafdsa', 'path', 'p');
assertTopScore(fuzzyScore, 'pa', 0, 'parse', 'pafdsa', 'path');
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册