Skip to content

Instantly share code, notes, and snippets.

@klemens-morgenstern
Created October 22, 2016 10:50
Show Gist options
  • Save klemens-morgenstern/fb955337964d4e2fb9211b013442f631 to your computer and use it in GitHub Desktop.
Save klemens-morgenstern/fb955337964d4e2fb9211b013442f631 to your computer and use it in GitHub Desktop.
/*
* ChaiScriptSyntaxHighlighter.cpp
*
* Created on: 21.10.2016
* Author: klemens.morgenstern
*/
#include <widgets/ChaiScriptSyntaxHighlighter.hpp>
namespace widgets
{
ChaiScriptSyntaxHighlighter::ChaiScriptSyntaxHighlighter(QTextDocument *parent)
: QSyntaxHighlighter(parent)
{
keywords = QStringList() << "attr" << "auto" << "break" << // "class" << "def" <<
"else" << "for" << "fun" << "if" << "try" << "catch" << "while" << "var"
<< "true" << "false"
;
operators = QStringList() << "=" <<
// Comparison
"==" << "!=" << "<" << "<=" << ">" << ">=" <<
// Arithmetic
"\\+" << "-" << "\\*" << "/" << "//" << "%" << "\\*\\*" <<
// In-place
"\\+=" << "-=" << "\\*=" << "/=" << "%=" <<
// Bitwise
"\\^" << "\\|" << "&" << "~" << ">>" << "<<";
braces = QStringList() << "{" << "}" << "\\(" << "\\)" << "\\[" << "]";
basicStyles.insert("keyword", getTextCharFormat("blue"));
basicStyles.insert("operator", getTextCharFormat("red"));
basicStyles.insert("brace", getTextCharFormat("darkGray"));
basicStyles.insert("defclass", getTextCharFormat("black", "bold"));
basicStyles.insert("brace", getTextCharFormat("darkGray"));
basicStyles.insert("string", getTextCharFormat("magenta"));
basicStyles.insert("comment", getTextCharFormat("darkGreen", "italic"));
basicStyles.insert("numbers", getTextCharFormat("brown"));
initializeRules();
}
void ChaiScriptSyntaxHighlighter::initializeRules()
{
for (auto & currKeyword : keywords)
{
rules.append(ChaiScriptRule(QString("\\b%1\\b").arg(currKeyword), 0, basicStyles.value("keyword")));
}
for (auto & currOperator : operators)
{
rules.append(ChaiScriptRule(QString("%1").arg(currOperator), 0, basicStyles.value("operator")));
}
for (auto & currBrace : braces)
{
rules.append(ChaiScriptRule(QString("%1").arg(currBrace), 0, basicStyles.value("brace")));
}
// Double-quoted string, possibly containing escape sequences
// FF: originally in python : r'"[^"\\]*(\\.[^"\\]*)*"'
rules.append(ChaiScriptRule("\"[^\"\\\\]*(\\\\.[^\"\\\\]*)*\"", 0, basicStyles.value("string")));
// Single-quoted string, possibly containing escape sequences
// FF: originally in python : r"'[^'\\]*(\\.[^'\\]*)*'"
rules.append(ChaiScriptRule("'[^'\\\\]*(\\\\.[^'\\\\]*)*'", 0, basicStyles.value("string")));
// 'def' followed by an identifier
// FF: originally: r'\bdef\b\s*(\w+)'
rules.append(ChaiScriptRule("\\bdef\\b\\s*(\\w+)", 1, basicStyles.value("defclass")));
// 'class' followed by an identifier
// FF: originally: r'\bclass\b\s*(\w+)'
rules.append(ChaiScriptRule("\\bclass\\b\\s*(\\w+)", 1, basicStyles.value("defclass")));
// From '#' until a newline
// FF: originally: r'#[^\\n]*'
rules.append(ChaiScriptRule("//[^\\n]*", 0, basicStyles.value("comment")));
// Numeric literals
rules.append(ChaiScriptRule("\\b[+-]?[0-9]+[lL]?\\b", 0, basicStyles.value("numbers"))); // r'\b[+-]?[0-9]+[lL]?\b'
rules.append(ChaiScriptRule("\\b[+-]?0[xX][0-9A-Fa-f]+[lL]?\\b", 0, basicStyles.value("numbers"))); // r'\b[+-]?0[xX][0-9A-Fa-f]+[lL]?\b'
rules.append(ChaiScriptRule("\\b[+-]?[0-9]+(?:\\.[0-9]+)?(?:[eE][+-]?[0-9]+)?\\b", 0, basicStyles.value("numbers"))); // r'\b[+-]?[0-9]+(?:\.[0-9]+)?(?:[eE][+-]?[0-9]+)?\b'
}
void ChaiScriptSyntaxHighlighter::highlightBlock(const QString &text)
{
for (ChaiScriptRule & currRule : rules)
{
int idx = currRule.pattern.indexIn(text, 0);
while (idx >= 0)
{
// Get index of Nth match
idx = currRule.pattern.pos(currRule.nth);
int length = currRule.pattern.cap(currRule.nth).length();
setFormat(idx, length, currRule.format);
idx = currRule.pattern.indexIn(text, idx + length);
}
}
setCurrentBlockState(0);
}
bool ChaiScriptSyntaxHighlighter::matchMultiline(const QString &text, const QRegExp &delimiter, const int inState, const QTextCharFormat &style)
{
int start = -1;
int add = -1;
int end = -1;
int length = 0;
// If inside triple-single quotes, start at 0
if (previousBlockState() == inState)
{
start = 0;
add = 0;
}
// Otherwise, look for the delimiter on this line
else {
start = delimiter.indexIn(text);
// Move past this match
add = delimiter.matchedLength();
}
// As long as there's a delimiter match on this line...
while (start >= 0)
{
// Look for the ending delimiter
end = delimiter.indexIn(text, start + add);
// Ending delimiter on this line?
if (end >= add) {
length = end - start + add + delimiter.matchedLength();
setCurrentBlockState(0);
}
// No; multi-line string
else {
setCurrentBlockState(inState);
length = text.length() - start + add;
}
// Apply formatting and look for next
setFormat(start, length, style);
start = delimiter.indexIn(text, start + length);
}
// Return True if still inside a multi-line string, False otherwise
if (currentBlockState() == inState)
return true;
else
return false;
}
const QTextCharFormat ChaiScriptSyntaxHighlighter::getTextCharFormat(const QString &colorName, const QString &style)
{
QTextCharFormat charFormat;
QColor color(colorName);
charFormat.setForeground(color);
if (style.contains("bold", Qt::CaseInsensitive))
charFormat.setFontWeight(QFont::Bold);
if (style.contains("italic", Qt::CaseInsensitive))
charFormat.setFontItalic(true);
return charFormat;
}
} /* namespace widgets */
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment