From 626836f95b31fb3a21dbafbeabb6bf4e2dc6fa2b Mon Sep 17 00:00:00 2001 From: scribam Date: Mon, 11 Jun 2018 22:28:21 +0200 Subject: [PATCH] qt: rewrite syntax highlighter - fix multi-line comments - remove compilation warnings "unknown escape sequence" - fewer lines of code --- rpcs3/rpcs3qt/cg_disasm_window.cpp | 114 +--------- rpcs3/rpcs3qt/cg_disasm_window.h | 4 + rpcs3/rpcs3qt/syntax_highlighter.cpp | 312 +++++++++++++-------------- rpcs3/rpcs3qt/syntax_highlighter.h | 99 +++------ 4 files changed, 187 insertions(+), 342 deletions(-) diff --git a/rpcs3/rpcs3qt/cg_disasm_window.cpp b/rpcs3/rpcs3qt/cg_disasm_window.cpp index 1960e08b89..dfc8e5c737 100644 --- a/rpcs3/rpcs3qt/cg_disasm_window.cpp +++ b/rpcs3/rpcs3qt/cg_disasm_window.cpp @@ -1,7 +1,6 @@ #include "stdafx.h" #include "cg_disasm_window.h" -#include "syntax_highlighter.h" #include #include @@ -35,124 +34,17 @@ cg_disasm_window::cg_disasm_window(std::shared_ptr 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); diff --git a/rpcs3/rpcs3qt/cg_disasm_window.h b/rpcs3/rpcs3qt/cg_disasm_window.h index e8f8a3672f..c3f4a0304b 100644 --- a/rpcs3/rpcs3qt/cg_disasm_window.h +++ b/rpcs3/rpcs3qt/cg_disasm_window.h @@ -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 xgui_settings; + AsmHighlighter* sh_asm; + GlslHighlighter* sh_glsl; + public: explicit cg_disasm_window(std::shared_ptr xSettings); diff --git a/rpcs3/rpcs3qt/syntax_highlighter.cpp b/rpcs3/rpcs3qt/syntax_highlighter.cpp index 74e4a8c86b..e3e0d91fee 100644 --- a/rpcs3/rpcs3qt/syntax_highlighter.cpp +++ b/rpcs3/rpcs3qt/syntax_highlighter.cpp @@ -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 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 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& colors) -{ - QVector 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("\\*/"); } diff --git a/rpcs3/rpcs3qt/syntax_highlighter.h b/rpcs3/rpcs3qt/syntax_highlighter.h index fa8f283191..8dd221fd6d 100644 --- a/rpcs3/rpcs3qt/syntax_highlighter.h +++ b/rpcs3/rpcs3qt/syntax_highlighter.h @@ -3,83 +3,44 @@ #include #include -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 expressions; - QTextCharFormat format; - SimpleRule(){} - SimpleRule(const QVector& expressions, const QTextCharFormat& format) - : expressions(expressions), format(format) {} - }; - struct MultiRule - { - QRegularExpression expression; - QVector formats; - MultiRule(){} - MultiRule(const QRegularExpression& expr, const QVector& 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): - "^(?[^\s]+) (?[^,]+),(?[^,]+),(?[^,]+),(?[^,]+)$" - */ - void AddMultiRule(const MultiRule& rule); - void AddMultiRule(const QString& expression, const QVector& 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 highlightingRules; - QVector m_rules; - QVector m_comment_rules; - QVector 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); +}; \ No newline at end of file