forked from qt-creator/qt-creator
Added the helper class MatchingText and use it to automagically insert text for curly braces.
This commit is contained in:
@@ -27,6 +27,7 @@
|
||||
**
|
||||
**************************************************************************/
|
||||
#include "BackwardsScanner.h"
|
||||
#include <Token.h>
|
||||
#include <QtGui/QTextCursor>
|
||||
|
||||
using namespace CPlusPlus;
|
||||
@@ -42,10 +43,16 @@ BackwardsScanner::BackwardsScanner(const QTextCursor &cursor, int maxBlockCount)
|
||||
_tokens.append(_tokenize(_text, previousBlockState(_block)));
|
||||
}
|
||||
|
||||
QList<SimpleToken> BackwardsScanner::tokens() const
|
||||
int BackwardsScanner::state() const
|
||||
{ return _tokenize.state(); }
|
||||
|
||||
const QList<SimpleToken> &BackwardsScanner::tokens() const
|
||||
{ return _tokens; }
|
||||
|
||||
const SimpleToken &BackwardsScanner::operator[](int i)
|
||||
const SimpleToken &BackwardsScanner::operator[](int i) const
|
||||
{ return const_cast<BackwardsScanner *>(this)->fetchToken(i); }
|
||||
|
||||
const SimpleToken &BackwardsScanner::fetchToken(int i)
|
||||
{
|
||||
while (_offset + i < 0) {
|
||||
_block = _block.previous();
|
||||
@@ -77,10 +84,13 @@ const SimpleToken &BackwardsScanner::operator[](int i)
|
||||
return _tokens.at(_offset + i);
|
||||
}
|
||||
|
||||
int BackwardsScanner::startToken() const
|
||||
{ return _tokens.size(); }
|
||||
|
||||
int BackwardsScanner::startPosition() const
|
||||
{ return _block.position(); }
|
||||
|
||||
const QString &BackwardsScanner::text() const
|
||||
QString BackwardsScanner::text() const
|
||||
{ return _text; }
|
||||
|
||||
QString BackwardsScanner::text(int begin, int end) const
|
||||
@@ -90,7 +100,14 @@ QString BackwardsScanner::text(int begin, int end) const
|
||||
return _text.mid(firstToken.begin(), lastToken.end() - firstToken.begin());
|
||||
}
|
||||
|
||||
int BackwardsScanner::previousBlockState(const QTextBlock &block)
|
||||
QStringRef BackwardsScanner::textRef(int begin, int end) const
|
||||
{
|
||||
const SimpleToken &firstToken = _tokens.at(begin + _offset);
|
||||
const SimpleToken &lastToken = _tokens.at(end + _offset - 1);
|
||||
return _text.midRef(firstToken.begin(), lastToken.end() - firstToken.begin());
|
||||
}
|
||||
|
||||
int BackwardsScanner::previousBlockState(const QTextBlock &block) const
|
||||
{
|
||||
const QTextBlock prevBlock = block.previous();
|
||||
|
||||
@@ -103,3 +120,45 @@ int BackwardsScanner::previousBlockState(const QTextBlock &block)
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
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));
|
||||
} 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));
|
||||
}
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
@@ -43,13 +43,23 @@ class CPLUSPLUS_EXPORT BackwardsScanner
|
||||
public:
|
||||
BackwardsScanner(const QTextCursor &cursor, int maxBlockCount = MAX_BLOCK_COUNT);
|
||||
|
||||
QList<SimpleToken> tokens() const;
|
||||
int startPosition() const;
|
||||
const QString &text() const;
|
||||
int state() const;
|
||||
int startToken() const;
|
||||
|
||||
const SimpleToken &operator[](int i);
|
||||
int startPosition() const;
|
||||
|
||||
QString text() const;
|
||||
QString text(int begin, int end) const;
|
||||
int previousBlockState(const QTextBlock &block);
|
||||
QStringRef textRef(int begin, int end) const;
|
||||
|
||||
const SimpleToken &operator[](int i) const;
|
||||
|
||||
int startOfMatchingBrace(int index) const;
|
||||
int previousBlockState(const QTextBlock &block) const;
|
||||
|
||||
private:
|
||||
const SimpleToken &fetchToken(int i);
|
||||
const QList<SimpleToken> &tokens() const;
|
||||
|
||||
private:
|
||||
QList<SimpleToken> _tokens;
|
||||
|
||||
@@ -43,46 +43,6 @@ ExpressionUnderCursor::ExpressionUnderCursor()
|
||||
ExpressionUnderCursor::~ExpressionUnderCursor()
|
||||
{ }
|
||||
|
||||
int ExpressionUnderCursor::startOfMatchingBrace(BackwardsScanner &tk, int index)
|
||||
{
|
||||
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));
|
||||
} 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));
|
||||
}
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
int ExpressionUnderCursor::startOfExpression(BackwardsScanner &tk, int index)
|
||||
{
|
||||
// tk is a reference to a const QList. So, don't worry about [] access.
|
||||
@@ -122,10 +82,10 @@ int ExpressionUnderCursor::startOfExpression(BackwardsScanner &tk, int index)
|
||||
}
|
||||
return index - 1;
|
||||
} else if (tk[index - 1].is(T_RPAREN)) {
|
||||
int rparenIndex = startOfMatchingBrace(tk, index);
|
||||
int rparenIndex = tk.startOfMatchingBrace(index);
|
||||
if (rparenIndex != index) {
|
||||
if (tk[rparenIndex - 1].is(T_GREATER)) {
|
||||
int lessIndex = startOfMatchingBrace(tk, rparenIndex);
|
||||
int lessIndex = tk.startOfMatchingBrace(rparenIndex);
|
||||
if (lessIndex != rparenIndex - 1) {
|
||||
if (tk[lessIndex - 1].is(T_DYNAMIC_CAST) ||
|
||||
tk[lessIndex - 1].is(T_STATIC_CAST) ||
|
||||
@@ -144,13 +104,13 @@ int ExpressionUnderCursor::startOfExpression(BackwardsScanner &tk, int index)
|
||||
}
|
||||
return index;
|
||||
} else if (tk[index - 1].is(T_RBRACKET)) {
|
||||
int rbracketIndex = startOfMatchingBrace(tk, index);
|
||||
int rbracketIndex = tk.startOfMatchingBrace(index);
|
||||
if (rbracketIndex != index)
|
||||
return startOfExpression(tk, rbracketIndex);
|
||||
return index;
|
||||
} else if (tk[index - 1].is(T_COLON_COLON)) {
|
||||
if (tk[index - 2].is(T_GREATER)) { // ### not exactly
|
||||
int lessIndex = startOfMatchingBrace(tk, index - 1);
|
||||
int lessIndex = tk.startOfMatchingBrace(index - 1);
|
||||
if (lessIndex != index - 1)
|
||||
return startOfExpression(tk, lessIndex);
|
||||
return index - 1;
|
||||
@@ -185,7 +145,7 @@ QString ExpressionUnderCursor::operator()(const QTextCursor &cursor)
|
||||
|
||||
_jumpedComma = false;
|
||||
|
||||
const int initialSize = scanner.tokens().size();
|
||||
const int initialSize = scanner.startToken();
|
||||
const int i = startOfExpression(scanner, initialSize);
|
||||
if (i == initialSize)
|
||||
return QString();
|
||||
@@ -199,7 +159,7 @@ int ExpressionUnderCursor::startOfFunctionCall(const QTextCursor &cursor)
|
||||
|
||||
BackwardsScanner scanner(cursor);
|
||||
|
||||
int index = scanner.tokens().size();
|
||||
int index = scanner.startToken();
|
||||
|
||||
forever {
|
||||
const SimpleToken &tk = scanner[index - 1];
|
||||
@@ -209,7 +169,7 @@ int ExpressionUnderCursor::startOfFunctionCall(const QTextCursor &cursor)
|
||||
else if (tk.is(T_LPAREN))
|
||||
return scanner.startPosition() + tk.position();
|
||||
else if (tk.is(T_RPAREN)) {
|
||||
int matchingBrace = startOfMatchingBrace(scanner, index);
|
||||
int matchingBrace = scanner.startOfMatchingBrace(index);
|
||||
|
||||
if (matchingBrace == index) // If no matching brace found
|
||||
return -1;
|
||||
|
||||
@@ -54,7 +54,6 @@ public:
|
||||
int startOfFunctionCall(const QTextCursor &cursor);
|
||||
|
||||
private:
|
||||
int startOfMatchingBrace(BackwardsScanner &tk, int index);
|
||||
int startOfExpression(BackwardsScanner &tk, int index);
|
||||
int previousBlockState(const QTextBlock &block);
|
||||
bool isAccessToken(const SimpleToken &tk);
|
||||
|
||||
131
src/libs/cplusplus/MatchingText.cpp
Normal file
131
src/libs/cplusplus/MatchingText.cpp
Normal file
@@ -0,0 +1,131 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** 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 "MatchingText.h"
|
||||
#include "BackwardsScanner.h"
|
||||
|
||||
#include <Token.h>
|
||||
#include <QtDebug>
|
||||
|
||||
using namespace CPlusPlus;
|
||||
|
||||
MatchingText::MatchingText()
|
||||
{ }
|
||||
|
||||
QString MatchingText::insertParagraphSeparator(const QTextCursor &tc) const
|
||||
{
|
||||
BackwardsScanner tk(tc, 400);
|
||||
int index = tk.startToken();
|
||||
|
||||
if (tk[index - 1].isNot(T_LBRACE))
|
||||
return QString(); // nothing to do.
|
||||
|
||||
--index; // consume the `{'
|
||||
|
||||
const SimpleToken &token = tk[index - 1];
|
||||
|
||||
if (token.is(T_STRING_LITERAL) && tk[index - 2].is(T_EXTERN)) {
|
||||
// recognized extern "C"
|
||||
return QLatin1String("}");
|
||||
|
||||
} else if (token.is(T_IDENTIFIER)) {
|
||||
int i = index - 1;
|
||||
|
||||
forever {
|
||||
const SimpleToken ¤t = tk[i - 1];
|
||||
|
||||
if (current.is(T_EOF_SYMBOL))
|
||||
break;
|
||||
|
||||
else if (current.is(T_CLASS) || current.is(T_STRUCT) || current.is(T_UNION))
|
||||
return QLatin1String("};"); // found a class key.
|
||||
|
||||
else if (current.is(T_NAMESPACE))
|
||||
return QLatin1String("}"); // found a namespace declaration
|
||||
|
||||
else if (current.is(T_SEMICOLON))
|
||||
break; // found the `;' sync token
|
||||
|
||||
else if (current.is(T_LBRACE) || current.is(T_RBRACE))
|
||||
break; // braces are considered sync tokens
|
||||
|
||||
else if (current.is(T_LPAREN) || current.is(T_RPAREN))
|
||||
break; // sync token
|
||||
|
||||
else if (current.is(T_LBRACKET) || current.is(T_RBRACKET))
|
||||
break; // sync token
|
||||
|
||||
--i;
|
||||
}
|
||||
}
|
||||
|
||||
if (token.is(T_NAMESPACE)) {
|
||||
// anonymous namespace
|
||||
return QLatin1String("}");
|
||||
|
||||
} else if (token.is(T_CLASS) || token.is(T_STRUCT) || token.is(T_UNION)) {
|
||||
if (tk[index - 2].is(T_TYPEDEF)) {
|
||||
// recognized:
|
||||
// typedef struct {
|
||||
//
|
||||
// in this case we don't want to insert the extra semicolon+newline.
|
||||
return QLatin1String("}");
|
||||
}
|
||||
|
||||
// anonymous class
|
||||
return QLatin1String("};");
|
||||
|
||||
} else if (token.is(T_RPAREN)) {
|
||||
// search the matching brace.
|
||||
const int lparenIndex = tk.startOfMatchingBrace(index);
|
||||
|
||||
if (lparenIndex == index) {
|
||||
// found an unmatched brace. We don't really know to do in this case.
|
||||
return QString();
|
||||
}
|
||||
|
||||
// look at the token before the matched brace
|
||||
const SimpleToken &tokenBeforeBrace = tk[lparenIndex - 1];
|
||||
|
||||
if (tokenBeforeBrace.is(T_IF)) {
|
||||
// recognized an if statement
|
||||
return QLatin1String("}");
|
||||
|
||||
} else if (tokenBeforeBrace.is(T_FOR) || tokenBeforeBrace.is(T_WHILE)) {
|
||||
// recognized a for-like statement
|
||||
return QLatin1String("}");
|
||||
|
||||
}
|
||||
|
||||
// if we reached this point there is a good chance that we are parsing a function definition
|
||||
return QLatin1String("}");
|
||||
}
|
||||
|
||||
// match the block
|
||||
return QLatin1String("}");
|
||||
}
|
||||
49
src/libs/cplusplus/MatchingText.h
Normal file
49
src/libs/cplusplus/MatchingText.h
Normal file
@@ -0,0 +1,49 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** 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.
|
||||
**
|
||||
**************************************************************************/
|
||||
#ifndef MATCHINGTEXT_H
|
||||
#define MATCHINGTEXT_H
|
||||
|
||||
#include <CPlusPlusForwardDeclarations.h>
|
||||
#include <QtGui/QTextCursor>
|
||||
|
||||
namespace CPlusPlus {
|
||||
|
||||
class BackwardsScanner;
|
||||
|
||||
class CPLUSPLUS_EXPORT MatchingText
|
||||
{
|
||||
public:
|
||||
MatchingText();
|
||||
|
||||
QString insertParagraphSeparator(const QTextCursor &tc) const;
|
||||
};
|
||||
|
||||
} // end of namespace CPlusPlus
|
||||
|
||||
#endif // MATCHINGTEXT_H
|
||||
@@ -9,6 +9,7 @@ HEADERS += \
|
||||
$$PWD/ExpressionUnderCursor.h \
|
||||
$$PWD/TokenUnderCursor.h \
|
||||
$$PWD/BackwardsScanner.h \
|
||||
$$PWD/MatchingText.h \
|
||||
$$PWD/OverviewModel.h
|
||||
|
||||
SOURCES += \
|
||||
@@ -16,6 +17,7 @@ SOURCES += \
|
||||
$$PWD/ExpressionUnderCursor.cpp \
|
||||
$$PWD/TokenUnderCursor.cpp \
|
||||
$$PWD/BackwardsScanner.cpp \
|
||||
$$PWD/MatchingText.cpp \
|
||||
$$PWD/OverviewModel.cpp
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user