XPlor/libs/core/highlighter_cfg.cpp

112 lines
4.3 KiB
C++

#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);
}
}