forked from qt-creator/qt-creator
Fixed the incremental scanner for the JS/QML highlighter.
This commit is contained in:
@@ -31,92 +31,28 @@
|
||||
|
||||
#include <QtCore/QSet>
|
||||
#include <QtCore/QtAlgorithms>
|
||||
#include <QtCore/QDebug>
|
||||
|
||||
using namespace SharedTools;
|
||||
|
||||
QSet<QString> QScriptHighlighter::m_keywords;
|
||||
|
||||
QScriptHighlighter::QScriptHighlighter(bool duiEnabled, QTextDocument *parent):
|
||||
QSyntaxHighlighter(parent),
|
||||
m_scanner(m_duiEnabled),
|
||||
m_duiEnabled(duiEnabled)
|
||||
{
|
||||
setFormats(defaultFormats());
|
||||
QVector<QTextCharFormat> rc;
|
||||
rc.resize(NumFormats);
|
||||
rc[NumberFormat].setForeground(Qt::blue);
|
||||
rc[StringFormat].setForeground(Qt::darkGreen);
|
||||
rc[TypeFormat].setForeground(Qt::darkMagenta);
|
||||
rc[KeywordFormat].setForeground(Qt::darkYellow);
|
||||
rc[LabelFormat].setForeground(Qt::darkRed);
|
||||
rc[CommentFormat].setForeground(Qt::red); rc[CommentFormat].setFontItalic(true);
|
||||
rc[PreProcessorFormat].setForeground(Qt::darkBlue);
|
||||
rc[VisualWhitespace].setForeground(Qt::lightGray); // for debug: rc[VisualWhitespace].setBackground(Qt::red);
|
||||
setFormats(rc);
|
||||
|
||||
m_scanner.setKeywords(keywords());
|
||||
}
|
||||
|
||||
QSet<QString> QScriptHighlighter::keywords()
|
||||
{
|
||||
if (m_keywords.isEmpty()) {
|
||||
m_keywords << QLatin1String("Infinity");
|
||||
m_keywords << QLatin1String("NaN");
|
||||
m_keywords << QLatin1String("abstract");
|
||||
m_keywords << QLatin1String("boolean");
|
||||
m_keywords << QLatin1String("break");
|
||||
m_keywords << QLatin1String("byte");
|
||||
m_keywords << QLatin1String("case");
|
||||
m_keywords << QLatin1String("catch");
|
||||
m_keywords << QLatin1String("char");
|
||||
m_keywords << QLatin1String("class");
|
||||
m_keywords << QLatin1String("const");
|
||||
m_keywords << QLatin1String("constructor");
|
||||
m_keywords << QLatin1String("continue");
|
||||
m_keywords << QLatin1String("debugger");
|
||||
m_keywords << QLatin1String("default");
|
||||
m_keywords << QLatin1String("delete");
|
||||
m_keywords << QLatin1String("do");
|
||||
m_keywords << QLatin1String("double");
|
||||
m_keywords << QLatin1String("else");
|
||||
m_keywords << QLatin1String("enum");
|
||||
m_keywords << QLatin1String("export");
|
||||
m_keywords << QLatin1String("extends");
|
||||
m_keywords << QLatin1String("false");
|
||||
m_keywords << QLatin1String("final");
|
||||
m_keywords << QLatin1String("finally");
|
||||
m_keywords << QLatin1String("float");
|
||||
m_keywords << QLatin1String("for");
|
||||
m_keywords << QLatin1String("function");
|
||||
m_keywords << QLatin1String("goto");
|
||||
m_keywords << QLatin1String("if");
|
||||
m_keywords << QLatin1String("implements");
|
||||
m_keywords << QLatin1String("import");
|
||||
m_keywords << QLatin1String("in");
|
||||
m_keywords << QLatin1String("instanceof");
|
||||
m_keywords << QLatin1String("int");
|
||||
m_keywords << QLatin1String("interface");
|
||||
m_keywords << QLatin1String("long");
|
||||
m_keywords << QLatin1String("native");
|
||||
m_keywords << QLatin1String("new");
|
||||
m_keywords << QLatin1String("package");
|
||||
m_keywords << QLatin1String("private");
|
||||
m_keywords << QLatin1String("protected");
|
||||
m_keywords << QLatin1String("public");
|
||||
m_keywords << QLatin1String("return");
|
||||
m_keywords << QLatin1String("short");
|
||||
m_keywords << QLatin1String("static");
|
||||
m_keywords << QLatin1String("super");
|
||||
m_keywords << QLatin1String("switch");
|
||||
m_keywords << QLatin1String("synchronized");
|
||||
m_keywords << QLatin1String("this");
|
||||
m_keywords << QLatin1String("throw");
|
||||
m_keywords << QLatin1String("throws");
|
||||
m_keywords << QLatin1String("transient");
|
||||
m_keywords << QLatin1String("true");
|
||||
m_keywords << QLatin1String("try");
|
||||
m_keywords << QLatin1String("typeof");
|
||||
m_keywords << QLatin1String("undefined");
|
||||
m_keywords << QLatin1String("var");
|
||||
m_keywords << QLatin1String("void");
|
||||
m_keywords << QLatin1String("volatile");
|
||||
m_keywords << QLatin1String("while");
|
||||
m_keywords << QLatin1String("with");
|
||||
}
|
||||
|
||||
return m_keywords;
|
||||
}
|
||||
|
||||
bool QScriptHighlighter::isDuiEnabled() const
|
||||
{ return m_duiEnabled; }
|
||||
|
||||
@@ -125,20 +61,19 @@ void QScriptHighlighter::highlightBlock(const QString &text)
|
||||
m_scanner(onBlockStart(), text);
|
||||
|
||||
QTextCharFormat emptyFormat;
|
||||
foreach (const QScriptIncrementalScanner::Token &token, m_scanner.tokens()) {
|
||||
int lastEnd = 0;
|
||||
const QList<QScriptIncrementalScanner::Token> tokens = m_scanner.tokens();
|
||||
for (int i = 0; i < tokens.size(); ++i) {
|
||||
const QScriptIncrementalScanner::Token token = tokens.at(i);
|
||||
|
||||
if (token.offset != lastEnd)
|
||||
setFormat(lastEnd, token.offset - lastEnd, m_formats[VisualWhitespace]);
|
||||
|
||||
switch (token.kind) {
|
||||
case QScriptIncrementalScanner::Token::Keyword:
|
||||
setFormat(token.offset, token.length, m_formats[KeywordFormat]);
|
||||
break;
|
||||
|
||||
case QScriptIncrementalScanner::Token::Type:
|
||||
setFormat(token.offset, token.length, m_formats[TypeFormat]);
|
||||
break;
|
||||
|
||||
case QScriptIncrementalScanner::Token::Label:
|
||||
setFormat(token.offset, token.length, m_formats[LabelFormat]);
|
||||
break;
|
||||
|
||||
case QScriptIncrementalScanner::Token::String:
|
||||
setFormat(token.offset, token.length, m_formats[StringFormat]);
|
||||
break;
|
||||
@@ -175,44 +110,123 @@ void QScriptHighlighter::highlightBlock(const QString &text)
|
||||
onClosingParenthesis(']', token.offset);
|
||||
break;
|
||||
|
||||
case QScriptIncrementalScanner::Token::PreProcessor:
|
||||
setFormat(token.offset, token.length, m_formats[PreProcessorFormat]);
|
||||
case QScriptIncrementalScanner::Token::Identifier:
|
||||
if (m_duiEnabled && (i + 1 != tokens.size()) && tokens.at(i + 1).kind == QScriptIncrementalScanner::Token::Colon) {
|
||||
setFormat(token.offset, token.length, m_formats[LabelFormat]);
|
||||
} else {
|
||||
const QChar c = text.at(token.offset);
|
||||
|
||||
if (m_duiEnabled && c.isUpper() || !m_duiEnabled && c == QLatin1Char('Q'))
|
||||
setFormat(token.offset, token.length, m_formats[TypeFormat]);
|
||||
else
|
||||
setFormat(token.offset, token.length, emptyFormat);
|
||||
}
|
||||
break;
|
||||
|
||||
case QScriptIncrementalScanner::Token::Empty:
|
||||
default:
|
||||
case QScriptIncrementalScanner::Token::Colon:
|
||||
if (m_duiEnabled && i > 0 && tokens.at(i - 1).kind == QScriptIncrementalScanner::Token::Identifier)
|
||||
setFormat(token.offset, token.length, m_formats[LabelFormat]);
|
||||
else
|
||||
setFormat(token.offset, token.length, emptyFormat);
|
||||
break;
|
||||
|
||||
case QScriptIncrementalScanner::Token::Operator:
|
||||
case QScriptIncrementalScanner::Token::Dot:
|
||||
setFormat(token.offset, token.length, emptyFormat);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
lastEnd = token.end();
|
||||
}
|
||||
|
||||
onBlockEnd(m_scanner.endState(), m_scanner.firstNonSpace());
|
||||
}
|
||||
const int firstNonSpace = m_scanner.firstNonSpace();
|
||||
if (firstNonSpace > lastEnd)
|
||||
setFormat(lastEnd, firstNonSpace - lastEnd, m_formats[VisualWhitespace]);
|
||||
else if (text.length() > lastEnd)
|
||||
setFormat(lastEnd, text.length() - lastEnd, m_formats[VisualWhitespace]);
|
||||
|
||||
const QVector<QTextCharFormat> &QScriptHighlighter::defaultFormats()
|
||||
{
|
||||
static QVector<QTextCharFormat> rc;
|
||||
if (rc.empty()) {
|
||||
rc.resize(NumFormats);
|
||||
rc[NumberFormat].setForeground(Qt::blue);
|
||||
rc[StringFormat].setForeground(Qt::darkGreen);
|
||||
rc[TypeFormat].setForeground(Qt::darkMagenta);
|
||||
rc[KeywordFormat].setForeground(Qt::darkYellow);
|
||||
rc[LabelFormat].setForeground(Qt::darkRed);
|
||||
rc[CommentFormat].setForeground(Qt::red);
|
||||
rc[CommentFormat].setFontItalic(true);
|
||||
rc[PreProcessorFormat].setForeground(Qt::darkBlue);
|
||||
rc[VisualWhitespace].setForeground(Qt::lightGray);
|
||||
}
|
||||
return rc;
|
||||
onBlockEnd(m_scanner.endState(), firstNonSpace);
|
||||
}
|
||||
|
||||
void QScriptHighlighter::setFormats(const QVector<QTextCharFormat> &s)
|
||||
{
|
||||
Q_ASSERT(s.size() == NumFormats);
|
||||
qCopy(s.constBegin(), s.constEnd(), m_formats);
|
||||
}
|
||||
|
||||
QSet<QString> QScriptHighlighter::keywords()
|
||||
{
|
||||
QSet<QString> keywords;
|
||||
|
||||
keywords << QLatin1String("Infinity");
|
||||
keywords << QLatin1String("NaN");
|
||||
keywords << QLatin1String("abstract");
|
||||
keywords << QLatin1String("boolean");
|
||||
keywords << QLatin1String("break");
|
||||
keywords << QLatin1String("byte");
|
||||
keywords << QLatin1String("case");
|
||||
keywords << QLatin1String("catch");
|
||||
keywords << QLatin1String("char");
|
||||
keywords << QLatin1String("class");
|
||||
keywords << QLatin1String("const");
|
||||
keywords << QLatin1String("constructor");
|
||||
keywords << QLatin1String("continue");
|
||||
keywords << QLatin1String("debugger");
|
||||
keywords << QLatin1String("default");
|
||||
keywords << QLatin1String("delete");
|
||||
keywords << QLatin1String("do");
|
||||
keywords << QLatin1String("double");
|
||||
keywords << QLatin1String("else");
|
||||
keywords << QLatin1String("enum");
|
||||
keywords << QLatin1String("export");
|
||||
keywords << QLatin1String("extends");
|
||||
keywords << QLatin1String("false");
|
||||
keywords << QLatin1String("final");
|
||||
keywords << QLatin1String("finally");
|
||||
keywords << QLatin1String("float");
|
||||
keywords << QLatin1String("for");
|
||||
keywords << QLatin1String("function");
|
||||
keywords << QLatin1String("goto");
|
||||
keywords << QLatin1String("if");
|
||||
keywords << QLatin1String("implements");
|
||||
keywords << QLatin1String("import");
|
||||
keywords << QLatin1String("in");
|
||||
keywords << QLatin1String("instanceof");
|
||||
keywords << QLatin1String("int");
|
||||
keywords << QLatin1String("interface");
|
||||
keywords << QLatin1String("long");
|
||||
keywords << QLatin1String("native");
|
||||
keywords << QLatin1String("new");
|
||||
keywords << QLatin1String("package");
|
||||
keywords << QLatin1String("private");
|
||||
keywords << QLatin1String("protected");
|
||||
keywords << QLatin1String("public");
|
||||
keywords << QLatin1String("return");
|
||||
keywords << QLatin1String("short");
|
||||
keywords << QLatin1String("static");
|
||||
keywords << QLatin1String("super");
|
||||
keywords << QLatin1String("switch");
|
||||
keywords << QLatin1String("synchronized");
|
||||
keywords << QLatin1String("this");
|
||||
keywords << QLatin1String("throw");
|
||||
keywords << QLatin1String("throws");
|
||||
keywords << QLatin1String("transient");
|
||||
keywords << QLatin1String("true");
|
||||
keywords << QLatin1String("try");
|
||||
keywords << QLatin1String("typeof");
|
||||
keywords << QLatin1String("undefined");
|
||||
keywords << QLatin1String("var");
|
||||
keywords << QLatin1String("void");
|
||||
keywords << QLatin1String("volatile");
|
||||
keywords << QLatin1String("while");
|
||||
keywords << QLatin1String("with");
|
||||
|
||||
return keywords;
|
||||
}
|
||||
|
||||
int QScriptHighlighter::onBlockStart()
|
||||
{
|
||||
int state = 0;
|
||||
|
||||
@@ -54,12 +54,11 @@ public:
|
||||
|
||||
// MS VC 6 compatible, still.
|
||||
void setFormats(const QVector<QTextCharFormat> &s);
|
||||
static const QVector<QTextCharFormat> &defaultFormats();
|
||||
|
||||
QTextCharFormat labelTextCharFormat() const
|
||||
{ return m_formats[LabelFormat]; }
|
||||
|
||||
static QSet<QString> keywords();
|
||||
QSet<QString> keywords();
|
||||
|
||||
protected:
|
||||
// The functions are notified whenever parentheses are encountered.
|
||||
@@ -74,7 +73,6 @@ protected:
|
||||
QScriptIncrementalScanner m_scanner;
|
||||
|
||||
private:
|
||||
static QSet<QString> m_keywords;
|
||||
bool m_duiEnabled;
|
||||
QTextCharFormat m_formats[NumFormats];
|
||||
};
|
||||
|
||||
@@ -4,8 +4,7 @@
|
||||
|
||||
using namespace SharedTools;
|
||||
|
||||
QScriptIncrementalScanner::QScriptIncrementalScanner(bool duiEnabled):
|
||||
m_duiEnabled(duiEnabled)
|
||||
QScriptIncrementalScanner::QScriptIncrementalScanner()
|
||||
{
|
||||
reset();
|
||||
}
|
||||
@@ -30,9 +29,7 @@ void QScriptIncrementalScanner::operator()(int startState, const QString &text)
|
||||
InputNumber,
|
||||
InputAsterix,
|
||||
InputSlash,
|
||||
InputParen,
|
||||
InputSpace,
|
||||
InputHash,
|
||||
InputQuotation,
|
||||
InputApostrophe,
|
||||
InputSep,
|
||||
@@ -42,13 +39,13 @@ void QScriptIncrementalScanner::operator()(int startState, const QString &text)
|
||||
// states
|
||||
enum {
|
||||
StateStandard,
|
||||
StateCommentStart1,
|
||||
StateCCommentStart2,
|
||||
StateCppCommentStart2,
|
||||
StateCComment,
|
||||
StateCppComment,
|
||||
StateCCommentEnd1,
|
||||
StateCCommentEnd2,
|
||||
StateCommentStart1, // '/'
|
||||
StateCCommentStart2, // '*' after a '/'
|
||||
StateCppCommentStart2, // '/' after a '/'
|
||||
StateCComment, // after a "/*"
|
||||
StateCppComment, // after a "//"
|
||||
StateCCommentEnd1, // '*' in a CppComment
|
||||
StateCCommentEnd2, // '/' after a '*' in a CppComment
|
||||
StateStringStart,
|
||||
StateString,
|
||||
StateStringEnd,
|
||||
@@ -56,32 +53,28 @@ void QScriptIncrementalScanner::operator()(int startState, const QString &text)
|
||||
StateString2,
|
||||
StateString2End,
|
||||
StateNumber,
|
||||
StatePreProcessor,
|
||||
NumStates
|
||||
};
|
||||
|
||||
static const uchar table[NumStates][NumInputs] = {
|
||||
{ StateStandard, StateNumber, StateStandard, StateCommentStart1, StateStandard, StateStandard, StatePreProcessor, StateStringStart, StateString2Start, StateStandard }, // StateStandard
|
||||
{ StateStandard, StateNumber, StateCCommentStart2, StateCppCommentStart2, StateStandard, StateStandard, StatePreProcessor, StateStringStart, StateString2Start, StateStandard }, // StateCommentStart1
|
||||
{ StateCComment, StateCComment, StateCCommentEnd1, StateCComment, StateCComment, StateCComment, StateCComment, StateCComment, StateCComment, StateCComment }, // StateCCommentStart2
|
||||
{ StateCppComment, StateCppComment, StateCppComment, StateCppComment, StateCppComment, StateCppComment, StateCppComment, StateCppComment, StateCppComment, StateCppComment }, // CppCommentStart2
|
||||
{ StateCComment, StateCComment, StateCCommentEnd1, StateCComment, StateCComment, StateCComment, StateCComment, StateCComment, StateCComment, StateCComment }, // StateCComment
|
||||
{ StateCppComment, StateCppComment, StateCppComment, StateCppComment, StateCppComment, StateCppComment, StateCppComment, StateCppComment, StateCppComment, StateCppComment }, // StateCppComment
|
||||
{ StateCComment, StateCComment, StateCCommentEnd1, StateCCommentEnd2, StateCComment, StateCComment, StateCComment, StateCComment, StateCComment, StateCComment }, // StateCCommentEnd1
|
||||
{ StateStandard, StateNumber, StateStandard, StateCommentStart1, StateStandard, StateStandard, StatePreProcessor, StateStringStart, StateString2Start, StateStandard }, // StateCCommentEnd2
|
||||
{ StateString, StateString, StateString, StateString, StateString, StateString, StateString, StateStringEnd, StateString, StateString }, // StateStringStart
|
||||
{ StateString, StateString, StateString, StateString, StateString, StateString, StateString, StateStringEnd, StateString, StateString }, // StateString
|
||||
{ StateStandard, StateStandard, StateStandard, StateCommentStart1, StateStandard, StateStandard, StatePreProcessor, StateStringStart, StateString2Start, StateStandard }, // StateStringEnd
|
||||
{ StateString2, StateString2, StateString2, StateString2, StateString2, StateString2, StateString2, StateString2, StateString2End, StateString2 }, // StateString2Start
|
||||
{ StateString2, StateString2, StateString2, StateString2, StateString2, StateString2, StateString2, StateString2, StateString2End, StateString2 }, // StateString2
|
||||
{ StateStandard, StateStandard, StateStandard, StateCommentStart1, StateStandard, StateStandard, StatePreProcessor, StateStringStart, StateString2Start, StateStandard }, // StateString2End
|
||||
{ StateNumber, StateNumber, StateStandard, StateCommentStart1, StateStandard, StateStandard, StatePreProcessor, StateStringStart, StateString2Start, StateStandard }, // StateNumber
|
||||
{ StatePreProcessor, StateStandard, StateStandard, StateCommentStart1, StateStandard, StateStandard, StatePreProcessor, StateStringStart, StateString2Start, StateStandard } // StatePreProcessor
|
||||
// InputAlpha InputNumber InputAsterix InputSlash InputSpace InputQuotation InputApostrophe InputSep
|
||||
{ StateStandard, StateNumber, StateStandard, StateCommentStart1, StateStandard, StateStringStart, StateString2Start, StateStandard }, // StateStandard
|
||||
{ StateStandard, StateNumber, StateCCommentStart2, StateCppCommentStart2, StateStandard, StateStringStart, StateString2Start, StateStandard }, // StateCommentStart1
|
||||
{ StateCComment, StateCComment, StateCCommentEnd1, StateCComment, StateCComment, StateCComment, StateCComment, StateCComment }, // StateCCommentStart2
|
||||
{ StateCppComment, StateCppComment, StateCppComment, StateCppComment, StateCppComment, StateCppComment, StateCppComment, StateCppComment }, // StateCppCommentStart2
|
||||
{ StateCComment, StateCComment, StateCCommentEnd1, StateCComment, StateCComment, StateCComment, StateCComment, StateCComment }, // StateCComment
|
||||
{ StateCppComment, StateCppComment, StateCppComment, StateCppComment, StateCppComment, StateCppComment, StateCppComment, StateCppComment }, // StateCppComment
|
||||
{ StateCComment, StateCComment, StateCCommentEnd1, StateCCommentEnd2, StateCComment, StateCComment, StateCComment, StateCComment }, // StateCCommentEnd1
|
||||
{ StateStandard, StateNumber, StateStandard, StateCommentStart1, StateStandard, StateStringStart, StateString2Start, StateStandard }, // StateCCommentEnd2
|
||||
{ StateString, StateString, StateString, StateString, StateString, StateStringEnd, StateString, StateString }, // StateStringStart
|
||||
{ StateString, StateString, StateString, StateString, StateString, StateStringEnd, StateString, StateString }, // StateString
|
||||
{ StateStandard, StateStandard, StateStandard, StateCommentStart1, StateStandard, StateStringStart, StateString2Start, StateStandard }, // StateStringEnd
|
||||
{ StateString2, StateString2, StateString2, StateString2, StateString2, StateString2, StateString2End, StateString2 }, // StateString2Start
|
||||
{ StateString2, StateString2, StateString2, StateString2, StateString2, StateString2, StateString2End, StateString2 }, // StateString2
|
||||
{ StateStandard, StateStandard, StateStandard, StateCommentStart1, StateStandard, StateStringStart, StateString2Start, StateStandard }, // StateString2End
|
||||
{ StateNumber, StateNumber, StateStandard, StateCommentStart1, StateStandard, StateStringStart, StateString2Start, StateStandard } // StateNumber
|
||||
};
|
||||
|
||||
QString buffer;
|
||||
buffer.reserve(text.length());
|
||||
|
||||
int state = startState;
|
||||
if (text.isEmpty()) {
|
||||
blockEnd(state, 0);
|
||||
@@ -96,7 +89,6 @@ void QScriptIncrementalScanner::operator()(int startState, const QString &text)
|
||||
static const QString alphabeth = QLatin1String("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ");
|
||||
static const QString mathChars = QString::fromLatin1("xXeE");
|
||||
static const QString numbers = QString::fromLatin1("0123456789");
|
||||
bool questionMark = false;
|
||||
QChar lastChar;
|
||||
|
||||
int firstNonSpace = -1;
|
||||
@@ -104,13 +96,11 @@ void QScriptIncrementalScanner::operator()(int startState, const QString &text)
|
||||
|
||||
forever {
|
||||
const QChar qc = text.at(i);
|
||||
|
||||
bool lookAtBinding = false;
|
||||
const char c = qc.toLatin1();
|
||||
|
||||
if (lastWasBackSlash) {
|
||||
input = InputSep;
|
||||
} else {
|
||||
const char c = qc.toLatin1();
|
||||
switch (c) {
|
||||
case '*':
|
||||
input = InputAsterix;
|
||||
@@ -118,34 +108,6 @@ void QScriptIncrementalScanner::operator()(int startState, const QString &text)
|
||||
case '/':
|
||||
input = InputSlash;
|
||||
break;
|
||||
case '(': case '[': case '{':
|
||||
input = InputParen;
|
||||
if (state == StateStandard
|
||||
|| state == StateNumber
|
||||
|| state == StatePreProcessor
|
||||
|| state == StateCCommentEnd2
|
||||
|| state == StateCCommentEnd1
|
||||
|| state == StateString2End
|
||||
|| state == StateStringEnd
|
||||
)
|
||||
openingParenthesis(c, i);
|
||||
break;
|
||||
case ')': case ']': case '}':
|
||||
input = InputParen;
|
||||
if (state == StateStandard
|
||||
|| state == StateNumber
|
||||
|| state == StatePreProcessor
|
||||
|| state == StateCCommentEnd2
|
||||
|| state == StateCCommentEnd1
|
||||
|| state == StateString2End
|
||||
|| state == StateStringEnd
|
||||
) {
|
||||
closingParenthesis(c, i);
|
||||
}
|
||||
break;
|
||||
case '#':
|
||||
input = InputHash;
|
||||
break;
|
||||
case '"':
|
||||
input = InputQuotation;
|
||||
break;
|
||||
@@ -166,45 +128,14 @@ void QScriptIncrementalScanner::operator()(int startState, const QString &text)
|
||||
input = InputNumber;
|
||||
}
|
||||
break;
|
||||
case ':': {
|
||||
input = InputSep;
|
||||
QChar nextChar = ' ';
|
||||
if (i < text.length() - 1)
|
||||
nextChar = text.at(i + 1);
|
||||
|
||||
if (state == StateStandard && !questionMark && lastChar != ':' && nextChar != ':') {
|
||||
int start = i - 1;
|
||||
|
||||
// skip white spaces
|
||||
for (; start != -1; --start) {
|
||||
if (! text.at(start).isSpace())
|
||||
break;
|
||||
}
|
||||
|
||||
int lastNonSpace = start + 1;
|
||||
|
||||
for (; start != -1; --start) {
|
||||
const QChar ch = text.at(start);
|
||||
if (! (ch.isLetterOrNumber() || ch == QLatin1Char('_') || ch == QLatin1Char('.')))
|
||||
break;
|
||||
}
|
||||
|
||||
++start;
|
||||
|
||||
lookAtBinding = true;
|
||||
|
||||
if (m_duiEnabled && text.midRef(start, lastNonSpace - start) == QLatin1String("id")) {
|
||||
setFormat(start, i - start, Token::Keyword);
|
||||
} else {
|
||||
setFormat(start, i - start, Token::Label);
|
||||
}
|
||||
}
|
||||
case '.':
|
||||
if (state == StateNumber)
|
||||
input = InputNumber;
|
||||
else
|
||||
input = InputSep;
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
if (!questionMark && qc == QLatin1Char('?'))
|
||||
questionMark = true;
|
||||
if (qc.isLetter() || qc == QLatin1Char('_'))
|
||||
if (qc.isLetter() || c == '_')
|
||||
input = InputAlpha;
|
||||
else
|
||||
input = InputSep;
|
||||
@@ -219,23 +150,20 @@ void QScriptIncrementalScanner::operator()(int startState, const QString &text)
|
||||
lastNonSpace = i;
|
||||
}
|
||||
|
||||
lastWasBackSlash = !lastWasBackSlash && qc == QLatin1Char('\\');
|
||||
|
||||
if (input == InputAlpha)
|
||||
buffer += qc;
|
||||
lastWasBackSlash = !lastWasBackSlash && c == '\\';
|
||||
|
||||
state = table[state][input];
|
||||
|
||||
switch (state) {
|
||||
case StateStandard: {
|
||||
setFormat(i, 1, Token::Empty);
|
||||
if (makeLastStandard)
|
||||
setFormat(i - 1, 1, Token::Empty);
|
||||
insertCharToken(i - 1, text.at(i - 1).toAscii());
|
||||
makeLastStandard = false;
|
||||
if (!buffer.isEmpty() && input != InputAlpha ) {
|
||||
if (! lookAtBinding)
|
||||
highlightKeyword(i, buffer);
|
||||
buffer.clear();
|
||||
|
||||
if (input == InputAlpha ) {
|
||||
insertIdentifier(i);
|
||||
} else if (input == InputSep || input == InputAsterix) {
|
||||
insertCharToken(i, c);
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -243,103 +171,82 @@ void QScriptIncrementalScanner::operator()(int startState, const QString &text)
|
||||
|
||||
case StateCommentStart1:
|
||||
if (makeLastStandard)
|
||||
setFormat(i - 1, 1, Token::Empty);
|
||||
insertCharToken(i - 1, text.at(i - 1).toAscii());
|
||||
makeLastStandard = true;
|
||||
buffer.resize(0);
|
||||
break;
|
||||
case StateCCommentStart2:
|
||||
setFormat(i - 1, 2, Token::Comment);
|
||||
makeLastStandard = false;
|
||||
buffer.resize(0);
|
||||
insertComment(i - 1, 2);
|
||||
break;
|
||||
case StateCppCommentStart2:
|
||||
setFormat(i - 1, 2, Token::Comment);
|
||||
insertComment(i - 1, 2);
|
||||
makeLastStandard = false;
|
||||
buffer.resize(0);
|
||||
break;
|
||||
case StateCComment:
|
||||
if (makeLastStandard)
|
||||
setFormat(i - 1, 1, Token::Empty);
|
||||
insertCharToken(i - 1, text.at(i - 1).toAscii());
|
||||
makeLastStandard = false;
|
||||
setFormat(i, 1, Token::Comment);
|
||||
buffer.resize(0);
|
||||
insertComment(i, 1);
|
||||
break;
|
||||
case StateCppComment:
|
||||
if (makeLastStandard)
|
||||
setFormat(i - 1, 1, Token::Empty);
|
||||
insertCharToken(i - 1, text.at(i - 1).toAscii());
|
||||
makeLastStandard = false;
|
||||
setFormat(i, 1, Token::Comment);
|
||||
buffer.resize(0);
|
||||
insertComment(i, 1);
|
||||
break;
|
||||
case StateCCommentEnd1:
|
||||
if (makeLastStandard)
|
||||
setFormat(i - 1, 1, Token::Empty);
|
||||
insertCharToken(i - 1, text.at(i - 1).toAscii());
|
||||
makeLastStandard = false;
|
||||
setFormat(i, 1, Token::Comment);
|
||||
buffer.resize(0);
|
||||
insertComment(i, 1);
|
||||
break;
|
||||
case StateCCommentEnd2:
|
||||
if (makeLastStandard)
|
||||
setFormat(i - 1, 1, Token::Empty);
|
||||
insertCharToken(i - 1, text.at(i - 1).toAscii());
|
||||
makeLastStandard = false;
|
||||
setFormat(i, 1, Token::Comment);
|
||||
buffer.resize(0);
|
||||
insertComment(i, 1);
|
||||
break;
|
||||
case StateStringStart:
|
||||
if (makeLastStandard)
|
||||
setFormat(i - 1, 1, Token::Empty);
|
||||
insertCharToken(i - 1, text.at(i - 1).toAscii());
|
||||
makeLastStandard = false;
|
||||
setFormat(i, 1, Token::Empty);
|
||||
buffer.resize(0);
|
||||
insertString(i);
|
||||
break;
|
||||
case StateString:
|
||||
if (makeLastStandard)
|
||||
setFormat(i - 1, 1, Token::Empty);
|
||||
insertCharToken(i - 1, text.at(i - 1).toAscii());
|
||||
makeLastStandard = false;
|
||||
setFormat(i, 1, Token::String);
|
||||
buffer.resize(0);
|
||||
insertString(i);
|
||||
break;
|
||||
case StateStringEnd:
|
||||
if (makeLastStandard)
|
||||
setFormat(i - 1, 1, Token::Empty);
|
||||
insertCharToken(i - 1, text.at(i - 1).toAscii());
|
||||
makeLastStandard = false;
|
||||
setFormat(i, 1, Token::Empty);
|
||||
buffer.resize(0);
|
||||
insertString(i);
|
||||
break;
|
||||
case StateString2Start:
|
||||
if (makeLastStandard)
|
||||
setFormat(i - 1, 1, Token::Empty);
|
||||
insertCharToken(i - 1, text.at(i - 1).toAscii());
|
||||
makeLastStandard = false;
|
||||
setFormat(i, 1, Token::Empty);
|
||||
buffer.resize(0);
|
||||
insertString(i);
|
||||
break;
|
||||
case StateString2:
|
||||
if (makeLastStandard)
|
||||
setFormat(i - 1, 1, Token::Empty);
|
||||
insertCharToken(i - 1, text.at(i - 1).toAscii());
|
||||
makeLastStandard = false;
|
||||
setFormat(i, 1, Token::String);
|
||||
buffer.resize(0);
|
||||
insertString(i);
|
||||
break;
|
||||
case StateString2End:
|
||||
if (makeLastStandard)
|
||||
setFormat(i - 1, 1, Token::Empty);
|
||||
insertCharToken(i - 1, text.at(i - 1).toAscii());
|
||||
makeLastStandard = false;
|
||||
setFormat(i, 1, Token::Empty);
|
||||
buffer.resize(0);
|
||||
insertString(i);
|
||||
break;
|
||||
case StateNumber:
|
||||
if (makeLastStandard)
|
||||
setFormat(i - 1, 1, Token::Empty);
|
||||
insertCharToken(i - 1, text.at(i - 1).toAscii());
|
||||
makeLastStandard = false;
|
||||
setFormat( i, 1, Token::Number);
|
||||
buffer.resize(0);
|
||||
break;
|
||||
case StatePreProcessor:
|
||||
if (makeLastStandard)
|
||||
setFormat(i - 1, 1, Token::Empty);
|
||||
makeLastStandard = false;
|
||||
setFormat(i, 1, Token::PreProcessor);
|
||||
buffer.resize(0);
|
||||
insertNumber(i);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -349,7 +256,7 @@ void QScriptIncrementalScanner::operator()(int startState, const QString &text)
|
||||
break;
|
||||
}
|
||||
|
||||
highlightKeyword(text.length(), buffer);
|
||||
scanForKeywords(text);
|
||||
|
||||
if (state == StateCComment
|
||||
|| state == StateCCommentEnd1
|
||||
@@ -363,63 +270,63 @@ void QScriptIncrementalScanner::operator()(int startState, const QString &text)
|
||||
blockEnd(state, firstNonSpace);
|
||||
}
|
||||
|
||||
void QScriptIncrementalScanner::highlightKeyword(int currentPos, const QString &buffer)
|
||||
void QScriptIncrementalScanner::insertToken(int start, int length, Token::Kind kind, bool forceNewToken)
|
||||
{
|
||||
if (buffer.isEmpty())
|
||||
return;
|
||||
|
||||
if ((m_duiEnabled && buffer.at(0).isUpper()) || (! m_duiEnabled && buffer.at(0) == QLatin1Char('Q'))) {
|
||||
setFormat(currentPos - buffer.length(), buffer.length(), Token::Type);
|
||||
if (m_tokens.isEmpty() || forceNewToken) {
|
||||
m_tokens.append(Token(start, length, kind));
|
||||
} else {
|
||||
if (m_keywords.contains(buffer))
|
||||
setFormat(currentPos - buffer.length(), buffer.length(), Token::Keyword);
|
||||
Token &lastToken(m_tokens.last());
|
||||
|
||||
if (lastToken.kind == kind && lastToken.end() == start) {
|
||||
lastToken.length += 1;
|
||||
} else {
|
||||
m_tokens.append(Token(start, length, kind));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void QScriptIncrementalScanner::openingParenthesis(char c, int i)
|
||||
void QScriptIncrementalScanner::insertCharToken(int start, const char c)
|
||||
{
|
||||
Token::Kind kind;
|
||||
|
||||
switch (c) {
|
||||
case '(':
|
||||
kind = Token::LeftParenthesis;
|
||||
break;
|
||||
case '!':
|
||||
case '<':
|
||||
case '>':
|
||||
case '+':
|
||||
case '-':
|
||||
case '*':
|
||||
case '/':
|
||||
case '%': kind = Token::Operator; break;
|
||||
|
||||
case '[':
|
||||
kind = Token::LeftBracket;
|
||||
break;
|
||||
case ';': kind = Token::Semicolon; break;
|
||||
case ':': kind = Token::Colon; break;
|
||||
case ',': kind = Token::Comma; break;
|
||||
case '.': kind = Token::Dot; break;
|
||||
|
||||
case '{':
|
||||
kind = Token::LeftBrace;
|
||||
break;
|
||||
case '(': kind = Token::LeftParenthesis; break;
|
||||
case ')': kind = Token::RightParenthesis; break;
|
||||
case '{': kind = Token::LeftBrace; break;
|
||||
case '}': kind = Token::RightBrace; break;
|
||||
case '[': kind = Token::LeftBracket; break;
|
||||
case ']': kind = Token::RightBracket; break;
|
||||
|
||||
default:
|
||||
return;
|
||||
default: kind = Token::Identifier; break;
|
||||
}
|
||||
|
||||
m_tokens.append(Token(i, 1, kind));
|
||||
insertToken(start, 1, kind, true);
|
||||
}
|
||||
|
||||
void QScriptIncrementalScanner::closingParenthesis(char c, int i)
|
||||
void QScriptIncrementalScanner::scanForKeywords(const QString &text)
|
||||
{
|
||||
Token::Kind kind;
|
||||
for (int i = 0; i < m_tokens.length(); ++i) {
|
||||
Token &t(m_tokens[i]);
|
||||
|
||||
switch (c) {
|
||||
case ')':
|
||||
kind = Token::RightParenthesis;
|
||||
break;
|
||||
if (t.kind != Token::Identifier)
|
||||
continue;
|
||||
|
||||
case ']':
|
||||
kind = Token::RightBracket;
|
||||
break;
|
||||
|
||||
case '}':
|
||||
kind = Token::RightBrace;
|
||||
break;
|
||||
|
||||
default:
|
||||
return;
|
||||
const QString id = text.mid(t.offset, t.length);
|
||||
if (m_keywords.contains(id))
|
||||
t.kind = Token::Keyword;
|
||||
}
|
||||
|
||||
m_tokens.append(Token(i, 1, kind));
|
||||
}
|
||||
|
||||
@@ -15,10 +15,8 @@ public:
|
||||
int offset;
|
||||
int length;
|
||||
enum Kind {
|
||||
Empty,
|
||||
Keyword,
|
||||
Type,
|
||||
Label,
|
||||
Identifier,
|
||||
String,
|
||||
Comment,
|
||||
Number,
|
||||
@@ -28,18 +26,23 @@ public:
|
||||
RightBrace,
|
||||
LeftBracket,
|
||||
RightBracket,
|
||||
PreProcessor
|
||||
Operator,
|
||||
Semicolon,
|
||||
Colon,
|
||||
Comma,
|
||||
Dot
|
||||
} kind;
|
||||
|
||||
Token(int o, int l, Kind k): offset(o), length(l), kind(k) {}
|
||||
inline Token(int o, int l, Kind k): offset(o), length(l), kind(k) {}
|
||||
inline int end() const { return offset + length; }
|
||||
};
|
||||
|
||||
public:
|
||||
QScriptIncrementalScanner(bool duiEnabled = false);
|
||||
QScriptIncrementalScanner();
|
||||
virtual ~QScriptIncrementalScanner();
|
||||
|
||||
void setKeywords(const QSet<QString> &keywords)
|
||||
{ m_keywords = keywords; }
|
||||
void setKeywords(const QSet<QString> keywords)
|
||||
{ m_keywords = keywords;; }
|
||||
|
||||
void reset();
|
||||
|
||||
@@ -57,15 +60,20 @@ public:
|
||||
private:
|
||||
void blockEnd(int state, int firstNonSpace)
|
||||
{ m_endState = state; m_firstNonSpace = firstNonSpace; }
|
||||
void setFormat(int start, int count, Token::Kind kind)
|
||||
{ m_tokens.append(Token(start, count, kind)); }
|
||||
void highlightKeyword(int currentPos, const QString &buffer);
|
||||
void openingParenthesis(char c, int i);
|
||||
void closingParenthesis(char c, int i);
|
||||
void insertString(int start)
|
||||
{ insertToken(start, 1, Token::String, false); }
|
||||
void insertComment(int start, int length)
|
||||
{ insertToken(start, length, Token::Comment, false); }
|
||||
void insertCharToken(int start, const char c);
|
||||
void insertIdentifier(int start)
|
||||
{ insertToken(start, 1, Token::Identifier, false); }
|
||||
void insertNumber(int start)
|
||||
{ insertToken(start, 1, Token::Number, false); }
|
||||
void insertToken(int start, int length, Token::Kind kind, bool forceNewToken);
|
||||
void scanForKeywords(const QString &text);
|
||||
|
||||
private:
|
||||
QSet<QString> m_keywords;
|
||||
bool m_duiEnabled;
|
||||
int m_endState;
|
||||
int m_firstNonSpace;
|
||||
QList<QScriptIncrementalScanner::Token> m_tokens;
|
||||
|
||||
@@ -33,13 +33,22 @@
|
||||
#include <QMainWindow>
|
||||
#include <QApplication>
|
||||
|
||||
QString presetText = "import Qt 4.6\n"
|
||||
"\n"
|
||||
"Item {\n"
|
||||
" id: Zoo\n"
|
||||
" width: 1 + -1*3\n"
|
||||
"}\n";
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
QApplication app(argc, argv);
|
||||
QMainWindow mw;
|
||||
|
||||
QTextEdit *textEdit = new QTextEdit;
|
||||
new SharedTools::QScriptHighlighter(textEdit->document());
|
||||
if (!presetText.isEmpty())
|
||||
textEdit->setText(presetText);
|
||||
new SharedTools::QScriptHighlighter(true, textEdit->document());
|
||||
mw.setCentralWidget(textEdit);
|
||||
mw.show();
|
||||
return app.exec();
|
||||
|
||||
Reference in New Issue
Block a user