diff --git a/src/shared/qscripthighlighter/qscripthighlighter.cpp b/src/shared/qscripthighlighter/qscripthighlighter.cpp index e96dd4146ce58077528ba3f79ff22cc651a0d28d..714e2189803be426f10356764f260c0c5ed6772e 100644 --- a/src/shared/qscripthighlighter/qscripthighlighter.cpp +++ b/src/shared/qscripthighlighter/qscripthighlighter.cpp @@ -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; diff --git a/src/shared/qscripthighlighter/qscripthighlighter.h b/src/shared/qscripthighlighter/qscripthighlighter.h index c9a66faeb59ed1004ab30b40c98815674c3863fc..46106fde538c7c9d0a50192bb96e020a567f24c8 100644 --- a/src/shared/qscripthighlighter/qscripthighlighter.h +++ b/src/shared/qscripthighlighter/qscripthighlighter.h @@ -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]; }; diff --git a/src/shared/qscripthighlighter/qscriptincrementalscanner.cpp b/src/shared/qscripthighlighter/qscriptincrementalscanner.cpp index 8aecb1f5683e2e3629fdc531e416b529e31df3b9..851110f6004fa8cdd26c39693f3dd257a391ce38 100644 --- a/src/shared/qscripthighlighter/qscriptincrementalscanner.cpp +++ b/src/shared/qscripthighlighter/qscriptincrementalscanner.cpp @@ -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); - makeLastStandard = false; - setFormat( i, 1, Token::Number); - buffer.resize(0); - break; - case StatePreProcessor: - if (makeLastStandard) - setFormat(i - 1, 1, Token::Empty); + insertCharToken(i - 1, text.at(i - 1).toAscii()); 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 '[': - kind = Token::LeftBracket; - break; - - case '{': - kind = Token::LeftBrace; - break; - - default: - return; + case '!': + case '<': + case '>': + case '+': + case '-': + case '*': + case '/': + case '%': kind = Token::Operator; break; + + case ';': kind = Token::Semicolon; break; + case ':': kind = Token::Colon; break; + case ',': kind = Token::Comma; break; + case '.': kind = Token::Dot; 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: 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; - - switch (c) { - case ')': - kind = Token::RightParenthesis; - break; + for (int i = 0; i < m_tokens.length(); ++i) { + Token &t(m_tokens[i]); - case ']': - kind = Token::RightBracket; - break; - - case '}': - kind = Token::RightBrace; - break; + if (t.kind != Token::Identifier) + continue; - 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)); } diff --git a/src/shared/qscripthighlighter/qscriptincrementalscanner.h b/src/shared/qscripthighlighter/qscriptincrementalscanner.h index 4164db431387e73899201cf02b289168bc4372a8..531a37464eeb11a2a84d598f4068ec88879aaf4d 100644 --- a/src/shared/qscripthighlighter/qscriptincrementalscanner.h +++ b/src/shared/qscripthighlighter/qscriptincrementalscanner.h @@ -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; diff --git a/src/shared/qscripthighlighter/test/main.cpp b/src/shared/qscripthighlighter/test/main.cpp index 749fa4876dd694aa49a726a0a4b0aba74af3df61..5f955e3243e0d7b6131c2f889025dd8b208edec0 100644 --- a/src/shared/qscripthighlighter/test/main.cpp +++ b/src/shared/qscripthighlighter/test/main.cpp @@ -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();