mirror of
				https://github.com/fralx/LimeReport.git
				synced 2025-10-31 13:21:22 +03:00 
			
		
		
		
	
		
			
				
	
	
		
			307 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			307 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| #include "lrscripthighlighter.h"
 | |
| 
 | |
| #include "lrglobal.h"
 | |
| 
 | |
| #include <QDebug>
 | |
| #include <QPalette>
 | |
| 
 | |
| 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<ParenthesisInfo*> 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
 |