#include "FuzzyMatch.h" namespace { // True when the character at `index` starts a word: the string start, a // character after '/', '.', '-', '_', or a step from lower case to upper // case. [[nodiscard]] bool startsWord(QStringView text, qsizetype index) { if (index == 0) { return true; } const QChar previous = text.at(index - 1); if (previous == QLatin1Char('/') || previous == QLatin1Char('.') || previous == QLatin1Char('-') || previous == QLatin1Char('_')) { return true; } return previous.isLower() && text.at(index).isUpper(); } } // namespace int fuzzyScore(QStringView haystack, QStringView needle) { if (needle.isEmpty()) { return 0; } int score = 0; qsizetype at = 0; qsizetype previousMatch = -1; const auto* scan = haystack.cbegin(); for (const QChar raw : needle) { const QChar wanted = raw.toLower(); bool found = false; for (; scan != haystack.cend(); ++scan, ++at) { if ((*scan).toLower() == wanted) { found = true; break; } // Skipped characters count against the score, but only before the // first match. Gaps between matches are free. if (previousMatch < 0) { --score; } } if (!found) { return -1; } if (startsWord(haystack, at)) { score += 8; } else if (at == previousMatch + 1) { score += 4; } previousMatch = at; ++scan; ++at; } return score; }