From d25340bc31c63e9ec26312709f11c26c5234d78b Mon Sep 17 00:00:00 2001 From: James Graham Date: Sat, 9 Dec 2023 14:28:00 +0000 Subject: [PATCH] Fix inline custom emojis in codeblocks Make sure that custom emojis in inline code blocks are not turned into images. By calling preprocess text in `texthandler` the whole function can be simplified as it will now never be called on any text inside any code block (which was the reason for all the split stuff previously). BUG: 477512 --- autotests/texthandlertest.cpp | 46 +++++++++++++++++++++++++++++++++ src/actionshandler.cpp | 2 -- src/models/customemojimodel.cpp | 20 +++++--------- src/models/customemojimodel.h | 2 +- src/texthandler.cpp | 13 ++++++++-- 5 files changed, 64 insertions(+), 19 deletions(-) diff --git a/autotests/texthandlertest.cpp b/autotests/texthandlertest.cpp index a9ea8592f..523a6f248 100644 --- a/autotests/texthandlertest.cpp +++ b/autotests/texthandlertest.cpp @@ -10,6 +10,8 @@ #include #include +#include "models/customemojimodel.h" +#include "neochatconnection.h" #include "utils.h" using namespace Quotient; @@ -48,6 +50,9 @@ private Q_SLOTS: void sendBadLinks(); void sendEscapeCode(); void sendCodeClass(); + void sendCustomEmoji(); + void sendCustomEmojiCode_data(); + void sendCustomEmojiCode(); void receiveStripReply(); void receivePlainTextIn(); @@ -80,6 +85,14 @@ void TextHandlerTest::initTestCase() connection = Connection::makeMockConnection(QStringLiteral("@bob:kde.org")); room = new TestRoom(connection, QStringLiteral("#myroom:kde.org"), JoinState::Join); + connection->setAccountData("im.ponies.user_emotes"_ls, + QJsonObject{{"images"_ls, + QJsonObject{{"test"_ls, + QJsonObject{{"body"_ls, "Test custom emoji"_ls}, + {"url"_ls, "mxc://example.org/test"_ls}, + {"usage"_ls, QJsonArray{"emoticon"_ls}}}}}}}); + CustomEmojiModel::instance().setConnection(static_cast(connection)); + QFile testTextHandlerSyncFile; testTextHandlerSyncFile.setFileName(QLatin1String(DATA_DIR) + u'/' + QLatin1String("test-texthandler-sync.json")); testTextHandlerSyncFile.open(QIODevice::ReadOnly); @@ -234,6 +247,39 @@ void TextHandlerTest::sendCodeClass() QCOMPARE(testTextHandler.handleSendText(), testOutputString); } +void TextHandlerTest::sendCustomEmoji() +{ + const QString testInputString = QStringLiteral(":test:"); + const QString testOutputString = QStringLiteral( + "

\":test:\"

"); + + TextHandler testTextHandler; + testTextHandler.setData(testInputString); + + QCOMPARE(testTextHandler.handleSendText(), testOutputString); +} + +void TextHandlerTest::sendCustomEmojiCode_data() +{ + QTest::addColumn("testInputString"); + QTest::addColumn("testOutputString"); + + QTest::newRow("inline") << QStringLiteral("`:test:`") << QStringLiteral("

:test:

"); + QTest::newRow("block") << QStringLiteral("```\n:test:\n```") << QStringLiteral("
:test:\n
"); +} + +// Custom emojis in code blocks should be left alone. +void TextHandlerTest::sendCustomEmojiCode() +{ + QFETCH(QString, testInputString); + QFETCH(QString, testOutputString); + + TextHandler testTextHandler; + testTextHandler.setData(testInputString); + + QCOMPARE(testTextHandler.handleSendText(), testOutputString); +} + void TextHandlerTest::receiveStripReply() { const QString testInputString = QStringLiteral( diff --git a/src/actionshandler.cpp b/src/actionshandler.cpp index a562e93f7..6967473e9 100644 --- a/src/actionshandler.cpp +++ b/src/actionshandler.cpp @@ -12,7 +12,6 @@ #include #include "models/actionsmodel.h" -#include "models/customemojimodel.h" #include "neochatconfig.h" #include "texthandler.h" @@ -135,7 +134,6 @@ void ActionsHandler::handleMessage(const QString &text, QString handledText, Cha } } - handledText = CustomEmojiModel::instance().preprocessText(handledText); TextHandler textHandler; textHandler.setData(handledText); handledText = textHandler.handleSendText(); diff --git a/src/models/customemojimodel.cpp b/src/models/customemojimodel.cpp index 88956bfe5..aafcb4cf3 100644 --- a/src/models/customemojimodel.cpp +++ b/src/models/customemojimodel.cpp @@ -188,22 +188,14 @@ QHash CustomEmojiModel::roleNames() const }; } -QString CustomEmojiModel::preprocessText(const QString &text) +QString CustomEmojiModel::preprocessText(QString text) { - auto parts = text.split("```"_ls); - bool skip = true; - for (auto &part : parts) { - skip = !skip; - if (skip) { - continue; - } - for (const auto &emoji : std::as_const(m_emojis)) { - part.replace( - emoji.regexp, - QStringLiteral(R"(%2)").arg(emoji.url, emoji.name)); - } + for (const auto &emoji : std::as_const(m_emojis)) { + text.replace( + emoji.regexp, + QStringLiteral(R"(%2)").arg(emoji.url, emoji.name)); } - return parts.join("```"_ls); + return text; } QVariantList CustomEmojiModel::filterModel(const QString &filter) diff --git a/src/models/customemojimodel.h b/src/models/customemojimodel.h index 1b374a301..c4b1e474e 100644 --- a/src/models/customemojimodel.h +++ b/src/models/customemojimodel.h @@ -85,7 +85,7 @@ public: /** * @brief Substitute any custom emojis for an image in the input text. */ - Q_INVOKABLE QString preprocessText(const QString &it); + Q_INVOKABLE QString preprocessText(QString text); /** * @brief Return a list of custom emojis where the name contains the filter text. diff --git a/src/texthandler.cpp b/src/texthandler.cpp index c228f43bf..ac3aa643d 100644 --- a/src/texthandler.cpp +++ b/src/texthandler.cpp @@ -16,6 +16,7 @@ #include +#include "models/customemojimodel.h" #include "utils.h" static const QStringList allowedTags = { @@ -63,13 +64,21 @@ QString TextHandler::handleSendText() next(); QString nextTokenBuffer = m_nextToken; - if (m_nextTokenType == Type::Text || m_nextTokenType == Type::TextCode) { + switch (m_nextTokenType) { + case Text: nextTokenBuffer = escapeHtml(nextTokenBuffer); - } else if (m_nextTokenType == Type::Tag) { + nextTokenBuffer = CustomEmojiModel::instance().preprocessText(nextTokenBuffer); + break; + case TextCode: + nextTokenBuffer = escapeHtml(nextTokenBuffer); + break; + case Tag: if (!isAllowedTag(getTagType())) { nextTokenBuffer = QString(); } nextTokenBuffer = cleanAttributes(getTagType(), nextTokenBuffer); + default: + break; } outputString.append(nextTokenBuffer);