| 
									
										
										
										
											2009-09-17 12:29:06 +02:00
										 |  |  | /**************************************************************************
 | 
					
						
							|  |  |  | ** | 
					
						
							|  |  |  | ** This file is part of Qt Creator | 
					
						
							|  |  |  | ** | 
					
						
							|  |  |  | ** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). | 
					
						
							|  |  |  | ** | 
					
						
							|  |  |  | ** Contact: Nokia Corporation (qt-info@nokia.com) | 
					
						
							|  |  |  | ** | 
					
						
							|  |  |  | ** Commercial Usage | 
					
						
							|  |  |  | ** | 
					
						
							|  |  |  | ** Licensees holding valid Qt Commercial licenses may use this file in | 
					
						
							|  |  |  | ** accordance with the Qt Commercial License Agreement provided with the | 
					
						
							|  |  |  | ** Software or, alternatively, in accordance with the terms contained in | 
					
						
							|  |  |  | ** a written agreement between you and Nokia. | 
					
						
							|  |  |  | ** | 
					
						
							|  |  |  | ** GNU Lesser General Public License Usage | 
					
						
							|  |  |  | ** | 
					
						
							|  |  |  | ** Alternatively, this file may be used under the terms of the GNU Lesser | 
					
						
							|  |  |  | ** General Public License version 2.1 as published by the Free Software | 
					
						
							|  |  |  | ** Foundation and appearing in the file LICENSE.LGPL included in the | 
					
						
							|  |  |  | ** packaging of this file.  Please review the following information to | 
					
						
							|  |  |  | ** ensure the GNU Lesser General Public License version 2.1 requirements | 
					
						
							|  |  |  | ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
 | 
					
						
							|  |  |  | ** | 
					
						
							|  |  |  | ** If you are unsure which license is appropriate for your use, please | 
					
						
							|  |  |  | ** contact the sales department at http://qt.nokia.com/contact.
 | 
					
						
							|  |  |  | ** | 
					
						
							|  |  |  | **************************************************************************/ | 
					
						
							|  |  |  | #include "BackwardsScanner.h"
 | 
					
						
							| 
									
										
										
										
											2009-09-17 15:44:54 +02:00
										 |  |  | #include <Token.h>
 | 
					
						
							| 
									
										
										
										
											2009-09-17 12:29:06 +02:00
										 |  |  | #include <QtGui/QTextCursor>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | using namespace CPlusPlus; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-09-17 17:57:17 +02:00
										 |  |  | BackwardsScanner::BackwardsScanner(const QTextCursor &cursor, const QString &suffix, int maxBlockCount) | 
					
						
							| 
									
										
										
										
											2009-09-17 12:29:06 +02:00
										 |  |  |     : _offset(0) | 
					
						
							|  |  |  |     , _blocksTokenized(0) | 
					
						
							|  |  |  |     , _block(cursor.block()) | 
					
						
							|  |  |  |     , _maxBlockCount(maxBlockCount) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2009-09-21 15:11:18 +02:00
										 |  |  |     _tokenize.setQtMocRunEnabled(true); | 
					
						
							| 
									
										
										
										
											2009-09-17 12:29:06 +02:00
										 |  |  |     _tokenize.setSkipComments(true); | 
					
						
							| 
									
										
										
										
											2009-11-11 09:21:06 +01:00
										 |  |  |     _tokenize.setObjCEnabled(true); | 
					
						
							| 
									
										
										
										
											2009-09-17 12:29:06 +02:00
										 |  |  |     _text = _block.text().left(cursor.position() - cursor.block().position()); | 
					
						
							| 
									
										
										
										
											2009-09-17 17:57:17 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if (! suffix.isEmpty()) | 
					
						
							|  |  |  |         _text += suffix; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-09-17 12:29:06 +02:00
										 |  |  |     _tokens.append(_tokenize(_text, previousBlockState(_block))); | 
					
						
							| 
									
										
										
										
											2009-09-18 11:14:54 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     _startToken = _tokens.size(); | 
					
						
							| 
									
										
										
										
											2009-09-17 12:29:06 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-09-17 15:44:54 +02:00
										 |  |  | int BackwardsScanner::state() const | 
					
						
							|  |  |  | { return _tokenize.state(); } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-09-21 15:11:18 +02:00
										 |  |  | SimpleToken BackwardsScanner::LA(int index) const | 
					
						
							| 
									
										
										
										
											2009-09-18 11:14:54 +02:00
										 |  |  | { return const_cast<BackwardsScanner *>(this)->fetchToken(_startToken - index); } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-09-21 15:11:18 +02:00
										 |  |  | SimpleToken BackwardsScanner::operator[](int index) const | 
					
						
							| 
									
										
										
										
											2009-09-18 11:14:54 +02:00
										 |  |  | { return const_cast<BackwardsScanner *>(this)->fetchToken(index); } | 
					
						
							| 
									
										
										
										
											2009-09-17 15:44:54 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | const SimpleToken &BackwardsScanner::fetchToken(int i) | 
					
						
							| 
									
										
										
										
											2009-09-17 12:29:06 +02:00
										 |  |  | { | 
					
						
							|  |  |  |     while (_offset + i < 0) { | 
					
						
							|  |  |  |         _block = _block.previous(); | 
					
						
							|  |  |  |         if (_blocksTokenized == _maxBlockCount || !_block.isValid()) { | 
					
						
							|  |  |  |             ++_offset; | 
					
						
							|  |  |  |             _tokens.prepend(SimpleToken()); // sentinel
 | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |             ++_blocksTokenized; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-12-07 18:26:47 +01:00
										 |  |  |             QString blockText = _block.text(); | 
					
						
							|  |  |  |             _text.prepend(QLatin1Char('\n')); | 
					
						
							| 
									
										
										
										
											2009-09-17 12:29:06 +02:00
										 |  |  |             _text.prepend(blockText); | 
					
						
							| 
									
										
										
										
											2009-09-21 15:11:18 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-09-17 12:29:06 +02:00
										 |  |  |             QList<SimpleToken> adaptedTokens; | 
					
						
							|  |  |  |             for (int i = 0; i < _tokens.size(); ++i) { | 
					
						
							| 
									
										
										
										
											2009-09-21 15:11:18 +02:00
										 |  |  |                 SimpleToken t = _tokens.at(i); | 
					
						
							| 
									
										
										
										
											2009-12-07 18:26:47 +01:00
										 |  |  |                 t.setPosition(t.position() + blockText.length() + 1); | 
					
						
							| 
									
										
										
										
											2009-09-21 15:11:18 +02:00
										 |  |  |                 t.setText(_text.midRef(t.position(), t.length())); | 
					
						
							|  |  |  |                 adaptedTokens.append(t); | 
					
						
							| 
									
										
										
										
											2009-09-17 12:29:06 +02:00
										 |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             _tokens = _tokenize(blockText, previousBlockState(_block)); | 
					
						
							|  |  |  |             _offset += _tokens.size(); | 
					
						
							|  |  |  |             _tokens += adaptedTokens; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return _tokens.at(_offset + i); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-09-17 15:44:54 +02:00
										 |  |  | int BackwardsScanner::startToken() const | 
					
						
							| 
									
										
										
										
											2009-09-18 11:14:54 +02:00
										 |  |  | { return _startToken; } | 
					
						
							| 
									
										
										
										
											2009-09-17 15:44:54 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-09-17 12:29:06 +02:00
										 |  |  | int BackwardsScanner::startPosition() const | 
					
						
							|  |  |  | { return _block.position(); } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-09-17 15:44:54 +02:00
										 |  |  | QString BackwardsScanner::text() const | 
					
						
							| 
									
										
										
										
											2009-09-17 12:29:06 +02:00
										 |  |  | { return _text; } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-09-21 17:38:25 +02:00
										 |  |  | QString BackwardsScanner::mid(int index) const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     const SimpleToken &firstToken = _tokens.at(index + _offset); | 
					
						
							|  |  |  |     return _text.mid(firstToken.begin()); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-09-21 16:09:01 +02:00
										 |  |  | QString BackwardsScanner::text(int index) const | 
					
						
							| 
									
										
										
										
											2009-09-17 12:29:06 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2009-09-21 16:09:01 +02:00
										 |  |  |     const SimpleToken &firstToken = _tokens.at(index + _offset); | 
					
						
							|  |  |  |     return _text.mid(firstToken.begin(), firstToken.length()); | 
					
						
							| 
									
										
										
										
											2009-09-17 12:29:06 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-09-21 16:09:01 +02:00
										 |  |  | QStringRef BackwardsScanner::textRef(int index) const | 
					
						
							| 
									
										
										
										
											2009-09-17 15:44:54 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2009-09-21 16:09:01 +02:00
										 |  |  |     const SimpleToken &firstToken = _tokens.at(index + _offset); | 
					
						
							|  |  |  |     return _text.midRef(firstToken.begin(), firstToken.length()); | 
					
						
							| 
									
										
										
										
											2009-09-17 15:44:54 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int BackwardsScanner::previousBlockState(const QTextBlock &block) const | 
					
						
							| 
									
										
										
										
											2009-09-17 12:29:06 +02:00
										 |  |  | { | 
					
						
							|  |  |  |     const QTextBlock prevBlock = block.previous(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (prevBlock.isValid()) { | 
					
						
							|  |  |  |         int state = prevBlock.userState(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (state != -1) | 
					
						
							|  |  |  |             return state; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return 0; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2009-09-17 15:44:54 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-11-02 19:14:40 +01:00
										 |  |  | int BackwardsScanner::size() const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return _tokens.size(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-09-17 15:44:54 +02:00
										 |  |  | int BackwardsScanner::startOfMatchingBrace(int index) const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     const BackwardsScanner &tk = *this; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (tk[index - 1].is(T_RPAREN)) { | 
					
						
							|  |  |  |         int i = index - 1; | 
					
						
							|  |  |  |         int count = 0; | 
					
						
							|  |  |  |         do { | 
					
						
							|  |  |  |             if (tk[i].is(T_LPAREN)) { | 
					
						
							|  |  |  |                 if (! ++count) | 
					
						
							|  |  |  |                     return i; | 
					
						
							|  |  |  |             } else if (tk[i].is(T_RPAREN)) | 
					
						
							|  |  |  |                 --count; | 
					
						
							|  |  |  |             --i; | 
					
						
							|  |  |  |         } while (count != 0 && tk[i].isNot(T_EOF_SYMBOL)); | 
					
						
							|  |  |  |     } else if (tk[index - 1].is(T_RBRACKET)) { | 
					
						
							|  |  |  |         int i = index - 1; | 
					
						
							|  |  |  |         int count = 0; | 
					
						
							|  |  |  |         do { | 
					
						
							|  |  |  |             if (tk[i].is(T_LBRACKET)) { | 
					
						
							|  |  |  |                 if (! ++count) | 
					
						
							|  |  |  |                     return i; | 
					
						
							|  |  |  |             } else if (tk[i].is(T_RBRACKET)) | 
					
						
							|  |  |  |                 --count; | 
					
						
							|  |  |  |             --i; | 
					
						
							|  |  |  |         } while (count != 0 && tk[i].isNot(T_EOF_SYMBOL)); | 
					
						
							| 
									
										
										
										
											2009-09-21 15:11:18 +02:00
										 |  |  |     } else if (tk[index - 1].is(T_RBRACE)) { | 
					
						
							|  |  |  |         int i = index - 1; | 
					
						
							|  |  |  |         int count = 0; | 
					
						
							|  |  |  |         do { | 
					
						
							|  |  |  |             if (tk[i].is(T_LBRACE)) { | 
					
						
							|  |  |  |                 if (! ++count) | 
					
						
							|  |  |  |                     return i; | 
					
						
							|  |  |  |             } else if (tk[i].is(T_RBRACE)) | 
					
						
							|  |  |  |                 --count; | 
					
						
							|  |  |  |             --i; | 
					
						
							|  |  |  |         } while (count != 0 && tk[i].isNot(T_EOF_SYMBOL)); | 
					
						
							| 
									
										
										
										
											2009-09-17 15:44:54 +02:00
										 |  |  |     } else if (tk[index - 1].is(T_GREATER)) { | 
					
						
							|  |  |  |         int i = index - 1; | 
					
						
							|  |  |  |         int count = 0; | 
					
						
							|  |  |  |         do { | 
					
						
							|  |  |  |             if (tk[i].is(T_LESS)) { | 
					
						
							|  |  |  |                 if (! ++count) | 
					
						
							|  |  |  |                     return i; | 
					
						
							|  |  |  |             } else if (tk[i].is(T_GREATER)) | 
					
						
							|  |  |  |                 --count; | 
					
						
							|  |  |  |             --i; | 
					
						
							|  |  |  |         } while (count != 0 && tk[i].isNot(T_EOF_SYMBOL)); | 
					
						
							| 
									
										
										
										
											2009-09-21 15:11:18 +02:00
										 |  |  |     } else { | 
					
						
							|  |  |  |         Q_ASSERT(0); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return index; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int BackwardsScanner::startOfLine(int index) const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     const BackwardsScanner tk(*this); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     forever { | 
					
						
							|  |  |  |         const SimpleToken &tok = tk[index - 1]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (tok.is(T_EOF_SYMBOL)) | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |         else if (tok.followsNewline()) | 
					
						
							|  |  |  |             return index - 1; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         --index; | 
					
						
							| 
									
										
										
										
											2009-09-17 15:44:54 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return index; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2009-09-21 15:11:18 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | int BackwardsScanner::startOfBlock(int index) const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     const BackwardsScanner tk(*this); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const int start = index; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     forever { | 
					
						
							|  |  |  |         SimpleToken token = tk[index - 1]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (token.is(T_EOF_SYMBOL)) { | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         } else if (token.is(T_GREATER)) { | 
					
						
							|  |  |  |             const int matchingBrace = startOfMatchingBrace(index); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             if (matchingBrace != index && tk[matchingBrace - 1].is(T_TEMPLATE)) | 
					
						
							|  |  |  |                 index = matchingBrace; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         } else if (token.is(T_RPAREN) || token.is(T_RBRACKET) || token.is(T_RBRACE)) { | 
					
						
							|  |  |  |             const int matchingBrace = startOfMatchingBrace(index); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             if (matchingBrace != index) | 
					
						
							|  |  |  |                 index = matchingBrace; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         } else if (token.is(T_LPAREN) || token.is(T_LBRACKET)) { | 
					
						
							|  |  |  |             break; // unmatched brace
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         } else if (token.is(T_LBRACE)) { | 
					
						
							|  |  |  |             return index - 1; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         --index; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return start; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-12-07 18:26:47 +01:00
										 |  |  | QString BackwardsScanner::indentationString(int index) const | 
					
						
							| 
									
										
										
										
											2009-09-21 15:11:18 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2009-12-07 18:26:47 +01:00
										 |  |  |     const SimpleToken tokenAfterNewline = operator[](startOfLine(index + 1)); | 
					
						
							|  |  |  |     const int newlinePos = qMax(0, _text.lastIndexOf(QLatin1Char('\n'), tokenAfterNewline.position())); | 
					
						
							|  |  |  |     return _text.mid(newlinePos, tokenAfterNewline.position() - newlinePos); | 
					
						
							| 
									
										
										
										
											2009-09-21 15:11:18 +02:00
										 |  |  | } |