tools/designer/src/lib/shared/qscripthighlighter.cpp
changeset 0 1918ee327afb
child 4 3b1da2848fc7
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the Qt Designer of the Qt Toolkit.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    15 **
       
    16 ** GNU Lesser General Public License Usage
       
    17 ** Alternatively, this file may be used under the terms of the GNU Lesser
       
    18 ** General Public License version 2.1 as published by the Free Software
       
    19 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    20 ** packaging of this file.  Please review the following information to
       
    21 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    23 **
       
    24 ** In addition, as a special exception, Nokia gives you certain additional
       
    25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    38 ** $QT_END_LICENSE$
       
    39 **
       
    40 ****************************************************************************/
       
    41 
       
    42 #include "qscripthighlighter_p.h"
       
    43 
       
    44 #include <QtCore/QSet>
       
    45 
       
    46 QT_BEGIN_NAMESPACE
       
    47 
       
    48 static const QSet<QString> &qscriptKeywords() {
       
    49     static QSet<QString> keywords;
       
    50     if (keywords.empty()) {
       
    51         keywords.insert(QLatin1String("Infinity"));
       
    52         keywords.insert(QLatin1String("NaN"));
       
    53         keywords.insert(QLatin1String("abstract"));
       
    54         keywords.insert(QLatin1String("boolean"));
       
    55         keywords.insert(QLatin1String("break"));
       
    56         keywords.insert(QLatin1String("byte"));
       
    57         keywords.insert(QLatin1String("case"));
       
    58         keywords.insert(QLatin1String("catch"));
       
    59         keywords.insert(QLatin1String("char"));
       
    60         keywords.insert(QLatin1String("class"));
       
    61         keywords.insert(QLatin1String("const"));
       
    62         keywords.insert(QLatin1String("constructor"));
       
    63         keywords.insert(QLatin1String("continue"));
       
    64         keywords.insert(QLatin1String("debugger"));
       
    65         keywords.insert(QLatin1String("default"));
       
    66         keywords.insert(QLatin1String("delete"));
       
    67         keywords.insert(QLatin1String("do"));
       
    68         keywords.insert(QLatin1String("double"));
       
    69         keywords.insert(QLatin1String("else"));
       
    70         keywords.insert(QLatin1String("enum"));
       
    71         keywords.insert(QLatin1String("export"));
       
    72         keywords.insert(QLatin1String("extends"));
       
    73         keywords.insert(QLatin1String("false"));
       
    74         keywords.insert(QLatin1String("final"));
       
    75         keywords.insert(QLatin1String("finally"));
       
    76         keywords.insert(QLatin1String("float"));
       
    77         keywords.insert(QLatin1String("for"));
       
    78         keywords.insert(QLatin1String("function"));
       
    79         keywords.insert(QLatin1String("goto"));
       
    80         keywords.insert(QLatin1String("if"));
       
    81         keywords.insert(QLatin1String("implements"));
       
    82         keywords.insert(QLatin1String("import"));
       
    83         keywords.insert(QLatin1String("in"));
       
    84         keywords.insert(QLatin1String("instanceof"));
       
    85         keywords.insert(QLatin1String("int"));
       
    86         keywords.insert(QLatin1String("interface"));
       
    87         keywords.insert(QLatin1String("long"));
       
    88         keywords.insert(QLatin1String("native"));
       
    89         keywords.insert(QLatin1String("new"));
       
    90         keywords.insert(QLatin1String("package"));
       
    91         keywords.insert(QLatin1String("private"));
       
    92         keywords.insert(QLatin1String("protected"));
       
    93         keywords.insert(QLatin1String("public"));
       
    94         keywords.insert(QLatin1String("return"));
       
    95         keywords.insert(QLatin1String("short"));
       
    96         keywords.insert(QLatin1String("static"));
       
    97         keywords.insert(QLatin1String("super"));
       
    98         keywords.insert(QLatin1String("switch"));
       
    99         keywords.insert(QLatin1String("synchronized"));
       
   100         keywords.insert(QLatin1String("this"));
       
   101         keywords.insert(QLatin1String("throw"));
       
   102         keywords.insert(QLatin1String("throws"));
       
   103         keywords.insert(QLatin1String("transient"));
       
   104         keywords.insert(QLatin1String("true"));
       
   105         keywords.insert(QLatin1String("try"));
       
   106         keywords.insert(QLatin1String("typeof"));
       
   107         keywords.insert(QLatin1String("undefined"));
       
   108         keywords.insert(QLatin1String("var"));
       
   109         keywords.insert(QLatin1String("void"));
       
   110         keywords.insert(QLatin1String("volatile"));
       
   111         keywords.insert(QLatin1String("while"));
       
   112         keywords.insert(QLatin1String("with"));    // end
       
   113     }
       
   114     return keywords;
       
   115 }
       
   116 
       
   117 static QSet<QChar> alphaChars() {
       
   118     QSet<QChar> rc;
       
   119     const QString alpha = QLatin1String("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ");
       
   120     foreach (QChar chr, alpha)
       
   121         rc.insert(chr);
       
   122     return rc;
       
   123 }
       
   124 
       
   125 namespace qdesigner_internal {
       
   126 
       
   127 QScriptHighlighter::QScriptHighlighter(QTextDocument *parent)
       
   128     : QSyntaxHighlighter(parent)
       
   129 {
       
   130     m_numberFormat.setForeground(Qt::blue);
       
   131     m_stringFormat.setForeground(Qt::darkGreen);
       
   132     m_typeFormat.setForeground(Qt::darkMagenta);
       
   133     m_keywordFormat.setForeground(Qt::darkYellow);
       
   134     m_labelFormat.setForeground(Qt::darkRed);
       
   135     m_commentFormat.setForeground(Qt::red);
       
   136     //m_commentFormat.setFontFamily("times");
       
   137     m_commentFormat.setFontItalic(true);
       
   138     m_preProcessorFormat.setForeground(Qt::darkBlue);
       
   139 }
       
   140 
       
   141 void QScriptHighlighter::highlightBlock(const QString &text)
       
   142 {
       
   143     // states
       
   144     enum {
       
   145         StateStandard,
       
   146         StateCommentStart1,
       
   147         StateCCommentStart2,
       
   148         StateCppCommentStart2,
       
   149         StateCComment,
       
   150         StateCppComment,
       
   151         StateCCommentEnd1,
       
   152         StateCCommentEnd2,
       
   153         StateStringStart,
       
   154         StateString,
       
   155         StateStringEnd,
       
   156         StateString2Start,
       
   157         StateString2,
       
   158         StateString2End,
       
   159         StateNumber,
       
   160         StatePreProcessor,
       
   161         NumStates
       
   162     };
       
   163     // tokens
       
   164     enum {
       
   165         InputAlpha,
       
   166         InputNumber,
       
   167         InputAsterix,
       
   168         InputSlash,
       
   169         InputParen,
       
   170         InputSpace,
       
   171         InputHash,
       
   172         InputQuotation,
       
   173         InputApostrophe,
       
   174         InputSep,
       
   175         NumInputs
       
   176     };
       
   177 
       
   178     static const uchar table[NumStates][NumInputs] = {
       
   179         { StateStandard,      StateNumber,     StateStandard,       StateCommentStart1,    StateStandard,   StateStandard,   StatePreProcessor, StateStringStart, StateString2Start, StateStandard }, // StateStandard
       
   180         { StateStandard,      StateNumber,   StateCCommentStart2, StateCppCommentStart2, StateStandard,   StateStandard,   StatePreProcessor, StateStringStart, StateString2Start, StateStandard }, // StateCommentStart1
       
   181         { StateCComment,      StateCComment,   StateCCommentEnd1,   StateCComment,         StateCComment,   StateCComment,   StateCComment,     StateCComment,    StateCComment,     StateCComment }, // StateCCommentStart2
       
   182         { StateCppComment,    StateCppComment, StateCppComment,     StateCppComment,       StateCppComment, StateCppComment, StateCppComment,   StateCppComment,  StateCppComment,   StateCppComment }, // CppCommentStart2
       
   183         { StateCComment,      StateCComment,   StateCCommentEnd1,   StateCComment,         StateCComment,   StateCComment,   StateCComment,     StateCComment,    StateCComment,     StateCComment }, // StateCComment
       
   184         { StateCppComment,    StateCppComment, StateCppComment,     StateCppComment,       StateCppComment, StateCppComment, StateCppComment,   StateCppComment,  StateCppComment,   StateCppComment }, // StateCppComment
       
   185         { StateCComment,      StateCComment,   StateCCommentEnd1,   StateCCommentEnd2,     StateCComment,   StateCComment,   StateCComment,     StateCComment,    StateCComment,     StateCComment }, // StateCCommentEnd1
       
   186         { StateStandard,      StateNumber,     StateStandard,       StateCommentStart1,    StateStandard,   StateStandard,   StatePreProcessor, StateStringStart, StateString2Start, StateStandard }, // StateCCommentEnd2
       
   187         { StateString,        StateString,     StateString,         StateString,           StateString,     StateString,     StateString,       StateStringEnd,   StateString,       StateString }, // StateStringStart
       
   188         { StateString,        StateString,     StateString,         StateString,           StateString,     StateString,     StateString,       StateStringEnd,   StateString,       StateString }, // StateString
       
   189         { StateStandard,      StateStandard,   StateStandard,       StateCommentStart1,    StateStandard,   StateStandard,   StatePreProcessor, StateStringStart, StateString2Start, StateStandard }, // StateStringEnd
       
   190         { StateString2,       StateString2,    StateString2,        StateString2,          StateString2,    StateString2,    StateString2,      StateString2,     StateString2End,   StateString2 }, // StateString2Start
       
   191         { StateString2,       StateString2,    StateString2,        StateString2,          StateString2,    StateString2,    StateString2,      StateString2,     StateString2End,   StateString2 }, // StateString2
       
   192         { StateStandard,      StateStandard,   StateStandard,       StateCommentStart1,    StateStandard,   StateStandard,   StatePreProcessor, StateStringStart, StateString2Start, StateStandard }, // StateString2End
       
   193         { StateNumber,        StateNumber,     StateStandard,       StateCommentStart1,    StateStandard,   StateStandard,   StatePreProcessor, StateStringStart, StateString2Start, StateStandard }, // StateNumber
       
   194         { StatePreProcessor,  StateStandard,   StateStandard,       StateCommentStart1,    StateStandard,   StateStandard,   StatePreProcessor, StateStringStart, StateString2Start, StateStandard } // StatePreProcessor
       
   195     };
       
   196 
       
   197     QString buffer;
       
   198     buffer.reserve(text.length());
       
   199     QTextCharFormat emptyFormat;
       
   200 
       
   201     int state = StateStandard;
       
   202     const int previousState = previousBlockState();
       
   203     if (previousState != -1)
       
   204         state = previousState;
       
   205 
       
   206     if (text.isEmpty()) {
       
   207         setCurrentBlockState(previousState);
       
   208         return;
       
   209     }
       
   210 
       
   211     int input = -1;
       
   212     int i = 0;
       
   213     bool lastWasBackSlash = false;
       
   214     bool makeLastStandard = false;
       
   215 
       
   216     static const QSet<QChar> alphabeth = alphaChars();
       
   217     static const QString mathChars = QString::fromLatin1("xXeE");
       
   218     static const QString numbers = QString::fromLatin1("0123456789");
       
   219     bool questionMark = false;
       
   220     QChar lastChar;
       
   221     QString firstWord;
       
   222     forever {
       
   223         const QChar c = text.at(i);
       
   224 
       
   225         if (lastWasBackSlash) {
       
   226             input = InputSep;
       
   227         } else {
       
   228             switch (c.toLatin1()) {
       
   229                 case '*':
       
   230                     input = InputAsterix;
       
   231                     break;
       
   232                 case '/':
       
   233                     input = InputSlash;
       
   234                     break;
       
   235                 case '(': case '[': case '{':
       
   236                     input = InputParen;
       
   237                     if (state == StateStandard
       
   238                         || state == StateNumber
       
   239                         || state == StatePreProcessor
       
   240                         || state == StateCCommentEnd2
       
   241                         || state == StateCCommentEnd1
       
   242                         || state == StateString2End
       
   243                         || state == StateStringEnd
       
   244                        )
       
   245                         //blockData->parentheses << Parenthesis(Parenthesis::Open, c, i);
       
   246                     break;
       
   247                 case ')': case ']': case '}':
       
   248                     input = InputParen;
       
   249                     if (state == StateStandard
       
   250                         || state == StateNumber
       
   251                         || state == StatePreProcessor
       
   252                         || state == StateCCommentEnd2
       
   253                         || state == StateCCommentEnd1
       
   254                         || state == StateString2End
       
   255                         || state == StateStringEnd
       
   256                        ) {
       
   257                         //blockData->parentheses << Parenthesis(Parenthesis::Closed, c, i);
       
   258                     }
       
   259                     break;
       
   260                 case '#':
       
   261                     input = InputHash;
       
   262                     break;
       
   263                 case '"':
       
   264                     input = InputQuotation;
       
   265                     break;
       
   266                 case '\'':
       
   267                     input = InputApostrophe;
       
   268                     break;
       
   269                 case ' ':
       
   270                     input = InputSpace;
       
   271                     break;
       
   272                 case '1': case '2': case '3': case '4': case '5':
       
   273                 case '6': case '7': case '8': case '9': case '0':
       
   274                     if (alphabeth.contains(lastChar)
       
   275                         && (!mathChars.contains(lastChar) || !numbers.contains(text.at(i - 1)))) {
       
   276                         input = InputAlpha;
       
   277                     } else {
       
   278                         if (input == InputAlpha && numbers.contains(lastChar))
       
   279                             input = InputAlpha;
       
   280                         else
       
   281                             input = InputNumber;
       
   282                     }
       
   283                     break;
       
   284                 case ':': {
       
   285                               input = InputAlpha;
       
   286                               QChar nextChar = QLatin1Char(' ');
       
   287                               if (i < text.length() - 1)
       
   288                                   nextChar = text.at(i + 1);
       
   289                               if (state == StateStandard && !questionMark &&
       
   290                                   lastChar != QLatin1Char(':') && nextChar != QLatin1Char(':')) {
       
   291                                   for (int j = 0; j < i; ++j) {
       
   292                                       if (format(j) == emptyFormat)
       
   293                                           setFormat(j, 1, m_labelFormat);
       
   294                                   }
       
   295                               }
       
   296                               break;
       
   297                           }
       
   298                 default: {
       
   299                              if (!questionMark && c == QLatin1Char('?'))
       
   300                                  questionMark = true;
       
   301                              if (c.isLetter() || c == QLatin1Char('_'))
       
   302                                  input = InputAlpha;
       
   303                              else
       
   304                                  input = InputSep;
       
   305                          } break;
       
   306             }
       
   307         }
       
   308 
       
   309         lastWasBackSlash = !lastWasBackSlash && c == QLatin1Char('\\');
       
   310 
       
   311         if (input == InputAlpha)
       
   312             buffer += c;
       
   313 
       
   314         state = table[state][input];
       
   315 
       
   316         switch (state) {
       
   317             case StateStandard: {
       
   318                                     setFormat(i, 1, emptyFormat);
       
   319                                     if (makeLastStandard)
       
   320                                         setFormat(i - 1, 1, emptyFormat);
       
   321                                     makeLastStandard = false;
       
   322                                     if (!buffer.isEmpty() && input != InputAlpha ) {
       
   323                                         highlightKeyword(i, buffer);
       
   324                                         buffer.clear();
       
   325                                     }
       
   326                                 } break;
       
   327             case StateCommentStart1:
       
   328                                 if (makeLastStandard)
       
   329                                     setFormat(i - 1, 1, emptyFormat);
       
   330                                 makeLastStandard = true;
       
   331                                 buffer.resize(0);
       
   332                                 break;
       
   333             case StateCCommentStart2:
       
   334                                 setFormat(i - 1, 2, m_commentFormat);
       
   335                                 makeLastStandard = false;
       
   336                                 buffer.resize(0);
       
   337                                 break;
       
   338             case StateCppCommentStart2:
       
   339                                 setFormat(i - 1, 2, m_commentFormat);
       
   340                                 makeLastStandard = false;
       
   341                                 buffer.resize(0);
       
   342                                 break;
       
   343             case StateCComment:
       
   344                                 if (makeLastStandard)
       
   345                                     setFormat(i - 1, 1, emptyFormat);
       
   346                                 makeLastStandard = false;
       
   347                                 setFormat(i, 1, m_commentFormat);
       
   348                                 buffer.resize(0);
       
   349                                 break;
       
   350             case StateCppComment:
       
   351                                 if (makeLastStandard)
       
   352                                     setFormat(i - 1, 1, emptyFormat);
       
   353                                 makeLastStandard = false;
       
   354                                 setFormat(i, 1, m_commentFormat);
       
   355                                 buffer.resize(0);
       
   356                                 break;
       
   357             case StateCCommentEnd1:
       
   358                                 if (makeLastStandard)
       
   359                                     setFormat(i - 1, 1, emptyFormat);
       
   360                                 makeLastStandard = false;
       
   361                                 setFormat(i, 1, m_commentFormat);
       
   362                                 buffer.resize(0);
       
   363                                 break;
       
   364             case StateCCommentEnd2:
       
   365                                 if (makeLastStandard)
       
   366                                     setFormat(i - 1, 1, emptyFormat);
       
   367                                 makeLastStandard = false;
       
   368                                 setFormat(i, 1, m_commentFormat);
       
   369                                 buffer.resize(0);
       
   370                                 break;
       
   371             case StateStringStart:
       
   372                                 if (makeLastStandard)
       
   373                                     setFormat(i - 1, 1, emptyFormat);
       
   374                                 makeLastStandard = false;
       
   375                                 setFormat(i, 1, emptyFormat);
       
   376                                 buffer.resize(0);
       
   377                                 break;
       
   378             case StateString:
       
   379                                 if (makeLastStandard)
       
   380                                     setFormat(i - 1, 1, emptyFormat);
       
   381                                 makeLastStandard = false;
       
   382                                 setFormat(i, 1, m_stringFormat);
       
   383                                 buffer.resize(0);
       
   384                                 break;
       
   385             case StateStringEnd:
       
   386                                 if (makeLastStandard)
       
   387                                     setFormat(i - 1, 1, emptyFormat);
       
   388                                 makeLastStandard = false;
       
   389                                 setFormat(i, 1, emptyFormat);
       
   390                                 buffer.resize(0);
       
   391                                 break;
       
   392             case StateString2Start:
       
   393                                 if (makeLastStandard)
       
   394                                     setFormat(i - 1, 1, emptyFormat);
       
   395                                 makeLastStandard = false;
       
   396                                 setFormat(i, 1, emptyFormat);
       
   397                                 buffer.resize(0);
       
   398                                 break;
       
   399             case StateString2:
       
   400                                 if (makeLastStandard)
       
   401                                     setFormat(i - 1, 1, emptyFormat);
       
   402                                 makeLastStandard = false;
       
   403                                 setFormat(i, 1, m_stringFormat);
       
   404                                 buffer.resize(0);
       
   405                                 break;
       
   406             case StateString2End:
       
   407                                 if (makeLastStandard)
       
   408                                     setFormat(i - 1, 1, emptyFormat);
       
   409                                 makeLastStandard = false;
       
   410                                 setFormat(i, 1, emptyFormat);
       
   411                                 buffer.resize(0);
       
   412                                 break;
       
   413             case StateNumber:
       
   414                                 if (makeLastStandard)
       
   415                                     setFormat(i - 1, 1, emptyFormat);
       
   416                                 makeLastStandard = false;
       
   417                                 setFormat( i, 1, m_numberFormat);
       
   418                                 buffer.resize(0);
       
   419                                 break;
       
   420             case StatePreProcessor:
       
   421                                 if (makeLastStandard)
       
   422                                     setFormat(i - 1, 1, emptyFormat);
       
   423                                 makeLastStandard = false;
       
   424                                 setFormat(i, 1, m_preProcessorFormat);
       
   425                                 buffer.resize(0);
       
   426                                 break;
       
   427         }
       
   428 
       
   429         lastChar = c;
       
   430         i++;
       
   431         if (i >= text.length())
       
   432             break;
       
   433     }
       
   434 
       
   435     highlightKeyword(text.length(), buffer);
       
   436 
       
   437     if (state == StateCComment
       
   438         || state == StateCCommentEnd1
       
   439         || state == StateCCommentStart2
       
   440        ) {
       
   441         state = StateCComment;
       
   442     } else if (state == StateString) {
       
   443         state = StateString;
       
   444     } else if (state == StateString2) {
       
   445         state =  StateString2;
       
   446     } else {
       
   447         state = StateStandard;
       
   448     }
       
   449 
       
   450     setCurrentBlockState(state);
       
   451 }
       
   452 
       
   453 void QScriptHighlighter::highlightKeyword(int currentPos, const QString &buffer)
       
   454 {
       
   455     if (buffer.isEmpty())
       
   456         return;
       
   457 
       
   458     if (buffer.at(0) == QLatin1Char('Q')) {
       
   459         setFormat(currentPos - buffer.length(), buffer.length(), m_typeFormat);
       
   460     } else {
       
   461         if (qscriptKeywords().contains(buffer)) {
       
   462             setFormat(currentPos - buffer.length(), buffer.length(), m_keywordFormat);
       
   463         }
       
   464     }
       
   465 }
       
   466 }
       
   467 
       
   468 QT_END_NAMESPACE