diff --git a/src/libs/cplusplus/BackwardsScanner.cpp b/src/libs/cplusplus/BackwardsScanner.cpp index 251fa9bd19e1f51010857c10db0fea9fdcc06375..07c4688757a103f05087997d84b9e032ae479029 100644 --- a/src/libs/cplusplus/BackwardsScanner.cpp +++ b/src/libs/cplusplus/BackwardsScanner.cpp @@ -32,7 +32,7 @@ using namespace CPlusPlus; -BackwardsScanner::BackwardsScanner(const QTextCursor &cursor, int maxBlockCount) +BackwardsScanner::BackwardsScanner(const QTextCursor &cursor, const QString &suffix, int maxBlockCount) : _offset(0) , _blocksTokenized(0) , _block(cursor.block()) @@ -40,6 +40,10 @@ BackwardsScanner::BackwardsScanner(const QTextCursor &cursor, int maxBlockCount) { _tokenize.setSkipComments(true); _text = _block.text().left(cursor.position() - cursor.block().position()); + + if (! suffix.isEmpty()) + _text += suffix; + _tokens.append(_tokenize(_text, previousBlockState(_block))); } diff --git a/src/libs/cplusplus/BackwardsScanner.h b/src/libs/cplusplus/BackwardsScanner.h index 925527cbcf1b39793b4c2377cdc3d3f178f492ce..7b8e3b6e717f4667956008857f3c9f841c29e228 100644 --- a/src/libs/cplusplus/BackwardsScanner.h +++ b/src/libs/cplusplus/BackwardsScanner.h @@ -41,7 +41,9 @@ class CPLUSPLUS_EXPORT BackwardsScanner enum { MAX_BLOCK_COUNT = 10 }; public: - BackwardsScanner(const QTextCursor &cursor, int maxBlockCount = MAX_BLOCK_COUNT); + BackwardsScanner(const QTextCursor &cursor, + const QString &suffix = QString(), + int maxBlockCount = MAX_BLOCK_COUNT); int state() const; int startToken() const; diff --git a/src/libs/cplusplus/ExpressionUnderCursor.cpp b/src/libs/cplusplus/ExpressionUnderCursor.cpp index 622b420048b6b845fddf8c2f575b6babca341444..106e3040b1bd8abe923f865103afad8beffccee5 100644 --- a/src/libs/cplusplus/ExpressionUnderCursor.cpp +++ b/src/libs/cplusplus/ExpressionUnderCursor.cpp @@ -153,10 +153,8 @@ QString ExpressionUnderCursor::operator()(const QTextCursor &cursor) return scanner.text(i, initialSize); } -int ExpressionUnderCursor::startOfFunctionCall(const QTextCursor &cursor) +int ExpressionUnderCursor::startOfFunctionCall(const QTextCursor &cursor) const { - QString text; - BackwardsScanner scanner(cursor); int index = scanner.startToken(); diff --git a/src/libs/cplusplus/ExpressionUnderCursor.h b/src/libs/cplusplus/ExpressionUnderCursor.h index 2c5ca12bcb6ae612146f0195e5d9ce73953af88a..35be67214df15603e3e2672e1b2456c7800ca58d 100644 --- a/src/libs/cplusplus/ExpressionUnderCursor.h +++ b/src/libs/cplusplus/ExpressionUnderCursor.h @@ -51,7 +51,7 @@ public: ~ExpressionUnderCursor(); QString operator()(const QTextCursor &cursor); - int startOfFunctionCall(const QTextCursor &cursor); + int startOfFunctionCall(const QTextCursor &cursor) const; private: int startOfExpression(BackwardsScanner &tk, int index); diff --git a/src/libs/cplusplus/MatchingText.cpp b/src/libs/cplusplus/MatchingText.cpp index 14449584d140db21803c82b60a50c12d38645bb8..86a31fc9ec58f4fee5e4c3046780fc6f12e09f7b 100644 --- a/src/libs/cplusplus/MatchingText.cpp +++ b/src/libs/cplusplus/MatchingText.cpp @@ -34,17 +34,124 @@ using namespace CPlusPlus; +enum { MAX_NUM_LINES = 400 }; + +static bool maybeOverrideChar(const QChar &ch) +{ + if (ch == QLatin1Char(')')) return true; + else if (ch == QLatin1Char(']')) return true; + else if (ch == QLatin1Char('"')) return true; + else if (ch == QLatin1Char('\'')) return true; + else return false; +} + +static bool isCompleteStringLiteral(const BackwardsScanner &tk, int index, int startToken) +{ + const QStringRef text = tk.textRef(index, startToken); + + if (text.length() < 2) + return false; + + else if (text.at(text.length() - 1) == QLatin1Char('"')) + return text.at(text.length() - 2) != QLatin1Char('\\'); // ### not exactly. + + return false; +} + +static bool isCompleteCharLiteral(const BackwardsScanner &tk, int index, int startToken) +{ + const QStringRef text = tk.textRef(index, startToken); + + if (text.length() < 2) + return false; + + else if (text.at(text.length() - 1) == QLatin1Char('\'')) + return text.at(text.length() - 2) != QLatin1Char('\\'); // ### not exactly. + + return false; +} + MatchingText::MatchingText() { } +QString MatchingText::insertMatchingBrace(const QTextCursor &cursor, const QString &textToProcess, int *skippedChars) const +{ + *skippedChars = 0; + + QTextCursor tc = cursor; + QString text = textToProcess; + + const QString blockText = tc.block().text().mid(tc.columnNumber()); + const int length = qMin(blockText.length(), textToProcess.length()); + + for (int i = 0; i < length; ++i) { + const QChar ch1 = blockText.at(i); + const QChar ch2 = textToProcess.at(i); + + if (ch1 != ch2) + break; + else if (! maybeOverrideChar(ch1)) + break; + + ++*skippedChars; + } + + if (*skippedChars != 0) { + tc.movePosition(QTextCursor::NextCharacter, QTextCursor::MoveAnchor, *skippedChars); + text = textToProcess.mid(*skippedChars); + } + + if (text.isEmpty()) + return QString(); + + BackwardsScanner tk(tc, textToProcess.left(*skippedChars), MAX_NUM_LINES); + const int startToken = tk.startToken(); + int index = startToken; + + const SimpleToken &token = tk[index - 1]; + + if (text.at(0) == QLatin1Char('"') && (token.is(T_STRING_LITERAL) || token.is(T_WIDE_STRING_LITERAL))) { + if (text.length() != 1) + qWarning() << Q_FUNC_INFO << "handle event compression"; + + if (isCompleteStringLiteral(tk, index - 1, startToken)) + return QLatin1String("\""); + + return QString(); + } else if (text.at(0) == QLatin1Char('\'') && (token.is(T_CHAR_LITERAL) || token.is(T_WIDE_CHAR_LITERAL))) { + if (text.length() != 1) + qWarning() << Q_FUNC_INFO << "handle event compression"; + + if (isCompleteCharLiteral(tk, index - 1, startToken)) + return QLatin1String("'"); + + return QString(); + } + + QString result; + + foreach (const QChar &ch, text) { + if (ch == QLatin1Char('(')) result += ')'; + else if (ch == QLatin1Char('[')) result += ']'; + else if (ch == QLatin1Char('"')) result += '"'; + else if (ch == QLatin1Char('\'')) result += '\''; + } + + return result; +} + QString MatchingText::insertParagraphSeparator(const QTextCursor &tc) const { - BackwardsScanner tk(tc, 400); + BackwardsScanner tk(tc, QString(), MAX_NUM_LINES); int index = tk.startToken(); if (tk[index - 1].isNot(T_LBRACE)) return QString(); // nothing to do. + const QString textBlock = tc.block().text().mid(tc.columnNumber()).trimmed(); + if (! textBlock.isEmpty()) + return QString(); + --index; // consume the `{' const SimpleToken &token = tk[index - 1]; diff --git a/src/libs/cplusplus/MatchingText.h b/src/libs/cplusplus/MatchingText.h index 3f7ef2cebf97c3481315cd576992c27950e7437c..f964c4245433d79601f1a18b06de15153fcc315e 100644 --- a/src/libs/cplusplus/MatchingText.h +++ b/src/libs/cplusplus/MatchingText.h @@ -41,6 +41,7 @@ class CPLUSPLUS_EXPORT MatchingText public: MatchingText(); + QString insertMatchingBrace(const QTextCursor &tc, const QString &text, int *skippedChars) const; QString insertParagraphSeparator(const QTextCursor &tc) const; }; diff --git a/src/plugins/cppeditor/cppeditor.cpp b/src/plugins/cppeditor/cppeditor.cpp index ee8f965497d9cc78321eaee44e914273f33411c3..714732e06f9a442314ce527cb38b42249d9bc15e 100644 --- a/src/plugins/cppeditor/cppeditor.cpp +++ b/src/plugins/cppeditor/cppeditor.cpp @@ -1269,6 +1269,27 @@ bool CPPEditor::isElectricCharacter(const QChar &ch) const return false; } +#if 1 +QString CPPEditor::autoComplete(QTextCursor &cursor, const QString &text) const +{ + if (!contextAllowsAutoParentheses(cursor)) + return QString(); + + QString autoText; + int skippedChars = 0; + + MatchingText matchingText; + autoText = matchingText.insertMatchingBrace(cursor, text, &skippedChars); + + if (skippedChars) { + const int pos = cursor.position(); + cursor.setPosition(pos + skippedChars); + cursor.setPosition(pos, QTextCursor::KeepAnchor); + } + + return autoText; +} +#else QString CPPEditor::autoComplete(QTextCursor &cursor, const QString &text) const { bool checkBlockEnd = m_allowSkippingOfBlockEnd; @@ -1328,6 +1349,7 @@ QString CPPEditor::autoComplete(QTextCursor &cursor, const QString &text) const return autoText; } +#endif bool CPPEditor::autoBackspace(QTextCursor &cursor) { @@ -1401,9 +1423,10 @@ bool CPPEditor::contextAllowsAutoParentheses(const QTextCursor &cursor) const { CPlusPlus::TokenUnderCursor tokenUnderCursor; const SimpleToken tk = tokenUnderCursor(cursor); - if (tk.isComment() || tk.isLiteral()) - if (tk.end() > cursor.position() - cursor.block().position()) - return false; + + if (tk.isComment()) + return false; + return true; }