DynExp
Highly flexible laboratory automation for dynamically changing experiments.
Loading...
Searching...
No Matches
PythonSyntaxHighlighter.cpp
Go to the documentation of this file.
1/*
2$Id: PythonSyntaxHighlighter.cpp 167 2013-11-03 17:01:22Z oliver $
3This is a C++ port of the following PyQt example
4http://diotavelli.net/PyQtWiki/Python%20syntax%20highlighting
5C++ port by Frankie Simon (www.kickdrive.de, www.fuh-edv.de)
6
7The following free software license applies for this file ("X11 license"):
8
9Permission is hereby granted, free of charge, to any person obtaining a copy of this software
10and associated documentation files (the "Software"), to deal in the Software without restriction,
11including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
12and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
13subject to the following conditions:
14
15The above copyright notice and this permission notice shall be included in all copies or substantial
16portions of the Software.
17
18THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
19LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
21ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
22USE OR OTHER DEALINGS IN THE SOFTWARE.
23*/
24
25#include "moc_PythonSyntaxHighlighter.cpp"
27
29{
30 keywords = QStringList() << "and" << "assert" << "break" << "class" << "continue" << "def" <<
31 "del" << "elif" << "else" << "except" << "exec" << "finally" <<
32 "for" << "from" << "global" << "if" << "import" << "in" <<
33 "is" << "lambda" << "not" << "or" << "pass" << "print" <<
34 "raise" << "return" << "try" << "while" << "yield" <<
35 "None" << "True" << "False";
36
37 operators = QStringList() << "=" <<
38 // Comparison
39 "==" << "!=" << "<" << "<=" << ">" << ">=" <<
40 // Arithmetic
41 "\\+" << "-" << "\\*" << "/" << "//" << "%" << "\\*\\*" <<
42 // In-place
43 "\\+=" << "-=" << "\\*=" << "/=" << "%=" <<
44 // Bitwise
45 "\\^" << "\\|" << "&" << "~" << ">>" << "<<";
46
47 braces = QStringList() << "{" << "}" << "\\(" << "\\)" << "\\[" << "]";
48
49 basicStyles.insert("keyword", getTextCharFormat("blue"));
50 basicStyles.insert("operator", getTextCharFormat("red"));
51 basicStyles.insert("brace", getTextCharFormat("darkGray"));
52 basicStyles.insert("defclass", getTextCharFormat("black", "bold"));
53 basicStyles.insert("brace", getTextCharFormat("darkGray"));
54 basicStyles.insert("string", getTextCharFormat("magenta"));
55 basicStyles.insert("string2", getTextCharFormat("darkMagenta"));
56 basicStyles.insert("comment", getTextCharFormat("darkGreen", "italic"));
57 basicStyles.insert("self", getTextCharFormat("black", "italic"));
58 basicStyles.insert("numbers", getTextCharFormat("brown"));
59
60 triSingleQuote.setPattern("'''");
61 triDoubleQuote.setPattern("\"\"\"");
62
64}
65
67{
68 foreach(QString currKeyword, keywords)
69 {
70 rules.append(HighlightingRule(QString("\\b%1\\b").arg(currKeyword), 0, basicStyles.value("keyword")));
71 }
72 foreach(QString currOperator, operators)
73 {
74 rules.append(HighlightingRule(QString("%1").arg(currOperator), 0, basicStyles.value("operator")));
75 }
76 foreach(QString currBrace, braces)
77 {
78 rules.append(HighlightingRule(QString("%1").arg(currBrace), 0, basicStyles.value("brace")));
79 }
80 // 'self'
81 rules.append(HighlightingRule("\\bself\\b", 0, basicStyles.value("self")));
82
83 // Double-quoted string, possibly containing escape sequences
84 // FF: originally in python : r'"[^"\\]*(\\.[^"\\]*)*"'
85 rules.append(HighlightingRule("\"[^\"\\\\]*(\\\\.[^\"\\\\]*)*\"", 0, basicStyles.value("string")));
86 // Single-quoted string, possibly containing escape sequences
87 // FF: originally in python : r"'[^'\\]*(\\.[^'\\]*)*'"
88 rules.append(HighlightingRule("'[^'\\\\]*(\\\\.[^'\\\\]*)*'", 0, basicStyles.value("string")));
89
90 // 'def' followed by an identifier
91 // FF: originally: r'\bdef\b\s*(\w+)'
92 rules.append(HighlightingRule("\\bdef\\b\\s*(\\w+)", 1, basicStyles.value("defclass")));
93 // 'class' followed by an identifier
94 // FF: originally: r'\bclass\b\s*(\w+)'
95 rules.append(HighlightingRule("\\bclass\\b\\s*(\\w+)", 1, basicStyles.value("defclass")));
96
97 // From '#' until a newline
98 // FF: originally: r'#[^\\n]*'
99 rules.append(HighlightingRule("#[^\\n]*", 0, basicStyles.value("comment")));
100
101 // Numeric literals
102 rules.append(HighlightingRule("\\b[+-]?[0-9]+[lL]?\\b", 0, basicStyles.value("numbers"))); // r'\b[+-]?[0-9]+[lL]?\b'
103 rules.append(HighlightingRule("\\b[+-]?0[xX][0-9A-Fa-f]+[lL]?\\b", 0, basicStyles.value("numbers"))); // r'\b[+-]?0[xX][0-9A-Fa-f]+[lL]?\b'
104 rules.append(HighlightingRule("\\b[+-]?[0-9]+(?:\\.[0-9]+)?(?:[eE][+-]?[0-9]+)?\\b", 0, basicStyles.value("numbers"))); // r'\b[+-]?[0-9]+(?:\.[0-9]+)?(?:[eE][+-]?[0-9]+)?\b'
105}
106
108{
109 foreach(HighlightingRule currRule, rules)
110 {
111 auto matches = currRule.pattern.globalMatch(text);
112 while (matches.hasNext())
113 {
114 // Get index of Nth match
115 auto match = matches.next();
116 auto idx = match.capturedStart(currRule.nth);
117 int length = match.captured(currRule.nth).length();
118 setFormat(idx, length, currRule.format);
119 }
120 }
121
122 setCurrentBlockState(0);
123
124 // Do multi-line strings
125 bool isInMultilne = matchMultiline(text, triSingleQuote, 1, basicStyles.value("string2"));
126 if (!isInMultilne)
127 isInMultilne = matchMultiline(text, triDoubleQuote, 2, basicStyles.value("string2"));
128}
129
130bool PythonSyntaxHighlighter::matchMultiline(const QString& text, const QRegularExpression& delimiter, const int inState, const QTextCharFormat& style)
131{
132 int start = -1;
133 int add = -1;
134 int end = -1;
135 int length = 0;
136
137 // If inside triple-single quotes, start at 0
138 if (previousBlockState() == inState) {
139 start = 0;
140 add = 0;
141 }
142 // Otherwise, look for the delimiter on this line
143 else {
144 auto match = delimiter.match(text);
145 start = match.capturedStart();
146 // Move past this match
147 add = match.capturedLength();
148 }
149
150 // As long as there's a delimiter match on this line...
151 while (start >= 0) {
152 // Look for the ending delimiter
153 auto match = delimiter.match(text, static_cast<qsizetype>(start) + add);
154 end = match.capturedStart();
155 // Ending delimiter on this line?
156 if (end >= add) {
157 length = static_cast<qsizetype>(end) - start + add + match.capturedLength();
158 setCurrentBlockState(0);
159 }
160 // No; multi-line string
161 else {
162 setCurrentBlockState(inState);
163 length = text.length() - start + add;
164 }
165 // Apply formatting and look for next
166 setFormat(start, length, style);
167 match = delimiter.match(text, static_cast<qsizetype>(start) + length);
168 start = match.capturedStart();
169 }
170 // Return True if still inside a multi-line string, False otherwise
171 if (currentBlockState() == inState)
172 return true;
173 else
174 return false;
175}
176
177const QTextCharFormat PythonSyntaxHighlighter::getTextCharFormat(const QString& colorName, const QString& style)
178{
179 QTextCharFormat charFormat;
180 QColor color(colorName);
181 charFormat.setForeground(color);
182 if (style.contains("bold", Qt::CaseInsensitive))
183 charFormat.setFontWeight(QFont::Bold);
184 if (style.contains("italic", Qt::CaseInsensitive))
185 charFormat.setFontItalic(true);
186 return charFormat;
187}
Container to describe a highlighting rule. Based on a regular expression, a relevant match # and the ...
QRegularExpression pattern
void highlightBlock(const QString &text)
const QTextCharFormat getTextCharFormat(const QString &colorName, const QString &style=QString())
QHash< QString, QTextCharFormat > basicStyles
bool matchMultiline(const QString &text, const QRegularExpression &delimiter, const int inState, const QTextCharFormat &style)
Highlighst multi-line strings, returns true if after processing we are still within the multi-line se...
QList< HighlightingRule > rules