qt: rewrite syntax highlighter

- fix multi-line comments
- remove compilation warnings "unknown escape sequence"
- fewer lines of code
This commit is contained in:
scribam 2018-06-11 22:28:21 +02:00 committed by Ivan
parent a8f19fbfae
commit 626836f95b
4 changed files with 187 additions and 342 deletions

View File

@ -1,7 +1,6 @@
#include "stdafx.h"
#include "cg_disasm_window.h"
#include "syntax_highlighter.h"
#include <QSplitter>
#include <QMenu>
@ -35,124 +34,17 @@ cg_disasm_window::cg_disasm_window(std::shared_ptr<gui_settings> xSettings): xgu
m_disasm_text->setReadOnly(true);
m_disasm_text->setWordWrapMode(QTextOption::NoWrap);
m_disasm_text->setFont(QFontDatabase::systemFont(QFontDatabase::FixedFont));
m_glsl_text = new QTextEdit(this);
m_glsl_text->setReadOnly(true);
m_glsl_text->setWordWrapMode(QTextOption::NoWrap);
m_glsl_text->setFont(QFontDatabase::systemFont(QFontDatabase::FixedFont));
// m_disasm_text syntax highlighter
syntax_highlighter* sh_asm = new syntax_highlighter(m_disasm_text->document());
sh_asm->AddCommentRule("#", QColor(Qt::darkGreen));
sh_asm->AddCommentRule("\/\*", QColor(Qt::darkGreen), true, "\*\/");
sh_asm->AddSimpleRule(QStringList("^([^\\s]+).*$"), QColor(Qt::darkBlue)); // Instructions
sh_asm->AddSimpleRule(QStringList(",?\\s(-?R\\d[^,;\\s]*)"), QColor(Qt::darkRed)); // -R0.*
sh_asm->AddSimpleRule(QStringList(",?\\s(-?H\\d[^,;\\s]*)"), QColor(Qt::red)); // -H1.*
sh_asm->AddSimpleRule(QStringList(",?\\s(-?v\\[\\d\\]*[^,;\\s]*)"), QColor(Qt::darkCyan)); // -v[xyz].*
sh_asm->AddSimpleRule(QStringList(",?\\s(-?o\\[\\d\\]*[^,;\\s]*)"), QColor(Qt::darkMagenta)); // -o[xyz].*
sh_asm->AddSimpleRule(QStringList(",?\\s(-?c\\[\\d\\]*[^,;\\s]*)"), QColor(Qt::darkYellow)); // -c[xyz].*
//sh_asm->AddMultiRule(
// "^([^\\s]+)(?:,?\\s*([^,\\;\\s]+))?(?:,?\\s*([^,\\;\\s]+))?(?:,?\\s*([^,\\;\\s]+))?(?:,?\\s*([^,\\;\\s]+))?.*$",
// { QColor(Qt::black), QColor(Qt::darkBlue), QColor(Qt::darkRed), QColor(Qt::darkMagenta), QColor(Qt::darkYellow), QColor(Qt::darkCyan) });
sh_asm = new AsmHighlighter(m_disasm_text->document());
// m_glsl_text syntax highlighter
QStringList glsl_syntax = QStringList()
// Selection-Iteration-Jump Statements:
<< "if" << "else" << "switch" << "case" << "default"
<< "for" << "while" << "do" << "foreach" //?
<< "return" << "break" << "continue" << "discard"
// Misc:
<< "void" << "char" << "short" << "long" << "template"
<< "class" << "struct" << "union" << "enum"
<< "static" << "virtual" << "inline" << "explicit"
<< "public" << "private" << "protected" << "namespace"
<< "typedef" << "typename" << "signed" << "unsigned"
<< "friend" << "operator" << "signals" << "slots"
// Qualifiers:
<< "in" << "packed" << "precision" << "const" << "smooth" << "sample"
<< "out" << "shared" << "highp" << "invariant" << "noperspective" << "centroid"
<< "inout" << "std140" << "mediump" << "uniform" << "flat" << "patch"
<< "buffer" << "std430" << "lowp"
<< "image"
// Removed Qualifiers?
<< "attribute" << "varying"
// Memory Qualifiers
<< "coherent" << "volatile" << "restrict" << "readonly" << "writeonly"
// Layout Qualifiers:
//<< "subroutine" << "layout" << "xfb_buffer" << "textureGrad" << "texture" << "dFdx" << "dFdy"
//<< "location" << "component" << "binding" << "offset"
//<< "xfb_offset" << "xfb_stride" << "vertices" << "max_vertices"
// Scalars and Vectors:
<< "bool" << "int" << "uint" << "float" << "double"
<< "bvec2" << "ivec2" << "uvec2" << "vec2" << "dvec2"
<< "bvec3" << "ivec3" << "uvec3" << "vec3" << "dvec3"
<< "bvec4" << "ivec4" << "uvec4" << "vec4" << "dvec4"
// Matrices:
<< "mat2" << "mat2x3" << "mat2x4"
<< "mat3" << "mat3x2" << "mat3x4"
<< "mat4" << "mat4x2" << "mat4x3"
// Sampler Types:
<< "sampler1D" << "isampler1D" << "usampler1D"
<< "sampler2D" << "isampler2D" << "usampler2D"
<< "sampler3D" << "isampler3D" << "usampler3D"
<< "samplerCube" << "isamplerCube" << "usamplerCube"
<< "sampler2DRect" << "isampler2DRect" << "usampler2DRect"
<< "sampler1DArray" << "isampler1DArray" << "usampler1DArray"
<< "sampler2DArray" << "isampler2DArray" << "usampler2DArray"
<< "samplerCubeArray" << "isamplerCubeArray" << "usamplerCubeArray"
<< "samplerBuffer" << "isamplerBuffer" << "usamplerBuffer"
<< "sampler2DMS" << "isampler2DMS" << "usampler2DMS"
<< "sampler2DMSArray" << "isampler2DMSArray" << "usampler2DMSArray"
// Shadow Samplers:
<< "sampler1DShadow"
<< "sampler2DShadow"
<< "samplerCubeShadow"
<< "sampler2DRectShadow"
<< "sampler1DArrayShadow"
<< "sampler2DArrayShadow"
<< "samplerCubeArrayShadow"
// Image Types:
<< "image1D" << "iimage1D" << "uimage1D"
<< "image2D" << "iimage2D" << "uimage2D"
<< "image3D" << "iimage3D" << "uimage3D"
<< "imageCube" << "iimageCube" << "uimageCube"
<< "image2DRect" << "iimage2DRect" << "uimage2DRect"
<< "image1DArray" << "iimage1DArray" << "uimage1DArray"
<< "image2DArray" << "iimage2DArray" << "uimage2DArray"
<< "imageCubeArray" << "iimageCubeArray" << "uimageCubeArray"
<< "imageBuffer" << "iimageBuffer" << "uimageBuffer"
<< "image2DMS" << "iimage2DMS" << "uimage2DMS"
<< "image2DMSArray" << "iimage2DMSArray" << "uimage2DMSArray"
// Image Formats:
// Floating-point: // Signed integer:
<< "rgba32f" << "rgba32i"
<< "rgba16f" << "rgba16i"
<< "rg32f" << "rgba8i"
<< "rg16f" << "rg32i"
<< "r11f_g11f_b10f" << "rg16i"
<< "r32f" << "rg8i"
<< "r16f" << "r32i"
<< "rgba16" << "r16i"
<< "rgb10_a2" << "r8i"
<< "rgba8" << "r8ui"
<< "rg16" // Unsigned integer:
<< "rg8" << "rgba32ui"
<< "r16" << "rgba16ui"
<< "r8" << "rgb10_a2ui"
<< "rgba16_snorm" << "rgba8ui"
<< "rgba8_snorm" << "rg32ui"
<< "rg16_snorm" << "rg16ui"
<< "rg8_snorm" << "rg8ui"
<< "r16_snorm" << "r32ui"
<< "r8_snorm" << "r16ui"
;
syntax_highlighter* sh_glsl = new syntax_highlighter(m_glsl_text->document());
sh_glsl->AddWordRule(glsl_syntax, QColor(Qt::darkBlue)); // normal words like: soka, nani, or gomen
sh_glsl->AddSimpleRule(QStringList("\\bGL_(?:[A-Z]|_)+\\b"), QColor(Qt::darkMagenta)); // constants like: GL_OMAE_WA_MOU_SHINDEIRU
sh_glsl->AddSimpleRule(QStringList("\\bgl_(?:[A-Z]|[a-z]|_)+\\b"), QColor(Qt::darkCyan)); // reserved types like: gl_exploooooosion
sh_glsl->AddSimpleRule(QStringList("\\B#[^\\s]+\\b"), QColor(Qt::darkGray)); // preprocessor instructions like: #waifu megumin
sh_glsl->AddCommentRule("\/\/", QColor(Qt::darkGreen)); // comments like: // No comment
sh_glsl->AddCommentRule("\/\*", QColor(Qt::darkGreen), true, "\*\/"); // comments like: /* I am trapped! Please help me! */
sh_glsl = new GlslHighlighter(m_glsl_text->document());
QSplitter* splitter = new QSplitter();
splitter->addWidget(m_disasm_text);

View File

@ -5,6 +5,7 @@
#include "stdafx.h"
#include "gui_settings.h"
#include "syntax_highlighter.h"
class cg_disasm_window : public QWidget
{
@ -25,6 +26,9 @@ private:
std::shared_ptr<gui_settings> xgui_settings;
AsmHighlighter* sh_asm;
GlslHighlighter* sh_glsl;
public:
explicit cg_disasm_window(std::shared_ptr<gui_settings> xSettings);

View File

@ -1,183 +1,171 @@
#include "syntax_highlighter.h"
syntax_highlighter::syntax_highlighter(QTextDocument *parent) : QSyntaxHighlighter(parent)
Highlighter::Highlighter(QTextDocument *parent) : QSyntaxHighlighter(parent)
{
}
void syntax_highlighter::AddSimpleRule(SimpleRule rule)
void Highlighter::addRule(const QString &pattern, const QBrush &brush)
{
rule.expressions.erase(std::remove_if(rule.expressions.begin(), rule.expressions.end(), [&](const auto &e){
return IsInvalidExpression(e) || e.captureCount() > 1;
}), rule.expressions.end());
HighlightingRule rule;
rule.pattern = QRegularExpression(pattern);
rule.format.setForeground(brush);
highlightingRules.append(rule);
}
if (rule.expressions.isEmpty())
void Highlighter::highlightBlock(const QString &text)
{
foreach (const HighlightingRule &rule, highlightingRules)
{
QRegularExpressionMatchIterator matchIterator = rule.pattern.globalMatch(text);
while (matchIterator.hasNext())
{
QRegularExpressionMatch match = matchIterator.next();
setFormat(match.capturedStart(), match.capturedLength(), rule.format);
}
}
setCurrentBlockState(0);
if (commentStartExpression.pattern().isEmpty() || commentEndExpression.pattern().isEmpty())
return;
}
m_rules.append(rule);
}
void syntax_highlighter::AddSimpleRule(const QStringList& expressions, const QColor& color)
{
QTextCharFormat format;
format.setForeground(color);
QVector<QRegularExpression> regexs;
for (const auto& expr : expressions)
int startIndex = 0;
if (previousBlockState() != 1)
startIndex = text.indexOf(commentStartExpression);
while (startIndex >= 0)
{
regexs.append(QRegularExpression(expr));
}
AddSimpleRule(SimpleRule(regexs, format));
}
QRegularExpressionMatch match = commentEndExpression.match(text, startIndex);
int endIndex = match.capturedStart();
int commentLength = 0;
void syntax_highlighter::AddWordRule(const QStringList& words, const QColor& color)
{
QTextCharFormat format;
format.setForeground(color);
QVector<QRegularExpression> regexs;
for (const auto& word : words)
{
regexs.append(QRegularExpression("\\b" + word + "\\b"));
}
AddSimpleRule(SimpleRule(regexs, format));
}
void syntax_highlighter::AddMultiRule(const MultiRule& rule)
{
if (IsInvalidExpression(rule.expression) || rule.formats.length() <= rule.expression.captureCount())
{
return;
}
m_multi_rules.append(rule);
}
void syntax_highlighter::AddMultiRule(const QString& expression, const QVector<QColor>& colors)
{
QVector<QTextCharFormat> formats;
for (const auto& color : colors)
{
QTextCharFormat format;
format.setForeground(color);
formats.append(format);
}
AddMultiRule(MultiRule(QRegularExpression(expression), formats));
}
void syntax_highlighter::AddCommentRule(const CommentRule& rule)
{
if (IsInvalidExpression(rule.start_expression) || (rule.multi_line && IsInvalidExpression(rule.end_expression)))
{
return;
}
m_comment_rules.append(rule);
}
void syntax_highlighter::AddCommentRule(const QString& start, const QColor& color, bool multi_line, const QString& end)
{
QTextCharFormat format;
format.setForeground(color);
AddCommentRule(CommentRule(QRegularExpression(start), QRegularExpression(end), format, multi_line));
}
void syntax_highlighter::highlightBlock(const QString &text)
{
m_current_block = text;
for (const auto& rule : m_multi_rules)
{
// Search for all the matching strings
QRegularExpressionMatchIterator iter = rule.expression.globalMatch(m_current_block);
// Iterate through the matching strings
while (iter.hasNext())
if (endIndex == -1)
{
// Apply formats to their respective found groups
QRegularExpressionMatch match = iter.next();
for (int i = 0; i <= match.lastCapturedIndex(); i++)
{
setFormat(match.capturedStart(i), match.capturedLength(i), rule.formats[i]);
}
setCurrentBlockState(1);
commentLength = text.length() - startIndex;
}
}
for (const auto& rule : m_rules)
{
for (const auto& expression : rule.expressions)
else
{
// Search for all the matching strings
QRegularExpressionMatchIterator iter = expression.globalMatch(m_current_block);
bool contains_group = expression.captureCount() > 0;
// Iterate through the matching strings
while (iter.hasNext())
{
// Apply format to the matching string
QRegularExpressionMatch match = iter.next();
if (contains_group)
{
setFormat(match.capturedStart(1), match.capturedLength(1), rule.format);
}
else
{
setFormat(match.capturedStart(), match.capturedLength(), rule.format);
}
}
}
}
for (const auto& rule : m_comment_rules)
{
int comment_start = 0; // Current comment's start position in the text block
int comment_end = 0; // Current comment's end position in the text block
int comment_length = 0; // Current comment length
// We assume we end outside a comment until we know better
setCurrentBlockState(block_state::ended_outside_comment);
// Search for the first comment in this block if we start outside or don't want to search for multiline comments
if (!rule.multi_line || previousBlockState() != block_state::ended_inside_comment)
{
comment_start = m_current_block.indexOf(rule.start_expression);
}
// Set format for the rest of this block/line
if (!rule.multi_line)
{
comment_length = m_current_block.length() - comment_start;
setFormat(comment_start, comment_length, rule.format);
break;
}
// Format all comments in this block (if they exist)
while (comment_start >= 0)
{
// Search for end of comment in the remaining text
QRegularExpressionMatch match = rule.end_expression.match(m_current_block, comment_start);
comment_end = match.capturedStart();
match.captured(1);
if (comment_end == -1)
{
// We end inside a comment and want to format the entire remaining text
setCurrentBlockState(block_state::ended_inside_comment);
comment_length = m_current_block.length() - comment_start;
}
else
{
// We found the end of the comment so we need to go another round
comment_length = comment_end - comment_start + match.capturedLength();
}
// Set format for this text segment
setFormat(comment_start, comment_length, rule.format);
// Search for the next comment
comment_start = m_current_block.indexOf(rule.start_expression, comment_start + comment_length);
commentLength = endIndex - startIndex
+ match.capturedLength();
}
setFormat(startIndex, commentLength, multiLineCommentFormat);
startIndex = text.indexOf(commentStartExpression, startIndex + commentLength);
}
}
bool syntax_highlighter::IsInvalidExpression(const QRegularExpression& expression)
AsmHighlighter::AsmHighlighter(QTextDocument *parent) : Highlighter(parent)
{
return !expression.isValid() || expression.pattern().isEmpty();
addRule("^([^\\s]+).*$", Qt::darkBlue); // Instructions
addRule(",?\\s(-?R\\d[^,;\\s]*)", Qt::darkRed); // -R0.*
addRule(",?\\s(-?H\\d[^,;\\s]*)", Qt::red); // -H1.*
addRule(",?\\s(-?v\\[\\d\\]*[^,;\\s]*)", Qt::darkCyan); // -v[xyz].*
addRule(",?\\s(-?o\\[\\d\\]*[^,;\\s]*)", Qt::darkMagenta); // -o[xyz].*
addRule(",?\\s(-?c\\[\\d\\]*[^,;\\s]*)", Qt::darkYellow); // -c[xyz].*
addRule("#[^\\n]*", Qt::darkGreen); // Single line comment
}
GlslHighlighter::GlslHighlighter(QTextDocument *parent) : Highlighter(parent)
{
QStringList keywordPatterns = QStringList()
// Selection-Iteration-Jump Statements:
<< "if" << "else" << "switch" << "case" << "default"
<< "for" << "while" << "do" << "foreach" //?
<< "return" << "break" << "continue" << "discard"
// Misc:
<< "void" << "char" << "short" << "long" << "template"
<< "class" << "struct" << "union" << "enum"
<< "static" << "virtual" << "inline" << "explicit"
<< "public" << "private" << "protected" << "namespace"
<< "typedef" << "typename" << "signed" << "unsigned"
<< "friend" << "operator" << "signals" << "slots"
// Qualifiers:
<< "in" << "packed" << "precision" << "const" << "smooth" << "sample"
<< "out" << "shared" << "highp" << "invariant" << "noperspective" << "centroid"
<< "inout" << "std140" << "mediump" << "uniform" << "flat" << "patch"
<< "buffer" << "std430" << "lowp"
<< "image"
// Removed Qualifiers?
<< "attribute" << "varying"
// Memory Qualifiers
<< "coherent" << "volatile" << "restrict" << "readonly" << "writeonly"
// Layout Qualifiers:
//<< "subroutine" << "layout" << "xfb_buffer" << "textureGrad" << "texture" << "dFdx" << "dFdy"
//<< "location" << "component" << "binding" << "offset"
//<< "xfb_offset" << "xfb_stride" << "vertices" << "max_vertices"
// Scalars and Vectors:
<< "bool" << "int" << "uint" << "float" << "double"
<< "bvec2" << "ivec2" << "uvec2" << "vec2" << "dvec2"
<< "bvec3" << "ivec3" << "uvec3" << "vec3" << "dvec3"
<< "bvec4" << "ivec4" << "uvec4" << "vec4" << "dvec4"
// Matrices:
<< "mat2" << "mat2x3" << "mat2x4"
<< "mat3" << "mat3x2" << "mat3x4"
<< "mat4" << "mat4x2" << "mat4x3"
// Sampler Types:
<< "sampler1D" << "isampler1D" << "usampler1D"
<< "sampler2D" << "isampler2D" << "usampler2D"
<< "sampler3D" << "isampler3D" << "usampler3D"
<< "samplerCube" << "isamplerCube" << "usamplerCube"
<< "sampler2DRect" << "isampler2DRect" << "usampler2DRect"
<< "sampler1DArray" << "isampler1DArray" << "usampler1DArray"
<< "sampler2DArray" << "isampler2DArray" << "usampler2DArray"
<< "samplerCubeArray" << "isamplerCubeArray" << "usamplerCubeArray"
<< "samplerBuffer" << "isamplerBuffer" << "usamplerBuffer"
<< "sampler2DMS" << "isampler2DMS" << "usampler2DMS"
<< "sampler2DMSArray" << "isampler2DMSArray" << "usampler2DMSArray"
// Shadow Samplers:
<< "sampler1DShadow"
<< "sampler2DShadow"
<< "samplerCubeShadow"
<< "sampler2DRectShadow"
<< "sampler1DArrayShadow"
<< "sampler2DArrayShadow"
<< "samplerCubeArrayShadow"
// Image Types:
<< "image1D" << "iimage1D" << "uimage1D"
<< "image2D" << "iimage2D" << "uimage2D"
<< "image3D" << "iimage3D" << "uimage3D"
<< "imageCube" << "iimageCube" << "uimageCube"
<< "image2DRect" << "iimage2DRect" << "uimage2DRect"
<< "image1DArray" << "iimage1DArray" << "uimage1DArray"
<< "image2DArray" << "iimage2DArray" << "uimage2DArray"
<< "imageCubeArray" << "iimageCubeArray" << "uimageCubeArray"
<< "imageBuffer" << "iimageBuffer" << "uimageBuffer"
<< "image2DMS" << "iimage2DMS" << "uimage2DMS"
<< "image2DMSArray" << "iimage2DMSArray" << "uimage2DMSArray"
// Image Formats:
// Floating-point: // Signed integer:
<< "rgba32f" << "rgba32i"
<< "rgba16f" << "rgba16i"
<< "rg32f" << "rgba8i"
<< "rg16f" << "rg32i"
<< "r11f_g11f_b10f" << "rg16i"
<< "r32f" << "rg8i"
<< "r16f" << "r32i"
<< "rgba16" << "r16i"
<< "rgb10_a2" << "r8i"
<< "rgba8" << "r8ui"
<< "rg16" // Unsigned integer:
<< "rg8" << "rgba32ui"
<< "r16" << "rgba16ui"
<< "r8" << "rgb10_a2ui"
<< "rgba16_snorm" << "rgba8ui"
<< "rgba8_snorm" << "rg32ui"
<< "rg16_snorm" << "rg16ui"
<< "rg8_snorm" << "rg8ui"
<< "r16_snorm" << "r32ui"
<< "r8_snorm" << "r16ui";
foreach (const QString &pattern, keywordPatterns)
addRule("\\b" + pattern + "\\b", Qt::darkBlue); // normal words like: soka, nani, or gomen
addRule("\\bGL_(?:[A-Z]|_)+\\b", Qt::darkMagenta); // constants like: GL_OMAE_WA_MOU_SHINDEIRU
addRule("\\bgl_(?:[A-Z]|[a-z]|_)+\\b", Qt::darkCyan); // reserved types like: gl_exploooooosion
addRule("\\B#[^\\s]+\\b", Qt::darkGray); // preprocessor instructions like: #waifu megumin
addRule("//[^\\n]*", Qt::darkGreen); // Single line comment
// Multi line comment
multiLineCommentFormat.setForeground(Qt::darkGreen);
commentStartExpression = QRegularExpression("/\\*");
commentEndExpression = QRegularExpression("\\*/");
}

View File

@ -3,83 +3,44 @@
#include <QSyntaxHighlighter>
#include <QRegularExpression>
class syntax_highlighter : public QSyntaxHighlighter
// Inspired by https://doc.qt.io/qt-5/qtwidgets-richtext-syntaxhighlighter-example.html
class Highlighter : public QSyntaxHighlighter
{
Q_OBJECT
enum block_state
{
ended_outside_comment,
ended_inside_comment
};
public:
syntax_highlighter(QTextDocument *parent = 0);
struct SimpleRule
{
QVector<QRegularExpression> expressions;
QTextCharFormat format;
SimpleRule(){}
SimpleRule(const QVector<QRegularExpression>& expressions, const QTextCharFormat& format)
: expressions(expressions), format(format) {}
};
struct MultiRule
{
QRegularExpression expression;
QVector<QTextCharFormat> formats;
MultiRule(){}
MultiRule(const QRegularExpression& expr, const QVector<QTextCharFormat>& formats)
: expression(expr), formats(formats) {}
};
struct CommentRule
{
QRegularExpression start_expression;
QRegularExpression end_expression;
QTextCharFormat format;
bool multi_line = false;
CommentRule(){}
CommentRule(const QRegularExpression& start, const QRegularExpression& end, const QTextCharFormat& format, bool multi_line)
: start_expression(start), end_expression(end), format(format), multi_line(multi_line) {}
};
/**
Add a simple highlighting rule that applies the given format to all given expressions.
You can add up to one Group to the expression. The full match group will be ignored
*/
void AddSimpleRule(SimpleRule rule);
void AddSimpleRule(const QStringList& expressions, const QColor& color);
/** Add a simple highlighting rule for words. Not supposed to be used with any other expression */
void AddWordRule(const QStringList& words, const QColor& color);
/**
Add a complex highlighting rule that applies different formats to the expression's groups.
Make sure you don't have more groups in your expression than formats !!!
Group 0 is always the full match, so the first color has to be for that !!!
Example expression for string "rdch $4,$6,$8,$5" with 6 groups (5 + full match):
"^(?<group1>[^\s]+) (?<group2>[^,]+),(?<group3>[^,]+),(?<group4>[^,]+),(?<group5>[^,]+)$"
*/
void AddMultiRule(const MultiRule& rule);
void AddMultiRule(const QString& expression, const QVector<QColor>& colors);
/**
Add a comment highlighting rule. Add them in ascending priority.
We only need rule.end_expression in case of rule.multi_line.
A block ends at the end of a line anyway.
*/
void AddCommentRule(const CommentRule& rule);
void AddCommentRule(const QString& start, const QColor& color, bool multi_line = false, const QString& end = "");
Highlighter(QTextDocument *parent = 0);
protected:
void highlightBlock(const QString &text) override;
void addRule(const QString &pattern, const QBrush &brush);
private:
/** Checks if an expression is invalid or empty */
static bool IsInvalidExpression(const QRegularExpression& expression);
struct HighlightingRule
{
QRegularExpression pattern;
QTextCharFormat format;
};
QVector<HighlightingRule> highlightingRules;
QVector<SimpleRule> m_rules;
QVector<CommentRule> m_comment_rules;
QVector<MultiRule> m_multi_rules;
QRegularExpression commentStartExpression;
QRegularExpression commentEndExpression;
QString m_current_block;
QTextCharFormat multiLineCommentFormat;
};
class AsmHighlighter : public Highlighter
{
Q_OBJECT
public:
AsmHighlighter(QTextDocument *parent = 0);
};
class GlslHighlighter : public Highlighter
{
Q_OBJECT
public:
GlslHighlighter(QTextDocument *parent = 0);
};