mirror of
https://github.com/Chatterino/chatterino2.git
synced 2024-11-13 19:49:51 +01:00
Add option for truecase username autocompletion (#1883)
Co-authored-by: Rasmus Karlsson <rasmus.karlsson@pajlada.com>
This commit is contained in:
parent
b8104863a5
commit
38966e2b19
|
@ -41,6 +41,7 @@
|
||||||
- Minor: Don't show update button for nightly builds on macOS and Linux, this was already the case for Windows (#2163, #2164)
|
- Minor: Don't show update button for nightly builds on macOS and Linux, this was already the case for Windows (#2163, #2164)
|
||||||
- Minor: Tab and split titles now use display/localized channel names (#2189)
|
- Minor: Tab and split titles now use display/localized channel names (#2189)
|
||||||
- Minor: Add a setting to limit the amount of historical messages loaded from the Recent Messages API (#2250, #2252)
|
- Minor: Add a setting to limit the amount of historical messages loaded from the Recent Messages API (#2250, #2252)
|
||||||
|
- Minor: Made username autocompletion truecase (#1199, #1883)
|
||||||
- Bugfix: Fix crash occurring when pressing Escape in the Color Picker Dialog (#1843)
|
- Bugfix: Fix crash occurring when pressing Escape in the Color Picker Dialog (#1843)
|
||||||
- Bugfix: Fix bug where the "check user follow state" event could trigger a network request requesting the user to follow or unfollow a user. By itself its quite harmless as it just repeats to Twitch the same follow state we had, so no follows should have been lost by this but it meant there was a rogue network request that was fired that could cause a crash (#1906)
|
- Bugfix: Fix bug where the "check user follow state" event could trigger a network request requesting the user to follow or unfollow a user. By itself its quite harmless as it just repeats to Twitch the same follow state we had, so no follows should have been lost by this but it meant there was a rogue network request that was fired that could cause a crash (#1906)
|
||||||
- Bugfix: /usercard command will now respect the "Automatically close user popup" setting (#1918)
|
- Bugfix: /usercard command will now respect the "Automatically close user popup" setting (#1918)
|
||||||
|
|
|
@ -37,6 +37,9 @@ if (BUILD_TESTS)
|
||||||
|
|
||||||
target_link_libraries(chatterino-test PajladaSerialize)
|
target_link_libraries(chatterino-test PajladaSerialize)
|
||||||
|
|
||||||
|
set_property(TARGET chatterino-test PROPERTY CXX_STANDARD 17)
|
||||||
|
set_property(TARGET chatterino-test PROPERTY CXX_STANDARD_REQUIRED ON)
|
||||||
|
|
||||||
gtest_discover_tests(chatterino-test)
|
gtest_discover_tests(chatterino-test)
|
||||||
else()
|
else()
|
||||||
message(FATAL_ERROR "This cmake file is only intended for tests right now. Use qmake to build chatterino2")
|
message(FATAL_ERROR "This cmake file is only intended for tests right now. Use qmake to build chatterino2")
|
||||||
|
|
|
@ -67,7 +67,7 @@ void ChannelChatters::addPartedUser(const QString &user)
|
||||||
|
|
||||||
void ChannelChatters::setChatters(UsernameSet &&set)
|
void ChannelChatters::setChatters(UsernameSet &&set)
|
||||||
{
|
{
|
||||||
*this->chatters_.access() = set;
|
this->chatters_.access()->merge(std::move(set));
|
||||||
}
|
}
|
||||||
|
|
||||||
const QColor ChannelChatters::getUserColor(const QString &user)
|
const QColor ChannelChatters::getUserColor(const QString &user)
|
||||||
|
|
|
@ -4,6 +4,30 @@
|
||||||
|
|
||||||
namespace chatterino {
|
namespace chatterino {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
std::pair<UsernameSet::Iterator, bool> findOrErase(
|
||||||
|
std::set<QString, CaseInsensitiveLess> &set, const QString &value)
|
||||||
|
{
|
||||||
|
if (!value.isLower())
|
||||||
|
{
|
||||||
|
auto iter = set.find(value);
|
||||||
|
if (iter != set.end())
|
||||||
|
{
|
||||||
|
if (QString::compare(*iter, value, Qt::CaseSensitive) != 0)
|
||||||
|
{
|
||||||
|
set.erase(iter);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return {iter, false};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return {set.end(), true};
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
//
|
//
|
||||||
// UsernameSet
|
// UsernameSet
|
||||||
//
|
//
|
||||||
|
@ -43,15 +67,25 @@ std::set<QString>::size_type UsernameSet::size() const
|
||||||
|
|
||||||
std::pair<UsernameSet::Iterator, bool> UsernameSet::insert(const QString &value)
|
std::pair<UsernameSet::Iterator, bool> UsernameSet::insert(const QString &value)
|
||||||
{
|
{
|
||||||
this->insertPrefix(value);
|
auto pair = findOrErase(this->items, value);
|
||||||
|
if (!pair.second)
|
||||||
|
{
|
||||||
|
return pair;
|
||||||
|
}
|
||||||
|
|
||||||
|
this->insertPrefix(value);
|
||||||
return this->items.insert(value);
|
return this->items.insert(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<UsernameSet::Iterator, bool> UsernameSet::insert(QString &&value)
|
std::pair<UsernameSet::Iterator, bool> UsernameSet::insert(QString &&value)
|
||||||
{
|
{
|
||||||
this->insertPrefix(value);
|
auto pair = findOrErase(this->items, value);
|
||||||
|
if (!pair.second)
|
||||||
|
{
|
||||||
|
return pair;
|
||||||
|
}
|
||||||
|
|
||||||
|
this->insertPrefix(value);
|
||||||
return this->items.insert(std::move(value));
|
return this->items.insert(std::move(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -68,6 +102,24 @@ bool UsernameSet::contains(const QString &value) const
|
||||||
return this->items.count(value) == 1;
|
return this->items.count(value) == 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void UsernameSet::merge(UsernameSet &&set)
|
||||||
|
{
|
||||||
|
for (auto it = this->items.begin(); it != this->items.end();)
|
||||||
|
{
|
||||||
|
auto iter = set.items.find(*it);
|
||||||
|
if (iter == set.items.end())
|
||||||
|
{
|
||||||
|
it = this->items.erase(it);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this->items.merge(set.items);
|
||||||
|
this->firstKeyForPrefix = set.firstKeyForPrefix;
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// Range
|
// Range
|
||||||
//
|
//
|
||||||
|
|
|
@ -77,6 +77,7 @@ public:
|
||||||
std::pair<Iterator, bool> insert(QString &&value);
|
std::pair<Iterator, bool> insert(QString &&value);
|
||||||
|
|
||||||
bool contains(const QString &value) const;
|
bool contains(const QString &value) const;
|
||||||
|
void merge(UsernameSet &&set);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void insertPrefix(const QString &string);
|
void insertPrefix(const QString &string);
|
||||||
|
|
|
@ -804,6 +804,7 @@ void TwitchChannel::fetchDisplayName()
|
||||||
.arg(channel->getName())
|
.arg(channel->getName())
|
||||||
.arg(user.displayName));
|
.arg(user.displayName));
|
||||||
}
|
}
|
||||||
|
channel->addRecentChatter(channel->getDisplayName());
|
||||||
channel->displayNameChanged.invoke();
|
channel->displayNameChanged.invoke();
|
||||||
},
|
},
|
||||||
[] {});
|
[] {});
|
||||||
|
|
|
@ -44,17 +44,40 @@ TEST(UsernameSet, insert)
|
||||||
|
|
||||||
EXPECT_EQ(set.size(), 1);
|
EXPECT_EQ(set.size(), 1);
|
||||||
|
|
||||||
|
// Non-lowercase variant should override full lowercase variant
|
||||||
|
p = set.insert("PAJLADA");
|
||||||
|
EXPECT_TRUE(p.second);
|
||||||
|
|
||||||
|
EXPECT_EQ(set.size(), 1);
|
||||||
|
|
||||||
|
// Lowercase variant should not override non-lowercase variant
|
||||||
|
p = set.insert("pajlada");
|
||||||
|
EXPECT_FALSE(p.second);
|
||||||
|
|
||||||
|
EXPECT_EQ(set.size(), 1);
|
||||||
|
|
||||||
p = set.insert("pajbot");
|
p = set.insert("pajbot");
|
||||||
EXPECT_TRUE(p.second);
|
EXPECT_TRUE(p.second);
|
||||||
|
|
||||||
EXPECT_EQ(set.size(), 2);
|
EXPECT_EQ(set.size(), 2);
|
||||||
|
|
||||||
p = set.insert("pajlada");
|
p = set.insert("pajbot");
|
||||||
EXPECT_FALSE(p.second);
|
EXPECT_FALSE(p.second);
|
||||||
|
|
||||||
EXPECT_EQ(set.size(), 2);
|
EXPECT_EQ(set.size(), 2);
|
||||||
|
|
||||||
p = set.insert("PAJLADA");
|
p = set.insert("Pajbot");
|
||||||
|
EXPECT_TRUE(p.second);
|
||||||
|
|
||||||
|
EXPECT_EQ(set.size(), 2);
|
||||||
|
|
||||||
|
p = set.insert("PAJBOT");
|
||||||
|
EXPECT_TRUE(p.second);
|
||||||
|
|
||||||
|
EXPECT_EQ(set.size(), 2);
|
||||||
|
|
||||||
|
// Same uppercase should not result in a change
|
||||||
|
p = set.insert("PAJBOT");
|
||||||
EXPECT_FALSE(p.second);
|
EXPECT_FALSE(p.second);
|
||||||
|
|
||||||
EXPECT_EQ(set.size(), 2);
|
EXPECT_EQ(set.size(), 2);
|
||||||
|
|
Loading…
Reference in a new issue