]> git.lyx.org Git - features.git/blob - src/frontends/qt/LaTeXHighlighter.cpp
Fix copy&paste error
[features.git] / src / frontends / qt / LaTeXHighlighter.cpp
1 /**
2  * \file LaTeXHighlighter.cpp
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author Bo Peng
7  *
8  * Full author contact details are available in file CREDITS.
9  */
10
11 #include <config.h>
12
13 #include "LaTeXHighlighter.h"
14 #include "qt_helpers.h"
15
16 #include <QString>
17 #include <QTextDocument>
18
19 namespace lyx {
20 namespace frontend {
21
22
23 LaTeXHighlighter::LaTeXHighlighter(QTextDocument * parent, bool at_letter)
24         : QSyntaxHighlighter(parent), at_letter_(at_letter)
25 {
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);
31         };
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,
37                                                   QPalette::Text));
38         mathFormat.setForeground(blend(Qt::red, text_color));
39         warningFormat.setForeground(Qt::red);
40         warningFormat.setFontWeight(QFont::Bold);
41 }
42
43
44 void LaTeXHighlighter::highlightBlock(QString const & text)
45 {
46 #if QT_VERSION < 0x060000
47         // $ $
48         static const QRegExp exprMath("\\$[^\\$]*\\$");
49         int index = exprMath.indexIn(text);
50         while (index >= 0) {
51                 int length = exprMath.matchedLength();
52                 setFormat(index, length, mathFormat);
53                 index = exprMath.indexIn(text, index + length);
54         }
55         // [ ]
56         static const QRegExp exprStartDispMath("(\\\\\\[|"
57                 "\\\\begin\\{equation\\**\\}|"
58                 "\\\\begin\\{eqnarray\\**\\}|"
59                 "\\\\begin\\{align(ed|at)*\\**\\}|"
60                 "\\\\begin\\{flalign\\**\\}|"
61                 "\\\\begin\\{gather\\**\\}|"
62                 "\\\\begin\\{multline\\**\\}|"
63                 "\\\\begin\\{array\\**\\}|"
64                 "\\\\begin\\{cases\\**\\}"
65                 ")");
66         static const QRegExp exprEndDispMath("(\\\\\\]|"
67                 "\\\\end\\{equation\\**\\}|"
68                 "\\\\end\\{eqnarray\\**\\}|"
69                 "\\\\end\\{align(ed|at)*\\**\\}|"
70                 "\\\\end\\{flalign\\**\\}|"
71                 "\\\\end\\{gather\\**\\}|"
72                 "\\\\end\\{multline\\**\\}|"
73                 "\\\\end\\{array\\**\\}|"
74                 "\\\\end\\{cases\\**\\}"
75                 ")");
76         int startIndex = 0;
77         // if previous block was in 'disp math'
78         // start search from 0 (for end disp math)
79         // otherwise, start search from 'begin disp math'
80         if (previousBlockState() != 1)
81                 startIndex = exprStartDispMath.indexIn(text);
82         while (startIndex >= 0) {
83                 int endIndex = exprEndDispMath.indexIn(text, startIndex);
84                 int length;
85                 if (endIndex == -1) {
86                         setCurrentBlockState(1);
87                         length = text.length() - startIndex;
88                 } else {
89                         length = endIndex - startIndex + exprEndDispMath.matchedLength();
90                 }
91                 setFormat(startIndex, length, mathFormat);
92                 startIndex = exprStartDispMath.indexIn(text, startIndex + length);
93         }
94         // \whatever
95         static const QRegExp exprKeywordAtOther("\\\\[A-Za-z]+");
96         // \wh@tever
97         static const QRegExp exprKeywordAtLetter("\\\\[A-Za-z@]+");
98         QRegExp const & exprKeyword = at_letter_ ? exprKeywordAtLetter
99                                                  : exprKeywordAtOther;
100         index = exprKeyword.indexIn(text);
101         while (index >= 0) {
102                 int length = exprKeyword.matchedLength();
103                 setFormat(index, length, keywordFormat);
104                 index = exprKeyword.indexIn(text, index + length);
105         }
106         // %comment
107         // Treat a line as a comment starting at a percent sign
108         // * that is the first character in a line
109         // * that is preceded by
110         // ** an even number of backslashes
111         // ** any character other than a backslash
112         QRegExp exprComment("(?:^|[^\\\\])(?:\\\\\\\\)*(%).*$");
113         exprComment.indexIn(text);
114         index = exprComment.pos(1);
115         while (index >= 0) {
116                 int const length = exprComment.matchedLength()
117                                  - (index - exprComment.pos(0));
118                 setFormat(index, length, commentFormat);
119                 exprComment.indexIn(text, index + length);
120                 index = exprComment.pos(1);
121         }
122         // <LyX Warning: ...>
123         QString lyxwarn = qt_("LyX Warning: ");
124         QRegExp exprWarning("<" + lyxwarn + "[^<]*>");
125         index = exprWarning.indexIn(text);
126         while (index >= 0) {
127                 int length = exprWarning.matchedLength();
128                 setFormat(index, length, warningFormat);
129                 index = exprWarning.indexIn(text, index + length);
130         }
131 #else
132         // $ $
133         static const QRegularExpression exprMath("\\$[^\\$]*\\$");
134         QRegularExpressionMatch match = exprMath.match(text);
135         int index = match.capturedStart(1);
136         while (index >= 0) {
137                 int length = match.capturedEnd(1) - index;
138                 setFormat(index, length, mathFormat);
139                 match = exprMath.match(text, index + length);
140                 index = match.capturedStart(1);
141         }
142         // [ ]
143         static const QRegularExpression exprStartDispMath("(\\\\\\[|"
144                 "\\\\begin\\{equation\\**\\}|"
145                 "\\\\begin\\{eqnarray\\**\\}|"
146                 "\\\\begin\\{align(ed|at)*\\**\\}|"
147                 "\\\\begin\\{flalign\\**\\}|"
148                 "\\\\begin\\{gather\\**\\}|"
149                 "\\\\begin\\{multline\\**\\}|"
150                 "\\\\begin\\{array\\**\\}|"
151                 "\\\\begin\\{cases\\**\\}"
152                 ")");
153         static const QRegularExpression exprEndDispMath("(\\\\\\]|"
154                 "\\\\end\\{equation\\**\\}|"
155                 "\\\\end\\{eqnarray\\**\\}|"
156                 "\\\\end\\{align(ed|at)*\\**\\}|"
157                 "\\\\end\\{flalign\\**\\}|"
158                 "\\\\end\\{gather\\**\\}|"
159                 "\\\\end\\{multline\\**\\}|"
160                 "\\\\end\\{array\\**\\}|"
161                 "\\\\end\\{cases\\**\\}"
162                 ")");
163         int startIndex = 0;
164         // if previous block was in 'disp math'
165         // start search from 0 (for end disp math)
166         // otherwise, start search from 'begin disp math'
167         if (previousBlockState() != 1) {
168                 match = exprStartDispMath.match(text);
169                 startIndex = match.capturedStart(1);
170         }
171         while (startIndex >= 0) {
172                 match = exprEndDispMath.match(text, startIndex);
173                 int endIndex = match.capturedStart(1);
174                 int length;
175                 if (endIndex == -1) {
176                         setCurrentBlockState(1);
177                         length = text.length() - startIndex;
178                 } else {
179                         length = match.capturedEnd(1) - startIndex;
180                 }
181                 setFormat(startIndex, length, mathFormat);
182                 match = exprStartDispMath.match(text, startIndex + length);
183                 startIndex = match.capturedStart(1);
184         }
185         // \whatever
186         static const QRegularExpression exprKeywordAtOther("\\\\[A-Za-z]+");
187         // \wh@tever
188         static const QRegularExpression exprKeywordAtLetter("\\\\[A-Za-z@]+");
189         QRegularExpression const & exprKeyword = at_letter_
190                         ? exprKeywordAtLetter : exprKeywordAtOther;
191         match = exprKeyword.match(text);
192         index = match.capturedStart(1);
193         while (index >= 0) {
194                 int length = match.capturedEnd(1) - index;
195                 setFormat(index, length, keywordFormat);
196                 match = exprKeyword.match(text, index + length);
197                 index = match.capturedStart(1);
198         }
199         // %comment
200         // Treat a line as a comment starting at a percent sign
201         // * that is the first character in a line
202         // * that is preceded by
203         // ** an even number of backslashes
204         // ** any character other than a backslash
205         QRegularExpression exprComment("(?:^|[^\\\\])(?:\\\\\\\\)*(%).*$");
206         match = exprComment.match(text);
207         index = match.capturedStart(1);
208         while (index >= 0) {
209                 int const length = match.capturedEnd(1) - index
210                                  - (index - match.capturedStart(0));
211                 setFormat(index, length, commentFormat);
212                 match = exprComment.match(text, index + length);
213                 index = match.capturedStart(1);
214         }
215         // <LyX Warning: ...>
216         QString lyxwarn = qt_("LyX Warning: ");
217         QRegularExpression exprWarning("<" + lyxwarn + "[^<]*>");
218         match = exprWarning.match(text);
219         index = match.capturedStart(1);
220         while (index >= 0) {
221                 int length = match.capturedEnd(1) - index;
222                 setFormat(index, length, warningFormat);
223                 match = exprWarning.match(text, index + length);
224                 index = match.capturedStart(1);
225         }
226 #endif
227 }
228
229 } // namespace frontend
230 } // namespace lyx