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 Linguist 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 "messagehighlighter.h"
30
31#include <QtCore/QTextStream>
32#include <QtWidgets/QTextEdit>
33
34QT_BEGIN_NAMESPACE
35
36MessageHighlighter::MessageHighlighter(QTextEdit *textEdit)
37 : QSyntaxHighlighter(textEdit->document())
38{
39 QTextCharFormat entityFormat;
40 entityFormat.setForeground(Qt::red);
41 m_formats[Entity] = entityFormat;
42
43 QTextCharFormat tagFormat;
44 tagFormat.setForeground(Qt::darkMagenta);
45 m_formats[Tag] = tagFormat;
46
47 QTextCharFormat commentFormat;
48 commentFormat.setForeground(Qt::gray);
49 commentFormat.setFontItalic(true);
50 m_formats[Comment] = commentFormat;
51
52 QTextCharFormat attributeFormat;
53 attributeFormat.setForeground(Qt::black);
54 attributeFormat.setFontItalic(true);
55 m_formats[Attribute] = attributeFormat;
56
57 QTextCharFormat valueFormat;
58 valueFormat.setForeground(Qt::blue);
59 m_formats[Value] = valueFormat;
60
61 QTextCharFormat acceleratorFormat;
62 acceleratorFormat.setFontUnderline(true);
63 m_formats[Accelerator] = acceleratorFormat;
64
65 QTextCharFormat variableFormat;
66 variableFormat.setForeground(Qt::blue);
67 m_formats[Variable] = variableFormat;
68
69 rehighlight();
70}
71
72void MessageHighlighter::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 endTag = QLatin1Char('>');
78 static const QLatin1Char quot = QLatin1Char('"');
79 static const QLatin1Char apos = QLatin1Char('\'');
80 static const QLatin1Char semicolon = QLatin1Char(';');
81 static const QLatin1Char equals = QLatin1Char('=');
82 static const QLatin1Char percent = QLatin1Char('%');
83 static const QLatin1String startComment = QLatin1String("<!--");
84 static const QLatin1String endComment = QLatin1String("-->");
85 static const QLatin1String endElement = QLatin1String("/>");
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 == QLatin1Char('<')) {
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 } else if (ch == amp && pos + 1 < len) {
117 // Default is Accelerator
118 if (text.at(i: pos + 1).isLetterOrNumber())
119 setFormat(start: pos + 1, count: 1, format: m_formats[Accelerator]);
120
121 // When a semicolon follows assume an Entity
122 start = pos;
123 ch = text.at(i: ++pos);
124 while (pos + 1 < len && ch != semicolon && ch.isLetterOrNumber())
125 ch = text.at(i: ++pos);
126 if (ch == semicolon)
127 setFormat(start, count: pos - start + 1, format: m_formats[Entity]);
128 } else if (ch == percent) {
129 start = pos;
130 // %[1-9]*
131 for (++pos; pos < len && text.at(i: pos).isDigit(); ++pos) {}
132 // %n
133 if (pos < len && pos == start + 1 && text.at(i: pos) == QLatin1Char('n'))
134 ++pos;
135 setFormat(start, count: pos - start, format: m_formats[Variable]);
136 } else {
137 // No tag, comment or entity started, continue...
138 ++pos;
139 }
140 }
141 break;
142 case InComment:
143 start = pos;
144 while (pos < len) {
145 if (text.mid(position: pos, n: 3) == endComment) {
146 pos += 3;
147 state = NormalState;
148 break;
149 } else {
150 ++pos;
151 }
152 }
153 setFormat(start, count: pos - start, format: m_formats[Comment]);
154 break;
155 case InTag:
156 QChar quote = QChar::Null;
157 while (pos < len) {
158 QChar ch = text.at(i: pos);
159 if (quote.isNull()) {
160 start = pos;
161 if (ch == apos || ch == quot) {
162 quote = ch;
163 } else if (ch == endTag) {
164 ++pos;
165 setFormat(start, count: pos - start, format: m_formats[Tag]);
166 state = NormalState;
167 break;
168 } else if (text.mid(position: pos, n: 2) == endElement) {
169 pos += 2;
170 setFormat(start, count: pos - start, format: m_formats[Tag]);
171 state = NormalState;
172 break;
173 } else if (ch != space && text.at(i: pos) != tab) {
174 // Tag not ending, not a quote and no whitespace, so
175 // we must be dealing with an attribute.
176 ++pos;
177 while (pos < len && text.at(i: pos) != space
178 && text.at(i: pos) != tab
179 && text.at(i: pos) != equals)
180 ++pos;
181 setFormat(start, count: pos - start, format: m_formats[Attribute]);
182 start = pos;
183 }
184 } else if (ch == quote) {
185 quote = QChar::Null;
186
187 // Anything quoted is a value
188 setFormat(start, count: pos - start, format: m_formats[Value]);
189 }
190 ++pos;
191 }
192 break;
193 }
194 }
195 setCurrentBlockState(state);
196}
197
198QT_END_NAMESPACE
199

source code of qttools/src/linguist/linguist/messagehighlighter.cpp