Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
messagehighlighter.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
3
5
6#include "globals.h"
7
8#include <QtCore/QTextStream>
9#include <QtWidgets/QTextEdit>
10
12
13using namespace Qt::Literals::StringLiterals;
14
15MessageHighlighter::MessageHighlighter(QTextEdit *textEdit)
16 : QSyntaxHighlighter(textEdit->document())
17{
19}
20
21void MessageHighlighter::highlightBlock(const QString &text)
22{
23 static constexpr QLatin1Char tab('\t');
24 static constexpr QLatin1Char space(' ');
25 static constexpr QLatin1Char amp('&');
26 static constexpr QLatin1Char endTag('>');
27 static constexpr QLatin1Char quot('"');
28 static constexpr QLatin1Char apos('\'');
29 static constexpr QLatin1Char semicolon(';');
30 static constexpr QLatin1Char equals('=');
31 static constexpr QLatin1Char percent('%');
32 static constexpr auto startComment = "<!--"_L1;
33 static constexpr auto endComment = "-->"_L1;
34 static constexpr auto endElement = "/>"_L1;
35
36 int state = previousBlockState();
37 int len = text.size();
38 int start = 0;
39 int pos = 0;
40
41 while (pos < len) {
42 switch (state) {
43 case NormalState:
44 default:
45 while (pos < len) {
46 QChar ch = text.at(pos);
47 if (ch == u'<') {
48 if (text.mid(pos, 4) == startComment) {
49 state = InComment;
50 } else {
51 state = InTag;
52 start = pos;
53 while (pos < len && text.at(pos) != space
54 && text.at(pos) != endTag
55 && text.at(pos) != tab
56 && text.mid(pos, 2) != endElement)
57 ++pos;
58 if (text.mid(pos, 2) == endElement)
59 ++pos;
60 setFormat(start, pos - start,
61 m_formats[Tag]);
62 break;
63 }
64 break;
65 } else if (ch == amp && pos + 1 < len) {
66 // Default is Accelerator
67 if (text.at(pos + 1).isLetterOrNumber())
68 setFormat(pos + 1, 1, m_formats[Accelerator]);
69
70 // When a semicolon follows assume an Entity
71 start = pos;
72 ch = text.at(++pos);
73 while (pos + 1 < len && ch != semicolon && ch.isLetterOrNumber())
74 ch = text.at(++pos);
75 if (ch == semicolon)
76 setFormat(start, pos - start + 1, m_formats[Entity]);
77 } else if (ch == percent) {
78 start = pos;
79 // %[1-9]*
80 for (++pos; pos < len && text.at(pos).isDigit(); ++pos) {}
81 // %n
82 if (pos < len && pos == start + 1 && text.at(pos) == u'n')
83 ++pos;
84 setFormat(start, pos - start, m_formats[Variable]);
85 } else {
86 // No tag, comment or entity started, continue...
87 ++pos;
88 }
89 }
90 break;
91 case InComment:
92 start = pos;
93 while (pos < len) {
94 if (text.mid(pos, 3) == endComment) {
95 pos += 3;
96 state = NormalState;
97 break;
98 } else {
99 ++pos;
100 }
101 }
102 setFormat(start, pos - start, m_formats[Comment]);
103 break;
104 case InTag:
105 QChar quote = QChar::Null;
106 while (pos < len) {
107 QChar ch = text.at(pos);
108 if (quote.isNull()) {
109 start = pos;
110 if (ch == apos || ch == quot) {
111 quote = ch;
112 } else if (ch == endTag) {
113 ++pos;
114 setFormat(start, pos - start, m_formats[Tag]);
115 state = NormalState;
116 break;
117 } else if (text.mid(pos, 2) == endElement) {
118 pos += 2;
119 setFormat(start, pos - start, m_formats[Tag]);
120 state = NormalState;
121 break;
122 } else if (ch != space && text.at(pos) != tab) {
123 // Tag not ending, not a quote and no whitespace, so
124 // we must be dealing with an attribute.
125 ++pos;
126 while (pos < len && text.at(pos) != space
127 && text.at(pos) != tab
128 && text.at(pos) != equals)
129 ++pos;
130 setFormat(start, pos - start, m_formats[Attribute]);
131 start = pos;
132 }
133 } else if (ch == quote) {
134 quote = QChar::Null;
135
136 // Anything quoted is a value
137 setFormat(start, pos - start, m_formats[Value]);
138 }
139 ++pos;
140 }
141 break;
142 }
143 }
144 setCurrentBlockState(state);
145}
146
148{
149 QTextCharFormat entityFormat;
150 QTextCharFormat tagFormat;
151 QTextCharFormat commentFormat;
152 QTextCharFormat attributeFormat;
153 QTextCharFormat valueFormat;
154 QTextCharFormat acceleratorFormat;
155 QTextCharFormat variableFormat;
156
157 if (isDarkMode()) {
158 entityFormat.setForeground(Qt::red);
159 tagFormat.setForeground(QColor(Qt::darkMagenta).lighter());
160 commentFormat.setForeground(Qt::gray);
161 attributeFormat.setForeground(QColor(Qt::darkGray).lighter());
162 valueFormat.setForeground(QColor(Qt::darkGreen).lighter());
163 variableFormat.setForeground(QColor(Qt::darkGreen).lighter());
164 } else {
165 entityFormat.setForeground(Qt::red);
166 tagFormat.setForeground(Qt::darkMagenta);
167 commentFormat.setForeground(Qt::gray);
168 attributeFormat.setForeground(Qt::black);
169 valueFormat.setForeground(Qt::darkGreen);
170 variableFormat.setForeground(Qt::darkGreen);
171 }
172
173 commentFormat.setFontItalic(true);
174 attributeFormat.setFontItalic(true);
175 acceleratorFormat.setFontUnderline(true);
176
177 m_formats[Entity] = entityFormat;
178 m_formats[Tag] = tagFormat;
179 m_formats[Comment] = commentFormat;
180 m_formats[Attribute] = attributeFormat;
181 m_formats[Value] = valueFormat;
182 m_formats[Accelerator] = acceleratorFormat;
183 m_formats[Variable] = variableFormat;
184
185 rehighlight();
186}
187
188QT_END_NAMESPACE
void highlightBlock(const QString &text) override
Highlights the given text block.
bool isDarkMode()
Definition globals.cpp:38