diff --git a/src/vs/base/common/scorer.ts b/src/vs/base/common/scorer.ts index fd75831a31a03..b3da8d89d24a7 100644 --- a/src/vs/base/common/scorer.ts +++ b/src/vs/base/common/scorer.ts @@ -373,25 +373,47 @@ export function compareItemsByScore(itemA: T, itemB: T, query: string, access return scoreA > scoreB ? -1 : 1; } - // 6.) at this point, scores are identical for both paths + // 6.) at this point, scores are identical for both items so we start to sort by length + // check for label + description length and prefer shorter const labelA = accessor.getItemLabel(itemA); const labelB = accessor.getItemLabel(itemB); - if (labelA.length !== labelB.length) { - return labelA.length - labelB.length; // prefer shorter labels + const descriptionA = accessor.getItemDescription(itemA); + const descriptionB = accessor.getItemDescription(itemB); + + const labelDescriptionALength = labelA.length + (descriptionA ? descriptionA.length : 0); + const labelDescriptionBLength = labelB.length + (descriptionB ? descriptionB.length : 0); + + if (labelDescriptionALength !== labelDescriptionBLength) { + return labelDescriptionALength - labelDescriptionBLength; } + // check for path length and prefer shorter const pathA = accessor.getItemPath(itemA); const pathB = accessor.getItemPath(itemB); if (pathA && pathB && pathA.length !== pathB.length) { - return pathA.length - pathB.length; // prefer shorter paths + return pathA.length - pathB.length; + } + + // 7.) finally we have equal scores and equal length, we fallback to comparer + + // compare by label + if (labelA !== labelB) { + return compareAnything(labelA, labelB, query); + } + + // compare by description + if (descriptionA && descriptionB && descriptionA !== descriptionB) { + return compareAnything(descriptionA, descriptionB, query); } - if (labelA === labelB && pathA && pathB) { - return compareAnything(pathA, pathB, query); // compare paths if labels are identical + // compare by path + if (pathA && pathB && pathA !== pathB) { + return compareAnything(pathA, pathB, query); } - return compareAnything(labelA, labelB, query); // finally compare by labels + // equal + return 0; } \ No newline at end of file diff --git a/src/vs/base/test/common/scorer.test.ts b/src/vs/base/test/common/scorer.test.ts index e6d4de7bbdfbd..650e531acacbf 100644 --- a/src/vs/base/test/common/scorer.test.ts +++ b/src/vs/base/test/common/scorer.test.ts @@ -366,4 +366,17 @@ suite('Scorer', () => { assert.equal(res[1], resourceB); assert.equal(res[2], resourceC); }); + + test('compareFilesByScore - prefer shorter paths (bug #17443)', function () { + const resourceA = URI.file('config/test/t1.js'); + const resourceB = URI.file('config/test.js'); + const resourceC = URI.file('config/test/t2.js'); + + let query = 'co/te'; + + let res = [resourceA, resourceB, resourceC].sort((r1, r2) => scorer.compareItemsByScore(r1, r2, query, ResourceAccessor, cache)); + assert.equal(res[0], resourceB); + assert.equal(res[1], resourceA); + assert.equal(res[2], resourceC); + }); }); \ No newline at end of file