matchItems static method
Returns ranked matches for query with deterministic scoring and
explainable evidence.
Public for testing and parity-validation workflows.
Implementation
static List<CommandPaletteMatch> matchItems(
List<CommandPaletteItem> items,
String query,
) {
final normalizedQuery = query.trim().toLowerCase();
final matches = <CommandPaletteMatch>[];
for (var index = 0; index < items.length; index++) {
final item = items[index];
if (!item.enabled) continue;
final evidence = <String, double>{};
final label = item.label.toLowerCase();
final description = item.description?.toLowerCase();
final group = item.group?.toLowerCase();
double score = 0;
if (normalizedQuery.isEmpty) {
evidence['query:empty'] = 1.0;
} else {
if (label == normalizedQuery) {
score += 10000;
evidence['label:exact'] = 10000;
}
if (label.startsWith(normalizedQuery)) {
score += 6000;
evidence['label:prefix'] = 6000;
}
if (label.contains(normalizedQuery)) {
score += 4000;
evidence['label:contains'] = 4000;
}
if (description != null && description.contains(normalizedQuery)) {
score += 1800;
evidence['description:contains'] = 1800;
}
if (group != null && group.contains(normalizedQuery)) {
score += 1200;
evidence['group:contains'] = 1200;
}
final subseq = _subsequenceScore(normalizedQuery, label);
if (subseq > 0) {
score += subseq;
evidence['label:subsequence'] = subseq;
}
final typo = _typoScore(normalizedQuery, label);
if (typo > 0) {
score += typo;
evidence['label:typo'] = typo;
}
}
if (normalizedQuery.isEmpty || score > 0) {
matches.add(
CommandPaletteMatch(
item: item,
score: score,
evidence: evidence,
originalIndex: index,
),
);
}
}
if (normalizedQuery.isEmpty) {
matches.sort(
(lhs, rhs) => lhs.originalIndex.compareTo(rhs.originalIndex),
);
} else {
matches.sort((lhs, rhs) {
final byScore = rhs.score.compareTo(lhs.score);
if (byScore != 0) return byScore;
final byLabel = lhs.item.label.compareTo(rhs.item.label);
if (byLabel != 0) return byLabel;
return lhs.originalIndex.compareTo(rhs.originalIndex);
});
}
return matches;
}