Allow striking through text with ~~
Similar to spoilers, some Markdown flavors like GitHub's or Discord's allow you to strike through text with ~~. Normally, the only way to do this on most Matrix clients (including Element) is surrounding text with <del> tags. As expected, no one knows how to do this. So now NeoChat supports the ~~ syntax. We can reuse the existing spoiler parser for this after making it generic. I have added new test cases for this syntax. This does not affect the quick format bar yet.
This commit is contained in:
@@ -43,8 +43,8 @@ private Q_SLOTS:
|
|||||||
void sendCustomEmoji();
|
void sendCustomEmoji();
|
||||||
void sendCustomEmojiCode_data();
|
void sendCustomEmojiCode_data();
|
||||||
void sendCustomEmojiCode();
|
void sendCustomEmojiCode();
|
||||||
void sendSpoilerTags_data();
|
void sendCustomTags_data();
|
||||||
void sendSpoilerTags();
|
void sendCustomTags();
|
||||||
|
|
||||||
void receiveSpacelessSelfClosingTag();
|
void receiveSpacelessSelfClosingTag();
|
||||||
void receiveStripReply();
|
void receiveStripReply();
|
||||||
@@ -251,20 +251,28 @@ void TextHandlerTest::sendCustomEmojiCode()
|
|||||||
QCOMPARE(testTextHandler.handleSendText(), testOutputString);
|
QCOMPARE(testTextHandler.handleSendText(), testOutputString);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TextHandlerTest::sendSpoilerTags_data()
|
void TextHandlerTest::sendCustomTags_data()
|
||||||
{
|
{
|
||||||
QTest::addColumn<QString>("testInputString");
|
QTest::addColumn<QString>("testInputString");
|
||||||
QTest::addColumn<QString>("testOutputString");
|
QTest::addColumn<QString>("testOutputString");
|
||||||
|
|
||||||
QTest::newRow("incomplete") << u"||test"_s << u"||test"_s;
|
// spoiler
|
||||||
QTest::newRow("complete") << u"||test||"_s << u"<span data-mx-spoiler>test</span>"_s;
|
QTest::newRow("incomplete spoiler") << u"||test"_s << u"||test"_s;
|
||||||
QTest::newRow("multiple") << u"||apple||banana||pear||"_s << u"<span data-mx-spoiler>apple</span>banana<span data-mx-spoiler>pear</span>"_s;
|
QTest::newRow("complete spoiler") << u"||test||"_s << u"<span data-mx-spoiler>test</span>"_s;
|
||||||
QTest::newRow("inside code block") << u"```||apple||```"_s << u"<code>||apple||</code>"_s;
|
QTest::newRow("multiple spoiler") << u"||apple||banana||pear||"_s << u"<span data-mx-spoiler>apple</span>banana<span data-mx-spoiler>pear</span>"_s;
|
||||||
QTest::newRow("outside code block") << u"||apple|| ```||banana||``` ||pear||"_s
|
QTest::newRow("inside code block spoiler") << u"```||apple||```"_s << u"<code>||apple||</code>"_s;
|
||||||
<< u"<span data-mx-spoiler>apple</span> <code>||banana||</code> <span data-mx-spoiler>pear</span>"_s;
|
QTest::newRow("outside code block spoiler") << u"||apple|| ```||banana||``` ||pear||"_s
|
||||||
|
<< u"<span data-mx-spoiler>apple</span> <code>||banana||</code> <span data-mx-spoiler>pear</span>"_s;
|
||||||
|
|
||||||
|
// strikethrough
|
||||||
|
QTest::newRow("incomplete strikethrough") << u"~~test"_s << u"~~test"_s;
|
||||||
|
QTest::newRow("complete strikethrough") << u"~~test~~"_s << u"<del>test</del>"_s;
|
||||||
|
QTest::newRow("inside code block strikethrough") << u"```~~apple~~```"_s << u"<code>~~apple~~</code>"_s;
|
||||||
|
QTest::newRow("outside code block strikethrough") << u"~~apple~~ ```~~banana~~``` ~~pear~~"_s
|
||||||
|
<< u"<del>apple</del> <code>~~banana~~</code> <del>pear</del>"_s;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TextHandlerTest::sendSpoilerTags()
|
void TextHandlerTest::sendCustomTags()
|
||||||
{
|
{
|
||||||
QFETCH(QString, testInputString);
|
QFETCH(QString, testInputString);
|
||||||
QFETCH(QString, testOutputString);
|
QFETCH(QString, testOutputString);
|
||||||
|
|||||||
@@ -706,45 +706,53 @@ QString TextHandler::customMarkdownToHtml(const QString &stringIn)
|
|||||||
{
|
{
|
||||||
QString buffer = stringIn;
|
QString buffer = stringIn;
|
||||||
|
|
||||||
qsizetype beginCodeBlockTag = buffer.indexOf(u"<code>"_s);
|
const auto processSyntax = [&buffer](const QString &syntax, const QString &beginTag, const QString &endTag) {
|
||||||
qsizetype endCodeBlockTag = buffer.indexOf(u"</code>"_s, beginCodeBlockTag + 1);
|
qsizetype beginCodeBlockTag = buffer.indexOf(u"<code>"_s);
|
||||||
|
qsizetype endCodeBlockTag = buffer.indexOf(u"</code>"_s, beginCodeBlockTag + 1);
|
||||||
|
|
||||||
// Indesx to search from
|
// Index to search from
|
||||||
qsizetype lastPos = 0;
|
qsizetype lastPos = 0;
|
||||||
while (true) {
|
while (true) {
|
||||||
const qsizetype pos = buffer.indexOf(u"||"_s, lastPos);
|
const qsizetype pos = buffer.indexOf(syntax, lastPos);
|
||||||
if (pos == -1) {
|
if (pos == -1) {
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we're inside a code block, ignore and move the search past the code block
|
||||||
|
const bool validCodeBlock = beginCodeBlockTag != -1 && endCodeBlockTag != -1;
|
||||||
|
if (validCodeBlock && pos > beginCodeBlockTag && pos < endCodeBlockTag) {
|
||||||
|
lastPos = endCodeBlockTag + 5;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
qsizetype nextPos = buffer.indexOf(syntax, pos + 1);
|
||||||
|
if (nextPos == -1) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Replace the beginning syntax
|
||||||
|
buffer.replace(pos, 2, beginTag);
|
||||||
|
|
||||||
|
// Update positions and re-search since the underlying text buffer changed
|
||||||
|
nextPos = buffer.indexOf(syntax, pos + 1);
|
||||||
|
beginCodeBlockTag = buffer.indexOf(u"<code>"_s, pos + 1);
|
||||||
|
endCodeBlockTag = buffer.indexOf(u"</code>"_s, beginCodeBlockTag + 1);
|
||||||
|
|
||||||
|
// Now replace the end syntax
|
||||||
|
buffer.replace(nextPos, 2, endTag);
|
||||||
|
|
||||||
|
// Move the search pointer past this point.
|
||||||
|
// Not technically needed in most cases since we replaced the original tag, but needed for code blocks
|
||||||
|
// which still have the characters.
|
||||||
|
lastPos = nextPos + 2;
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// If we're inside of a code block, ignore and move the search past the code block
|
// spoilers
|
||||||
const bool validCodeBlock = beginCodeBlockTag != -1 && endCodeBlockTag != -1;
|
processSyntax(u"||"_s, u"<span data-mx-spoiler>"_s, u"</span>"_s);
|
||||||
if (validCodeBlock && pos > beginCodeBlockTag && pos < endCodeBlockTag) {
|
|
||||||
lastPos = endCodeBlockTag + 5;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
qsizetype nextPos = buffer.indexOf(u"||"_s, pos + 1);
|
// strikethrough
|
||||||
if (nextPos == -1) {
|
processSyntax(u"~~"_s, u"<del>"_s, u"</del>"_s);
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Replace the begin ||
|
|
||||||
buffer.replace(pos, 2, QStringLiteral("<span data-mx-spoiler>"));
|
|
||||||
|
|
||||||
// Update positions and re-search since the underlying text buffer changed
|
|
||||||
nextPos = buffer.indexOf(u"||"_s, pos + 1);
|
|
||||||
beginCodeBlockTag = buffer.indexOf(u"<code>"_s, pos + 1);
|
|
||||||
endCodeBlockTag = buffer.indexOf(u"</code>"_s, beginCodeBlockTag + 1);
|
|
||||||
|
|
||||||
// Now replace the end ||
|
|
||||||
buffer.replace(nextPos, 2, QStringLiteral("</span>"));
|
|
||||||
|
|
||||||
// Move the search pointer past this point.
|
|
||||||
// Not technically needed in most cases since we replaced the original tag, but needed for code blocks
|
|
||||||
// which still have the characters.
|
|
||||||
lastPos = nextPos + 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user