mirror of
https://github.com/microsoft/vscode.git
synced 2026-05-08 17:19:48 +01:00
improve scorer on file paths
This commit is contained in:
@@ -45,7 +45,7 @@ BEGIN THIRD PARTY
|
||||
* Start of word/path bonus: 7
|
||||
* Start of string bonus: 8
|
||||
*/
|
||||
export function _doScore(target: string, query: string): Score {
|
||||
export function _doScore(target: string, query: string, inverse?: boolean): Score {
|
||||
if (!target || !query) {
|
||||
return NO_SCORE; // return early if target or query are undefined
|
||||
}
|
||||
@@ -62,11 +62,25 @@ export function _doScore(target: string, query: string): Score {
|
||||
|
||||
const matchingPositions: number[] = [];
|
||||
|
||||
let index = 0;
|
||||
let startAt = 0;
|
||||
let index: number;
|
||||
let startAt: number;
|
||||
if (!inverse) {
|
||||
index = 0;
|
||||
startAt = 0;
|
||||
} else {
|
||||
index = queryLen - 1; // inverse: from end of query to beginning
|
||||
startAt = target.length - 1; // inverse: from end of target to beginning
|
||||
}
|
||||
|
||||
let score = 0;
|
||||
while (index < queryLen) {
|
||||
let indexOf = targetLower.indexOf(queryLower[index], startAt);
|
||||
while (inverse ? index >= 0 : index < queryLen) {
|
||||
let indexOf: number;
|
||||
if (!inverse) {
|
||||
indexOf = targetLower.indexOf(queryLower[index], startAt);
|
||||
} else {
|
||||
indexOf = targetLower.lastIndexOf(queryLower[index], startAt); // inverse: look from the end
|
||||
}
|
||||
|
||||
if (indexOf < 0) {
|
||||
|
||||
// console.log(`Character not part of target ${query[index]}`);
|
||||
@@ -120,8 +134,18 @@ export function _doScore(target: string, query: string): Score {
|
||||
|
||||
// console.groupEnd();
|
||||
|
||||
startAt = indexOf + 1;
|
||||
index++;
|
||||
if (!inverse) {
|
||||
startAt = indexOf + 1;
|
||||
index++;
|
||||
} else {
|
||||
startAt = indexOf - 1; // inverse: go to begining from end
|
||||
index--; // inverse: also for query index
|
||||
}
|
||||
}
|
||||
|
||||
// inverse: flip the matching positions so that they appear in order
|
||||
if (inverse) {
|
||||
matchingPositions.reverse();
|
||||
}
|
||||
|
||||
const res: Score = (score > 0) ? [score, matchingPositions] : NO_SCORE;
|
||||
@@ -248,7 +272,18 @@ function doScoreItem<T>(label: string, description: string, path: string, query:
|
||||
const descriptionPrefixLength = descriptionPrefix.length;
|
||||
const descriptionAndLabel = `${descriptionPrefix}${label}`;
|
||||
|
||||
const [labelDescriptionScore, labelDescriptionPositions] = _doScore(descriptionAndLabel, query);
|
||||
let [labelDescriptionScore, labelDescriptionPositions] = _doScore(descriptionAndLabel, query);
|
||||
|
||||
// Optimize for file paths: score from the back to the beginning to catch more specific folder
|
||||
// names that match on the end of the file. This yields better results in most cases.
|
||||
if (!!path) {
|
||||
const [labelDescriptionScoreInverse, labelDescriptionPositionsInverse] = _doScore(descriptionAndLabel, query, true /* inverse */);
|
||||
if (labelDescriptionScoreInverse && labelDescriptionScoreInverse > labelDescriptionScore) {
|
||||
labelDescriptionScore = labelDescriptionScoreInverse;
|
||||
labelDescriptionPositions = labelDescriptionPositionsInverse;
|
||||
}
|
||||
}
|
||||
|
||||
if (labelDescriptionScore) {
|
||||
const labelDescriptionMatches = createMatches(labelDescriptionPositions);
|
||||
const labelMatch: IMatch[] = [];
|
||||
|
||||
@@ -79,7 +79,7 @@ suite('Scorer', () => {
|
||||
assert.equal(positions[1], 6);
|
||||
});
|
||||
|
||||
test('scoreFile - matches are proper', function () {
|
||||
test('scoreItem - matches are proper', function () {
|
||||
let res = scorer.scoreItem(null, 'something', ResourceAccessor, cache);
|
||||
assert.ok(!res.score);
|
||||
|
||||
@@ -151,7 +151,25 @@ suite('Scorer', () => {
|
||||
assert.ok(pathRes.score > noRes.score);
|
||||
});
|
||||
|
||||
test('compareFilesByScore - identity', function () {
|
||||
test('scoreItem - optimize for file paths', function () {
|
||||
const resource = URI.file('/xyz/others/spath/some/xsp/file123.txt');
|
||||
|
||||
// xsp is more relevant to the end of the file path even though it matches
|
||||
// fuzzy also in the beginning. we verify the more relevant match at the
|
||||
// end gets returned.
|
||||
const pathRes = scorer.scoreItem(resource, 'xspfile123', ResourceAccessor, cache);
|
||||
assert.ok(pathRes.score);
|
||||
assert.ok(pathRes.descriptionMatch);
|
||||
assert.ok(pathRes.labelMatch);
|
||||
assert.equal(pathRes.labelMatch.length, 1);
|
||||
assert.equal(pathRes.labelMatch[0].start, 0);
|
||||
assert.equal(pathRes.labelMatch[0].end, 7);
|
||||
assert.equal(pathRes.descriptionMatch.length, 1);
|
||||
assert.equal(pathRes.descriptionMatch[0].start, 23);
|
||||
assert.equal(pathRes.descriptionMatch[0].end, 26);
|
||||
});
|
||||
|
||||
test('compareItemsByScore - identity', function () {
|
||||
const resourceA = URI.file('/some/path/fileA.txt');
|
||||
const resourceB = URI.file('/some/path/other/fileB.txt');
|
||||
const resourceC = URI.file('/unrelated/some/path/other/fileC.txt');
|
||||
|
||||
Reference in New Issue
Block a user