1 // Copyright (C) 2015-2016 OPEN CASCADE
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License, or (at your option) any later version.
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 // Lesser General Public License for more details.
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
19 // File : PyEditor_PyHighlighter.cxx
20 // Author : Maxim GLIBIN, Open CASCADE S.A.S. (maxim.glibin@opencascade.com)
23 #include "PyEditor_PyHighlighter.h"
25 #include "PyEditor_Keywords.h"
30 #define TRIPLESINGLE 1
31 #define TRIPLEDOUBLE 2
34 \class PyEditor_PyHighlighter
35 \brief Python highlighter class defines the syntax highlighting rules.
38 PyEditor_PyHighlighter::TextBlockData::TextBlockData()
42 QVector<PyEditor_PyHighlighter::ParenthesisInfo*> PyEditor_PyHighlighter::TextBlockData::parentheses()
47 void PyEditor_PyHighlighter::TextBlockData::insert( PyEditor_PyHighlighter::ParenthesisInfo* theInfo )
50 while ( i < myParentheses.size() && theInfo->position > myParentheses.at(i)->position )
53 myParentheses.insert( i, theInfo );
58 \param theDocument container for structured rich text documents.
60 PyEditor_PyHighlighter::PyEditor_PyHighlighter( QTextDocument* theDocument,
61 PyEditor_Keywords* std,
62 PyEditor_Keywords* user )
63 : QSyntaxHighlighter( theDocument ),
65 myUserKeywords( user )
68 connect(myStdKeywords, SIGNAL( keywordsChanged() ),
69 this, SLOT( onKeywordsChanged() ) );
70 connect(myUserKeywords, SIGNAL( keywordsChanged() ),
71 this, SLOT( onKeywordsChanged() ) );
76 void PyEditor_PyHighlighter::highlightBlock( const QString& theText )
78 TextBlockData* aData = new TextBlockData;
80 insertBracketsData( RoundBrackets, aData, theText );
81 insertBracketsData( CurlyBrackets, aData, theText );
82 insertBracketsData( SquareBrackets, aData, theText );
84 setCurrentBlockUserData( aData );
86 foreach ( const HighlightingRule& rule, highlightingRules )
88 QRegExp expression( rule.pattern );
89 int anIndex = expression.indexIn( theText );
90 while ( anIndex >= 0 )
92 anIndex = expression.pos( rule.capture );
93 int aLength = expression.cap( rule.capture ).length();
94 setFormat( anIndex, aLength, rule.format );
95 anIndex = expression.indexIn( theText, anIndex + aLength );
99 setCurrentBlockState( NORMAL );
101 if ( theText.indexOf( tripleQuotesExpression ) != -1 )
104 QList<int> aTripleSingle;
105 aTripleSingle << theText.indexOf( tripleSingleExpression ) << TRIPLESINGLE;
107 QList<int> aTripleDouble;
108 aTripleDouble << theText.indexOf( tripleDoubleExpression ) << TRIPLEDOUBLE;
110 QList< QList<int> > aTripleExpressions;
111 aTripleExpressions << aTripleSingle << aTripleDouble;
113 for ( int i = 0; i < aTripleExpressions.length(); i++ )
115 QList<int> aBlock = aTripleExpressions[i];
116 int anIndex = aBlock[0];
117 int aState = aBlock[1];
118 if ( previousBlockState() == aState )
122 anIndex = theText.length();
123 setCurrentBlockState( aState );
125 setFormat( 0, anIndex + 3, multiLineCommentFormat );
127 else if ( anIndex > -1 )
129 setCurrentBlockState( aState );
130 setFormat( anIndex, theText.length(), multiLineCommentFormat );
135 void PyEditor_PyHighlighter::insertBracketsData( char theLeftSymbol,
137 TextBlockData* theData,
138 const QString& theText )
140 int leftPosition = theText.indexOf( theLeftSymbol );
141 while( leftPosition != -1 )
143 ParenthesisInfo* info = new ParenthesisInfo();
144 info->character = theLeftSymbol;
145 info->position = leftPosition;
147 theData->insert( info );
148 leftPosition = theText.indexOf( theLeftSymbol, leftPosition + 1 );
151 int rightPosition = theText.indexOf( theRightSymbol );
152 while( rightPosition != -1 )
154 ParenthesisInfo* info = new ParenthesisInfo();
155 info->character = theRightSymbol;
156 info->position = rightPosition;
158 theData->insert( info );
159 rightPosition = theText.indexOf( theRightSymbol, rightPosition + 1 );
163 void PyEditor_PyHighlighter::insertBracketsData( Brackets theBrackets,
164 TextBlockData* theData,
165 const QString& theText )
168 char rightChar = '0';
170 switch( theBrackets )
186 insertBracketsData( leftChar, rightChar, theData, theText );
189 void PyEditor_PyHighlighter::onKeywordsChanged()
195 void PyEditor_PyHighlighter::updateHighlight()
197 highlightingRules.clear();
199 HighlightingRule aRule;
201 QList<PyEditor_Keywords*> dictList;
202 dictList << myStdKeywords << myUserKeywords;
205 QSet<QString> existing;
206 for ( QList<PyEditor_Keywords*>::const_iterator it = dictList.begin();
207 it != dictList.end(); ++it ) {
208 PyEditor_Keywords* kwDict = *it;
209 QList<QColor> colors = kwDict->colors();
210 for ( QList<QColor>::const_iterator itr = colors.begin(); itr != colors.end(); ++itr ) {
212 QTextCharFormat format;
213 format.setForeground( color );
214 QStringList keywords = kwDict->keywords( color );
215 foreach ( const QString& keyword, keywords ) {
216 if ( existing.contains( keyword ) )
219 aRule.pattern = QRegExp( QString( "\\b%1\\b" ).arg( keyword ) );
220 aRule.format = format;
222 highlightingRules.append( aRule );
223 existing.insert( keyword );
228 // Reference to the current instance of the class
229 referenceClassFormat.setForeground( QColor( 179, 143, 0 ) );
230 referenceClassFormat.setFontItalic( true );
231 aRule.pattern = QRegExp( "\\bself\\b" );
232 aRule.format = referenceClassFormat;
234 highlightingRules.append( aRule );
237 numberFormat.setForeground( Qt::darkMagenta );
238 aRule.pattern = QRegExp( "\\b([-+])?(\\d+(\\.)?\\d*|\\d*(\\.)?\\d+)(([eE]([-+])?)?\\d+)?\\b" );
239 aRule.format = numberFormat;
241 highlightingRules.append( aRule );
244 quotationFormat.setForeground( Qt::darkGreen );
245 aRule.pattern = QRegExp( "(?:'[^']*'|\"[^\"]*\")" );
246 aRule.pattern.setMinimal( true );
247 aRule.format = quotationFormat;
249 highlightingRules.append( aRule );
252 functionFormat.setFontWeight( QFont::Bold );
253 aRule.pattern = QRegExp( "(?:def\\s*)(\\b[A-Za-z0-9_]+)(?=[\\W])" );
255 aRule.format = functionFormat;
256 highlightingRules.append( aRule );
259 classFormat.setForeground( Qt::darkBlue );
260 classFormat.setFontWeight( QFont::Bold );
261 aRule.pattern = QRegExp( "(?:class\\s*)(\\b[A-Za-z0-9_]+)(?=[\\W])" );
263 aRule.format = classFormat;
264 highlightingRules.append( aRule );
266 // Multi line comments
267 multiLineCommentFormat.setForeground( Qt::darkRed );
268 tripleQuotesExpression = QRegExp( "(:?\"[\"]\".*\"[\"]\"|'''.*''')" );
269 aRule.pattern = tripleQuotesExpression;
270 aRule.pattern.setMinimal( true );
271 aRule.format = multiLineCommentFormat;
273 highlightingRules.append( aRule );
275 tripleSingleExpression = QRegExp( "'''(?!\")" );
276 tripleDoubleExpression = QRegExp( "\"\"\"(?!')" );
279 singleLineCommentFormat.setForeground( Qt::darkGray );
280 aRule.pattern = QRegExp( "#[^\n]*" );
281 aRule.format = singleLineCommentFormat;
283 highlightingRules.append( aRule );