#include "highlighter_cfg.h" Highlighter_CFG::Highlighter_CFG(QTextDocument *parent) : QSyntaxHighlighter(parent) { HighlightingRule rule; // Command keywords: set, seta, bind, etc. keywordFormat.setForeground(QColor("#569CD6")); keywordFormat.setFontWeight(QFont::Bold); const QString keywordPatterns[] = { QStringLiteral("\\bset\\b"), QStringLiteral("\\bseta\\b"), QStringLiteral("\\bbind\\b"), QStringLiteral("\\bvstr\\b"), QStringLiteral("\\bsay\\b"), QStringLiteral("\\bwait\\b"), QStringLiteral("\\bexec\\b"), QStringLiteral("\\bunbind\\b"), QStringLiteral("\\bcreatefx\\b"), QStringLiteral("\\bcreatefx_drawdist\\b"), QStringLiteral("\\bcreatefx_scaleid\\b"), QStringLiteral("\\bbindaxis\\b") }; for (const QString &pattern : keywordPatterns) { rule.pattern = QRegularExpression(pattern); rule.format = keywordFormat; highlightingRules.append(rule); } // Button constants: BUTTON_*, DPAD_* buttonFormat.setForeground(QColor("#4EC9B0")); rule.pattern = QRegularExpression(QStringLiteral("\\b(BUTTON|DPAD)_[A-Z]+\\b")); rule.format = buttonFormat; highlightingRules.append(rule); // Highlight *entire* 'bind var' or 'seta var' as one match, so we can highlight the variable part manually in highlightBlock() // Regex captures the command and the following variable as two groups bindSetVariablePattern = QRegularExpression(QStringLiteral("\\b(bind|bindaxis|set|seta)\\s+(\\w+)")); // Quoted strings (highlight first so numbers inside are overridden) quotationFormat.setForeground(QColor("#CE9178")); rule.pattern = QRegularExpression(QStringLiteral("\".*?\"")); rule.format = quotationFormat; highlightingRules.append(rule); // Numbers (normal numbers, no filtering for inside strings, since strings override them) numberFormat.setForeground(QColor("#B5CEA8")); rule.pattern = QRegularExpression(QStringLiteral("\\b-?\\d+(\\.\\d+)?f?\\b")); rule.format = numberFormat; highlightingRules.append(rule); // Comments: single-line comments with // singleLineCommentFormat.setForeground(QColor("#6A9955")); rule.pattern = QRegularExpression(QStringLiteral("//[^\n]*")); rule.format = singleLineCommentFormat; highlightingRules.append(rule); // Command chaining symbol: ; operatorFormat.setForeground(QColor("#D4D4D4")); rule.pattern = QRegularExpression(QStringLiteral(";")); rule.format = operatorFormat; highlightingRules.append(rule); } void Highlighter_CFG::highlightBlock(const QString &text) { // Apply all standard highlighting rules 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); } } // Highlight the immediate variable after 'bind', 'bindaxis', 'set', or 'seta' QRegularExpressionMatchIterator iter = bindSetVariablePattern.globalMatch(text); while (iter.hasNext()) { QRegularExpressionMatch match = iter.next(); int varStart = match.capturedStart(2); // Group 2 is the variable int varLength = match.capturedLength(2); setFormat(varStart, varLength, variableFormat); } setCurrentBlockState(0); // Handle multiline comments safely int startIndex = 0; if (previousBlockState() != 1) startIndex = text.indexOf(commentStartExpression); while (startIndex >= 0) { QRegularExpressionMatch match = commentEndExpression.match(text, startIndex); int endIndex = match.hasMatch() ? match.capturedStart() : -1; int commentLength; if (endIndex == -1) { setCurrentBlockState(1); commentLength = text.length() - startIndex; } else { commentLength = endIndex - startIndex + match.capturedLength(); } // Safety check to avoid infinite loops if (commentLength <= 0) { break; } setFormat(startIndex, commentLength, multiLineCommentFormat); startIndex = text.indexOf(commentStartExpression, startIndex + commentLength); } }