diff --git a/src/vs/base/common/filters.ts b/src/vs/base/common/filters.ts index 19056d36a50f7d6c52f64c75ad5d1200538e9f69..8719c8c662a6d006888375d626680a22c6193092 100644 --- a/src/vs/base/common/filters.ts +++ b/src/vs/base/common/filters.ts @@ -450,7 +450,7 @@ _seps[':'] = true; const enum Arrow { Top = 0b1, Diag = 0b10, Left = 0b100 } -export function fuzzyScore(pattern: string, word: string): [number, number[]] { +export function fuzzyScore(pattern: string, word: string, patternOffset: number = 0, wordOffset: number = 0): [number, number[]] { const patternLen = pattern.length > 100 ? 100 : pattern.length; const wordLen = word.length > 100 ? 100 : word.length; @@ -465,16 +465,16 @@ export function fuzzyScore(pattern: string, word: string): [number, number[]] { const lowPattern = pattern.toLowerCase(); const lowWord = word.toLowerCase(); - let i = 0; - let j = 0; + let patternPos = patternOffset; + let wordPos = wordOffset; - while (i < patternLen && j < wordLen) { - if (lowPattern[i] === lowWord[j]) { - i += 1; + while (patternPos < patternLen && wordPos < wordLen) { + if (lowPattern[patternPos] === lowWord[wordPos]) { + patternPos += 1; } - j += 1; + wordPos += 1; } - if (i !== patternLen) { + if (patternPos !== patternLen) { // no simple matches found -> return early return undefined; } @@ -482,24 +482,24 @@ export function fuzzyScore(pattern: string, word: string): [number, number[]] { // keep track of the maximum score let maxScore = -1; - for (i = 1; i <= patternLen; i++) { + for (patternPos = patternOffset + 1; patternPos <= patternLen; patternPos++) { let lastLowWordChar = ''; - for (j = 1; j <= wordLen; j++) { + for (wordPos = wordOffset + 1; wordPos <= wordLen; wordPos++) { let score = -1; - let lowWordChar = lowWord[j - 1]; - if (lowPattern[i - 1] === lowWordChar) { + let lowWordChar = lowWord[wordPos - 1]; + if (lowPattern[patternPos - 1] === lowWordChar) { - if (j === 1) { - if (pattern[i - 1] === word[j - 1]) { + if (wordPos === wordOffset + 1) { + if (pattern[patternPos - 1] === word[wordPos - 1]) { score = 7; } else { score = 5; } - } else if (lowWordChar !== word[j - 1]) { - if (pattern[i - 1] === word[j - 1]) { + } else if (lowWordChar !== word[wordPos - 1]) { + if (pattern[patternPos - 1] === word[wordPos - 1]) { score = 7; } else { score = 5; @@ -512,38 +512,38 @@ export function fuzzyScore(pattern: string, word: string): [number, number[]] { } } - _scores[i][j] = score; + _scores[patternPos][wordPos] = score; if (score > maxScore) { maxScore = score; } - let diag = _table[i - 1][j - 1] + (score > 1 ? 1 : score); - let top = _table[i - 1][j] + -1; - let left = _table[i][j - 1] + -1; + let diag = _table[patternPos - 1][wordPos - 1] + (score > 1 ? 1 : score); + let top = _table[patternPos - 1][wordPos] + -1; + let left = _table[patternPos][wordPos - 1] + -1; if (left >= top) { // left or diag if (left > diag) { - _table[i][j] = left; - _arrows[i][j] = Arrow.Left; + _table[patternPos][wordPos] = left; + _arrows[patternPos][wordPos] = Arrow.Left; } else if (left === diag) { - _table[i][j] = left; - _arrows[i][j] = Arrow.Left | Arrow.Diag; + _table[patternPos][wordPos] = left; + _arrows[patternPos][wordPos] = Arrow.Left | Arrow.Diag; } else { - _table[i][j] = diag; - _arrows[i][j] = Arrow.Diag; + _table[patternPos][wordPos] = diag; + _arrows[patternPos][wordPos] = Arrow.Diag; } } else { // top or diag if (top > diag) { - _table[i][j] = top; - _arrows[i][j] = Arrow.Top; + _table[patternPos][wordPos] = top; + _arrows[patternPos][wordPos] = Arrow.Top; } else if (top === diag) { - _table[i][j] = top; - _arrows[i][j] = Arrow.Top | Arrow.Diag; + _table[patternPos][wordPos] = top; + _arrows[patternPos][wordPos] = Arrow.Top | Arrow.Diag; } else { - _table[i][j] = diag; - _arrows[i][j] = Arrow.Diag; + _table[patternPos][wordPos] = diag; + _arrows[patternPos][wordPos] = Arrow.Diag; } } @@ -562,7 +562,7 @@ export function fuzzyScore(pattern: string, word: string): [number, number[]] { } let bucket: [number, number[]][] = []; - findAllMatches(patternLen, patternLen, wordLen, 0, [], bucket, false); + findAllMatches(patternLen, patternLen, patternOffset, wordLen, wordOffset, 0, [], bucket, false); if (bucket.length === 0) { return undefined; @@ -580,7 +580,7 @@ export function fuzzyScore(pattern: string, word: string): [number, number[]] { return topMatch; } -function findAllMatches(patternLen: number, patternPos: number, wordPos: number, total: number, matches: number[], bucket: [number, number[]][], lastMatched: boolean): void { +function findAllMatches(patternLen: number, patternPos: number, patternOffset: number, wordPos: number, wordOffset: number, total: number, matches: number[], bucket: [number, number[]][], lastMatched: boolean): void { if (bucket.length >= 10) { return; @@ -588,7 +588,7 @@ function findAllMatches(patternLen: number, patternPos: number, wordPos: number, let simpleMatchCount = 0; - while (patternPos > 0 && wordPos > 0) { + while (patternPos > patternOffset && wordPos > wordOffset) { let score = _scores[patternPos][wordPos]; let arrow = _arrows[patternPos][wordPos]; @@ -609,8 +609,8 @@ function findAllMatches(patternLen: number, patternPos: number, wordPos: number, if (arrow & Arrow.Left) { // left findAllMatches( - patternLen, patternPos, - wordPos - 1, + patternLen, patternPos, patternOffset, + wordPos - 1, wordOffset, matches.length !== 0 ? total - 1 : total, matches.slice(0), bucket, lastMatched ); diff --git a/src/vs/base/test/common/filters.test.ts b/src/vs/base/test/common/filters.test.ts index ed8f708e757d4549986f3fd7b743b93a47cad55a..797df43d1a2d6b1d2271e2d1770c8fb95217a068 100644 --- a/src/vs/base/test/common/filters.test.ts +++ b/src/vs/base/test/common/filters.test.ts @@ -325,6 +325,13 @@ suite('Filters', () => { assertMatches('f', ':foo', ':^foo', fuzzyScore); }); + test('fuzzyScore with offset', function () { + const matches = fuzzyScore('bc', 'abc', 0, 1); + assert.ok(matches); + const [, range] = matches; + assert.deepEqual(range, [1, 2]); + }); + function assertTopScore(filter: typeof fuzzyScore, pattern: string, expected: number, ...words: string[]) { let topScore = -(100 * 10); let topIdx = 0;