diff --git a/src/vs/base/parts/quickopen/common/quickOpenScorer.ts b/src/vs/base/parts/quickopen/common/quickOpenScorer.ts index 981c6c830a787..2d8ea22ecc03e 100644 --- a/src/vs/base/parts/quickopen/common/quickOpenScorer.ts +++ b/src/vs/base/parts/quickopen/common/quickOpenScorer.ts @@ -338,7 +338,7 @@ function doScoreItem(label: string, description: string, path: string, query: return NO_ITEM_SCORE; } -export function compareItemsByScore(itemA: T, itemB: T, query: string, fuzzy: boolean, accessor: IItemAccessor, cache: ScorerCache): number { +export function compareItemsByScore(itemA: T, itemB: T, query: string, fuzzy: boolean, accessor: IItemAccessor, cache: ScorerCache, fallbackComparer = fallbackCompare): number { const scoreA = scoreItem(itemA, query, fuzzy, accessor, cache).score; const scoreB = scoreItem(itemB, query, fuzzy, accessor, cache).score; @@ -395,7 +395,11 @@ export function compareItemsByScore(itemA: T, itemB: T, query: string, fuzzy: return scoreA > scoreB ? -1 : 1; } - // 6.) at this point, scores are identical for both items so we start to sort by length + // 6.) at this point, scores are identical for both items so we start to use the fallback compare + return fallbackComparer(itemA, itemB, query, accessor); +} + +export function fallbackCompare(itemA: T, itemB: T, query: string, accessor: IItemAccessor): number { // check for label + description length and prefer shorter const labelA = accessor.getItemLabel(itemA); diff --git a/src/vs/base/parts/quickopen/test/common/quickOpenScorer.test.ts b/src/vs/base/parts/quickopen/test/common/quickOpenScorer.test.ts index 111e9515a6adf..5af281048e298 100644 --- a/src/vs/base/parts/quickopen/test/common/quickOpenScorer.test.ts +++ b/src/vs/base/parts/quickopen/test/common/quickOpenScorer.test.ts @@ -407,4 +407,19 @@ suite('Quick Open Scorer', () => { assert.equal(res[1], resourceA); assert.equal(res[2], resourceC); }); + + test('compareFilesByScore - allow to provide fallback sorter (bug #31591)', function () { + const resourceA = URI.file('virtual/vscode.d.ts'); + const resourceB = URI.file('vscode/src/vs/vscode.d.ts'); + + let query = 'vscode'; + + let res = [resourceA, resourceB].sort((r1, r2) => scorer.compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache, (r1, r2, query, ResourceAccessor) => -1)); + assert.equal(res[0], resourceA); + assert.equal(res[1], resourceB); + + res = [resourceB, resourceA].sort((r1, r2) => scorer.compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache, (r1, r2, query, ResourceAccessor) => -1)); + assert.equal(res[0], resourceB); + assert.equal(res[1], resourceA); + }); }); \ No newline at end of file diff --git a/src/vs/workbench/browser/parts/quickopen/quickOpenController.ts b/src/vs/workbench/browser/parts/quickopen/quickOpenController.ts index 38d4e6d010d2d..69f2abf2800ff 100644 --- a/src/vs/workbench/browser/parts/quickopen/quickOpenController.ts +++ b/src/vs/workbench/browser/parts/quickopen/quickOpenController.ts @@ -1219,8 +1219,9 @@ class EditorHistoryHandler { return true; }) - // Sort by score - .sort((e1, e2) => compareItemsByScore(e1, e2, searchValue, false, accessor, this.scorerCache)); + // Sort by score and provide a fallback sorter that keeps the + // recency of items in case the score for items is the same + .sort((e1, e2) => compareItemsByScore(e1, e2, searchValue, false, accessor, this.scorerCache, (e1, e2, searchValue, accessor) => -1)); } }