From d3b6e294ed38fa8587c367c5da6f257641c28b86 Mon Sep 17 00:00:00 2001 From: hemirt Date: Sun, 8 Jul 2018 16:21:33 +0200 Subject: [PATCH 01/11] ignore phrases --- src/controllers/ignores/IgnoreModel.cpp | 9 ++++-- src/controllers/ignores/IgnorePhrase.hpp | 32 ++++++++++++++++--- src/providers/twitch/TwitchMessageBuilder.cpp | 13 ++++++-- src/providers/twitch/TwitchMessageBuilder.hpp | 2 +- src/singletons/Settings.hpp | 3 ++ src/widgets/settingspages/IgnoresPage.cpp | 5 +-- 6 files changed, 52 insertions(+), 12 deletions(-) diff --git a/src/controllers/ignores/IgnoreModel.cpp b/src/controllers/ignores/IgnoreModel.cpp index 869d2ec4f..3b495de3d 100644 --- a/src/controllers/ignores/IgnoreModel.cpp +++ b/src/controllers/ignores/IgnoreModel.cpp @@ -8,7 +8,7 @@ namespace chatterino { // commandmodel IgnoreModel::IgnoreModel(QObject *parent) - : SignalVectorModel(2, parent) + : SignalVectorModel(4, parent) { } @@ -18,8 +18,9 @@ IgnorePhrase IgnoreModel::getItemFromRow(std::vector &row, { // key, regex - return IgnorePhrase{row[0]->data(Qt::DisplayRole).toString(), - row[1]->data(Qt::CheckStateRole).toBool()}; + return IgnorePhrase{ + row[0]->data(Qt::DisplayRole).toString(), row[1]->data(Qt::CheckStateRole).toBool(), + row[2]->data(Qt::CheckStateRole).toBool(), row[3]->data(Qt::DisplayRole).toString()}; } // turns a row in the model into a vector item @@ -27,6 +28,8 @@ void IgnoreModel::getRowFromItem(const IgnorePhrase &item, std::vector @@ -16,15 +17,18 @@ class IgnorePhrase public: bool operator==(const IgnorePhrase &other) const { - return std::tie(this->pattern_, this->isRegex_) == std::tie(other.pattern_, other.isRegex_); + return std::tie(this->pattern_, this->isRegex_, this->isReplace_, this->replace_) == + std::tie(other.pattern_, other.isRegex_, other.isReplace_, other.replace_); } - IgnorePhrase(const QString &pattern, bool isRegex) + IgnorePhrase(const QString &pattern, bool isRegex, bool isReplace, const QString &replace) : pattern_(pattern) , isRegex_(isRegex) , regex_(isRegex_ ? pattern : "\\b" + QRegularExpression::escape(pattern) + "\\b", QRegularExpression::CaseInsensitiveOption | QRegularExpression::UseUnicodePropertiesOption) + , isReplace_(isReplace) + , replace_(replace) { } @@ -47,10 +51,22 @@ public: return this->isValid() && this->regex_.match(subject).hasMatch(); } + bool isReplace() const + { + return this->isReplace_; + } + + const QString &getReplace() const + { + return this->replace_; + } + private: QString pattern_; bool isRegex_; QRegularExpression regex_; + bool isReplace_; + QString replace_; }; } // namespace chatterino @@ -66,6 +82,8 @@ struct Serialize { AddMember(ret, "pattern", value.getPattern(), a); AddMember(ret, "regex", value.isRegex(), a); + AddMember(ret, "onlyWord", value.isReplace(), a); + AddMember(ret, "replace", value.getReplace(), a); return ret; } @@ -76,16 +94,22 @@ struct Deserialize { static chatterino::IgnorePhrase get(const rapidjson::Value &value) { if (!value.IsObject()) { - return chatterino::IgnorePhrase(QString(), false); + return chatterino::IgnorePhrase( + QString(), false, false, + ::chatterino::getSettings()->ignoredPhraseReplace.getValue()); } QString _pattern; bool _isRegex = false; + bool _isReplace = false; + QString _replace; chatterino::rj::getSafe(value, "pattern", _pattern); chatterino::rj::getSafe(value, "regex", _isRegex); + chatterino::rj::getSafe(value, "onlyWord", _isReplace); + chatterino::rj::getSafe(value, "replace", _replace); - return chatterino::IgnorePhrase(_pattern, _isRegex); + return chatterino::IgnorePhrase(_pattern, _isRegex, _isReplace, _replace); } }; diff --git a/src/providers/twitch/TwitchMessageBuilder.cpp b/src/providers/twitch/TwitchMessageBuilder.cpp index e54d71202..f01a78ecd 100644 --- a/src/providers/twitch/TwitchMessageBuilder.cpp +++ b/src/providers/twitch/TwitchMessageBuilder.cpp @@ -56,7 +56,7 @@ bool TwitchMessageBuilder::isIgnored() const // TODO(pajlada): Do we need to check if the phrase is valid first? for (const auto &phrase : app->ignores->phrases.getVector()) { - if (phrase.isMatch(this->originalMessage_)) { + if (!phrase.isReplace() && phrase.isMatch(this->originalMessage_)) { Log("Blocking message because it contains ignored phrase {}", phrase.getPattern()); return true; } @@ -168,13 +168,22 @@ MessagePtr TwitchMessageBuilder::build() auto currentTwitchEmote = twitchEmotes.begin(); + /*for (const auto &phrase : app->ignores->phrases.getVector()) { + if (phrase.isReplace() && phrase.isMatch(this->originalMessage_)) { + Log("Replacing message because it contains ignored phrase {}", phrase.getPattern()); + this->originalMessage_.replace(phrase.getPattern(), phrase.getReplace()); + } + }*/ + // words QStringList splits = this->originalMessage_.split(' '); long int i = 0; - for (QString split : splits) { + for (int current = 0; current < splits.size(); ++current) { + const QString &split = splits[current]; + Log("Splits {} {} {}", current, split, i); MessageColor textColor = this->action_ ? MessageColor(this->usernameColor_) : MessageColor(MessageColor::Text); diff --git a/src/providers/twitch/TwitchMessageBuilder.hpp b/src/providers/twitch/TwitchMessageBuilder.hpp index 80d80fe7b..22375b5ad 100644 --- a/src/providers/twitch/TwitchMessageBuilder.hpp +++ b/src/providers/twitch/TwitchMessageBuilder.hpp @@ -61,7 +61,7 @@ private: QString roomID_; QColor usernameColor_; - const QString originalMessage_; + QString originalMessage_; bool senderIsBroadcaster{}; const bool action_ = false; diff --git a/src/singletons/Settings.hpp b/src/singletons/Settings.hpp index ac0cbf0b8..fd30642f1 100644 --- a/src/singletons/Settings.hpp +++ b/src/singletons/Settings.hpp @@ -83,6 +83,9 @@ public: BoolSetting linksDoubleClickOnly = {"/links/doubleClickToOpen", false}; BoolSetting lowercaseLink = {"/links/linkLowercase", true}; + /// Ignored phrases + QStringSetting ignoredPhraseReplace = {"/ignore/ignoredPhraseReplace", "***"}; + /// Ingored Users BoolSetting enableTwitchIgnoredUsers = {"/ignore/enableTwitchIgnoredUsers", true}; diff --git a/src/widgets/settingspages/IgnoresPage.cpp b/src/widgets/settingspages/IgnoresPage.cpp index fe7b86d0e..6c642b0f5 100644 --- a/src/widgets/settingspages/IgnoresPage.cpp +++ b/src/widgets/settingspages/IgnoresPage.cpp @@ -45,7 +45,7 @@ void addPhrasesTab(LayoutCreator layout) { EditableModelView *view = layout.emplace(getApp()->ignores->createModel(nullptr)).getElement(); - view->setTitles({"Pattern", "Regex"}); + view->setTitles({"Pattern", "Regex", "Replace", "Pattern"}); view->getTableView()->horizontalHeader()->setSectionResizeMode(QHeaderView::Fixed); view->getTableView()->horizontalHeader()->setSectionResizeMode(0, QHeaderView::Stretch); @@ -55,7 +55,8 @@ void addPhrasesTab(LayoutCreator layout) }); view->addButtonPressed.connect([] { - getApp()->ignores->phrases.appendItem(IgnorePhrase{"my phrase", false}); + getApp()->ignores->phrases.appendItem(IgnorePhrase{ + "my phrase", false, false, getSettings()->ignoredPhraseReplace.getValue()}); }); } From 1834342f74c4fbff38b81fa2c2fcfd6c55adc0d5 Mon Sep 17 00:00:00 2001 From: hemirt Date: Sun, 8 Jul 2018 21:03:13 +0200 Subject: [PATCH 02/11] IgnorePhrase replacement also removes twitch emotes info about the matched and changed parts and shifts positions of other emotes from emote infos to the corresponding new position --- src/controllers/ignores/IgnorePhrase.hpp | 7 ++- src/providers/twitch/TwitchMessageBuilder.cpp | 56 ++++++++++++++++++- 2 files changed, 59 insertions(+), 4 deletions(-) diff --git a/src/controllers/ignores/IgnorePhrase.hpp b/src/controllers/ignores/IgnorePhrase.hpp index 517e26323..3d2938dea 100644 --- a/src/controllers/ignores/IgnorePhrase.hpp +++ b/src/controllers/ignores/IgnorePhrase.hpp @@ -24,7 +24,7 @@ public: IgnorePhrase(const QString &pattern, bool isRegex, bool isReplace, const QString &replace) : pattern_(pattern) , isRegex_(isRegex) - , regex_(isRegex_ ? pattern : "\\b" + QRegularExpression::escape(pattern) + "\\b", + , regex_(!isRegex ? pattern : QRegularExpression::escape(pattern), QRegularExpression::CaseInsensitiveOption | QRegularExpression::UseUnicodePropertiesOption) , isReplace_(isReplace) @@ -51,6 +51,11 @@ public: return this->isValid() && this->regex_.match(subject).hasMatch(); } + const QRegularExpression &getRegex() const + { + return this->regex_; + } + bool isReplace() const { return this->isReplace_; diff --git a/src/providers/twitch/TwitchMessageBuilder.cpp b/src/providers/twitch/TwitchMessageBuilder.cpp index f01a78ecd..32a16c05b 100644 --- a/src/providers/twitch/TwitchMessageBuilder.cpp +++ b/src/providers/twitch/TwitchMessageBuilder.cpp @@ -166,6 +166,58 @@ MessagePtr TwitchMessageBuilder::build() [](const auto &a, const auto &b) { return a.first < b.first; }); } + const auto &phrases = app->ignores->phrases.getVector(); + auto removeEmotesInRange = [&twitchEmotes](int pos, int len) mutable { + twitchEmotes.erase( + std::remove_if(twitchEmotes.begin(), twitchEmotes.end(), + [&pos, &len](const auto &item) { + return ((item.first >= pos) && item.first < (pos + len)); + }), + twitchEmotes.end()); + }; + + auto shiftIndicesAfter = [&twitchEmotes](int pos, int by) mutable { + auto it = std::find_if(twitchEmotes.begin(), twitchEmotes.end(), + [&pos](const auto &item) { return item.first >= pos; }); + while (it != twitchEmotes.end()) { + it->first += by; + ++it; + } + }; + + for (const auto &phrase : phrases) { + if (!phrase.isReplace() || !phrase.isValid()) { + continue; + } + if (phrase.isRegex()) { + const auto ®ex = phrase.getRegex(); + QRegularExpressionMatch match; + int from = 0; + while ((from = this->originalMessage_.indexOf(regex, from, &match)) != -1) { + int len = match.capturedLength(); + removeEmotesInRange(from, len); + auto mid = this->originalMessage_.mid(from, len); + mid.replace(regex, phrase.getReplace()); + this->originalMessage_.replace(from, len, mid); + int midsize = mid.size(); + from += midsize; + shiftIndicesAfter(from, midsize - len); + } + } else { + const auto &pattern = phrase.getPattern(); + int from = 0; + while ((from = this->originalMessage_.indexOf(pattern, from)) != -1) { + int len = pattern.size(); + removeEmotesInRange(from, len); + const auto &replace = phrase.getReplace(); + this->originalMessage_.replace(from, len, replace); + int replacesize = replace.size(); + from += replacesize; + shiftIndicesAfter(from, replacesize - len); + } + } + } + auto currentTwitchEmote = twitchEmotes.begin(); /*for (const auto &phrase : app->ignores->phrases.getVector()) { @@ -181,9 +233,7 @@ MessagePtr TwitchMessageBuilder::build() long int i = 0; - for (int current = 0; current < splits.size(); ++current) { - const QString &split = splits[current]; - Log("Splits {} {} {}", current, split, i); + for (const auto &split : splits) { MessageColor textColor = this->action_ ? MessageColor(this->usernameColor_) : MessageColor(MessageColor::Text); From 4385fcd13fe6e011b91a3f4a29fd440d019fc499 Mon Sep 17 00:00:00 2001 From: hemirt Date: Sun, 8 Jul 2018 21:09:14 +0200 Subject: [PATCH 03/11] remove commented code --- src/providers/twitch/TwitchMessageBuilder.cpp | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/providers/twitch/TwitchMessageBuilder.cpp b/src/providers/twitch/TwitchMessageBuilder.cpp index 32a16c05b..fdca2f9ae 100644 --- a/src/providers/twitch/TwitchMessageBuilder.cpp +++ b/src/providers/twitch/TwitchMessageBuilder.cpp @@ -220,13 +220,6 @@ MessagePtr TwitchMessageBuilder::build() auto currentTwitchEmote = twitchEmotes.begin(); - /*for (const auto &phrase : app->ignores->phrases.getVector()) { - if (phrase.isReplace() && phrase.isMatch(this->originalMessage_)) { - Log("Replacing message because it contains ignored phrase {}", phrase.getPattern()); - this->originalMessage_.replace(phrase.getPattern(), phrase.getReplace()); - } - }*/ - // words QStringList splits = this->originalMessage_.split(' '); From 00c9fa080aeb8a4a187743d708ba139cbed5a849 Mon Sep 17 00:00:00 2001 From: hemirt Date: Mon, 9 Jul 2018 19:53:53 +0200 Subject: [PATCH 04/11] add case sensitivity checkbox and fix validity issues due to isValid that checked regex --- src/controllers/ignores/IgnoreModel.cpp | 10 ++-- src/controllers/ignores/IgnorePhrase.hpp | 47 +++++++++++++------ src/providers/twitch/TwitchMessageBuilder.cpp | 11 ++++- src/widgets/settingspages/IgnoresPage.cpp | 4 +- 4 files changed, 50 insertions(+), 22 deletions(-) diff --git a/src/controllers/ignores/IgnoreModel.cpp b/src/controllers/ignores/IgnoreModel.cpp index 3b495de3d..a5b241c5e 100644 --- a/src/controllers/ignores/IgnoreModel.cpp +++ b/src/controllers/ignores/IgnoreModel.cpp @@ -8,7 +8,7 @@ namespace chatterino { // commandmodel IgnoreModel::IgnoreModel(QObject *parent) - : SignalVectorModel(4, parent) + : SignalVectorModel(5, parent) { } @@ -20,7 +20,8 @@ IgnorePhrase IgnoreModel::getItemFromRow(std::vector &row, return IgnorePhrase{ row[0]->data(Qt::DisplayRole).toString(), row[1]->data(Qt::CheckStateRole).toBool(), - row[2]->data(Qt::CheckStateRole).toBool(), row[3]->data(Qt::DisplayRole).toString()}; + row[3]->data(Qt::CheckStateRole).toBool(), row[4]->data(Qt::DisplayRole).toString(), + row[2]->data(Qt::CheckStateRole).toBool()}; } // turns a row in the model into a vector item @@ -28,8 +29,9 @@ void IgnoreModel::getRowFromItem(const IgnorePhrase &item, std::vectorpattern_, this->isRegex_, this->isReplace_, this->replace_) == - std::tie(other.pattern_, other.isRegex_, other.isReplace_, other.replace_); + return std::tie(this->pattern_, this->isRegex_, this->isReplace_, this->replace_, + this->caseInsensitive_) == std::tie(other.pattern_, other.isRegex_, + other.isReplace_, other.replace_, + other.caseInsensitive_); } - IgnorePhrase(const QString &pattern, bool isRegex, bool isReplace, const QString &replace) + IgnorePhrase(const QString &pattern, bool isRegex, bool isReplace, const QString &replace, + bool caseInsensitive) : pattern_(pattern) , isRegex_(isRegex) - , regex_(!isRegex ? pattern : QRegularExpression::escape(pattern), - QRegularExpression::CaseInsensitiveOption | - QRegularExpression::UseUnicodePropertiesOption) + , regex_(pattern) , isReplace_(isReplace) , replace_(replace) + , caseInsensitive_(caseInsensitive) { + if (this->caseInsensitive_) { + regex_.setPatternOptions(QRegularExpression::CaseInsensitiveOption | + QRegularExpression::UseUnicodePropertiesOption); + } else { + regex_.setPatternOptions(QRegularExpression::UseUnicodePropertiesOption); + } } const QString &getPattern() const @@ -41,14 +49,11 @@ public: return this->isRegex_; } - bool isValid() const - { - return !this->pattern_.isEmpty() && this->regex_.isValid(); - } - bool isMatch(const QString &subject) const { - return this->isValid() && this->regex_.match(subject).hasMatch(); + return !this->pattern_.isEmpty() && + (this->isRegex() ? (this->regex_.isValid() && this->regex_.match(subject).hasMatch()) + : subject.contains(this->pattern_, this->caseSensitivity())); } const QRegularExpression &getRegex() const @@ -66,12 +71,23 @@ public: return this->replace_; } + bool caseInsensitive() const + { + return this->caseInsensitive_; + } + + Qt::CaseSensitivity caseSensitivity() const + { + return this->caseInsensitive_ ? Qt::CaseInsensitive : Qt::CaseSensitive; + } + private: QString pattern_; bool isRegex_; QRegularExpression regex_; bool isReplace_; QString replace_; + bool caseInsensitive_; }; } // namespace chatterino @@ -89,6 +105,7 @@ struct Serialize { AddMember(ret, "regex", value.isRegex(), a); AddMember(ret, "onlyWord", value.isReplace(), a); AddMember(ret, "replace", value.getReplace(), a); + AddMember(ret, "caseInsens", value.caseInsensitive(), a); return ret; } @@ -101,20 +118,22 @@ struct Deserialize { if (!value.IsObject()) { return chatterino::IgnorePhrase( QString(), false, false, - ::chatterino::getSettings()->ignoredPhraseReplace.getValue()); + ::chatterino::getSettings()->ignoredPhraseReplace.getValue(), false); } QString _pattern; bool _isRegex = false; bool _isReplace = false; QString _replace; + bool _caseInsens = false; chatterino::rj::getSafe(value, "pattern", _pattern); chatterino::rj::getSafe(value, "regex", _isRegex); chatterino::rj::getSafe(value, "onlyWord", _isReplace); chatterino::rj::getSafe(value, "replace", _replace); + chatterino::rj::getSafe(value, "caseInsens", _caseInsens); - return chatterino::IgnorePhrase(_pattern, _isRegex, _isReplace, _replace); + return chatterino::IgnorePhrase(_pattern, _isRegex, _isReplace, _replace, _caseInsens); } }; diff --git a/src/providers/twitch/TwitchMessageBuilder.cpp b/src/providers/twitch/TwitchMessageBuilder.cpp index fdca2f9ae..73654ae0f 100644 --- a/src/providers/twitch/TwitchMessageBuilder.cpp +++ b/src/providers/twitch/TwitchMessageBuilder.cpp @@ -186,11 +186,14 @@ MessagePtr TwitchMessageBuilder::build() }; for (const auto &phrase : phrases) { - if (!phrase.isReplace() || !phrase.isValid()) { + if (!phrase.isReplace()) { continue; } if (phrase.isRegex()) { const auto ®ex = phrase.getRegex(); + if (!regex.isValid()) { + continue; + } QRegularExpressionMatch match; int from = 0; while ((from = this->originalMessage_.indexOf(regex, from, &match)) != -1) { @@ -205,8 +208,12 @@ MessagePtr TwitchMessageBuilder::build() } } else { const auto &pattern = phrase.getPattern(); + if (pattern.isEmpty()) { + continue; + } int from = 0; - while ((from = this->originalMessage_.indexOf(pattern, from)) != -1) { + while ((from = this->originalMessage_.indexOf(pattern, from, + phrase.caseSensitivity())) != -1) { int len = pattern.size(); removeEmotesInRange(from, len); const auto &replace = phrase.getReplace(); diff --git a/src/widgets/settingspages/IgnoresPage.cpp b/src/widgets/settingspages/IgnoresPage.cpp index 6c642b0f5..743320cc7 100644 --- a/src/widgets/settingspages/IgnoresPage.cpp +++ b/src/widgets/settingspages/IgnoresPage.cpp @@ -45,7 +45,7 @@ void addPhrasesTab(LayoutCreator layout) { EditableModelView *view = layout.emplace(getApp()->ignores->createModel(nullptr)).getElement(); - view->setTitles({"Pattern", "Regex", "Replace", "Pattern"}); + view->setTitles({"Pattern", "Regex", "Case Insensitive", "Replace", "Pattern"}); view->getTableView()->horizontalHeader()->setSectionResizeMode(QHeaderView::Fixed); view->getTableView()->horizontalHeader()->setSectionResizeMode(0, QHeaderView::Stretch); @@ -56,7 +56,7 @@ void addPhrasesTab(LayoutCreator layout) view->addButtonPressed.connect([] { getApp()->ignores->phrases.appendItem(IgnorePhrase{ - "my phrase", false, false, getSettings()->ignoredPhraseReplace.getValue()}); + "my phrase", false, false, getSettings()->ignoredPhraseReplace.getValue(), false}); }); } From f00d3da537ec14aebd9cbb84d63f7b16c196f199 Mon Sep 17 00:00:00 2001 From: hemirt Date: Sat, 28 Jul 2018 19:53:55 +0200 Subject: [PATCH 05/11] rename variables to fit better, emotes in capture groups from regex work --- src/controllers/ignores/IgnoreModel.cpp | 4 +- src/controllers/ignores/IgnorePhrase.hpp | 62 ++++++++------- src/providers/twitch/TwitchMessageBuilder.cpp | 77 +++++++++++++------ src/providers/twitch/TwitchMessageBuilder.hpp | 2 +- src/widgets/settingspages/IgnoresPage.cpp | 4 +- 5 files changed, 92 insertions(+), 57 deletions(-) diff --git a/src/controllers/ignores/IgnoreModel.cpp b/src/controllers/ignores/IgnoreModel.cpp index a5b241c5e..f12fdfe6d 100644 --- a/src/controllers/ignores/IgnoreModel.cpp +++ b/src/controllers/ignores/IgnoreModel.cpp @@ -29,8 +29,8 @@ void IgnoreModel::getRowFromItem(const IgnorePhrase &item, std::vectorpattern_, this->isRegex_, this->isReplace_, this->replace_, - this->caseInsensitive_) == std::tie(other.pattern_, other.isRegex_, - other.isReplace_, other.replace_, - other.caseInsensitive_); + return std::tie(this->pattern_, this->isRegex_, this->isBlock_, this->replace_, + this->isCaseSensitive_) == std::tie(other.pattern_, other.isRegex_, + other.isBlock_, other.replace_, + other.isCaseSensitive_); } - IgnorePhrase(const QString &pattern, bool isRegex, bool isReplace, const QString &replace, - bool caseInsensitive) + IgnorePhrase(const QString &pattern, bool isRegex, bool isBlock, const QString &replace, + bool isCaseSensitive) : pattern_(pattern) , isRegex_(isRegex) , regex_(pattern) - , isReplace_(isReplace) + , isBlock_(isBlock) , replace_(replace) - , caseInsensitive_(caseInsensitive) + , isCaseSensitive_(isCaseSensitive) { - if (this->caseInsensitive_) { + if (this->isCaseSensitive_) { + regex_.setPatternOptions(QRegularExpression::UseUnicodePropertiesOption); + } else { regex_.setPatternOptions(QRegularExpression::CaseInsensitiveOption | QRegularExpression::UseUnicodePropertiesOption); - } else { - regex_.setPatternOptions(QRegularExpression::UseUnicodePropertiesOption); } } @@ -44,11 +44,17 @@ public: { return this->pattern_; } + bool isRegex() const { return this->isRegex_; } + bool isRegexValid() const + { + return this->regex_.isValid(); + } + bool isMatch(const QString &subject) const { return !this->pattern_.isEmpty() && @@ -61,9 +67,9 @@ public: return this->regex_; } - bool isReplace() const + bool isBlock() const { - return this->isReplace_; + return this->isBlock_; } const QString &getReplace() const @@ -71,23 +77,23 @@ public: return this->replace_; } - bool caseInsensitive() const + bool isCaseSensitive() const { - return this->caseInsensitive_; + return this->isCaseSensitive_; } Qt::CaseSensitivity caseSensitivity() const { - return this->caseInsensitive_ ? Qt::CaseInsensitive : Qt::CaseSensitive; + return this->isCaseSensitive_ ? Qt::CaseSensitive : Qt::CaseInsensitive; } private: QString pattern_; bool isRegex_; QRegularExpression regex_; - bool isReplace_; + bool isBlock_; QString replace_; - bool caseInsensitive_; + bool isCaseSensitive_; }; } // namespace chatterino @@ -103,9 +109,9 @@ struct Serialize { AddMember(ret, "pattern", value.getPattern(), a); AddMember(ret, "regex", value.isRegex(), a); - AddMember(ret, "onlyWord", value.isReplace(), a); - AddMember(ret, "replace", value.getReplace(), a); - AddMember(ret, "caseInsens", value.caseInsensitive(), a); + AddMember(ret, "isBlock", value.isBlock(), a); + AddMember(ret, "replaceWith", value.getReplace(), a); + AddMember(ret, "caseSensitive", value.isCaseSensitive(), a); return ret; } @@ -118,22 +124,22 @@ struct Deserialize { if (!value.IsObject()) { return chatterino::IgnorePhrase( QString(), false, false, - ::chatterino::getSettings()->ignoredPhraseReplace.getValue(), false); + ::chatterino::getSettings()->ignoredPhraseReplace.getValue(), true); } QString _pattern; bool _isRegex = false; - bool _isReplace = false; + bool _isBlock = false; QString _replace; - bool _caseInsens = false; + bool _caseSens = true; chatterino::rj::getSafe(value, "pattern", _pattern); chatterino::rj::getSafe(value, "regex", _isRegex); - chatterino::rj::getSafe(value, "onlyWord", _isReplace); - chatterino::rj::getSafe(value, "replace", _replace); - chatterino::rj::getSafe(value, "caseInsens", _caseInsens); + chatterino::rj::getSafe(value, "isBlock", _isBlock); + chatterino::rj::getSafe(value, "replaceWith", _replace); + chatterino::rj::getSafe(value, "caseSensitive", _caseSens); - return chatterino::IgnorePhrase(_pattern, _isRegex, _isReplace, _replace, _caseInsens); + return chatterino::IgnorePhrase(_pattern, _isRegex, _isBlock, _replace, _caseSens); } }; diff --git a/src/providers/twitch/TwitchMessageBuilder.cpp b/src/providers/twitch/TwitchMessageBuilder.cpp index 73654ae0f..a9337e3f6 100644 --- a/src/providers/twitch/TwitchMessageBuilder.cpp +++ b/src/providers/twitch/TwitchMessageBuilder.cpp @@ -56,7 +56,7 @@ bool TwitchMessageBuilder::isIgnored() const // TODO(pajlada): Do we need to check if the phrase is valid first? for (const auto &phrase : app->ignores->phrases.getVector()) { - if (!phrase.isReplace() && phrase.isMatch(this->originalMessage_)) { + if (phrase.isBlock() && phrase.isMatch(this->originalMessage_)) { Log("Blocking message because it contains ignored phrase {}", phrase.getPattern()); return true; } @@ -152,7 +152,7 @@ MessagePtr TwitchMessageBuilder::build() } // twitch emotes - std::vector> twitchEmotes; + std::vector> twitchEmotes; iterator = this->tags.find("emotes"); if (iterator != this->tags.end()) { @@ -161,32 +161,31 @@ MessagePtr TwitchMessageBuilder::build() for (QString emote : emoteString) { this->appendTwitchEmote(ircMessage, emote, twitchEmotes); } - - std::sort(twitchEmotes.begin(), twitchEmotes.end(), - [](const auto &a, const auto &b) { return a.first < b.first; }); } const auto &phrases = app->ignores->phrases.getVector(); auto removeEmotesInRange = [&twitchEmotes](int pos, int len) mutable { - twitchEmotes.erase( - std::remove_if(twitchEmotes.begin(), twitchEmotes.end(), - [&pos, &len](const auto &item) { - return ((item.first >= pos) && item.first < (pos + len)); - }), - twitchEmotes.end()); + auto it = std::remove_if( + twitchEmotes.begin(), twitchEmotes.end(), [&pos, &len](const auto &item) { + return ((std::get<0>(item) >= pos) && std::get<0>(item) < (pos + len)); + }); + + std::vector> v(it, twitchEmotes.end()); + twitchEmotes.erase(it, twitchEmotes.end()); + return v; }; auto shiftIndicesAfter = [&twitchEmotes](int pos, int by) mutable { auto it = std::find_if(twitchEmotes.begin(), twitchEmotes.end(), - [&pos](const auto &item) { return item.first >= pos; }); + [&pos](const auto &item) { return std::get<0>(item) >= pos; }); while (it != twitchEmotes.end()) { - it->first += by; + std::get<0>(*it) += by; ++it; } }; for (const auto &phrase : phrases) { - if (!phrase.isReplace()) { + if (phrase.isBlock()) { continue; } if (phrase.isRegex()) { @@ -198,9 +197,23 @@ MessagePtr TwitchMessageBuilder::build() int from = 0; while ((from = this->originalMessage_.indexOf(regex, from, &match)) != -1) { int len = match.capturedLength(); - removeEmotesInRange(from, len); + auto vret = removeEmotesInRange(from, len); auto mid = this->originalMessage_.mid(from, len); mid.replace(regex, phrase.getReplace()); + + // hemirt + // doesnt check for own emotes in the Replace part + // mb in IgnoredPhrase ?? + + for (auto &tup : vret) { + int index = 0; + const auto &emote = std::get<2>(tup); + while ((index = mid.indexOf(emote, index)) != -1) { + std::get<0>(tup) = from + index; + index += emote.size(); + twitchEmotes.push_back(tup); + } + } this->originalMessage_.replace(from, len, mid); int midsize = mid.size(); from += midsize; @@ -215,8 +228,22 @@ MessagePtr TwitchMessageBuilder::build() while ((from = this->originalMessage_.indexOf(pattern, from, phrase.caseSensitivity())) != -1) { int len = pattern.size(); - removeEmotesInRange(from, len); - const auto &replace = phrase.getReplace(); + auto vret = removeEmotesInRange(from, len); + auto replace = phrase.getReplace(); + + // hemirt + // doesnt check for own emotes in the Replace part + // mb in IgnoredPhrase ?? + + for (auto &tup : vret) { + int index = 0; + const auto &emote = std::get<2>(tup); + while ((index = replace.indexOf(emote, index)) != -1) { + std::get<0>(tup) = from + index; + index += emote.size(); + twitchEmotes.push_back(tup); + } + } this->originalMessage_.replace(from, len, replace); int replacesize = replace.size(); from += replacesize; @@ -225,6 +252,8 @@ MessagePtr TwitchMessageBuilder::build() } } + std::sort(twitchEmotes.begin(), twitchEmotes.end(), + [](const auto &a, const auto &b) { return std::get<0>(a) < std::get<0>(b); }); auto currentTwitchEmote = twitchEmotes.begin(); // words @@ -238,8 +267,8 @@ MessagePtr TwitchMessageBuilder::build() this->action_ ? MessageColor(this->usernameColor_) : MessageColor(MessageColor::Text); // twitch emote - if (currentTwitchEmote != twitchEmotes.end() && currentTwitchEmote->first == i) { - auto emoteImage = currentTwitchEmote->second; + if (currentTwitchEmote != twitchEmotes.end() && std::get<0>(*currentTwitchEmote) == i) { + auto emoteImage = std::get<1>(*currentTwitchEmote); this->emplace(emoteImage, MessageElement::TwitchEmote); i += split.length() + 1; @@ -586,9 +615,9 @@ void TwitchMessageBuilder::parseHighlights() } } -void TwitchMessageBuilder::appendTwitchEmote(const Communi::IrcMessage *ircMessage, - const QString &emote, - std::vector> &vec) +void TwitchMessageBuilder::appendTwitchEmote( + const Communi::IrcMessage *ircMessage, const QString &emote, + std::vector> &vec) { auto app = getApp(); if (!emote.contains(':')) { @@ -621,8 +650,8 @@ void TwitchMessageBuilder::appendTwitchEmote(const Communi::IrcMessage *ircMessa QString name = this->originalMessage_.mid(start, end - start + 1); - vec.push_back( - std::pair(start, app->emotes->twitch.getEmoteById(id, name))); + vec.push_back(std::tuple( + start, app->emotes->twitch.getEmoteById(id, name), name)); } } diff --git a/src/providers/twitch/TwitchMessageBuilder.hpp b/src/providers/twitch/TwitchMessageBuilder.hpp index 22375b5ad..246f3d50f 100644 --- a/src/providers/twitch/TwitchMessageBuilder.hpp +++ b/src/providers/twitch/TwitchMessageBuilder.hpp @@ -51,7 +51,7 @@ private: void parseHighlights(); void appendTwitchEmote(const Communi::IrcMessage *ircMessage, const QString &emote, - std::vector> &vec); + std::vector > &vec); bool tryAppendEmote(QString &emoteString); void appendTwitchBadges(); diff --git a/src/widgets/settingspages/IgnoresPage.cpp b/src/widgets/settingspages/IgnoresPage.cpp index 743320cc7..a8465a619 100644 --- a/src/widgets/settingspages/IgnoresPage.cpp +++ b/src/widgets/settingspages/IgnoresPage.cpp @@ -45,7 +45,7 @@ void addPhrasesTab(LayoutCreator layout) { EditableModelView *view = layout.emplace(getApp()->ignores->createModel(nullptr)).getElement(); - view->setTitles({"Pattern", "Regex", "Case Insensitive", "Replace", "Pattern"}); + view->setTitles({"Pattern", "Regex", "Case Sensitive", "Block", "Pattern"}); view->getTableView()->horizontalHeader()->setSectionResizeMode(QHeaderView::Fixed); view->getTableView()->horizontalHeader()->setSectionResizeMode(0, QHeaderView::Stretch); @@ -56,7 +56,7 @@ void addPhrasesTab(LayoutCreator layout) view->addButtonPressed.connect([] { getApp()->ignores->phrases.appendItem(IgnorePhrase{ - "my phrase", false, false, getSettings()->ignoredPhraseReplace.getValue(), false}); + "my phrase", false, false, getSettings()->ignoredPhraseReplace.getValue(), true}); }); } From e7f2f397378d0582d989ff8fcbe83bcec41449a1 Mon Sep 17 00:00:00 2001 From: hemirt Date: Sat, 11 Aug 2018 21:54:01 +0200 Subject: [PATCH 06/11] emotedata --- src/controllers/ignores/IgnorePhrase.hpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/controllers/ignores/IgnorePhrase.hpp b/src/controllers/ignores/IgnorePhrase.hpp index 7fd3ca5e3..428022a2e 100644 --- a/src/controllers/ignores/IgnorePhrase.hpp +++ b/src/controllers/ignores/IgnorePhrase.hpp @@ -1,6 +1,8 @@ #pragma once +#include "Application.hpp" #include "common/SerializeCustom.hpp" +#include "controllers/accounts/AccountController.hpp" #include "singletons/Settings.hpp" #include "util/RapidjsonHelpers.hpp" @@ -38,6 +40,11 @@ public: regex_.setPatternOptions(QRegularExpression::CaseInsensitiveOption | QRegularExpression::UseUnicodePropertiesOption); } + + /*const auto &accvec = getApp()->accounts->twitch.accounts.getVector(); + for (const auto &acc : accvec) { + // + }*/ } const QString &getPattern() const @@ -94,6 +101,7 @@ private: bool isBlock_; QString replace_; bool isCaseSensitive_; + std::map emotes; }; } // namespace chatterino From e8e059f8473271128086c5230cf1c40b235af380 Mon Sep 17 00:00:00 2001 From: hemirt Date: Sun, 19 Aug 2018 00:25:58 +0200 Subject: [PATCH 07/11] add replaced emotes into twitchEmotes --- src/controllers/ignores/IgnorePhrase.hpp | 23 ++++++-- src/providers/twitch/TwitchMessageBuilder.cpp | 56 +++++++++++++++++-- 2 files changed, 71 insertions(+), 8 deletions(-) diff --git a/src/controllers/ignores/IgnorePhrase.hpp b/src/controllers/ignores/IgnorePhrase.hpp index c39c898b6..c53ecfd51 100644 --- a/src/controllers/ignores/IgnorePhrase.hpp +++ b/src/controllers/ignores/IgnorePhrase.hpp @@ -42,10 +42,15 @@ public: QRegularExpression::UseUnicodePropertiesOption); } - /*const auto &accvec = getApp()->accounts->twitch.accounts.getVector(); + const auto &accvec = getApp()->accounts->twitch.accounts.getVector(); for (const auto &acc : accvec) { - // - }*/ + const auto &accemotes = *acc->accessEmotes(); + for (const auto &emote : accemotes.emotes) { + if (this->replace_.contains(emote.first.string, Qt::CaseSensitive)) { + this->emotes_.emplace(emote.first, emote.second); + } + } + } } const QString &getPattern() const @@ -95,6 +100,16 @@ public: return this->isCaseSensitive_ ? Qt::CaseSensitive : Qt::CaseInsensitive; } + const std::unordered_map &getEmotes() const + { + return this->emotes_; + } + + bool containsEmote() const + { + return !this->emotes_.empty(); + } + private: QString pattern_; bool isRegex_; @@ -102,7 +117,7 @@ private: bool isBlock_; QString replace_; bool isCaseSensitive_; - std::map emotes; + std::unordered_map emotes_; }; } // namespace chatterino diff --git a/src/providers/twitch/TwitchMessageBuilder.cpp b/src/providers/twitch/TwitchMessageBuilder.cpp index 3fafb7254..d1deaf719 100644 --- a/src/providers/twitch/TwitchMessageBuilder.cpp +++ b/src/providers/twitch/TwitchMessageBuilder.cpp @@ -167,7 +167,11 @@ MessagePtr TwitchMessageBuilder::build() twitchEmotes.begin(), twitchEmotes.end(), [&pos, &len](const auto &item) { return ((std::get<0>(item) >= pos) && std::get<0>(item) < (pos + len)); }); - + for (; it != twitchEmotes.end(); ++it) { + if (std::get<1>(*it) == nullptr) { + log("remem nullptr {}", std::get<2>(*it).string); + } + } std::vector> v(it, twitchEmotes.end()); twitchEmotes.erase(it, twitchEmotes.end()); return v; @@ -182,6 +186,27 @@ MessagePtr TwitchMessageBuilder::build() } }; + auto addReplEmotes = [&twitchEmotes](const IgnorePhrase &phrase, const QString &midrepl, + int startIndex) mutable { + if (!phrase.containsEmote()) { + return; + } + QStringList words = midrepl.split(' '); + int pos = 0; + for (const auto &word : words) { + for (const auto &emote : phrase.getEmotes()) { + if (word == emote.first.string) { + if (emote.second == nullptr) { + log("emote null {}", emote.first.string); + } + twitchEmotes.push_back(std::tuple{ + startIndex + pos, emote.second, emote.first}); + } + } + pos += word.length() + 1; + } + }; + for (const auto &phrase : phrases) { if (phrase.isBlock()) { continue; @@ -204,6 +229,9 @@ MessagePtr TwitchMessageBuilder::build() // mb in IgnoredPhrase ?? for (auto &tup : vret) { + if (std::get<1>(tup) == nullptr) { + log("v nullptr {}", std::get<2>(tup).string); + } int index = 0; const auto &emote = std::get<2>(tup); while ((index = mid.indexOf(emote.string, index)) != -1) { @@ -212,6 +240,9 @@ MessagePtr TwitchMessageBuilder::build() twitchEmotes.push_back(tup); } } + + addReplEmotes(phrase, mid, from); + this->originalMessage_.replace(from, len, mid); int midsize = mid.size(); from += midsize; @@ -234,6 +265,9 @@ MessagePtr TwitchMessageBuilder::build() // mb in IgnoredPhrase ?? for (auto &tup : vret) { + if (std::get<1>(tup) == nullptr) { + log("v nullptr {}", std::get<2>(tup).string); + } int index = 0; const auto &emote = std::get<2>(tup); while ((index = replace.indexOf(emote.string, index)) != -1) { @@ -242,6 +276,9 @@ MessagePtr TwitchMessageBuilder::build() twitchEmotes.push_back(tup); } } + + addReplEmotes(phrase, replace, from); + this->originalMessage_.replace(from, len, replace); int replacesize = replace.size(); from += replacesize; @@ -252,6 +289,11 @@ MessagePtr TwitchMessageBuilder::build() std::sort(twitchEmotes.begin(), twitchEmotes.end(), [](const auto &a, const auto &b) { return std::get<0>(a) < std::get<0>(b); }); + twitchEmotes.erase(std::unique(twitchEmotes.begin(), twitchEmotes.end(), + [](const auto &first, const auto &second) { + return std::get<0>(first) == std::get<0>(second); + }), + twitchEmotes.end()); auto currentTwitchEmote = twitchEmotes.begin(); // words @@ -274,6 +316,9 @@ void TwitchMessageBuilder::addWords( // check if it's a twitch emote twitch emote if (currentTwitchEmote != twitchEmotes.end() && std::get<0>(*currentTwitchEmote) == i) { auto emoteImage = std::get<1>(*currentTwitchEmote); + if (emoteImage == nullptr) { + log("emoteImage nullptr {}", std::get<2>(*currentTwitchEmote).string); + } this->emplace(emoteImage, MessageElementFlag::TwitchEmote); i += word.length() + 1; @@ -689,9 +734,12 @@ void TwitchMessageBuilder::appendTwitchEmote(const Communi::IrcMessage *ircMessa } auto name = EmoteName{this->originalMessage_.mid(start, end - start + 1)}; - - vec.push_back(std::tuple{ - start, app->emotes->twitch.getOrCreateEmote(id, name), name}); + auto tup = std::tuple{ + start, app->emotes->twitch.getOrCreateEmote(id, name), name}; + if (std::get<1>(tup) == nullptr) { + log("nullptr {}", std::get<2>(tup).string); + } + vec.push_back(std::move(tup)); } } From 646268ab1883a955291f152029fa37f4416e681e Mon Sep 17 00:00:00 2001 From: hemirt Date: Sun, 19 Aug 2018 01:06:36 +0200 Subject: [PATCH 08/11] fix build --- src/controllers/ignores/IgnorePhrase.hpp | 30 +++++++++---------- src/providers/twitch/TwitchMessageBuilder.cpp | 2 +- 2 files changed, 15 insertions(+), 17 deletions(-) diff --git a/src/controllers/ignores/IgnorePhrase.hpp b/src/controllers/ignores/IgnorePhrase.hpp index e60e90827..bdf571fd2 100644 --- a/src/controllers/ignores/IgnorePhrase.hpp +++ b/src/controllers/ignores/IgnorePhrase.hpp @@ -150,23 +150,21 @@ struct Deserialize { QString(), false, false, ::chatterino::getSettings()->ignoredPhraseReplace.getValue(), true); } - }; - QString _pattern; - bool _isRegex = false; - bool _isBlock = false; - QString _replace; - bool _caseSens = true; + QString _pattern; + bool _isRegex = false; + bool _isBlock = false; + QString _replace; + bool _caseSens = true; - chatterino::rj::getSafe(value, "pattern", _pattern); - chatterino::rj::getSafe(value, "regex", _isRegex); - chatterino::rj::getSafe(value, "isBlock", _isBlock); - chatterino::rj::getSafe(value, "replaceWith", _replace); - chatterino::rj::getSafe(value, "caseSensitive", _caseSens); - - return chatterino::IgnorePhrase(_pattern, _isRegex, _isBlock, _replace, _caseSens); -} -}; // namespace Settings + chatterino::rj::getSafe(value, "pattern", _pattern); + chatterino::rj::getSafe(value, "regex", _isRegex); + chatterino::rj::getSafe(value, "isBlock", _isBlock); + chatterino::rj::getSafe(value, "replaceWith", _replace); + chatterino::rj::getSafe(value, "caseSensitive", _caseSens); -} // namespace pajlada + return chatterino::IgnorePhrase(_pattern, _isRegex, _isBlock, _replace, _caseSens); + } +}; +} // namespace Settings } // namespace pajlada diff --git a/src/providers/twitch/TwitchMessageBuilder.cpp b/src/providers/twitch/TwitchMessageBuilder.cpp index f6feb61d9..aa0ef33e2 100644 --- a/src/providers/twitch/TwitchMessageBuilder.cpp +++ b/src/providers/twitch/TwitchMessageBuilder.cpp @@ -154,7 +154,7 @@ MessagePtr TwitchMessageBuilder::build() this->appendTwitchEmote(ircMessage, emote, twitchEmotes); } } - + auto app = getApp(); const auto &phrases = app->ignores->phrases.getVector(); auto removeEmotesInRange = [&twitchEmotes](int pos, int len) mutable { auto it = std::remove_if( From 1acb1278aa0109359e0e349ae240d10b34de9d34 Mon Sep 17 00:00:00 2001 From: hemirt Date: Sun, 23 Sep 2018 19:52:03 +0200 Subject: [PATCH 09/11] fix replacement with emotes issues --- src/controllers/ignores/IgnorePhrase.hpp | 25 +-- src/providers/twitch/TwitchMessageBuilder.cpp | 145 +++++++++++++----- 2 files changed, 119 insertions(+), 51 deletions(-) diff --git a/src/controllers/ignores/IgnorePhrase.hpp b/src/controllers/ignores/IgnorePhrase.hpp index bdf571fd2..c07c66720 100644 --- a/src/controllers/ignores/IgnorePhrase.hpp +++ b/src/controllers/ignores/IgnorePhrase.hpp @@ -41,16 +41,6 @@ public: regex_.setPatternOptions(QRegularExpression::CaseInsensitiveOption | QRegularExpression::UseUnicodePropertiesOption); } - - const auto &accvec = getApp()->accounts->twitch.accounts.getVector(); - for (const auto &acc : accvec) { - const auto &accemotes = *acc->accessEmotes(); - for (const auto &emote : accemotes.emotes) { - if (this->replace_.contains(emote.first.string, Qt::CaseSensitive)) { - this->emotes_.emplace(emote.first, emote.second); - } - } - } } const QString &getPattern() const @@ -107,6 +97,18 @@ public: bool containsEmote() const { + if (!this->emotesChecked_) { + const auto &accvec = getApp()->accounts->twitch.accounts.getVector(); + for (const auto &acc : accvec) { + const auto &accemotes = *acc->accessEmotes(); + for (const auto &emote : accemotes.emotes) { + if (this->replace_.contains(emote.first.string, Qt::CaseSensitive)) { + this->emotes_.emplace(emote.first, emote.second); + } + } + } + this->emotesChecked_ = true; + } return !this->emotes_.empty(); } @@ -117,7 +119,8 @@ private: bool isBlock_; QString replace_; bool isCaseSensitive_; - std::unordered_map emotes_; + mutable std::unordered_map emotes_; + mutable bool emotesChecked_{false}; }; } // namespace chatterino diff --git a/src/providers/twitch/TwitchMessageBuilder.cpp b/src/providers/twitch/TwitchMessageBuilder.cpp index aa0ef33e2..469bdd649 100644 --- a/src/providers/twitch/TwitchMessageBuilder.cpp +++ b/src/providers/twitch/TwitchMessageBuilder.cpp @@ -19,6 +19,7 @@ #include #include #include +#include #include namespace chatterino { @@ -156,36 +157,39 @@ MessagePtr TwitchMessageBuilder::build() } auto app = getApp(); const auto &phrases = app->ignores->phrases.getVector(); - auto removeEmotesInRange = [&twitchEmotes](int pos, int len) mutable { - auto it = std::remove_if( - twitchEmotes.begin(), twitchEmotes.end(), [&pos, &len](const auto &item) { - return ((std::get<0>(item) >= pos) && std::get<0>(item) < (pos + len)); - }); - for (; it != twitchEmotes.end(); ++it) { - if (std::get<1>(*it) == nullptr) { - log("remem nullptr {}", std::get<2>(*it).string); + auto removeEmotesInRange = + [](int pos, int len, + std::vector> &twitchEmotes) mutable { + auto it = std::partition( + twitchEmotes.begin(), twitchEmotes.end(), [pos, len](const auto &item) { + return !((std::get<0>(item) >= pos) && std::get<0>(item) < (pos + len)); + }); + for (auto copy = it; copy != twitchEmotes.end(); ++copy) { + if (std::get<1>(*copy) == nullptr) { + log("remem nullptr {}", std::get<2>(*copy).string); + } } - } - std::vector> v(it, twitchEmotes.end()); - twitchEmotes.erase(it, twitchEmotes.end()); - return v; - }; + std::vector> v(it, twitchEmotes.end()); + twitchEmotes.erase(it, twitchEmotes.end()); + return v; + }; auto shiftIndicesAfter = [&twitchEmotes](int pos, int by) mutable { - auto it = std::find_if(twitchEmotes.begin(), twitchEmotes.end(), - [&pos](const auto &item) { return std::get<0>(item) >= pos; }); - while (it != twitchEmotes.end()) { - std::get<0>(*it) += by; - ++it; + for (auto &item : twitchEmotes) { + auto &index = std::get<0>(item); + if (index >= pos) { + index += by; + } } }; - auto addReplEmotes = [&twitchEmotes](const IgnorePhrase &phrase, const QString &midrepl, + auto addReplEmotes = [&twitchEmotes](const IgnorePhrase &phrase, const QStringRef &midrepl, int startIndex) mutable { if (!phrase.containsEmote()) { return; } - QStringList words = midrepl.split(' '); + + QVector words = midrepl.split(' '); int pos = 0; for (const auto &word : words) { for (const auto &emote : phrase.getEmotes()) { @@ -214,17 +218,14 @@ MessagePtr TwitchMessageBuilder::build() int from = 0; while ((from = this->originalMessage_.indexOf(regex, from, &match)) != -1) { int len = match.capturedLength(); - auto vret = removeEmotesInRange(from, len); + auto vret = removeEmotesInRange(from, len, twitchEmotes); auto mid = this->originalMessage_.mid(from, len); mid.replace(regex, phrase.getReplace()); - // hemirt - // doesnt check for own emotes in the Replace part - // mb in IgnoredPhrase ?? - - for (auto &tup : vret) { + /*for (auto &tup : vret) { if (std::get<1>(tup) == nullptr) { log("v nullptr {}", std::get<2>(tup).string); + continue; } int index = 0; const auto &emote = std::get<2>(tup); @@ -233,14 +234,45 @@ MessagePtr TwitchMessageBuilder::build() index += emote.string.size(); twitchEmotes.push_back(tup); } + }*/ + int midsize = mid.size(); + this->originalMessage_.replace(from, len, mid); + int pos1 = from; + while (pos1 > 0) { + if (this->originalMessage_[pos1 - 1] == ' ') { + break; + } + --pos1; + } + int pos2 = from + midsize; + while (pos2 < this->originalMessage_.length()) { + if (this->originalMessage_[pos2] == ' ') { + break; + } + ++pos2; } - addReplEmotes(phrase, mid, from); + shiftIndicesAfter(from + len, midsize - len); + + auto midExtendedRef = this->originalMessage_.midRef(pos1, pos2 - pos1); + + for (auto &tup : vret) { + if (std::get<1>(tup) == nullptr) { + log("v nullptr {}", std::get<2>(tup).string); + continue; + } + int index = 0; + QString emote = " " + std::get<2>(tup).string + " "; + while ((index = midExtendedRef.indexOf(emote, index)) != -1) { + std::get<0>(tup) = from + index + 1; + index += emote.size() - 1; + twitchEmotes.push_back(tup); + } + } + + addReplEmotes(phrase, midExtendedRef, pos1); - this->originalMessage_.replace(from, len, mid); - int midsize = mid.size(); from += midsize; - shiftIndicesAfter(from, midsize - len); } } else { const auto &pattern = phrase.getPattern(); @@ -251,16 +283,13 @@ MessagePtr TwitchMessageBuilder::build() while ((from = this->originalMessage_.indexOf(pattern, from, phrase.caseSensitivity())) != -1) { int len = pattern.size(); - auto vret = removeEmotesInRange(from, len); + auto vret = removeEmotesInRange(from, len, twitchEmotes); auto replace = phrase.getReplace(); - // hemirt - // doesnt check for own emotes in the Replace part - // mb in IgnoredPhrase ?? - - for (auto &tup : vret) { + /*for (auto &tup : vret) { if (std::get<1>(tup) == nullptr) { log("v nullptr {}", std::get<2>(tup).string); + continue; } int index = 0; const auto &emote = std::get<2>(tup); @@ -269,14 +298,47 @@ MessagePtr TwitchMessageBuilder::build() index += emote.string.size(); twitchEmotes.push_back(tup); } + }*/ + + int replacesize = replace.size(); + this->originalMessage_.replace(from, len, replace); + + int pos1 = from; + while (pos1 > 0) { + if (this->originalMessage_[pos1 - 1] == ' ') { + break; + } + --pos1; + } + int pos2 = from + replacesize; + while (pos2 < this->originalMessage_.length()) { + if (this->originalMessage_[pos2] == ' ') { + break; + } + ++pos2; } - addReplEmotes(phrase, replace, from); + shiftIndicesAfter(from + len, replacesize - len); + + auto midExtendedRef = this->originalMessage_.midRef(pos1, pos2 - pos1); + + for (auto &tup : vret) { + if (std::get<1>(tup) == nullptr) { + log("v nullptr {}", std::get<2>(tup).string); + continue; + } + int index = 0; + QString emote = " " + std::get<2>(tup).string + " "; + while ((index = midExtendedRef.indexOf(emote, index)) != -1) { + std::get<0>(tup) = from + index + 1; + index += emote.size() - 1; + twitchEmotes.push_back(tup); + } + } + + addReplEmotes(phrase, midExtendedRef, pos1); - this->originalMessage_.replace(from, len, replace); - int replacesize = replace.size(); from += replacesize; - shiftIndicesAfter(from, replacesize - len); } } } @@ -308,6 +370,9 @@ void TwitchMessageBuilder::addWords( for (const auto &word : words) { // check if it's a twitch emote twitch emote + while (currentTwitchEmote != twitchEmotes.end() && std::get<0>(*currentTwitchEmote) < i) { + ++currentTwitchEmote; + } if (currentTwitchEmote != twitchEmotes.end() && std::get<0>(*currentTwitchEmote) == i) { auto emoteImage = std::get<1>(*currentTwitchEmote); if (emoteImage == nullptr) { From f08cc4cf88c49140a282d3d29af5ad8e7179bb7c Mon Sep 17 00:00:00 2001 From: hemirt Date: Sun, 23 Sep 2018 19:52:30 +0200 Subject: [PATCH 10/11] delete out commented code --- src/providers/twitch/TwitchMessageBuilder.cpp | 27 ------------------- 1 file changed, 27 deletions(-) diff --git a/src/providers/twitch/TwitchMessageBuilder.cpp b/src/providers/twitch/TwitchMessageBuilder.cpp index 469bdd649..a50609401 100644 --- a/src/providers/twitch/TwitchMessageBuilder.cpp +++ b/src/providers/twitch/TwitchMessageBuilder.cpp @@ -222,19 +222,6 @@ MessagePtr TwitchMessageBuilder::build() auto mid = this->originalMessage_.mid(from, len); mid.replace(regex, phrase.getReplace()); - /*for (auto &tup : vret) { - if (std::get<1>(tup) == nullptr) { - log("v nullptr {}", std::get<2>(tup).string); - continue; - } - int index = 0; - const auto &emote = std::get<2>(tup); - while ((index = mid.indexOf(emote.string, index)) != -1) { - std::get<0>(tup) = from + index; - index += emote.string.size(); - twitchEmotes.push_back(tup); - } - }*/ int midsize = mid.size(); this->originalMessage_.replace(from, len, mid); int pos1 = from; @@ -286,20 +273,6 @@ MessagePtr TwitchMessageBuilder::build() auto vret = removeEmotesInRange(from, len, twitchEmotes); auto replace = phrase.getReplace(); - /*for (auto &tup : vret) { - if (std::get<1>(tup) == nullptr) { - log("v nullptr {}", std::get<2>(tup).string); - continue; - } - int index = 0; - const auto &emote = std::get<2>(tup); - while ((index = replace.indexOf(emote.string, index)) != -1) { - std::get<0>(tup) = from + index; - index += emote.string.size(); - twitchEmotes.push_back(tup); - } - }*/ - int replacesize = replace.size(); this->originalMessage_.replace(from, len, replace); From 5cfcf114b65ea7c0fca9654393ac2faa78610098 Mon Sep 17 00:00:00 2001 From: hemirt Date: Sun, 23 Sep 2018 20:00:16 +0200 Subject: [PATCH 11/11] rename second pattern to replacement --- src/widgets/settingspages/IgnoresPage.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/widgets/settingspages/IgnoresPage.cpp b/src/widgets/settingspages/IgnoresPage.cpp index dd08a19a6..42a939850 100644 --- a/src/widgets/settingspages/IgnoresPage.cpp +++ b/src/widgets/settingspages/IgnoresPage.cpp @@ -46,7 +46,7 @@ void addPhrasesTab(LayoutCreator layout) { EditableModelView *view = layout.emplace(getApp()->ignores->createModel(nullptr)).getElement(); - view->setTitles({"Pattern", "Regex", "Case Sensitive", "Block", "Pattern"}); + view->setTitles({"Pattern", "Regex", "Case Sensitive", "Block", "Replacement"}); view->getTableView()->horizontalHeader()->setSectionResizeMode(QHeaderView::Fixed); view->getTableView()->horizontalHeader()->setSectionResizeMode(0, QHeaderView::Stretch);