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:
@@ -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;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user