2017-09-16 16:04:29 +03:00
|
|
|
#include "lrscripthighlighter.h"
|
2018-04-04 00:22:44 +03:00
|
|
|
#include "lrglobal.h"
|
2017-09-16 16:04:29 +03:00
|
|
|
#include <QDebug>
|
2017-09-19 19:05:38 +03:00
|
|
|
#include <QPalette>
|
2017-09-16 16:04:29 +03:00
|
|
|
|
|
|
|
namespace LimeReport{
|
|
|
|
|
2021-06-16 15:05:13 +03:00
|
|
|
#define KEYWORDS_COUNT 60
|
2017-09-16 16:04:29 +03:00
|
|
|
|
|
|
|
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",
|
2021-06-16 15:05:13 +03:00
|
|
|
"synchronized","let"
|
2017-09-16 16:04:29 +03:00
|
|
|
};
|
|
|
|
|
2021-06-16 15:05:13 +03:00
|
|
|
enum LiteralsType {
|
|
|
|
SpaceFound,
|
|
|
|
AlpahabetFound,
|
|
|
|
NumberFound,
|
|
|
|
HashFound,
|
|
|
|
SlashFound,
|
|
|
|
AsterixFound,
|
|
|
|
BracketFound,
|
|
|
|
QuotationFound,
|
|
|
|
ApostropheFound,
|
|
|
|
Apostrophe2Found,
|
|
|
|
SeparatorFound,
|
|
|
|
BackSlashFound,
|
|
|
|
LiteralsCount
|
|
|
|
};
|
|
|
|
|
|
|
|
enum States {
|
2021-06-18 16:04:39 +03:00
|
|
|
Undefined = -1,
|
2021-06-16 15:05:13 +03:00
|
|
|
Start,
|
|
|
|
MayBeKeyWord,
|
|
|
|
Code,
|
|
|
|
MayBeComment,
|
|
|
|
Comment,
|
|
|
|
Comment2,
|
|
|
|
MayBeComment2End,
|
|
|
|
String,
|
|
|
|
String2,
|
|
|
|
String3,
|
|
|
|
MayBeNumber,
|
|
|
|
Separator,
|
|
|
|
StatesCount
|
|
|
|
};
|
2017-09-19 19:05:38 +03:00
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
2017-09-16 16:04:29 +03:00
|
|
|
|
|
|
|
void ScriptHighlighter::highlightBlock(const QString& text)
|
|
|
|
{
|
|
|
|
int literal = -1;
|
|
|
|
bool lastWasBackSlash = false;
|
2021-06-16 15:05:13 +03:00
|
|
|
States prevState = (States)previousBlockState();
|
2021-06-18 16:04:39 +03:00
|
|
|
States state = prevState != Undefined ? (States)prevState : Start;
|
|
|
|
States oldState = Undefined;
|
2021-06-16 15:05:13 +03:00
|
|
|
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},
|
2017-09-16 16:04:29 +03:00
|
|
|
};
|
|
|
|
|
|
|
|
QString buffer;
|
|
|
|
|
2021-06-18 16:04:39 +03:00
|
|
|
setCurrentBlockState(Undefined);
|
2021-06-16 15:05:13 +03:00
|
|
|
|
|
|
|
if (text.isEmpty())
|
|
|
|
{
|
|
|
|
if (prevState == Comment2)
|
|
|
|
setCurrentBlockState(Comment2);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-09-16 16:04:29 +03:00
|
|
|
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;
|
2021-06-16 15:05:13 +03:00
|
|
|
case '`':
|
|
|
|
literal = Apostrophe2Found;
|
|
|
|
break;
|
2017-09-16 16:04:29 +03:00
|
|
|
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];
|
|
|
|
|
2017-09-19 19:05:38 +03:00
|
|
|
buffer += currentChar;
|
|
|
|
|
2021-06-16 15:05:13 +03:00
|
|
|
if (oldState != state) {
|
2017-09-16 16:04:29 +03:00
|
|
|
switch( state ){
|
|
|
|
case MayBeComment:
|
2017-09-19 19:05:38 +03:00
|
|
|
if (oldState == MayBeNumber){
|
|
|
|
setFormat(i-(buffer.length()-1), buffer.length()-1, m_formats[NumberFormat]);
|
|
|
|
}
|
2017-09-16 16:04:29 +03:00
|
|
|
buffer.clear();
|
|
|
|
buffer += currentChar;
|
2017-12-16 18:02:13 +03:00
|
|
|
break;
|
|
|
|
case String:
|
|
|
|
case String2:
|
2021-06-16 15:05:13 +03:00
|
|
|
case String3:
|
2017-12-16 18:02:13 +03:00
|
|
|
buffer.clear();
|
|
|
|
buffer += currentChar;
|
2017-09-16 16:04:29 +03:00
|
|
|
break;
|
2017-09-19 19:05:38 +03:00
|
|
|
case MayBeKeyWord:
|
|
|
|
case MayBeNumber:
|
|
|
|
buffer.clear();
|
2017-09-16 16:04:29 +03:00
|
|
|
buffer += currentChar;
|
|
|
|
break;
|
2017-09-19 19:05:38 +03:00
|
|
|
case Comment2:
|
|
|
|
setCurrentBlockState(Comment2);
|
2017-09-16 16:04:29 +03:00
|
|
|
case Separator:
|
|
|
|
switch(oldState){
|
2017-09-19 19:05:38 +03:00
|
|
|
case MayBeComment2End:
|
|
|
|
setFormat(i-(buffer.length()-1), buffer.length(), m_formats[CommentFormat]);
|
2021-06-18 16:04:39 +03:00
|
|
|
setCurrentBlockState(Undefined);
|
2017-09-19 19:05:38 +03:00
|
|
|
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:
|
2021-06-16 15:05:13 +03:00
|
|
|
case String3:
|
2017-09-19 19:05:38 +03:00
|
|
|
setFormat(i-(buffer.length()-1), buffer.length(), m_formats[StringFormat]);
|
2017-09-16 16:04:29 +03:00
|
|
|
buffer.clear();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
2017-09-19 19:05:38 +03:00
|
|
|
}
|
2021-06-16 15:05:13 +03:00
|
|
|
else if (state == Comment2)
|
|
|
|
{
|
|
|
|
setCurrentBlockState(Comment2);
|
|
|
|
}
|
2017-09-19 19:05:38 +03:00
|
|
|
|
|
|
|
if ( state == Comment || state == Comment2 ){
|
|
|
|
setFormat(i-(buffer.length()-1), buffer.length(), m_formats[CommentFormat]);
|
|
|
|
}
|
|
|
|
|
2021-06-16 15:05:13 +03:00
|
|
|
if ( state == String || state == String2 || state == String3 ){
|
2017-09-19 19:05:38 +03:00
|
|
|
setFormat(i-(buffer.length()-1), buffer.length(), m_formats[StringFormat]);
|
2017-09-16 16:04:29 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
i++;
|
|
|
|
if ( i>= text.length()) break;
|
|
|
|
}
|
2017-09-19 19:05:38 +03:00
|
|
|
|
2021-06-16 15:05:13 +03:00
|
|
|
if (buffer.length())
|
|
|
|
{
|
2021-06-18 16:04:39 +03:00
|
|
|
if (state == MayBeKeyWord)
|
2021-06-16 15:05:13 +03:00
|
|
|
{
|
|
|
|
if (isKeyWord(buffer))
|
2021-06-18 16:04:39 +03:00
|
|
|
setFormat(i - buffer.length(), buffer.length(), m_formats[KeywordFormat]);
|
|
|
|
}
|
|
|
|
else if (state == MayBeNumber)
|
|
|
|
{
|
|
|
|
setFormat(i - buffer.length(), buffer.length(), m_formats[NumberFormat]);
|
2021-06-16 15:05:13 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-09-19 19:05:38 +03:00
|
|
|
TextBlockData *data = new TextBlockData;
|
|
|
|
|
2021-06-18 16:04:39 +03:00
|
|
|
for (int i = 0; i < PARENHEIS_COUNT; ++i) {
|
2017-09-19 19:05:38 +03:00
|
|
|
createParentheisisInfo(parenthesisCharacters[LeftParenthesis][i].toLatin1(), data, text);
|
|
|
|
createParentheisisInfo(parenthesisCharacters[RightParenthesis][i].toLatin1(), data, text);
|
|
|
|
}
|
|
|
|
|
|
|
|
setCurrentBlockUserData(data);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ScriptHighlighter::isKeyWord(const QString& word)
|
|
|
|
{
|
2020-09-17 10:35:48 +03:00
|
|
|
return m_keywords.contains(word);
|
2017-09-19 19:05:38 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
ScriptHighlighter::ScriptHighlighter(QTextDocument* parent):
|
|
|
|
QSyntaxHighlighter(parent)
|
|
|
|
{
|
2020-09-17 10:35:48 +03:00
|
|
|
for(int i=0; i<KEYWORDS_COUNT; ++i){
|
|
|
|
m_keywords.insert(keywords[i]);
|
|
|
|
}
|
2017-09-19 19:05:38 +03:00
|
|
|
|
2021-08-23 08:07:08 +03:00
|
|
|
if ( isColorDark(QPalette().window().color())){
|
2017-09-19 19:05:38 +03:00
|
|
|
m_formats[NumberFormat].setForeground(Qt::darkBlue);
|
|
|
|
m_formats[StringFormat].setForeground(Qt::darkGreen);
|
|
|
|
m_formats[KeywordFormat].setForeground(Qt::darkYellow);
|
|
|
|
m_formats[CommentFormat].setForeground(Qt::darkGreen);
|
|
|
|
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("#a1a4a9"));
|
|
|
|
m_formats[CommentFormat].setFontItalic(true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-03-07 19:46:23 +03:00
|
|
|
TextBlockData::~TextBlockData()
|
|
|
|
{
|
|
|
|
foreach(ParenthesisInfo* info, m_parentheses){
|
|
|
|
delete info;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-09-19 19:05:38 +03:00
|
|
|
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);
|
2017-09-16 16:04:29 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace LimeReport
|