fix(StatusSyntaxHighlighter): code block fixes

- make the code bg/fg color configurable
- simplify the code, no need for an extra helper class
- fix code(block) regexes

Needed for https://github.com/status-im/status-desktop/issues/8649
This commit is contained in:
Lukáš Tinkl 2023-01-06 23:39:19 +01:00 committed by Michał
parent dda5e100f6
commit 210552b927
3 changed files with 107 additions and 64 deletions

View File

@ -1,50 +1,61 @@
#ifndef STATUSSYNTAXHIGHLIGHTER_H #pragma once
#define STATUSSYNTAXHIGHLIGHTER_H
#include <QSyntaxHighlighter> #include <QQmlParserStatus>
#include <QTextCharFormat>
#include <QRegularExpression> #include <QRegularExpression>
#include <QSyntaxHighlighter>
class QQuickTextDocument; class QQuickTextDocument;
class QTextCharFormat;
class StatusSyntaxHighlighter : public QSyntaxHighlighter class StatusSyntaxHighlighter : public QSyntaxHighlighter, public QQmlParserStatus
{ {
Q_OBJECT Q_OBJECT
Q_PROPERTY(QQuickTextDocument* quickTextDocument READ quickTextDocument WRITE setQuickTextDocument NOTIFY
quickTextDocumentChanged REQUIRED)
Q_PROPERTY(QColor codeBackgroundColor READ codeBackgroundColor WRITE setCodeBackgroundColor NOTIFY
codeBackgroundColorChanged REQUIRED)
Q_PROPERTY(QColor codeForegroundColor READ codeForegroundColor WRITE setCodeForegroundColor NOTIFY
codeForegroundColorChanged REQUIRED)
Q_INTERFACES(QQmlParserStatus)
public: public:
StatusSyntaxHighlighter(QTextDocument *parent = nullptr); explicit StatusSyntaxHighlighter(QObject* parent = nullptr);
QQuickTextDocument* quickTextDocument() const;
void setQuickTextDocument(QQuickTextDocument* quickTextDocument);
protected: protected:
void highlightBlock(const QString &text) override; void classBegin() override{};
void componentComplete() override;
void highlightBlock(const QString& text) override;
signals:
void quickTextDocumentChanged();
void codeBackgroundColorChanged();
void codeForegroundColorChanged();
private: private:
QQuickTextDocument* m_quicktextdocument{nullptr};
QColor m_codeBackgroundColor;
QColor codeBackgroundColor() const;
void setCodeBackgroundColor(const QColor& color);
QColor m_codeForegroundColor;
QColor codeForegroundColor() const;
void setCodeForegroundColor(const QColor& color);
struct HighlightingRule struct HighlightingRule
{ {
QRegularExpression pattern; QRegularExpression pattern;
QTextCharFormat format; QTextCharFormat format;
}; };
QVector<HighlightingRule> highlightingRules; QVector<HighlightingRule> highlightingRules{5};
QTextCharFormat singlelineBoldFormat; QTextCharFormat singlelineBoldFormat;
QTextCharFormat singleLineItalicFormat; QTextCharFormat singleLineItalicFormat;
QTextCharFormat singlelineCodeBlockFormat; QTextCharFormat codeFormat;
QTextCharFormat singleLineStrikeThroughFormat; QTextCharFormat singleLineStrikeThroughFormat;
QTextCharFormat multiLineCodeBlockFormat;
}; };
class StatusSyntaxHighlighterHelper : public QObject {
Q_OBJECT
Q_PROPERTY(QQuickTextDocument *quickTextDocument READ quickTextDocument WRITE
setQuickTextDocument NOTIFY quickTextDocumentChanged)
public:
StatusSyntaxHighlighterHelper(QObject *parent = nullptr)
: QObject(parent), m_quicktextdocument(nullptr) {}
QQuickTextDocument *quickTextDocument() const;
void setQuickTextDocument(QQuickTextDocument *quickTextDocument);
signals:
void quickTextDocumentChanged();
private:
QQuickTextDocument *m_quicktextdocument;
};
#endif // STATUSSYNTAXHIGHLIGHTER_H

View File

@ -84,7 +84,7 @@ void register_meta_types()
{ {
qRegisterMetaType<QVector<int>>(); qRegisterMetaType<QVector<int>>();
qmlRegisterType<StatusWindow>("DotherSide", 0 , 1, "StatusWindow"); qmlRegisterType<StatusWindow>("DotherSide", 0 , 1, "StatusWindow");
qmlRegisterType<StatusSyntaxHighlighterHelper>("DotherSide", 0 , 1, "StatusSyntaxHighlighter"); qmlRegisterType<StatusSyntaxHighlighter>("DotherSide", 0 , 1, "StatusSyntaxHighlighter");
qmlRegisterSingletonType<QClipboardProxy>("DotherSide", 0 , 1, "QClipboardProxy", &QClipboardProxy::qmlInstance); qmlRegisterSingletonType<QClipboardProxy>("DotherSide", 0 , 1, "QClipboardProxy", &QClipboardProxy::qmlInstance);
qmlRegisterType<RXValidator>("DotherSide", 0, 1, "RXValidator"); qmlRegisterType<RXValidator>("DotherSide", 0, 1, "RXValidator");
qqsfpm::registerTypes(); qqsfpm::registerTypes();

View File

@ -1,71 +1,103 @@
#include "DOtherSide/DOtherSideStatusSyntaxHighlighter.h" #include "DOtherSide/DOtherSideStatusSyntaxHighlighter.h"
#include <QQuickTextDocument>
#include <Qt>
#include <QBrush>
StatusSyntaxHighlighter::StatusSyntaxHighlighter(QTextDocument *parent) #include <QQuickTextDocument>
StatusSyntaxHighlighter::StatusSyntaxHighlighter(QObject* parent)
: QSyntaxHighlighter(parent) : QSyntaxHighlighter(parent)
{ }
void StatusSyntaxHighlighter::componentComplete()
{ {
HighlightingRule rule; HighlightingRule rule;
//BOLD //BOLD
singlelineBoldFormat.setFontWeight(QFont::Bold); singlelineBoldFormat.setFontWeight(QFont::Bold);
rule.pattern = QRegularExpression(QStringLiteral("(\\*\\*(.*?)\\*\\*)|(\\_\\_(.*?)\\_\\_)")); rule.pattern = QRegularExpression(QStringLiteral("(\\*\\*(.*?)\\*\\*)|(\\_\\_(.*?)\\_\\_)"));
rule.format = singlelineBoldFormat; rule.format = singlelineBoldFormat;
highlightingRules.append(rule); highlightingRules.append(rule);
//BOLD //BOLD
//ITALIC //ITALIC
singleLineItalicFormat.setFontItalic(true); singleLineItalicFormat.setFontItalic(true);
rule.pattern = QRegularExpression(QStringLiteral("(\\*(.*?)\\*)|(\\_(.*?)\\_)")); rule.pattern = QRegularExpression(QStringLiteral("(\\*(.*?)\\*)|(\\_(.*?)\\_)"));
rule.format = singleLineItalicFormat; rule.format = singleLineItalicFormat;
highlightingRules.append(rule); highlightingRules.append(rule);
//ITALIC //ITALIC
//CODE //STRIKETHROUGH
singlelineCodeBlockFormat.setFontFamily("Roboto Mono");
singlelineCodeBlockFormat.setBackground(QBrush(Qt::lightGray));
rule.pattern = QRegularExpression(QStringLiteral("\\`(.*?)\\`"));
rule.format = singlelineCodeBlockFormat;
highlightingRules.append(rule);
//CODE
//STRIKETHROUGH
singleLineStrikeThroughFormat.setFontStrikeOut(true); singleLineStrikeThroughFormat.setFontStrikeOut(true);
rule.pattern = QRegularExpression(QStringLiteral("\\~\\~(.*?)\\~\\~")); rule.pattern = QRegularExpression(QStringLiteral("\\~\\~(.*?)\\~\\~"));
rule.format = singleLineStrikeThroughFormat; rule.format = singleLineStrikeThroughFormat;
highlightingRules.append(rule); highlightingRules.append(rule);
//STRIKETHROUGH //STRIKETHROUGH
//CODE BLOCK //CODE (`foo`)
multiLineCodeBlockFormat.setFontFamily("Roboto Mono"); codeFormat.setFontFamily(QStringLiteral("Roboto Mono"));
multiLineCodeBlockFormat.setBackground(QBrush(Qt::lightGray)); codeFormat.setBackground(m_codeBackgroundColor);
rule.pattern = QRegularExpression(QStringLiteral("\\`\\`\\`(.*?)\\`\\`\\`")); codeFormat.setForeground(m_codeForegroundColor);
rule.format = multiLineCodeBlockFormat; rule.pattern = QRegularExpression(QStringLiteral("\\`{1}(.+)\\`{1}"),
// to not match single backtick pair inside a triple backtick block below
QRegularExpression::InvertedGreedinessOption);
rule.format = codeFormat;
highlightingRules.append(rule); highlightingRules.append(rule);
//CODE BLOCK //CODE
//CODEBLOCK (```\nfoo\nbar```)
rule.pattern = QRegularExpression(QStringLiteral("\\`{3}(.+)\\`{3}"));
rule.format = codeFormat;
highlightingRules.append(rule);
//CODEBLOCK
} }
void StatusSyntaxHighlighter::highlightBlock(const QString &text) void StatusSyntaxHighlighter::highlightBlock(const QString& text)
{ {
for (const HighlightingRule &rule : qAsConst(highlightingRules)) { for(const HighlightingRule& rule : qAsConst(highlightingRules))
QRegularExpressionMatchIterator matchIterator = rule.pattern.globalMatch(text); {
while (matchIterator.hasNext()) { QRegularExpressionMatchIterator matchIterator =
QRegularExpressionMatch match = matchIterator.next(); rule.pattern.globalMatch(text, 0, QRegularExpression::PartialPreferCompleteMatch);
while(matchIterator.hasNext())
{
const QRegularExpressionMatch match = matchIterator.next();
setFormat(match.capturedStart(), match.capturedLength(), rule.format); setFormat(match.capturedStart(), match.capturedLength(), rule.format);
} }
} }
setCurrentBlockState(0);
} }
QQuickTextDocument *StatusSyntaxHighlighterHelper::quickTextDocument() const { QQuickTextDocument* StatusSyntaxHighlighter::quickTextDocument() const
{
return m_quicktextdocument; return m_quicktextdocument;
} }
void StatusSyntaxHighlighterHelper::setQuickTextDocument( void StatusSyntaxHighlighter::setQuickTextDocument(QQuickTextDocument* quickTextDocument)
QQuickTextDocument *quickTextDocument) { {
if(!quickTextDocument) return;
if(quickTextDocument == m_quicktextdocument) return;
m_quicktextdocument = quickTextDocument; m_quicktextdocument = quickTextDocument;
if (m_quicktextdocument) { setDocument(m_quicktextdocument->textDocument());
new StatusSyntaxHighlighter(m_quicktextdocument->textDocument()); emit quickTextDocumentChanged();
} }
QColor StatusSyntaxHighlighter::codeBackgroundColor() const
{
return m_codeBackgroundColor;
}
void StatusSyntaxHighlighter::setCodeBackgroundColor(const QColor& color)
{
if(color == m_codeBackgroundColor) return;
m_codeBackgroundColor = color;
emit codeBackgroundColorChanged();
}
QColor StatusSyntaxHighlighter::codeForegroundColor() const
{
return m_codeForegroundColor;
}
void StatusSyntaxHighlighter::setCodeForegroundColor(const QColor& color)
{
if(color == m_codeForegroundColor) return;
m_codeForegroundColor = color;
emit codeForegroundColorChanged();
} }