From e9209b06f9d8b762c674496ffe4481204759af2b Mon Sep 17 00:00:00 2001 From: noavarice Date: Fri, 7 Jul 2017 22:21:50 +0300 Subject: [PATCH] refactor: independent URL highlighting Brief list of changes: - removed workarounds while applying markdown; - URL highlighting now is independent for markdown support; - URL patterns reverted to the state they were before. --- src/chatlog/chatmessage.cpp | 1 + src/chatlog/textformatter.cpp | 85 +++++++++++++---------------------- src/chatlog/textformatter.h | 2 + 3 files changed, 34 insertions(+), 54 deletions(-) diff --git a/src/chatlog/chatmessage.cpp b/src/chatlog/chatmessage.cpp index 75e8196c7..a8dc796cd 100644 --- a/src/chatlog/chatmessage.cpp +++ b/src/chatlog/chatmessage.cpp @@ -56,6 +56,7 @@ ChatMessage::Ptr ChatMessage::createChatMessage(const QString& sender, const QSt // quotes (green text) text = detectQuotes(text, type); + text = highlightURL(text); // text styling Settings::StyleType styleType = Settings::getInstance().getStylePreference(); diff --git a/src/chatlog/textformatter.cpp b/src/chatlog/textformatter.cpp index e0cbcf721..b94c41b50 100644 --- a/src/chatlog/textformatter.cpp +++ b/src/chatlog/textformatter.cpp @@ -36,8 +36,6 @@ enum TextStyle HREF }; -static const QString HTML_CHARACTER_CODE = QStringLiteral("&#%1"); - // clang-format off static const QVector MARKDOWN_SYMBOLS { '*', @@ -70,7 +68,7 @@ static const QVector htmlPatterns{QStringLiteral("%1"), QStringLiteral("%1"), QStringLiteral( "%1"), - QStringLiteral("%2")}; + QStringLiteral("%1")}; #define STRING_FROM_TYPE(type) QString(MARKDOWN_SYMBOLS[type]) @@ -89,15 +87,38 @@ static const QVector> textPatternStyle{ REGEX_MARKDOWN_PAIR(STRIKE, 2), {QRegularExpression(MULTILINE_CODE), htmlPatterns[CODE]}}; -static const QVector urlPatterns { - QRegularExpression("((\\bhttp[s]?://(www\\.)?)|(\\bwww\\.))" - "[^. \\n]+\\.[^ \\n]+"), - QRegularExpression("\\b(ftp|smb)://[^ \\n]+"), - QRegularExpression("\\bfile://(localhost)?/[^ \\n]+"), - QRegularExpression("\\btox:[a-zA-Z\\d]{76}"), - QRegularExpression("\\b(mailto|tox):[^ \\n]+@[^ \\n]+") +static const QRegularExpression URL_PATTERNS[] = { + QRegularExpression("\\b(www\\.|((http[s]?)|ftp)://)\\w+\\S+"), + QRegularExpression("\\b(file|smb)://([\\S| ]*)"), + QRegularExpression("\\btox:[a-zA-Z\\d]{76}"), + QRegularExpression("\\bmailto:\\S+@\\S+\\.\\S+"), + QRegularExpression("\\btox:\\S+@\\S+") }; +/** + * @brief Highlights URLs within passed message string + * @param message Where search for URLs + * @return Copy of message with highlighted URLs + */ +QString highlightURL(const QString& message) +{ + QString result = message; + for (QRegularExpression exp : URL_PATTERNS) { + int startLength = result.length(); + int offset = 0; + QRegularExpressionMatchIterator iter = exp.globalMatch(result); + while (iter.hasNext()) { + QRegularExpressionMatch match = iter.next(); + int startPos = match.capturedStart() + offset; + int length = match.capturedLength(); + QString wrappedURL = htmlPatterns[TextStyle::HREF].arg(match.captured()); + result.replace(startPos, length, wrappedURL); + offset = result.length() - startLength; + } + } + return result; +} + // clang-format on /** * @class TextFormatter @@ -145,28 +166,6 @@ static bool isTagIntersection(const QString& str) return openingTagCount != closingTagCount; } -/** - * @brief Applies a function for URL's which can be extracted from passed string - * @param str String in which we are looking for URL's - * @param func Function which is applied to URL - */ -static void processUrl(QString& str, std::function func) -{ - int startLength = str.length(); - int offset = 0; - for (QRegularExpression exp : urlPatterns) { - QRegularExpressionMatchIterator iter = exp.globalMatch(str); - while (iter.hasNext()) { - QRegularExpressionMatch match = iter.next(); - int startPos = match.capturedStart() + offset; - int length = match.capturedLength(); - QString url = str.mid(startPos, length); - str.replace(startPos, length, func(url)); - offset = str.length() - startLength; - } - } -} - /** * @brief Applies styles to the font of text that was passed to the constructor * @param showFormattingSymbols True, if it is supposed to include formatting symbols into resulting @@ -174,13 +173,6 @@ static void processUrl(QString& str, std::function func) */ void TextFormatter::applyHtmlFontStyling(bool showFormattingSymbols) { - processUrl(message, [](QString& str) { - for (char c : MARKDOWN_SYMBOLS) { - QString charCode = QString::number(static_cast(c)); - str.replace(c, HTML_CHARACTER_CODE.arg(charCode)); - } - return str; - }); for (QPair pair : textPatternStyle) { QRegularExpressionMatchIterator matchesIterator = pair.first.globalMatch(message); int insertedTagSymbolsCount = 0; @@ -206,20 +198,6 @@ void TextFormatter::applyHtmlFontStyling(bool showFormattingSymbols) insertedTagSymbolsCount += pair.second.length() - 2 - 2 * choppingSignsCount; } } - for (char c : MARKDOWN_SYMBOLS) { - QString charCode = QString::number(static_cast(c)); - message.replace(HTML_CHARACTER_CODE.arg(charCode), QString(c)); - } -} - -/** - * @brief Wraps all found URL's in HTML hyperlink tag - */ -void TextFormatter::wrapUrl() -{ - processUrl(message, [](QString& str) { - return htmlPatterns[TextStyle::HREF].arg(str.startsWith("www") ? "http://" : "", str); - }); } /** @@ -231,6 +209,5 @@ void TextFormatter::wrapUrl() QString TextFormatter::applyStyling(bool showFormattingSymbols) { applyHtmlFontStyling(showFormattingSymbols); - wrapUrl(); return message; } diff --git a/src/chatlog/textformatter.h b/src/chatlog/textformatter.h index a10d0ff4d..646b5cabe 100644 --- a/src/chatlog/textformatter.h +++ b/src/chatlog/textformatter.h @@ -22,6 +22,8 @@ #include +QString highlightURL(const QString& message); + class TextFormatter { private: