1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the Qt Designer of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:GPL-EXCEPT$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU
19** General Public License version 3 as published by the Free Software
20** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
21** included in the packaging of this file. Please review the following
22** information to ensure the GNU General Public License requirements will
23** be met: https://www.gnu.org/licenses/gpl-3.0.html.
24**
25** $QT_END_LICENSE$
26**
27****************************************************************************/
28
29#include "csshighlighter_p.h"
30
31QT_BEGIN_NAMESPACE
32
33namespace qdesigner_internal {
34
35CssHighlighter::CssHighlighter(QTextDocument *document)
36: QSyntaxHighlighter(document)
37{
38}
39
40void CssHighlighter::highlightBlock(const QString& text)
41{
42 enum Token { ALNUM, LBRACE, RBRACE, COLON, SEMICOLON, COMMA, QUOTE, SLASH, STAR };
43 static const int transitions[10][9] = {
44 { Selector, Property, Selector, Pseudo, Property, Selector, Quote, MaybeComment, Selector }, // Selector
45 { Property, Property, Selector, Value, Property, Property, Quote, MaybeComment, Property }, // Property
46 { Value, Property, Selector, Value, Property, Value, Quote, MaybeComment, Value }, // Value
47 { Pseudo1, Property, Selector, Pseudo2, Selector, Selector, Quote, MaybeComment, Pseudo }, // Pseudo
48 { Pseudo1, Property, Selector, Pseudo, Selector, Selector, Quote, MaybeComment, Pseudo1 }, // Pseudo1
49 { Pseudo2, Property, Selector, Pseudo, Selector, Selector, Quote, MaybeComment, Pseudo2 }, // Pseudo2
50 { Quote, Quote, Quote, Quote, Quote, Quote, -1, Quote, Quote }, // Quote
51 { -1, -1, -1, -1, -1, -1, -1, -1, Comment }, // MaybeComment
52 { Comment, Comment, Comment, Comment, Comment, Comment, Comment, Comment, MaybeCommentEnd }, // Comment
53 { Comment, Comment, Comment, Comment, Comment, Comment, Comment, -1, MaybeCommentEnd } // MaybeCommentEnd
54 };
55
56 int lastIndex = 0;
57 bool lastWasSlash = false;
58 int state = previousBlockState(), save_state;
59 if (state == -1) {
60 // As long as the text is empty, leave the state undetermined
61 if (text.isEmpty()) {
62 setCurrentBlockState(-1);
63 return;
64 }
65 // The initial state is based on the precense of a : and the absense of a {.
66 // This is because Qt style sheets support both a full stylesheet as well as
67 // an inline form with just properties.
68 state = save_state = (text.indexOf(c: QLatin1Char(':')) > -1 &&
69 text.indexOf(c: QLatin1Char('{')) == -1) ? Property : Selector;
70 } else {
71 save_state = state>>16;
72 state &= 0x00ff;
73 }
74
75 if (state == MaybeCommentEnd) {
76 state = Comment;
77 } else if (state == MaybeComment) {
78 state = save_state;
79 }
80
81 for (int i = 0; i < text.length(); i++) {
82 int token = ALNUM;
83 const QChar c = text.at(i);
84 const char a = c.toLatin1();
85
86 if (state == Quote) {
87 if (a == '\\') {
88 lastWasSlash = true;
89 } else {
90 if (a == '\"' && !lastWasSlash) {
91 token = QUOTE;
92 }
93 lastWasSlash = false;
94 }
95 } else {
96 switch (a) {
97 case '{': token = LBRACE; break;
98 case '}': token = RBRACE; break;
99 case ':': token = COLON; break;
100 case ';': token = SEMICOLON; break;
101 case ',': token = COMMA; break;
102 case '\"': token = QUOTE; break;
103 case '/': token = SLASH; break;
104 case '*': token = STAR; break;
105 default: break;
106 }
107 }
108
109 int new_state = transitions[state][token];
110
111 if (new_state != state) {
112 bool include_token = new_state == MaybeCommentEnd || (state == MaybeCommentEnd && new_state!= Comment)
113 || state == Quote;
114 highlight(text, lastIndex, i-lastIndex+include_token, state);
115
116 if (new_state == Comment) {
117 lastIndex = i-1; // include the slash and star
118 } else {
119 lastIndex = i + ((token == ALNUM || new_state == Quote) ? 0 : 1);
120 }
121 }
122
123 if (new_state == -1) {
124 state = save_state;
125 } else if (state <= Pseudo2) {
126 save_state = state;
127 state = new_state;
128 } else {
129 state = new_state;
130 }
131 }
132
133 highlight(text, lastIndex, text.length() - lastIndex, state);
134 setCurrentBlockState(state + (save_state<<16));
135}
136
137void CssHighlighter::highlight(const QString &text, int start, int length, int state)
138{
139 if (start >= text.length() || length <= 0)
140 return;
141
142 QTextCharFormat format;
143
144 switch (state) {
145 case Selector:
146 setFormat(start, count: length, color: Qt::darkRed);
147 break;
148 case Property:
149 setFormat(start, count: length, color: Qt::blue);
150 break;
151 case Value:
152 setFormat(start, count: length, color: Qt::black);
153 break;
154 case Pseudo1:
155 setFormat(start, count: length, color: Qt::darkRed);
156 break;
157 case Pseudo2:
158 setFormat(start, count: length, color: Qt::darkRed);
159 break;
160 case Quote:
161 setFormat(start, count: length, color: Qt::darkMagenta);
162 break;
163 case Comment:
164 case MaybeCommentEnd:
165 format.setForeground(Qt::darkGreen);
166 setFormat(start, count: length, format);
167 break;
168 default:
169 break;
170 }
171}
172
173} // namespace qdesigner_internal
174
175QT_END_NAMESPACE
176

source code of qttools/src/designer/src/lib/shared/csshighlighter.cpp