diff --git a/loader/include/Geode/utils/string.hpp b/loader/include/Geode/utils/string.hpp index 90d64fa5..07cdad20 100644 --- a/loader/include/Geode/utils/string.hpp +++ b/loader/include/Geode/utils/string.hpp @@ -4,6 +4,7 @@ #include #include #include +#include namespace geode::utils::string { /** @@ -64,4 +65,10 @@ namespace geode::utils::string { GEODE_DLL bool startsWith(std::string const& str, std::string const& prefix); GEODE_DLL bool endsWith(std::string const& str, std::string const& suffix); + + /** + * Similar to strcmp, but case insensitive. + * Uses std::tolower, but could change in the future for better locale support + */ + GEODE_DLL std::strong_ordering caseInsensitiveCompare(std::string_view a, std::string_view b); } diff --git a/loader/src/ui/mods/sources/ModListSource.hpp b/loader/src/ui/mods/sources/ModListSource.hpp index 49f2c849..c86ccd69 100644 --- a/loader/src/ui/mods/sources/ModListSource.hpp +++ b/loader/src/ui/mods/sources/ModListSource.hpp @@ -194,6 +194,7 @@ void filterModsWithLocalQuery(ModListSource::ProvidedMods& mods, Query const& qu std::vector> filtered; // Filter installed mods based on query + // TODO: maybe skip fuzzy matching altogether if query is empty? for (auto& src : mods.mods) { double weighted = 0; bool addToList = true; @@ -226,7 +227,10 @@ void filterModsWithLocalQuery(ModListSource::ProvidedMods& mods, Query const& qu return a.second > b.second; } // Sort secondarily alphabetically - return a.first.getMetadata().getName() < b.first.getMetadata().getName(); + return utils::string::caseInsensitiveCompare( + a.first.getMetadata().getName(), + b.first.getMetadata().getName() + ) == std::strong_ordering::less; }); mods.mods.clear(); diff --git a/loader/src/utils/string.cpp b/loader/src/utils/string.cpp index 0323a61e..ed46bc31 100644 --- a/loader/src/utils/string.cpp +++ b/loader/src/utils/string.cpp @@ -192,3 +192,20 @@ std::string utils::string::normalize(std::string const& str) { auto ret = str; return utils::string::normalizeIP(ret); } + +std::strong_ordering utils::string::caseInsensitiveCompare(std::string_view str1, std::string_view str2) { + for (size_t i = 0; i < str1.size() && i < str2.size(); i++) { + auto const a = std::tolower(str1[i]); + auto const b = std::tolower(str2[i]); + if (a < b) { + return std::strong_ordering::less; + } else if (a > b) { + return std::strong_ordering::greater; + } + } + if (str1.size() < str2.size()) + return std::strong_ordering::less; + else if (str1.size() > str2.size()) + return std::strong_ordering::greater; + return std::strong_ordering::equal; +} \ No newline at end of file