From b60f6b0705102cc1875baa777644036e94b43508 Mon Sep 17 00:00:00 2001 From: John Preston Date: Thu, 15 Jan 2026 23:31:59 +0400 Subject: [PATCH] Implement word-based matching in settings search. Use TextUtilities::PrepareSearchWords() to normalize query and entry text: split into words, remove accents, and lowercase. Match by word prefix: each query word must match at least one entry word by startsWith(). Co-Authored-By: Claude Opus 4.5 --- .../SourceFiles/settings/settings_search.cpp | 49 ++++++++++++------- 1 file changed, 30 insertions(+), 19 deletions(-) diff --git a/Telegram/SourceFiles/settings/settings_search.cpp b/Telegram/SourceFiles/settings/settings_search.cpp index 594b4b81ef..ac975a3e21 100644 --- a/Telegram/SourceFiles/settings/settings_search.cpp +++ b/Telegram/SourceFiles/settings/settings_search.cpp @@ -13,6 +13,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "settings/settings_builder.h" #include "settings/settings_common.h" #include "ui/painter.h" +#include "ui/text/text_entity.h" #include "ui/search_field_controller.h" #include "ui/vertical_list.h" #include "ui/widgets/buttons.h" @@ -36,37 +37,47 @@ struct SearchResult { int score = 0; }; +[[nodiscard]] QStringList PrepareEntryWords(const Builder::SearchEntry &entry) { + auto combined = entry.title; + for (const auto &keyword : entry.keywords) { + combined += ' ' + keyword; + } + return TextUtilities::PrepareSearchWords(combined); +} + +[[nodiscard]] bool MatchesWord( + const QStringList &entryWords, + const QString &queryWord) { + for (const auto &entryWord : entryWords) { + if (entryWord.startsWith(queryWord)) { + return true; + } + } + return false; +} + [[nodiscard]] int CalculateScore( const Builder::SearchEntry &entry, - const QString &query) { - const auto queryLower = query.toLower(); - const auto titleLower = entry.title.toLower(); - if (titleLower.startsWith(queryLower)) { - return 100; + const QStringList &queryWords) { + if (queryWords.isEmpty()) { + return 0; } - if (titleLower.contains(queryLower)) { - return 80; - } - for (const auto &keyword : entry.keywords) { - if (keyword.toLower().startsWith(queryLower)) { - return 60; - } - if (keyword.toLower().contains(queryLower)) { - return 40; + const auto entryWords = PrepareEntryWords(entry); + for (const auto &queryWord : queryWords) { + if (!MatchesWord(entryWords, queryWord)) { + return 0; } } - if (entry.id.toLower().contains(queryLower)) { - return 20; - } - return 0; + return 100; } [[nodiscard]] std::vector FilterAndSort( const std::vector &entries, const QString &query) { + const auto queryWords = TextUtilities::PrepareSearchWords(query); auto results = std::vector(); for (const auto &entry : entries) { - const auto score = CalculateScore(entry, query); + const auto score = CalculateScore(entry, queryWords); if (score > 0) { results.push_back({ entry, score }); }