112 lines
4.3 KiB
C++
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);
|
||
|
|
}
|
||
|
|
}
|