From 44bd3376cee24f4d4a689addeb94ba6f214dee86 Mon Sep 17 00:00:00 2001 From: LordMZTE Date: Fri, 26 Mar 2021 00:42:46 +0100 Subject: [PATCH 01/13] add /rainbow command --- src/Utils.cpp | 77 +++++++++++++++++++++++++++++++++++++-- src/Utils.h | 2 +- src/timeline/InputBar.cpp | 6 ++- src/timeline/InputBar.h | 4 +- 4 files changed, 82 insertions(+), 7 deletions(-) diff --git a/src/Utils.cpp b/src/Utils.cpp index 8a3b9e4c..36406361 100644 --- a/src/Utils.cpp +++ b/src/Utils.cpp @@ -18,6 +18,7 @@ #include #include +#include #include #include @@ -468,11 +469,81 @@ utils::escapeBlacklistedHtml(const QString &rawStr) } QString -utils::markdownToHtml(const QString &text) +utils::markdownToHtml(const QString &text, bool rainbowify) { - const auto str = text.toUtf8(); - const char *tmp_buf = cmark_markdown_to_html(str.constData(), str.size(), CMARK_OPT_UNSAFE); + const auto str = text.toUtf8(); + cmark_node *const node = + cmark_parse_document(str.constData(), str.size(), CMARK_OPT_UNSAFE); + if (rainbowify) { + // create iterator over node + cmark_iter *iter = cmark_iter_new(node); + + cmark_event_type ev_type; + + // First loop to get total text length + int textLen = 0; + while ((ev_type = cmark_iter_next(iter)) != CMARK_EVENT_DONE) { + cmark_node *cur = cmark_iter_get_node(iter); + // only text nodes (no code or semilar) + if (cmark_node_get_type(cur) != CMARK_NODE_TEXT) + continue; + // count up by length of current node's text + textLen += strlen(cmark_node_get_literal(cur)); + } + + // create new iter to start over + cmark_iter_free(iter); + iter = cmark_iter_new(node); + + // Second loop to rainbowify + int charIdx = 0; + while ((ev_type = cmark_iter_next(iter)) != CMARK_EVENT_DONE) { + cmark_node *cur = cmark_iter_get_node(iter); + // only text nodes (no code or semilar) + if (cmark_node_get_type(cur) != CMARK_NODE_TEXT) + continue; + + // get text in current node + const char *tmp_buf = cmark_node_get_literal(cur); + std::string nodeText(tmp_buf); + // create buffer to append rainbow text to + std::string buf; + for (int i = 0; i < nodeText.length(); i++) { + // Don't rainbowify spaces + if (nodeText.at(i) == ' ') { + buf.push_back(' '); + continue; + } + + // get correct color for char index + auto color = QColor::fromHsvF(1.0 / textLen * charIdx, 1.0, 1.0); + // format color for HTML + auto colorString = color.name(QColor::NameFormat::HexRgb); + // create HTML element for current char + auto curChar = fmt::format("{}", + colorString.toStdString(), + nodeText.at(i)); + // append colored HTML element to buffer + buf.append(curChar); + + charIdx++; + } + + // create HTML_INLINE node to prevent HTML from being escaped + auto htmlNode = cmark_node_new(CMARK_NODE_HTML_INLINE); + // set content of HTML node to buffer contents + cmark_node_set_literal(htmlNode, buf.c_str()); + // replace current node with HTML node + cmark_node_replace(cur, htmlNode); + // free memory of old node + cmark_node_free(cur); + } + + cmark_iter_free(iter); + } + + const char *tmp_buf = cmark_render_html(node, CMARK_OPT_UNSAFE); // Copy the null terminated output buffer. std::string html(tmp_buf); diff --git a/src/Utils.h b/src/Utils.h index f8ead68c..37c1baba 100644 --- a/src/Utils.h +++ b/src/Utils.h @@ -268,7 +268,7 @@ linkifyMessage(const QString &body); //! Convert the input markdown text to html. QString -markdownToHtml(const QString &text); +markdownToHtml(const QString &text, bool rainbowify = false); //! Escape every html tag, that was not whitelisted QString diff --git a/src/timeline/InputBar.cpp b/src/timeline/InputBar.cpp index 8a5e4346..2d76e7fb 100644 --- a/src/timeline/InputBar.cpp +++ b/src/timeline/InputBar.cpp @@ -255,7 +255,7 @@ InputBar::openFileSelection() } void -InputBar::message(QString msg, MarkdownOverride useMarkdown) +InputBar::message(QString msg, MarkdownOverride useMarkdown, bool rainbowify) { mtx::events::msg::Text text = {}; text.body = msg.trimmed().toStdString(); @@ -263,7 +263,7 @@ InputBar::message(QString msg, MarkdownOverride useMarkdown) if ((ChatPage::instance()->userSettings()->markdown() && useMarkdown == MarkdownOverride::NOT_SPECIFIED) || useMarkdown == MarkdownOverride::ON) { - text.formatted_body = utils::markdownToHtml(msg).toStdString(); + text.formatted_body = utils::markdownToHtml(msg, rainbowify).toStdString(); // Remove markdown links by completer text.body = msg.trimmed().replace(conf::strings::matrixToMarkdownLink, "\\1").toStdString(); @@ -524,6 +524,8 @@ InputBar::command(QString command, QString args) message(args, MarkdownOverride::ON); } else if (command == "plain") { message(args, MarkdownOverride::OFF); + } else if (command == "rainbow") { + message(args, MarkdownOverride::NOT_SPECIFIED, true); } } diff --git a/src/timeline/InputBar.h b/src/timeline/InputBar.h index acd9e22c..f7a60488 100644 --- a/src/timeline/InputBar.h +++ b/src/timeline/InputBar.h @@ -53,7 +53,9 @@ public slots: void updateState(int selectionStart, int selectionEnd, int cursorPosition, QString text); void openFileSelection(); bool uploading() const { return uploading_; } - void message(QString body, MarkdownOverride useMarkdown = MarkdownOverride::NOT_SPECIFIED); + void message(QString body, + MarkdownOverride useMarkdown = MarkdownOverride::NOT_SPECIFIED, + bool rainbowify = false); private slots: void startTyping(); From 947b8c0291911f945b695e457b74cc40d711156e Mon Sep 17 00:00:00 2001 From: LordMZTE Date: Sat, 27 Mar 2021 12:47:18 +0100 Subject: [PATCH 02/13] fix size type --- src/Utils.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Utils.cpp b/src/Utils.cpp index 36406361..c43d6cbe 100644 --- a/src/Utils.cpp +++ b/src/Utils.cpp @@ -17,6 +17,7 @@ #include #include +#include #include #include #include @@ -509,7 +510,7 @@ utils::markdownToHtml(const QString &text, bool rainbowify) std::string nodeText(tmp_buf); // create buffer to append rainbow text to std::string buf; - for (int i = 0; i < nodeText.length(); i++) { + for (std::size_t i = 0; i < nodeText.length(); i++) { // Don't rainbowify spaces if (nodeText.at(i) == ' ') { buf.push_back(' '); From a898abcecb1f35acb961e51798e5558920b15d09 Mon Sep 17 00:00:00 2001 From: LordMZTE Date: Sat, 27 Mar 2021 14:16:40 +0100 Subject: [PATCH 03/13] use qtextboundary finder to rainbowify. (not working for unicode chars yet) --- src/Utils.cpp | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/src/Utils.cpp b/src/Utils.cpp index c43d6cbe..1f0936f5 100644 --- a/src/Utils.cpp +++ b/src/Utils.cpp @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -27,6 +28,7 @@ #include "Cache.h" #include "Config.h" #include "EventAccessors.h" +#include "Logging.h" #include "MatrixClient.h" #include "UserSettingsPage.h" @@ -510,9 +512,15 @@ utils::markdownToHtml(const QString &text, bool rainbowify) std::string nodeText(tmp_buf); // create buffer to append rainbow text to std::string buf; - for (std::size_t i = 0; i < nodeText.length(); i++) { + int boundaryStart = 0; + int boundaryEnd = 0; + QTextBoundaryFinder tbf(QTextBoundaryFinder::BoundaryType::Grapheme, QString::fromStdString(nodeText)); + while ((boundaryEnd = tbf.toNextBoundary()) != -1) { + nhlog::ui()->info("from {} to {}", boundaryStart, boundaryEnd); + auto curChar = nodeText.substr(boundaryStart, boundaryEnd - boundaryEnd + 1); + boundaryStart = boundaryEnd; // Don't rainbowify spaces - if (nodeText.at(i) == ' ') { + if (curChar == " ") { buf.push_back(' '); continue; } @@ -522,11 +530,11 @@ utils::markdownToHtml(const QString &text, bool rainbowify) // format color for HTML auto colorString = color.name(QColor::NameFormat::HexRgb); // create HTML element for current char - auto curChar = fmt::format("{}", + auto curCharColored = fmt::format("{}", colorString.toStdString(), - nodeText.at(i)); + curChar); // append colored HTML element to buffer - buf.append(curChar); + buf.append(curCharColored); charIdx++; } From 939f00c90dfaf604a7a512024fd122835fab2927 Mon Sep 17 00:00:00 2001 From: LordMZTE Date: Sat, 27 Mar 2021 14:35:06 +0100 Subject: [PATCH 04/13] rainbow now works with unicode! --- src/Utils.cpp | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/src/Utils.cpp b/src/Utils.cpp index 1f0936f5..06df59df 100644 --- a/src/Utils.cpp +++ b/src/Utils.cpp @@ -492,7 +492,10 @@ utils::markdownToHtml(const QString &text, bool rainbowify) if (cmark_node_get_type(cur) != CMARK_NODE_TEXT) continue; // count up by length of current node's text - textLen += strlen(cmark_node_get_literal(cur)); + QTextBoundaryFinder tbf(QTextBoundaryFinder::BoundaryType::Grapheme, + QString(cmark_node_get_literal(cur))); + while (tbf.toNextBoundary() != -1) + textLen++; } // create new iter to start over @@ -510,14 +513,19 @@ utils::markdownToHtml(const QString &text, bool rainbowify) // get text in current node const char *tmp_buf = cmark_node_get_literal(cur); std::string nodeText(tmp_buf); + auto qNodeText = QString::fromStdString(nodeText); // create buffer to append rainbow text to std::string buf; int boundaryStart = 0; - int boundaryEnd = 0; - QTextBoundaryFinder tbf(QTextBoundaryFinder::BoundaryType::Grapheme, QString::fromStdString(nodeText)); + int boundaryEnd = 0; + // use QTextBoundaryFinder to iterate ofer graphemes + QTextBoundaryFinder tbf(QTextBoundaryFinder::BoundaryType::Grapheme, + qNodeText); while ((boundaryEnd = tbf.toNextBoundary()) != -1) { - nhlog::ui()->info("from {} to {}", boundaryStart, boundaryEnd); - auto curChar = nodeText.substr(boundaryStart, boundaryEnd - boundaryEnd + 1); + // Split text to get current char + auto curChar = + qNodeText.mid(boundaryStart, boundaryEnd - boundaryStart) + .toStdString(); boundaryStart = boundaryEnd; // Don't rainbowify spaces if (curChar == " ") { @@ -531,8 +539,8 @@ utils::markdownToHtml(const QString &text, bool rainbowify) auto colorString = color.name(QColor::NameFormat::HexRgb); // create HTML element for current char auto curCharColored = fmt::format("{}", - colorString.toStdString(), - curChar); + colorString.toStdString(), + curChar); // append colored HTML element to buffer buf.append(curCharColored); From 39ff68c6e64a711cec32329d2678dab7a4772ac9 Mon Sep 17 00:00:00 2001 From: LordMZTE Date: Sat, 27 Mar 2021 16:06:42 +0100 Subject: [PATCH 05/13] use QString to format in rainbow function --- src/Utils.cpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/Utils.cpp b/src/Utils.cpp index 06df59df..5ae1776f 100644 --- a/src/Utils.cpp +++ b/src/Utils.cpp @@ -19,7 +19,6 @@ #include #include -#include #include #include @@ -524,8 +523,7 @@ utils::markdownToHtml(const QString &text, bool rainbowify) while ((boundaryEnd = tbf.toNextBoundary()) != -1) { // Split text to get current char auto curChar = - qNodeText.mid(boundaryStart, boundaryEnd - boundaryStart) - .toStdString(); + qNodeText.mid(boundaryStart, boundaryEnd - boundaryStart); boundaryStart = boundaryEnd; // Don't rainbowify spaces if (curChar == " ") { @@ -538,9 +536,10 @@ utils::markdownToHtml(const QString &text, bool rainbowify) // format color for HTML auto colorString = color.name(QColor::NameFormat::HexRgb); // create HTML element for current char - auto curCharColored = fmt::format("{}", - colorString.toStdString(), - curChar); + auto curCharColored = QString("%1") + .arg(colorString) + .arg(curChar) + .toStdString(); // append colored HTML element to buffer buf.append(curCharColored); From 64e29b07e2cb2887fe2037ece4c01afaa7ed6837 Mon Sep 17 00:00:00 2001 From: LordMZTE Date: Sat, 27 Mar 2021 17:04:00 +0100 Subject: [PATCH 06/13] remove incorrect include --- src/Utils.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Utils.cpp b/src/Utils.cpp index 5ae1776f..4be3c480 100644 --- a/src/Utils.cpp +++ b/src/Utils.cpp @@ -17,7 +17,6 @@ #include #include -#include #include #include #include From 4e6150f28e4b2fccc07e48b02ef957f4cee95297 Mon Sep 17 00:00:00 2001 From: LordMZTE Date: Sun, 28 Mar 2021 14:00:35 +0200 Subject: [PATCH 07/13] implement requested changes --- src/Utils.cpp | 17 +++++++---------- src/timeline/InputBar.cpp | 2 +- 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/src/Utils.cpp b/src/Utils.cpp index 4be3c480..05e1a584 100644 --- a/src/Utils.cpp +++ b/src/Utils.cpp @@ -18,7 +18,7 @@ #include #include -#include +#include #include #include @@ -26,7 +26,6 @@ #include "Cache.h" #include "Config.h" #include "EventAccessors.h" -#include "Logging.h" #include "MatrixClient.h" #include "UserSettingsPage.h" @@ -509,24 +508,22 @@ utils::markdownToHtml(const QString &text, bool rainbowify) continue; // get text in current node - const char *tmp_buf = cmark_node_get_literal(cur); - std::string nodeText(tmp_buf); - auto qNodeText = QString::fromStdString(nodeText); + QString nodeText(cmark_node_get_literal(cur)); // create buffer to append rainbow text to std::string buf; int boundaryStart = 0; int boundaryEnd = 0; // use QTextBoundaryFinder to iterate ofer graphemes QTextBoundaryFinder tbf(QTextBoundaryFinder::BoundaryType::Grapheme, - qNodeText); + nodeText); while ((boundaryEnd = tbf.toNextBoundary()) != -1) { // Split text to get current char auto curChar = - qNodeText.mid(boundaryStart, boundaryEnd - boundaryStart); + nodeText.midRef(boundaryStart, boundaryEnd - boundaryStart); boundaryStart = boundaryEnd; - // Don't rainbowify spaces - if (curChar == " ") { - buf.push_back(' '); + // Don't rainbowify whitespaces + if (curChar.trimmed().isEmpty()) { + buf.append(curChar.toString().toStdString()); continue; } diff --git a/src/timeline/InputBar.cpp b/src/timeline/InputBar.cpp index 2d76e7fb..69d129ce 100644 --- a/src/timeline/InputBar.cpp +++ b/src/timeline/InputBar.cpp @@ -525,7 +525,7 @@ InputBar::command(QString command, QString args) } else if (command == "plain") { message(args, MarkdownOverride::OFF); } else if (command == "rainbow") { - message(args, MarkdownOverride::NOT_SPECIFIED, true); + message(args, MarkdownOverride::ON, true); } } From e7f20eeae0813278eb50b22c1025aba84fb6fd52 Mon Sep 17 00:00:00 2001 From: LordMZTE Date: Sun, 28 Mar 2021 14:14:05 +0200 Subject: [PATCH 08/13] use QString as buf in rainbowifyer --- src/Utils.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/Utils.cpp b/src/Utils.cpp index 05e1a584..60b11e55 100644 --- a/src/Utils.cpp +++ b/src/Utils.cpp @@ -510,7 +510,7 @@ utils::markdownToHtml(const QString &text, bool rainbowify) // get text in current node QString nodeText(cmark_node_get_literal(cur)); // create buffer to append rainbow text to - std::string buf; + QString buf; int boundaryStart = 0; int boundaryEnd = 0; // use QTextBoundaryFinder to iterate ofer graphemes @@ -523,7 +523,7 @@ utils::markdownToHtml(const QString &text, bool rainbowify) boundaryStart = boundaryEnd; // Don't rainbowify whitespaces if (curChar.trimmed().isEmpty()) { - buf.append(curChar.toString().toStdString()); + buf.append(curChar.toString()); continue; } @@ -534,8 +534,7 @@ utils::markdownToHtml(const QString &text, bool rainbowify) // create HTML element for current char auto curCharColored = QString("%1") .arg(colorString) - .arg(curChar) - .toStdString(); + .arg(curChar); // append colored HTML element to buffer buf.append(curCharColored); @@ -545,7 +544,7 @@ utils::markdownToHtml(const QString &text, bool rainbowify) // create HTML_INLINE node to prevent HTML from being escaped auto htmlNode = cmark_node_new(CMARK_NODE_HTML_INLINE); // set content of HTML node to buffer contents - cmark_node_set_literal(htmlNode, buf.c_str()); + cmark_node_set_literal(htmlNode, buf.toUtf8().data()); // replace current node with HTML node cmark_node_replace(cur, htmlNode); // free memory of old node From ff2e7bb98934cc97047aad8e0fa28856a67df4eb Mon Sep 17 00:00:00 2001 From: LordMZTE Date: Sun, 28 Mar 2021 14:49:34 +0200 Subject: [PATCH 09/13] commands now also work with newline after them --- src/timeline/InputBar.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/timeline/InputBar.cpp b/src/timeline/InputBar.cpp index 69d129ce..2e311169 100644 --- a/src/timeline/InputBar.cpp +++ b/src/timeline/InputBar.cpp @@ -204,6 +204,8 @@ InputBar::send() if (text().startsWith('/')) { int command_end = text().indexOf(' '); + if (command_end == -1) + command_end = text().indexOf('\n'); if (command_end == -1) command_end = text().size(); auto name = text().mid(1, command_end - 1); From 6c31bb6ddc88b5eccf2c24b47044da485231d002 Mon Sep 17 00:00:00 2001 From: LordMZTE Date: Sun, 28 Mar 2021 15:36:46 +0200 Subject: [PATCH 10/13] fix command parsing --- src/timeline/InputBar.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/timeline/InputBar.cpp b/src/timeline/InputBar.cpp index 2e311169..d7db50a9 100644 --- a/src/timeline/InputBar.cpp +++ b/src/timeline/InputBar.cpp @@ -15,6 +15,7 @@ #include #include +#include #include "Cache.h" #include "ChatPage.h" @@ -203,9 +204,7 @@ InputBar::send() auto wasEdit = !room->edit().isEmpty(); if (text().startsWith('/')) { - int command_end = text().indexOf(' '); - if (command_end == -1) - command_end = text().indexOf('\n'); + int command_end = text().indexOf(QRegExp("\\s+")); if (command_end == -1) command_end = text().size(); auto name = text().mid(1, command_end - 1); From 463dd206826d9fbe33b3ac10fadb438028a9eed9 Mon Sep 17 00:00:00 2001 From: "DeepBlueV7.X" Date: Sun, 28 Mar 2021 13:59:47 +0000 Subject: [PATCH 11/13] Use QRegularExpression --- src/timeline/InputBar.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/timeline/InputBar.cpp b/src/timeline/InputBar.cpp index d7db50a9..0b498e82 100644 --- a/src/timeline/InputBar.cpp +++ b/src/timeline/InputBar.cpp @@ -204,7 +204,7 @@ InputBar::send() auto wasEdit = !room->edit().isEmpty(); if (text().startsWith('/')) { - int command_end = text().indexOf(QRegExp("\\s+")); + int command_end = text().indexOf(QRegularExpression("\\s")); if (command_end == -1) command_end = text().size(); auto name = text().mid(1, command_end - 1); From 3317d4582da791498e1fdd9a518052fbff243f92 Mon Sep 17 00:00:00 2001 From: "DeepBlueV7.X" Date: Sun, 28 Mar 2021 14:00:13 +0000 Subject: [PATCH 12/13] Update src/timeline/InputBar.cpp --- src/timeline/InputBar.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/timeline/InputBar.cpp b/src/timeline/InputBar.cpp index 0b498e82..a2c26b13 100644 --- a/src/timeline/InputBar.cpp +++ b/src/timeline/InputBar.cpp @@ -15,7 +15,7 @@ #include #include -#include +#include #include "Cache.h" #include "ChatPage.h" From 4b45c61024342834c4f91433ce7b17e73d60d33b Mon Sep 17 00:00:00 2001 From: LordMZTE Date: Sun, 28 Mar 2021 17:37:36 +0200 Subject: [PATCH 13/13] run formatter --- src/Utils.cpp | 2 +- src/timeline/InputBar.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Utils.cpp b/src/Utils.cpp index 60b11e55..32d435f0 100644 --- a/src/Utils.cpp +++ b/src/Utils.cpp @@ -17,8 +17,8 @@ #include #include -#include #include +#include #include #include diff --git a/src/timeline/InputBar.cpp b/src/timeline/InputBar.cpp index a2c26b13..4a27b4bc 100644 --- a/src/timeline/InputBar.cpp +++ b/src/timeline/InputBar.cpp @@ -13,9 +13,9 @@ #include #include +#include #include #include -#include #include "Cache.h" #include "ChatPage.h"