1
0
mirror of https://github.com/AvengeMedia/DankMaterialShell.git synced 2026-04-03 20:32:07 -04:00

fix(dropdown): sort fuzzy search results by score and fix empty results on reopen (#2051)

fzf.js relied on stable Array.sort to preserve score ordering, which is
not guaranteed in QML's JS engine. Results appeared in arbitrary order
with low-relevance matches above exact matches. The sort comparator now
explicitly sorts by score descending, with a length-based tiebreaker so
shorter matches rank first when scores are tied.

Also fixed Object.assign mutating the shared defaultOpts object, which
could cause options to leak between Finder instances.

DankDropdown's onOpened handler now reinitializes the search when previous
search text exists, fixing the empty results shown on reopen.

Added resetSearch() for consumers to clear search state externally.
This commit is contained in:
Jeff Corcoran
2026-03-23 09:24:51 -04:00
committed by GitHub
parent c5f145be36
commit 4d649468d5
2 changed files with 25 additions and 10 deletions

View File

@@ -1249,7 +1249,7 @@ const defaultOpts = {
};
class Finder {
constructor(list, ...optionsTuple) {
this.opts = Object.assign(defaultOpts, optionsTuple[0]);
this.opts = Object.assign({}, defaultOpts, optionsTuple[0]);
this.items = list;
this.runesList = list.map((item) => strToRunes(this.opts.selector(item).normalize()));
this.algoFn = exactMatchNaive;
@@ -1283,14 +1283,15 @@ function postProcessResultItems(result, opts) {
if (opts.sort) {
const { selector } = opts;
result.sort((a, b) => {
if (a.score === b.score) {
if (a.score !== b.score) {
return b.score - a.score;
}
for (const tiebreaker of opts.tiebreakers) {
const diff = tiebreaker(a, b, selector);
if (diff !== 0) {
return diff;
}
}
}
return 0;
});
}

View File

@@ -58,6 +58,13 @@ Item {
dropdownMenu.close();
}
function resetSearch() {
searchField.text = "";
dropdownMenu.fzfFinder = null;
dropdownMenu.searchQuery = "";
dropdownMenu.selectedIndex = -1;
}
width: compactMode ? dropdownWidth : parent.width
implicitHeight: compactMode ? 40 : Math.max(60, labelColumn.implicitHeight + Theme.spacingM)
@@ -206,7 +213,9 @@ Item {
fzfFinder = new Fzf.Finder(root.options, {
"selector": option => option,
"limit": 50,
"casing": "case-insensitive"
"casing": "case-insensitive",
"sort": true,
"tiebreakers": [(a, b, selector) => selector(a.item).length - selector(b.item).length]
});
}
@@ -233,9 +242,14 @@ Item {
}
onOpened: {
selectedIndex = -1;
if (searchField.text.length > 0) {
initFinder();
searchQuery = searchField.text;
} else {
fzfFinder = null;
searchQuery = "";
selectedIndex = -1;
}
}
parent: Overlay.overlay