2 * \file LaTeXHighlighter.cpp
3 * This file is part of LyX, the document processor.
4 * Licence details can be found in the file COPYING.
8 * Full author contact details are available in file CREDITS.
13 #include "LaTeXHighlighter.h"
14 #include "qt_helpers.h"
17 #include <QTextDocument>
23 LaTeXHighlighter::LaTeXHighlighter(QTextDocument * parent, bool at_letter, bool keyval)
24 : QSyntaxHighlighter(parent), at_letter_(at_letter), keyval_(keyval)
30 void LaTeXHighlighter::setupColors()
32 auto blend = [](QColor color1, QColor color2) {
33 int r = 0.5 * (color1.red() + color2.red());
34 int g = 0.5 * (color1.green() + color2.green());
35 int b = 0.5 * (color1.blue() + color2.blue());
36 return QColor(r, g, b);
38 QPalette palette = QPalette();
39 QColor text_color = palette.color(QPalette::Active, QPalette::Text);
40 keywordFormat.setForeground(blend(Qt::blue, text_color));
41 keywordFormat.setFontWeight(QFont::Bold);
42 commentFormat.setForeground(palette.color(QPalette::Disabled,
44 mathFormat.setForeground(blend(Qt::red, text_color));
45 warningFormat.setForeground(Qt::red);
46 warningFormat.setFontWeight(QFont::Bold);
47 keyFormat.setForeground(blend(Qt::darkRed, text_color));
48 keyFormat.setFontWeight(QFont::Bold);
49 valFormat.setForeground(blend(Qt::darkGreen, text_color));
53 void LaTeXHighlighter::highlightBlock(QString const & text)
57 // Highlight key-val options. Used in some option widgets.
58 // 1. The keys. Might or might not have values
59 static QRegularExpression exprKeyvalkey("[^=,}]+");
60 // 2. These are grouped values such as "key1={val,val},key2=val"
61 static QRegularExpression exprKeyvalgval("[^=,{]+{[^}]+}");
62 // 3. And normal values if we don't find grouped ones
63 static QRegularExpression exprKeyvalval("[^,]+");
64 QRegularExpressionMatch matchkey = exprKeyvalkey.match(text);
65 int kvindex = matchkey.capturedStart(0);
66 while (kvindex >= 0) {
67 int length = matchkey.capturedLength(0);
68 setFormat(kvindex, length, keyFormat);
69 if (text.size() > kvindex + length && text.at(kvindex + length) == '=') {
70 QRegularExpressionMatch matchgval =
71 exprKeyvalgval.match(text, kvindex + length);
72 int kvvindex = matchgval.capturedStart(0);
74 int vlength = matchgval.capturedLength(0);
76 setFormat(kvvindex, vlength, valFormat);
78 QRegularExpressionMatch matchval =
79 exprKeyvalval.match(text, kvindex + length);
80 kvvindex = matchval.capturedStart(0);
82 int vlength = matchval.capturedLength(0);
84 setFormat(kvvindex, vlength, valFormat);
88 matchkey = exprKeyvalkey.match(text, kvindex + length);
89 kvindex = matchkey.capturedStart(0);
93 static const QRegularExpression exprMath("\\$[^\\$]*\\$");
94 QRegularExpressionMatch match = exprMath.match(text);
95 int index = match.capturedStart(0);
97 int length = match.capturedLength(0);
98 setFormat(index, length, mathFormat);
99 match = exprMath.match(text, index + length);
100 index = match.capturedStart(0);
103 static const QRegularExpression exprStartDispMath("(\\\\\\[|"
104 "\\\\begin\\{equation\\**\\}|"
105 "\\\\begin\\{eqnarray\\**\\}|"
106 "\\\\begin\\{align(ed|at)*\\**\\}|"
107 "\\\\begin\\{flalign\\**\\}|"
108 "\\\\begin\\{gather\\**\\}|"
109 "\\\\begin\\{multline\\**\\}|"
110 "\\\\begin\\{array\\**\\}|"
111 "\\\\begin\\{cases\\**\\}"
113 static const QRegularExpression exprEndDispMath("(\\\\\\]|"
114 "\\\\end\\{equation\\**\\}|"
115 "\\\\end\\{eqnarray\\**\\}|"
116 "\\\\end\\{align(ed|at)*\\**\\}|"
117 "\\\\end\\{flalign\\**\\}|"
118 "\\\\end\\{gather\\**\\}|"
119 "\\\\end\\{multline\\**\\}|"
120 "\\\\end\\{array\\**\\}|"
121 "\\\\end\\{cases\\**\\}"
124 // if previous block was in 'disp math'
125 // start search from 0 (for end disp math)
126 // otherwise, start search from 'begin disp math'
127 if (previousBlockState() != 1) {
128 match = exprStartDispMath.match(text);
129 startIndex = match.capturedStart(0);
131 while (startIndex >= 0) {
132 match = exprEndDispMath.match(text, startIndex);
133 int endIndex = match.capturedStart(0);
135 if (endIndex == -1) {
136 setCurrentBlockState(1);
137 length = text.length() - startIndex;
139 length = endIndex - startIndex + match.capturedLength(0);
141 setFormat(startIndex, length, mathFormat);
142 match = exprStartDispMath.match(text, startIndex + length);
143 startIndex = match.capturedStart(0);
146 static const QRegularExpression exprKeywordAtOther("\\\\[A-Za-z]+");
148 static const QRegularExpression exprKeywordAtLetter("\\\\[A-Za-z@]+");
149 QRegularExpression const & exprKeyword = at_letter_
150 ? exprKeywordAtLetter : exprKeywordAtOther;
151 match = exprKeyword.match(text);
152 index = match.capturedStart(0);
154 int length = match.capturedLength(0);
155 setFormat(index, length, keywordFormat);
156 match = exprKeyword.match(text, index + length);
157 index = match.capturedStart(0);
160 // Treat a line as a comment starting at a percent sign
161 // * that is the first character in a line
162 // * that is preceded by
163 // ** an even number of backslashes
164 // ** any character other than a backslash
165 QRegularExpression exprComment("(?:^|[^\\\\])(?:\\\\\\\\)*(%).*$");
166 match = exprComment.match(text);
167 index = match.capturedStart(1);
169 int const length = match.capturedLength(0)
170 - (index - match.capturedStart(0));
171 setFormat(index, length, commentFormat);
172 match = exprComment.match(text, index + length);
173 index = match.capturedStart(1);
175 // <LyX Warning: ...>
176 QString lyxwarn = qt_("LyX Warning: ");
177 QRegularExpression exprWarning("<" + lyxwarn + "[^<]*>");
178 match = exprWarning.match(text);
179 index = match.capturedStart(0);
181 int length = match.capturedLength(0);
182 setFormat(index, length, warningFormat);
183 match = exprWarning.match(text, index + length);
184 index = match.capturedStart(0);
188 } // namespace frontend