source: trunk/src/scripttools/debugging/qscriptsyntaxhighlighter.cpp@ 477

Last change on this file since 477 was 2, checked in by Dmitry A. Kuminov, 16 years ago

Initially imported qt-all-opensource-src-4.5.1 from Trolltech.

File size: 22.4 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4** Contact: Qt Software Information ([email protected])
5**
6** This file is part of the QtSCriptTools module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial Usage
10** Licensees holding valid Qt Commercial licenses may use this file in
11** accordance with the Qt Commercial License Agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and Nokia.
14**
15** GNU Lesser General Public License Usage
16** Alternatively, this file may be used under the terms of the GNU Lesser
17** General Public License version 2.1 as published by the Free Software
18** Foundation and appearing in the file LICENSE.LGPL included in the
19** packaging of this file. Please review the following information to
20** ensure the GNU Lesser General Public License version 2.1 requirements
21** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
22**
23** In addition, as a special exception, Nokia gives you certain
24** additional rights. These rights are described in the Nokia Qt LGPL
25** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
26** package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you are unsure which license is appropriate for your use, please
37** contact the sales department at [email protected].
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "qscriptsyntaxhighlighter_p.h"
43#include "private/qfunctions_p.h"
44
45#ifndef QT_NO_SYNTAXHIGHLIGHTER
46
47QT_BEGIN_NAMESPACE
48
49enum ScriptIds {
50 Comment = 1,
51 Number,
52 String,
53 Type,
54 Keyword,
55 PreProcessor,
56 Label
57};
58
59#define MAX_KEYWORD 63
60static const char *const keywords[MAX_KEYWORD] = {
61 "Infinity",
62 "NaN",
63 "abstract",
64 "boolean",
65 "break",
66 "byte",
67 "case",
68 "catch",
69 "char",
70 "class",
71 "const",
72 "constructor",
73 "continue",
74 "debugger",
75 "default",
76 "delete",
77 "do",
78 "double",
79 "else",
80 "enum",
81 "export",
82 "extends",
83 "false",
84 "final",
85 "finally",
86 "float",
87 "for",
88 "function",
89 "goto",
90 "if",
91 "implements",
92 "import",
93 "in",
94 "instanceof",
95 "int",
96 "interface",
97 "long",
98 "native",
99 "new",
100 "package",
101 "private",
102 "protected",
103 "public",
104 "return",
105 "short",
106 "static",
107 "super",
108 "switch",
109 "synchronized",
110 "this",
111 "throw",
112 "throws",
113 "transient",
114 "true",
115 "try",
116 "typeof",
117 "undefined",
118 "var",
119 "void",
120 "volatile",
121 "while",
122 "with", // end of array
123 0
124};
125
126struct KeywordHelper
127{
128 inline KeywordHelper(const QString &word) : needle(word) {}
129 const QString needle;
130};
131
132Q_STATIC_GLOBAL_OPERATOR bool operator<(const KeywordHelper &helper, const char *kw)
133{
134 return helper.needle < QLatin1String(kw);
135}
136
137Q_STATIC_GLOBAL_OPERATOR bool operator<(const char *kw, const KeywordHelper &helper)
138{
139 return QLatin1String(kw) < helper.needle;
140}
141
142static bool isKeyword(const QString &word)
143{
144 const char * const *start = &keywords[0];
145 const char * const *end = &keywords[MAX_KEYWORD - 1];
146 const char * const *kw = qBinaryFind(start, end, KeywordHelper(word));
147
148 return kw != end;
149}
150
151QScriptSyntaxHighlighter::QScriptSyntaxHighlighter(QTextDocument *document)
152 : QSyntaxHighlighter(document)
153{
154
155 m_formats[ScriptNumberFormat].setForeground(Qt::darkBlue);
156 m_formats[ScriptStringFormat].setForeground(Qt::darkGreen);
157 m_formats[ScriptTypeFormat].setForeground(Qt::darkMagenta);
158 m_formats[ScriptKeywordFormat].setForeground(Qt::darkYellow);
159 m_formats[ScriptPreprocessorFormat].setForeground(Qt::darkBlue);
160 m_formats[ScriptLabelFormat].setForeground(Qt::darkRed);
161 m_formats[ScriptCommentFormat].setForeground(Qt::darkGreen);
162 m_formats[ScriptCommentFormat].setFontItalic(true);
163}
164
165QScriptSyntaxHighlighter::~QScriptSyntaxHighlighter()
166{
167}
168
169void QScriptSyntaxHighlighter::highlightBlock(const QString &text)
170{
171
172 // states
173 enum States { StateStandard, StateCommentStart1, StateCCommentStart2,
174 StateScriptCommentStart2, StateCComment, StateScriptComment, StateCCommentEnd1,
175 StateCCommentEnd2, StateStringStart, StateString, StateStringEnd,
176 StateString2Start, StateString2, StateString2End,
177 StateNumber, StatePreProcessor, NumStates };
178
179 // tokens
180 enum Tokens { InputAlpha, InputNumber, InputAsterix, InputSlash, InputParen,
181 InputSpace, InputHash, InputQuotation, InputApostrophe, InputSep, NumTokens };
182
183 static uchar table[NumStates][NumTokens] = {
184 { StateStandard, StateNumber, StateStandard, StateCommentStart1, StateStandard, StateStandard, StatePreProcessor, StateStringStart, StateString2Start, StateStandard }, // StateStandard
185 { StateStandard, StateNumber, StateCCommentStart2, StateScriptCommentStart2, StateStandard, StateStandard, StatePreProcessor, StateStringStart, StateString2Start, StateStandard }, // StateCommentStart1
186 { StateCComment, StateCComment, StateCCommentEnd1, StateCComment, StateCComment, StateCComment, StateCComment, StateCComment, StateCComment, StateCComment }, // StateCCommentStart2
187 { StateScriptComment, StateScriptComment, StateScriptComment, StateScriptComment, StateScriptComment, StateScriptComment, StateScriptComment, StateScriptComment, StateScriptComment, StateScriptComment }, // ScriptCommentStart2
188 { StateCComment, StateCComment, StateCCommentEnd1, StateCComment, StateCComment, StateCComment, StateCComment, StateCComment, StateCComment, StateCComment }, // StateCComment
189 { StateScriptComment, StateScriptComment, StateScriptComment, StateScriptComment, StateScriptComment, StateScriptComment, StateScriptComment, StateScriptComment, StateScriptComment, StateScriptComment }, // StateScriptComment
190 { StateCComment, StateCComment, StateCCommentEnd1, StateCCommentEnd2, StateCComment, StateCComment, StateCComment, StateCComment, StateCComment, StateCComment }, // StateCCommentEnd1
191 { StateStandard, StateNumber, StateStandard, StateCommentStart1, StateStandard, StateStandard, StatePreProcessor, StateStringStart, StateString2Start, StateStandard }, // StateCCommentEnd2
192 { StateString, StateString, StateString, StateString, StateString, StateString, StateString, StateStringEnd, StateString, StateString }, // StateStringStart
193 { StateString, StateString, StateString, StateString, StateString, StateString, StateString, StateStringEnd, StateString, StateString }, // StateString
194 { StateStandard, StateStandard, StateStandard, StateCommentStart1, StateStandard, StateStandard, StatePreProcessor, StateStringStart, StateString2Start, StateStandard }, // StateStringEnd
195 { StateString2, StateString2, StateString2, StateString2, StateString2, StateString2, StateString2, StateString2, StateString2End, StateString2 }, // StateString2Start
196 { StateString2, StateString2, StateString2, StateString2, StateString2, StateString2, StateString2, StateString2, StateString2End, StateString2 }, // StateString2
197 { StateStandard, StateStandard, StateStandard, StateCommentStart1, StateStandard, StateStandard, StatePreProcessor, StateStringStart, StateString2Start, StateStandard }, // StateString2End
198 { StateNumber, StateNumber, StateStandard, StateCommentStart1, StateStandard, StateStandard, StatePreProcessor, StateStringStart, StateString2Start, StateStandard }, // StateNumber
199 { StatePreProcessor, StateStandard, StateStandard, StateCommentStart1, StateStandard, StateStandard, StatePreProcessor, StateStringStart, StateString2Start, StateStandard } // StatePreProcessor
200 };
201
202 QString buffer;
203 buffer.reserve(text.length());
204
205 QTextCharFormat emptyFormat;
206
207 int state = StateStandard;
208 int braceDepth = 0;
209 const int previousState = previousBlockState();
210 if (previousState != -1) {
211 state = previousState & 0xff;
212 braceDepth = previousState >> 8;
213 }
214
215 if (text.isEmpty()) {
216 setCurrentBlockState(previousState);
217#if 0
218 TextEditDocumentLayout::clearParentheses(currentBlock());
219#endif
220 return;
221 }
222#if 0
223 Parentheses parentheses;
224 parentheses.reserve(20); // assume wizard level ;-)
225#endif
226 int input = -1;
227 int i = 0;
228 bool lastWasBackSlash = false;
229 bool makeLastStandard = false;
230
231 static const QString alphabeth = QLatin1String("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ");
232 static const QString mathChars = QLatin1String("xXeE");
233 static const QString numbers = QLatin1String("0123456789");
234 bool questionMark = false;
235 QChar lastChar;
236
237 int firstNonSpace = -1;
238 int lastNonSpace = -1;
239
240 for (;;) {
241 const QChar c = text.at(i);
242
243 if (lastWasBackSlash) {
244 input = InputSep;
245 } else {
246 switch (c.toAscii()) {
247 case '*':
248 input = InputAsterix;
249 break;
250 case '/':
251 input = InputSlash;
252 break;
253 case '{':
254 braceDepth++;
255 // fall through
256 case '(': case '[':
257 input = InputParen;
258 switch (state) {
259 case StateStandard:
260 case StateNumber:
261 case StatePreProcessor:
262 case StateCCommentEnd2:
263 case StateCCommentEnd1:
264 case StateString2End:
265 case StateStringEnd:
266// parentheses.push_back(Parenthesis(Parenthesis::Opened, c, i));
267 break;
268 default:
269 break;
270 }
271 break;
272 case '}':
273 if (--braceDepth < 0)
274 braceDepth = 0;
275 // fall through
276 case ')': case ']':
277 input = InputParen;
278 switch (state) {
279 case StateStandard:
280 case StateNumber:
281 case StatePreProcessor:
282 case StateCCommentEnd2:
283 case StateCCommentEnd1:
284 case StateString2End:
285 case StateStringEnd:
286// parentheses.push_back(Parenthesis(Parenthesis::Closed, c, i));
287 break;
288 default:
289 break;
290 }
291 break;
292 case '#':
293 input = InputHash;
294 break;
295 case '"':
296 input = InputQuotation;
297 break;
298 case '\'':
299 input = InputApostrophe;
300 break;
301 case ' ':
302 input = InputSpace;
303 break;
304 case '1': case '2': case '3': case '4': case '5':
305 case '6': case '7': case '8': case '9': case '0':
306 if (alphabeth.contains(lastChar)
307 && (!mathChars.contains(lastChar) || !numbers.contains(text.at(i - 1)))
308 ) {
309 input = InputAlpha;
310 } else {
311 if (input == InputAlpha && numbers.contains(lastChar))
312 input = InputAlpha;
313 else
314 input = InputNumber;
315 }
316 break;
317 case ':': {
318 input = InputAlpha;
319 const QChar colon = QLatin1Char(':');
320 if (state == StateStandard && !questionMark && lastChar != colon) {
321 const QChar nextChar = i < text.length() - 1 ? text.at(i + 1) : QLatin1Char(' ');
322 if (nextChar != colon)
323 for (int j = 0; j < i; ++j) {
324 if (format(j) == emptyFormat )
325 setFormat(j, 1, m_formats[ScriptLabelFormat]);
326 }
327 }
328 } break;
329 default:
330 if (!questionMark && c == QLatin1Char('?'))
331 questionMark = true;
332 if (c.isLetter() || c == QLatin1Char('_'))
333 input = InputAlpha;
334 else