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 <QtCore/qtextstream.h>
30#include <QtWidgets/qtextedit.h>
31
32#include "htmlhighlighter_p.h"
33
34QT_BEGIN_NAMESPACE
35
36namespace qdesigner_internal {
37
38HtmlHighlighter::HtmlHighlighter(QTextEdit *textEdit)
39 : QSyntaxHighlighter(textEdit->document())
40{
41 QTextCharFormat entityFormat;
42 entityFormat.setForeground(Qt::red);
43 setFormatFor(construct: Entity, format: entityFormat);
44
45 QTextCharFormat tagFormat;
46 tagFormat.setForeground(Qt::darkMagenta);
47 tagFormat.setFontWeight(QFont::Bold);
48 setFormatFor(construct: Tag, format: tagFormat);
49
50 QTextCharFormat commentFormat;
51 commentFormat.setForeground(Qt::gray);
52 commentFormat.setFontItalic(true);
53 setFormatFor(construct: Comment, format: commentFormat);
54
55 QTextCharFormat attributeFormat;
56 attributeFormat.setForeground(Qt::black);
57 attributeFormat.setFontWeight(QFont::Bold);
58 setFormatFor(construct: Attribute, format: attributeFormat);
59
60 QTextCharFormat valueFormat;
61 valueFormat.setForeground(Qt::blue);
62 setFormatFor(construct: Value, format: valueFormat);
63}
64
65void HtmlHighlighter::setFormatFor(Construct construct,
66 const QTextCharFormat &format)
67{
68 m_formats[construct] = format;
69 rehighlight();
70}
71
72void HtmlHighlighter::highlightBlock(const QString &text)
73{
74 static const QLatin1Char tab = QLatin1Char('\t');
75 static const QLatin1Char space = QLatin1Char(' ');
76 static const QLatin1Char amp = QLatin1Char('&');
77 static const QLatin1Char startTag = QLatin1Char('<');
78 static const QLatin1Char endTag = QLatin1Char('>');
79 static const QLatin1Char quot = QLatin1Char('"');
80 static const QLatin1Char apos = QLatin1Char('\'');
81 static const QLatin1Char semicolon = QLatin1Char(';');
82 static const QLatin1Char equals = QLatin1Char('=');
83 static const QLatin1String startComment("<!--");
84 static const QLatin1String endComment("-->");
85 static const QLatin1String endElement("/>");
86
87 int state = previousBlockState();
88 int len = text.length();
89 int start = 0;
90 int pos = 0;
91
92 while (pos < len) {
93 switch (state) {
94 case NormalState:
95 default:
96 while (pos < len) {
97 QChar ch = text.at(i: pos);
98 if (ch == startTag) {
99 if (text.mid(position: pos, n: 4) == startComment) {
100 state = InComment;
101 } else {
102 state = InTag;
103 start = pos;
104 while (pos < len && text.at(i: pos) != space
105 && text.at(i: pos) != endTag
106 && text.at(i: pos) != tab
107 && text.mid(position: pos, n: 2) != endElement)
108 ++pos;
109 if (text.mid(position: pos, n: 2) == endElement)
110 ++pos;
111 setFormat(start, count: pos - start,
112 format: m_formats[Tag]);
113 break;
114 }
115 break;
116 }
117 if (ch == amp) {
118 start = pos;
119 while (pos < len && text.at(i: pos++) != semicolon)
120 ;
121 setFormat(start, count: pos - start,
122 format: m_formats[Entity]);
123 } else {
124 // No tag, comment or entity started, continue...
125 ++pos;
126 }
127 }
128 break;
129 case InComment:
130 start = pos;
131 for ( ; pos < len; ++pos) {
132 if (text.mid(position: pos, n: 3) == endComment) {
133 pos += 3;
134 state = NormalState;
135 break;
136 }
137 }
138 setFormat(start, count: pos - start, format: m_formats[Comment]);
139 break;
140 case InTag:
141 QChar quote = QChar::Null;
142 while (pos < len) {
143 QChar ch = text.at(i: pos);
144 if (quote.isNull()) {
145 start = pos;
146 if (ch == apos || ch == quot) {
147 quote = ch;
148 } else if (ch == endTag) {
149 ++pos;
150 setFormat(start, count: pos - start, format: m_formats[Tag]);
151 state = NormalState;
152 break;
153 } else if (text.mid(position: pos, n: 2) == endElement) {
154 pos += 2;
155 setFormat(start, count: pos - start, format: m_formats[Tag]);
156 state = NormalState;
157 break;
158 } else if (ch != space && text.at(i: pos) != tab) {
159 // Tag not ending, not a quote and no whitespace, so
160 // we must be dealing with an attribute.
161 ++pos;
162 while (pos < len && text.at(i: pos) != space
163 && text.at(i: pos) != tab
164 && text.at(i: pos) != equals)
165 ++pos;
166 setFormat(start, count: pos - start, format: m_formats[Attribute]);
167 start = pos;
168 }
169 } else if (ch == quote) {
170 quote = QChar::Null;
171
172 // Anything quoted is a value
173 setFormat(start, count: pos - start, format: m_formats[Value]);
174 }
175 ++pos;
176 }
177 break;
178 }
179 }
180 setCurrentBlockState(state);
181}
182
183} // namespace qdesigner_internal
184
185QT_END_NAMESPACE
186

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