#include "lrscripthighlighter.h" #include "lrglobal.h" #include #include namespace LimeReport { #define KEYWORDS_COUNT 60 static const char* const keywords[KEYWORDS_COUNT] = { "do", "if", "in", "for", "int", "new", "try", "var", "byte", "case", "char", "else", "enum", "goto", "long", "null", "this", "true", "void", "with", "break", "catch", "class", "const", "false", "final", "float", "short", "super", "throw", "while", "delete", "double", "export", "import", "native", "public", "return", "static", "switch", "throws", "typeof", "boolean", "default", "extends", "finally", "package", "private", "abstract", "continue", "debugger", "function", "volatile", "interface", "protected", "transient", "implements", "instanceof", "synchronized", "let" }; enum LiteralsType { SpaceFound, AlpahabetFound, NumberFound, HashFound, SlashFound, AsterixFound, BracketFound, QuotationFound, ApostropheFound, Apostrophe2Found, SeparatorFound, BackSlashFound, LiteralsCount }; enum States { Undefined = -1, Start, MayBeKeyWord, Code, MayBeComment, Comment, Comment2, MayBeComment2End, String, String2, String3, MayBeNumber, Separator, StatesCount }; void ScriptHighlighter::createParentheisisInfo(const char& literal, TextBlockData* data, const QString& text) { int pos = text.indexOf(literal); while (pos != -1) { ParenthesisInfo* info = new ParenthesisInfo; info->character = literal; info->position = pos; data->insert(info); pos = text.indexOf(literal, pos + 1); } } void ScriptHighlighter::highlightBlock(const QString& text) { int literal = -1; bool lastWasBackSlash = false; States prevState = (States)previousBlockState(); States state = prevState != Undefined ? (States)prevState : Start; States oldState = Undefined; const States stateMaschine[StatesCount][LiteralsCount] = { // Space Alpahabet Number Hash Slash Asterix, // Bracket, Quotation, Apostrophe, Apostrophe2 Separator, Back Slash { Separator, MayBeKeyWord, MayBeNumber, Separator, MayBeComment, Separator, Separator, String, String2, String3, Separator, Separator }, { Separator, MayBeKeyWord, Code, Separator, MayBeComment, Separator, Separator, String, String2, String3, Separator, Separator }, { Separator, Code, Code, Separator, Separator, Separator, Separator, String, String2, String3, Separator, Separator }, { Separator, Code, MayBeNumber, Code, Comment, Comment2, Code, String, String2, String3, Separator, Code }, { Comment, Comment, Comment, Comment, Comment, Comment, Comment, Comment, Comment, Comment, Comment, Comment }, { Comment2, Comment2, Comment2, Comment2, Comment2, MayBeComment2End, Comment2, Comment2, Comment2, Comment2, Comment2, Comment2 }, { Comment2, Comment2, Comment2, Comment2, Separator, Comment2, Comment2, Comment2, Comment2, Comment2, Comment2, Comment2 }, { String, String, String, String, String, String, String, Separator, String, String, String, String }, { String2, String2, String2, String2, String2, String2, String2, String2, Separator, String2, String2, String2 }, { String3, String3, String3, String3, String3, String3, String3, String3, String3, Separator, String3, String3 }, { Separator, Code, MayBeNumber, Separator, MayBeComment, Separator, Separator, String, String2, String3, Separator, Code }, { Separator, MayBeKeyWord, MayBeNumber, Separator, MayBeComment, Separator, Separator, String, String2, String3, Separator, Separator }, }; QString buffer; setCurrentBlockState(Undefined); if (text.isEmpty()) { if (prevState == Comment2) setCurrentBlockState(Comment2); return; } int i = 0; for (;;) { QChar currentChar = text.at(i); switch (currentChar.toLatin1()) { case ' ': literal = SpaceFound; break; case '/': literal = SlashFound; break; case '*': literal = AsterixFound; break; case '#': literal = HashFound; break; case '\'': literal = ApostropheFound; break; case '\\': literal = BackSlashFound; break; case '"': literal = QuotationFound; break; case '`': literal = Apostrophe2Found; break; case '{': case '[': case '(': case '}': case ']': case ')': literal = BracketFound; break; case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case '0': literal = NumberFound; break; default: if (currentChar.isLetter()) literal = AlpahabetFound; else literal = SeparatorFound; }; lastWasBackSlash = !lastWasBackSlash && currentChar == QLatin1Char('\\'); oldState = state; state = stateMaschine[state][literal]; buffer += currentChar; if (oldState != state) { switch (state) { case MayBeComment: if (oldState == MayBeNumber) { setFormat(i - (buffer.length() - 1), buffer.length() - 1, m_formats[NumberFormat]); } buffer.clear(); buffer += currentChar; break; case String: case String2: case String3: buffer.clear(); buffer += currentChar; break; case MayBeKeyWord: case MayBeNumber: buffer.clear(); buffer += currentChar; break; case Comment2: setCurrentBlockState(Comment2); case Separator: switch (oldState) { case MayBeComment2End: setFormat(i - (buffer.length() - 1), buffer.length(), m_formats[CommentFormat]); setCurrentBlockState(Undefined); buffer.clear(); break; case MayBeKeyWord: if (isKeyWord(buffer.left(buffer.length() - 1))) { setFormat(i - (buffer.length() - 1), buffer.length() - 1, m_formats[KeywordFormat]); } buffer.clear(); break; case MayBeNumber: setFormat(i - (buffer.length() - 1), buffer.length() - 1, m_formats[NumberFormat]); buffer.clear(); case String: case String2: case String3: setFormat(i - (buffer.length() - 1), buffer.length(), m_formats[StringFormat]); buffer.clear(); break; } default: break; } } else if (state == Comment2) { setCurrentBlockState(Comment2); } if (state == Comment || state == Comment2) { setFormat(i - (buffer.length() - 1), buffer.length(), m_formats[CommentFormat]); } if (state == String || state == String2 || state == String3) { setFormat(i - (buffer.length() - 1), buffer.length(), m_formats[StringFormat]); } i++; if (i >= text.length()) break; } if (buffer.length()) { if (state == MayBeKeyWord) { if (isKeyWord(buffer)) setFormat(i - buffer.length(), buffer.length(), m_formats[KeywordFormat]); } else if (state == MayBeNumber) { setFormat(i - buffer.length(), buffer.length(), m_formats[NumberFormat]); } } TextBlockData* data = new TextBlockData; for (int i = 0; i < PARENHEIS_COUNT; ++i) { createParentheisisInfo(parenthesisCharacters[LeftParenthesis][i].toLatin1(), data, text); createParentheisisInfo(parenthesisCharacters[RightParenthesis][i].toLatin1(), data, text); } setCurrentBlockUserData(data); } bool ScriptHighlighter::isKeyWord(const QString& word) { return m_keywords.contains(word); } ScriptHighlighter::ScriptHighlighter(QTextDocument* parent): QSyntaxHighlighter(parent) { for (int i = 0; i < KEYWORDS_COUNT; ++i) { m_keywords.insert(keywords[i]); } if (isColorDark(QPalette().window().color())) { m_formats[NumberFormat].setForeground(QColor("#45c6d1")); m_formats[StringFormat].setForeground(Qt::darkGreen); m_formats[KeywordFormat].setForeground(QColor("#cd5125")); m_formats[CommentFormat].setForeground(QColor("#80807e")); m_formats[CommentFormat].setFontItalic(true); } else { m_formats[NumberFormat].setForeground(QColor("#ff6aad")); m_formats[StringFormat].setForeground(QColor("#b27f40")); m_formats[KeywordFormat].setForeground(QColor("#45c5d5")); m_formats[CommentFormat].setForeground(QColor("#a8aaab")); m_formats[CommentFormat].setFontItalic(true); } } TextBlockData::~TextBlockData() { foreach (ParenthesisInfo* info, m_parentheses) { delete info; } } QVector TextBlockData::parentheses() { return m_parentheses; } void TextBlockData::insert(ParenthesisInfo* info) { int i = 0; while (i < m_parentheses.size() && info->position > m_parentheses.at(i)->position) ++i; m_parentheses.insert(i, info); } } // namespace LimeReport