From a4818bd32797a8c1ae351cab6b12a8c92a8e8c3d Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Tue, 1 Aug 2023 13:39:25 +0200 Subject: [PATCH] initial WIP js highlighter for article filters dialog --- src/librssguard/CMakeLists.txt | 2 + .../gui/dialogs/formmessagefiltersmanager.cpp | 3 + .../gui/dialogs/formmessagefiltersmanager.h | 2 + .../gui/reusable/jssyntaxhighlighter.cpp | 94 +++++++++++++++++++ .../gui/reusable/jssyntaxhighlighter.h | 38 ++++++++ 5 files changed, 139 insertions(+) create mode 100755 src/librssguard/gui/reusable/jssyntaxhighlighter.cpp create mode 100755 src/librssguard/gui/reusable/jssyntaxhighlighter.h diff --git a/src/librssguard/CMakeLists.txt b/src/librssguard/CMakeLists.txt index c2dc72eae..edf190f79 100644 --- a/src/librssguard/CMakeLists.txt +++ b/src/librssguard/CMakeLists.txt @@ -109,6 +109,8 @@ set(SOURCES gui/reusable/edittableview.h gui/reusable/helpspoiler.cpp gui/reusable/helpspoiler.h + gui/reusable/jssyntaxhighlighter.cpp + gui/reusable/jssyntaxhighlighter.h gui/reusable/labelsmenu.cpp gui/reusable/labelsmenu.h gui/reusable/labelwithstatus.cpp diff --git a/src/librssguard/gui/dialogs/formmessagefiltersmanager.cpp b/src/librssguard/gui/dialogs/formmessagefiltersmanager.cpp index 3d83f4f8b..f5a86f3d1 100644 --- a/src/librssguard/gui/dialogs/formmessagefiltersmanager.cpp +++ b/src/librssguard/gui/dialogs/formmessagefiltersmanager.cpp @@ -13,6 +13,7 @@ #include "exceptions/filteringexception.h" #include "gui/guiutilities.h" #include "gui/messagebox.h" +#include "gui/reusable/jssyntaxhighlighter.h" #include "miscellaneous/application.h" #include "miscellaneous/feedreader.h" #include "miscellaneous/iconfactory.h" @@ -28,6 +29,8 @@ FormMessageFiltersManager::FormMessageFiltersManager(FeedReader* reader, m_reader(reader), m_loadingFilter(false), m_msgModel(new MessagesForFiltersModel(this)) { m_ui.setupUi(this); + m_highlighter = new JsSyntaxHighlighter(m_ui.m_txtScript->document()); + std::sort(m_accounts.begin(), m_accounts.end(), [](const ServiceRoot* lhs, const ServiceRoot* rhs) { return lhs->title().compare(rhs->title(), Qt::CaseSensitivity::CaseInsensitive) < 0; }); diff --git a/src/librssguard/gui/dialogs/formmessagefiltersmanager.h b/src/librssguard/gui/dialogs/formmessagefiltersmanager.h index 235521b49..978cf5b41 100644 --- a/src/librssguard/gui/dialogs/formmessagefiltersmanager.h +++ b/src/librssguard/gui/dialogs/formmessagefiltersmanager.h @@ -13,6 +13,7 @@ class AccountCheckSortedModel; class MessageFilter; class FeedReader; class MessagesForFiltersModel; +class JsSyntaxHighlighter; class FormMessageFiltersManager : public QDialog { Q_OBJECT @@ -72,6 +73,7 @@ class FormMessageFiltersManager : public QDialog { FeedReader* m_reader; bool m_loadingFilter; MessagesForFiltersModel* m_msgModel; + JsSyntaxHighlighter* m_highlighter; }; #endif // FORMMESSAGEFILTERSMANAGER_H diff --git a/src/librssguard/gui/reusable/jssyntaxhighlighter.cpp b/src/librssguard/gui/reusable/jssyntaxhighlighter.cpp new file mode 100755 index 000000000..d7a352b84 --- /dev/null +++ b/src/librssguard/gui/reusable/jssyntaxhighlighter.cpp @@ -0,0 +1,94 @@ +// For license of this file, see /LICENSE.md. + +#include "gui/reusable/jssyntaxhighlighter.h" + +#include "definitions/definitions.h" + +JsSyntaxHighlighter::JsSyntaxHighlighter(QTextDocument* parent) : QSyntaxHighlighter(parent) { + HighlightingRule rule; + + keywordFormat.setForeground(Qt::GlobalColor::magenta); + keywordFormat.setFontWeight(QFont::Weight::Bold); + + const QString keywordPatterns[] = { + QSL("\\babstract\\b"), QSL("\\barguments\\b"), QSL("\\bawait\\*\\b"), QSL("\\bboolean\\b"), + QSL("\\bbreak\\b"), QSL("\\bbyte\\b"), QSL("\\bcase\\b"), QSL("\\bcatch\\b"), + QSL("\\bchar\\b"), QSL("\\bclass\\*\\b"), QSL("\\bconst\\b"), QSL("\\bcontinue\\b"), + QSL("\\bdebugger\\b"), QSL("\\bdefault\\b"), QSL("\\bdelete\\b"), QSL("\\bdo\\b"), + QSL("\\bdouble\\b"), QSL("\\belse\\b"), QSL("\\benum\\*\\b"), QSL("\\beval\\b"), + QSL("\\bexport\\*\\b"), QSL("\\bextends\\*\\b"), QSL("\\bfalse\\b"), QSL("\\bfinal\\b"), + QSL("\\bfinally\\b"), QSL("\\bfloat\\b"), QSL("\\bfor\\b"), QSL("\\bfunction\\b"), + QSL("\\bgoto\\b"), QSL("\\bif\\b"), QSL("\\bimplements\\b"), QSL("\\bimport\\*\\b"), + QSL("\\bin\\b"), QSL("\\binstanceof\\b"), QSL("\\bint\\b"), QSL("\\binterface\\b"), + QSL("\\blet\\*\\b"), QSL("\\blong\\b"), QSL("\\bnative\\b"), QSL("\\bnew\\b"), + QSL("\\bnull\\b"), QSL("\\bpackage\\b"), QSL("\\bprivate\\b"), QSL("\\bprotected\\b"), + QSL("\\bpublic\\b"), QSL("\\breturn\\b"), QSL("\\bshort\\b"), QSL("\\bstatic\\b"), + QSL("\\bsuper\\*\\b"), QSL("\\bswitch\\b"), QSL("\\bsynchronized\\b"), QSL("\\bthis\\b"), + QSL("\\bthrow\\b"), QSL("\\bthrows\\b"), QSL("\\btransient\\b"), QSL("\\btrue\\b"), + QSL("\\btry\\b"), QSL("\\btypeof\\b"), QSL("\\bvar\\b"), QSL("\\bvoid\\b"), + QSL("\\bvolatile\\b"), QSL("\\bwhile\\b"), QSL("\\bwith\\b"), QSL("\\byield\\b")}; + + for (const QString& pattern : keywordPatterns) { + rule.pattern = QRegularExpression(pattern); + rule.format = keywordFormat; + highlightingRules.append(rule); + } + + classFormat.setFontWeight(QFont::Bold); + classFormat.setForeground(Qt::darkMagenta); + rule.pattern = QRegularExpression(QStringLiteral("\\bQ[A-Za-z]+\\b")); + rule.format = classFormat; + highlightingRules.append(rule); + + singleLineCommentFormat.setForeground(Qt::red); + rule.pattern = QRegularExpression(QStringLiteral("//[^\n]*")); + rule.format = singleLineCommentFormat; + highlightingRules.append(rule); + + multiLineCommentFormat.setForeground(Qt::red); + + quotationFormat.setForeground(Qt::darkGreen); + rule.pattern = QRegularExpression(QStringLiteral("\".*\"")); + rule.format = quotationFormat; + highlightingRules.append(rule); + + functionFormat.setFontItalic(true); + functionFormat.setForeground(Qt::GlobalColor::green); + rule.pattern = QRegularExpression(QStringLiteral("\\b[A-Za-z0-9_]+(?=\\()")); + rule.format = functionFormat; + highlightingRules.append(rule); + + commentStartExpression = QRegularExpression(QStringLiteral("/\\*")); + commentEndExpression = QRegularExpression(QStringLiteral("\\*/")); +} + +void JsSyntaxHighlighter::highlightBlock(const QString& text) { + for (const HighlightingRule& rule : std::as_const(highlightingRules)) { + QRegularExpressionMatchIterator matchIterator = rule.pattern.globalMatch(text); + while (matchIterator.hasNext()) { + QRegularExpressionMatch match = matchIterator.next(); + setFormat(match.capturedStart(), match.capturedLength(), rule.format); + } + } + + setCurrentBlockState(0); + + int startIndex = 0; + if (previousBlockState() != 1) + startIndex = text.indexOf(commentStartExpression); + + while (startIndex >= 0) { + QRegularExpressionMatch match = commentEndExpression.match(text, startIndex); + int endIndex = match.capturedStart(); + int commentLength = 0; + if (endIndex == -1) { + setCurrentBlockState(1); + commentLength = text.length() - startIndex; + } + else { + commentLength = endIndex - startIndex + match.capturedLength(); + } + setFormat(startIndex, commentLength, multiLineCommentFormat); + startIndex = text.indexOf(commentStartExpression, startIndex + commentLength); + } +} diff --git a/src/librssguard/gui/reusable/jssyntaxhighlighter.h b/src/librssguard/gui/reusable/jssyntaxhighlighter.h new file mode 100755 index 000000000..5b7507b8f --- /dev/null +++ b/src/librssguard/gui/reusable/jssyntaxhighlighter.h @@ -0,0 +1,38 @@ +// For license of this file, see /LICENSE.md. + +#ifndef JSSYNTAXHIGHLIGHTER_H +#define JSSYNTAXHIGHLIGHTER_H + +#include + +#include + +class JsSyntaxHighlighter : public QSyntaxHighlighter { + Q_OBJECT + + public: + JsSyntaxHighlighter(QTextDocument *parent); + + protected: + virtual void highlightBlock(const QString& text) override; + + private: + struct HighlightingRule { + QRegularExpression pattern; + QTextCharFormat format; + }; + + QList highlightingRules; + + QRegularExpression commentStartExpression; + QRegularExpression commentEndExpression; + + QTextCharFormat keywordFormat; + QTextCharFormat classFormat; + QTextCharFormat singleLineCommentFormat; + QTextCharFormat multiLineCommentFormat; + QTextCharFormat quotationFormat; + QTextCharFormat functionFormat; +}; + +#endif // JSSYNTAXHIGHLIGHTER_H