From 6b5996a1bd025106af41265661de0a111b6bb545 Mon Sep 17 00:00:00 2001 From: Joshua Goins Date: Sun, 27 Apr 2025 17:04:05 -0400 Subject: [PATCH] Add custom syntax for tagging spoilers Currently the only two ways to spoiler text in your message is either: * Using the /spoiler command * Manually typing the data-mx-spoiler span HTML blocks Neither one is discoverable, or friendly to users really. Instead, we should extend our existing Markdown-based formatting syntax with one that can handle spoiler tags. I chose the || syntax to match Discord, since Element doesn't seem to adopt one. Unfortunately, CMark does not support custom extensions (see https://github.com/commonmark/cmark/pull/123) so we have to implement our own parsing function. New tests are also added for this too. --- autotests/texthandlertest.cpp | 23 +++++++++++++++++++++++ src/libneochat/texthandler.cpp | 26 ++++++++++++++++++++++++++ src/libneochat/texthandler.h | 1 + 3 files changed, 50 insertions(+) diff --git a/autotests/texthandlertest.cpp b/autotests/texthandlertest.cpp index 47fb473a3..7b90b0023 100644 --- a/autotests/texthandlertest.cpp +++ b/autotests/texthandlertest.cpp @@ -43,6 +43,8 @@ private Q_SLOTS: void sendCustomEmoji(); void sendCustomEmojiCode_data(); void sendCustomEmojiCode(); + void sendSpoilerTags_data(); + void sendSpoilerTags(); void receiveSpacelessSelfClosingTag(); void receiveStripReply(); @@ -249,6 +251,27 @@ void TextHandlerTest::sendCustomEmojiCode() QCOMPARE(testTextHandler.handleSendText(), testOutputString); } +void TextHandlerTest::sendSpoilerTags_data() +{ + QTest::addColumn("testInputString"); + QTest::addColumn("testOutputString"); + + QTest::newRow("incomplete") << u"||test"_s << u"||test"_s; + QTest::newRow("complete") << u"||test||"_s << u"test"_s; + QTest::newRow("multiple") << u"||apple||banana||pear||"_s << u"applebananapear"_s; +} + +void TextHandlerTest::sendSpoilerTags() +{ + QFETCH(QString, testInputString); + QFETCH(QString, testOutputString); + + TextHandler testTextHandler; + testTextHandler.setData(testInputString); + + QCOMPARE(testTextHandler.handleSendText(), testOutputString); +} + void TextHandlerTest::receiveSpacelessSelfClosingTag() { const QString testInputString = u"Test...
...ing"_s; diff --git a/src/libneochat/texthandler.cpp b/src/libneochat/texthandler.cpp index 65e930ecd..35384dda3 100644 --- a/src/libneochat/texthandler.cpp +++ b/src/libneochat/texthandler.cpp @@ -53,6 +53,7 @@ QString TextHandler::handleSendText() { m_pos = 0; m_dataBuffer = markdownToHTML(m_data); + m_dataBuffer = customMarkdownToHtml(m_dataBuffer); m_nextTokenType = nextTokenType(m_dataBuffer, m_pos, m_nextToken, m_nextTokenType); @@ -701,6 +702,31 @@ QString TextHandler::linkifyUrls(QString stringIn) return stringIn; } +QString TextHandler::customMarkdownToHtml(const QString &stringIn) +{ + QString buffer = stringIn; + + while (true) { + const int pos = buffer.indexOf(u"||"_s); + if (pos == -1) { + break; + } + + int nextPos = buffer.indexOf(u"||"_s, pos + 1); + if (nextPos == -1) { + break; + } + + buffer.replace(pos, 2, QStringLiteral("")); + + // we have to re-search because the index moved! + nextPos = buffer.indexOf(u"||"_s, pos + 1); + buffer.replace(nextPos, 2, QStringLiteral("")); + } + + return buffer; +} + QString TextHandler::editString() const { Kirigami::Platform::PlatformTheme *theme = diff --git a/src/libneochat/texthandler.h b/src/libneochat/texthandler.h index 9a240a6fa..ac356482d 100644 --- a/src/libneochat/texthandler.h +++ b/src/libneochat/texthandler.h @@ -140,6 +140,7 @@ private: QString escapeHtml(QString stringIn); QString unescapeHtml(QString stringIn); QString linkifyUrls(QString stringIn); + QString customMarkdownToHtml(const QString &stringIn); QString editString() const; QString emoteString(const NeoChatRoom *room = nullptr, const Quotient::RoomEvent *event = nullptr) const;