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, bool optsnippet)
24 : QSyntaxHighlighter(parent), at_letter_(at_letter), keyval_(keyval), optsnippet_(optsnippet)
26 auto blend = [](QColor color1, QColor color2) {
27 int r = 0.5 * (color1.red() + color2.red());
28 int g = 0.5 * (color1.green() + color2.green());
29 int b = 0.5 * (color1.blue() + color2.blue());
30 return QColor(r, g, b);
32 QPalette palette = QPalette();
33 QColor text_color = palette.color(QPalette::Active, QPalette::Text);
34 keywordFormat.setForeground(blend(Qt::blue, text_color));
35 keywordFormat.setFontWeight(QFont::Bold);
36 commentFormat.setForeground(palette.color(QPalette::Disabled,
38 mathFormat.setForeground(blend(Qt::red, text_color));
39 warningFormat.setForeground(Qt::red);
40 warningFormat.setFontWeight(QFont::Bold);
41 keyFormat.setForeground(blend(Qt::darkRed, text_color));
42 keyFormat.setFontWeight(QFont::Bold);
43 valFormat.setForeground(blend(Qt::darkGreen, text_color));
47 void LaTeXHighlighter::highlightBlock(QString const & text)
51 // Highlight key-val options. Used in some option widgets.
52 static QRegularExpression exprKeyvalkey("[^=,]+");
53 static QRegularExpression exprKeyvalgval("[^,]+{[^}]+}");
54 static QRegularExpression exprKeyvalval("[^,]+");
56 static QRegularExpression exprKeyvalkey("^=,+");
57 static QRegularExpression exprKeyvalval("^,+");
59 QRegularExpressionMatch matchkey = exprKeyvalkey.match(text);
60 int kvindex = matchkey.capturedStart(0);
61 while (kvindex >= 0) {
62 int length = matchkey.capturedLength(0);
63 setFormat(kvindex, length, keyFormat);
64 if (text.size() > kvindex + length && text.at(kvindex + length) == '=') {
65 QRegularExpressionMatch matchgval =
66 exprKeyvalgval.match(text, kvindex + length);
67 int kvvindex = matchgval.capturedStart(0);
69 int vlength = matchgval.capturedLength(0);
71 setFormat(kvvindex, vlength, valFormat);
73 QRegularExpressionMatch matchval =
74 exprKeyvalval.match(text, kvindex + length);
75 kvvindex = matchval.capturedStart(0);
77 int vlength = matchval.capturedLength(0);
79 setFormat(kvvindex, vlength, valFormat);
83 matchkey = exprKeyvalkey.match(text, kvindex + length);
84 kvindex = matchkey.capturedStart(0);
88 static const QRegularExpression exprMath("\\$[^\\$]*\\$");
89 QRegularExpressionMatch match = exprMath.match(text);
90 int index = match.capturedStart(0);
92 int length = match.capturedLength(0);
93 setFormat(index, length, mathFormat);
94 match = exprMath.match(text, index + length);
95 index = match.capturedStart(0);
98 static const QRegularExpression exprStartDispMath("(\\\\\\[|"
99 "\\\\begin\\{equation\\**\\}|"
100 "\\\\begin\\{eqnarray\\**\\}|"
101 "\\\\begin\\{align(ed|at)*\\**\\}|"
102 "\\\\begin\\{flalign\\**\\}|"
103 "\\\\begin\\{gather\\**\\}|"
104 "\\\\begin\\{multline\\**\\}|"
105 "\\\\begin\\{array\\**\\}|"
106 "\\\\begin\\{cases\\**\\}"
108 static const QRegularExpression exprEndDispMath("(\\\\\\]|"
109 "\\\\end\\{equation\\**\\}|"
110 "\\\\end\\{eqnarray\\**\\}|"
111 "\\\\end\\{align(ed|at)*\\**\\}|"
112 "\\\\end\\{flalign\\**\\}|"
113 "\\\\end\\{gather\\**\\}|"
114 "\\\\end\\{multline\\**\\}|"
115 "\\\\end\\{array\\**\\}|"
116 "\\\\end\\{cases\\**\\}"
119 // if previous block was in 'disp math'
120 // start search from 0 (for end disp math)
121 // otherwise, start search from 'begin disp math'
122 if (previousBlockState() != 1) {
123 match = exprStartDispMath.match(text);
124 startIndex = match.capturedStart(0);
126 while (startIndex >= 0) {
127 match = exprEndDispMath.match(text, startIndex);
128 int endIndex = match.capturedStart(0);
130 if (endIndex == -1) {
131 setCurrentBlockState(1);
132 length = text.length() - startIndex;
134 length = endIndex - startIndex + match.capturedLength(0);
136 setFormat(startIndex, length, mathFormat);
137 match = exprStartDispMath.match(text, startIndex + length);
138 startIndex = match.capturedStart(0);
141 static const QRegularExpression exprKeywordAtOther("\\\\[A-Za-z]+");
143 static const QRegularExpression exprKeywordAtLetter("\\\\[A-Za-z@]+");
144 QRegularExpression const & exprKeyword = at_letter_
145 ? exprKeywordAtLetter : exprKeywordAtOther;
146 match = exprKeyword.match(text);
147 index = match.capturedStart(0);
149 int length = match.capturedLength(0);
150 setFormat(index, length, keywordFormat);
151 match = exprKeyword.match(text, index + length);
152 index = match.capturedStart(0);
155 // Treat a line as a comment starting at a percent sign
156 // * that is the first character in a line
157 // * that is preceded by
158 // ** an even number of backslashes
159 // ** any character other than a backslash
160 QRegularExpression exprComment("(?:^|[^\\\\])(?:\\\\\\\\)*(%).*$");
161 match = exprComment.match(text);
162 index = match.capturedStart(1);
164 int const length = match.capturedLength(0)
165 - (index - match.capturedStart(0));
166 setFormat(index, length, commentFormat);
167 match = exprComment.match(text, index + length);
168 index = match.capturedStart(1);
170 // <LyX Warning: ...>
171 QString lyxwarn = qt_("LyX Warning: ");
172 QRegularExpression exprWarning("<" + lyxwarn + "[^<]*>");
173 match = exprWarning.match(text);
174 index = match.capturedStart(0);
176 int length = match.capturedLength(0);
177 setFormat(index, length, warningFormat);
178 match = exprWarning.match(text, index + length);
179 index = match.capturedStart(0);
183 } // namespace frontend