diff --git a/src/libs/cplusplus/MatchingText.cpp b/src/libs/cplusplus/MatchingText.cpp index 16264894d9f..787d98b99f7 100644 --- a/src/libs/cplusplus/MatchingText.cpp +++ b/src/libs/cplusplus/MatchingText.cpp @@ -125,10 +125,52 @@ static int countSkippedChars(const QString blockText, const QString &textToProce return skippedChars; } -bool MatchingText::shouldInsertMatchingText(const QTextCursor &tc) +static const Token tokenAtPosition(const Tokens &tokens, const unsigned pos) { - QTextDocument *doc = tc.document(); - return shouldInsertMatchingText(doc->characterAt(tc.selectionEnd())); + for (int i = tokens.size() - 1; i >= 0; --i) { + const Token tk = tokens.at(i); + if (pos >= tk.utf16charsBegin() && pos < tk.utf16charsEnd()) + return tk; + } + return Token(); +} + +bool MatchingText::contextAllowsAutoParentheses(const QTextCursor &cursor, + const QString &textToInsert) +{ + QChar ch; + + if (!textToInsert.isEmpty()) + ch = textToInsert.at(0); + + if (!shouldInsertMatchingText(cursor) && ch != QLatin1Char('\'') && ch != QLatin1Char('"')) + return false; + else if (isInCommentHelper(cursor)) + return false; + + return true; +} + +bool MatchingText::contextAllowsElectricCharacters(const QTextCursor &cursor) +{ + Token token; + + if (isInCommentHelper(cursor, &token)) + return false; + + if (token.isStringLiteral() || token.isCharLiteral()) { + const unsigned pos = cursor.selectionEnd() - cursor.block().position(); + if (pos <= token.utf16charsEnd()) + return false; + } + + return true; +} + +bool MatchingText::shouldInsertMatchingText(const QTextCursor &cursor) +{ + QTextDocument *doc = cursor.document(); + return shouldInsertMatchingText(doc->characterAt(cursor.selectionEnd())); } bool MatchingText::shouldInsertMatchingText(QChar lookAhead) @@ -147,6 +189,66 @@ bool MatchingText::shouldInsertMatchingText(QChar lookAhead) } // switch } +static Tokens getTokens(const QTextCursor &cursor, int &prevState) +{ + LanguageFeatures features; + features.qtEnabled = false; + features.qtKeywordsEnabled = false; + features.qtMocRunEnabled = false; + features.cxx11Enabled = true; + features.c99Enabled = true; + + SimpleLexer tokenize; + tokenize.setLanguageFeatures(features); + + prevState = BackwardsScanner::previousBlockState(cursor.block()) & 0xFF; + return tokenize(cursor.block().text(), prevState); +} + +bool MatchingText::isInCommentHelper(const QTextCursor &cursor, Token *retToken) +{ + int prevState = 0; + const Tokens tokens = getTokens(cursor, prevState); + + const unsigned pos = cursor.selectionEnd() - cursor.block().position(); + + if (tokens.isEmpty() || pos < tokens.first().utf16charsBegin()) + return prevState > 0; + + if (pos >= tokens.last().utf16charsEnd()) { + const Token tk = tokens.last(); + if (retToken) + *retToken = tk; + if (tk.is(T_CPP_COMMENT) || tk.is(T_CPP_DOXY_COMMENT)) + return true; + return tk.isComment() && (cursor.block().userState() & 0xFF); + } + + Token tk = tokenAtPosition(tokens, pos); + if (retToken) + *retToken = tk; + return tk.isComment(); +} + +bool MatchingText::isInStringHelper(const QTextCursor &cursor) +{ + int prevState = 0; + const Tokens tokens = getTokens(cursor, prevState); + + const unsigned pos = cursor.selectionEnd() - cursor.block().position(); + + if (tokens.isEmpty() || pos <= tokens.first().utf16charsBegin()) + return false; + + if (pos >= tokens.last().utf16charsEnd()) { + const Token tk = tokens.last(); + return tk.isStringLiteral() && prevState > 0; + } + + Token tk = tokenAtPosition(tokens, pos); + return tk.isStringLiteral() && pos > tk.utf16charsBegin(); +} + QString MatchingText::insertMatchingBrace(const QTextCursor &cursor, const QString &textToProcess, QChar la, int *skippedChars) { @@ -211,15 +313,15 @@ static bool shouldInsertNewline(const QTextCursor &tc) return newlines <= 1 && doc->characterAt(pos) != QLatin1Char('}'); } -QString MatchingText::insertParagraphSeparator(const QTextCursor &tc) +QString MatchingText::insertParagraphSeparator(const QTextCursor &cursor) { - BackwardsScanner tk(tc, LanguageFeatures::defaultFeatures(), MAX_NUM_LINES); + BackwardsScanner tk(cursor, LanguageFeatures::defaultFeatures(), 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.positionInBlock()).trimmed(); + const QString textBlock = cursor.block().text().mid(cursor.positionInBlock()).trimmed(); if (! textBlock.isEmpty()) return QString(); @@ -244,7 +346,7 @@ QString MatchingText::insertParagraphSeparator(const QTextCursor &tc) // found a class key. QString str = QLatin1String("};"); - if (shouldInsertNewline(tc)) + if (shouldInsertNewline(cursor)) str += QLatin1Char('\n'); return str; @@ -310,7 +412,7 @@ QString MatchingText::insertParagraphSeparator(const QTextCursor &tc) // if we reached this point there is a good chance that we are parsing a function definition QString str = QLatin1String("}"); - if (shouldInsertNewline(tc)) + if (shouldInsertNewline(cursor)) str += QLatin1Char('\n'); return str; diff --git a/src/libs/cplusplus/MatchingText.h b/src/libs/cplusplus/MatchingText.h index f2d27c4ea8d..b13ede23fc9 100644 --- a/src/libs/cplusplus/MatchingText.h +++ b/src/libs/cplusplus/MatchingText.h @@ -36,9 +36,16 @@ namespace CPlusPlus { class CPLUSPLUS_EXPORT MatchingText { public: + static bool contextAllowsAutoParentheses(const QTextCursor &cursor, + const QString &textToInsert); + static bool contextAllowsElectricCharacters(const QTextCursor &cursor); + static bool shouldInsertMatchingText(const QTextCursor &tc); static bool shouldInsertMatchingText(QChar lookAhead); + static bool isInCommentHelper(const QTextCursor &currsor, Token *retToken = 0); + static bool isInStringHelper(const QTextCursor &cursor); + static QString insertMatchingBrace(const QTextCursor &tc, const QString &text, QChar la, int *skippedChars); static QString insertParagraphSeparator(const QTextCursor &tc); diff --git a/src/plugins/cppeditor/cppautocompleter.cpp b/src/plugins/cppeditor/cppautocompleter.cpp index 2e5a20c9af9..e838660836d 100644 --- a/src/plugins/cppeditor/cppautocompleter.cpp +++ b/src/plugins/cppeditor/cppautocompleter.cpp @@ -26,133 +26,31 @@ #include "cppautocompleter.h" #include -#include -#include #include using namespace CppEditor; using namespace Internal; -using namespace CPlusPlus; - -static const Token tokenAtPosition(const Tokens &tokens, const unsigned pos) -{ - for (int i = tokens.size() - 1; i >= 0; --i) { - const Token tk = tokens.at(i); - if (pos >= tk.utf16charsBegin() && pos < tk.utf16charsEnd()) - return tk; - } - return Token(); -} - -static bool isInCommentHelper(const QTextCursor &cursor, Token *retToken = 0) -{ - LanguageFeatures features; - features.qtEnabled = false; - features.qtKeywordsEnabled = false; - features.qtMocRunEnabled = false; - features.cxx11Enabled = true; - features.c99Enabled = true; - - SimpleLexer tokenize; - tokenize.setLanguageFeatures(features); - - const int prevState = BackwardsScanner::previousBlockState(cursor.block()) & 0xFF; - const Tokens tokens = tokenize(cursor.block().text(), prevState); - - const unsigned pos = cursor.selectionEnd() - cursor.block().position(); - - if (tokens.isEmpty() || pos < tokens.first().utf16charsBegin()) - return prevState > 0; - - if (pos >= tokens.last().utf16charsEnd()) { - const Token tk = tokens.last(); - if (tk.is(T_CPP_COMMENT) || tk.is(T_CPP_DOXY_COMMENT)) - return true; - return tk.isComment() && (cursor.block().userState() & 0xFF); - } - - Token tk = tokenAtPosition(tokens, pos); - - if (retToken) - *retToken = tk; - - return tk.isComment(); -} - -static bool isInStringHelper(const QTextCursor &cursor, Token *retToken = 0) -{ - LanguageFeatures features; - features.qtEnabled = false; - features.qtKeywordsEnabled = false; - features.qtMocRunEnabled = false; - features.cxx11Enabled = true; - features.c99Enabled = true; - - SimpleLexer tokenize; - tokenize.setLanguageFeatures(features); - - const int prevState = BackwardsScanner::previousBlockState(cursor.block()) & 0xFF; - const Tokens tokens = tokenize(cursor.block().text(), prevState); - - const unsigned pos = cursor.selectionEnd() - cursor.block().position(); - - if (tokens.isEmpty() || pos <= tokens.first().utf16charsBegin()) - return false; - - if (pos >= tokens.last().utf16charsEnd()) { - const Token tk = tokens.last(); - return tk.isStringLiteral() && prevState > 0; - } - - Token tk = tokenAtPosition(tokens, pos); - if (retToken) - *retToken = tk; - return tk.isStringLiteral() && pos > tk.utf16charsBegin(); -} bool CppAutoCompleter::contextAllowsAutoParentheses(const QTextCursor &cursor, const QString &textToInsert) const { - QChar ch; - - if (!textToInsert.isEmpty()) - ch = textToInsert.at(0); - - if (!(MatchingText::shouldInsertMatchingText(cursor) - || ch == QLatin1Char('\'') - || ch == QLatin1Char('"'))) - return false; - else if (isInCommentHelper(cursor)) - return false; - - return true; + return CPlusPlus::MatchingText::contextAllowsAutoParentheses(cursor, textToInsert); } bool CppAutoCompleter::contextAllowsElectricCharacters(const QTextCursor &cursor) const { - Token token; - - if (isInCommentHelper(cursor, &token)) - return false; - - if (token.isStringLiteral() || token.isCharLiteral()) { - const unsigned pos = cursor.selectionEnd() - cursor.block().position(); - if (pos <= token.utf16charsEnd()) - return false; - } - - return true; + return CPlusPlus::MatchingText::contextAllowsElectricCharacters(cursor); } bool CppAutoCompleter::isInComment(const QTextCursor &cursor) const { - return isInCommentHelper(cursor); + return CPlusPlus::MatchingText::isInCommentHelper(cursor); } bool CppAutoCompleter::isInString(const QTextCursor &cursor) const { - return isInStringHelper(cursor); + return CPlusPlus::MatchingText::isInStringHelper(cursor); } QString CppAutoCompleter::insertMatchingBrace(const QTextCursor &cursor, @@ -160,12 +58,12 @@ QString CppAutoCompleter::insertMatchingBrace(const QTextCursor &cursor, QChar la, int *skippedChars) const { - return MatchingText::insertMatchingBrace(cursor, text, la, skippedChars); + return CPlusPlus::MatchingText::insertMatchingBrace(cursor, text, la, skippedChars); } QString CppAutoCompleter::insertParagraphSeparator(const QTextCursor &cursor) const { - return MatchingText::insertParagraphSeparator(cursor); + return CPlusPlus::MatchingText::insertParagraphSeparator(cursor); } #ifdef WITH_TESTS diff --git a/src/plugins/glsleditor/glslautocompleter.cpp b/src/plugins/glsleditor/glslautocompleter.cpp index 9c98858d417..b2e7d6313b7 100644 --- a/src/plugins/glsleditor/glslautocompleter.cpp +++ b/src/plugins/glsleditor/glslautocompleter.cpp @@ -25,96 +25,27 @@ #include "glslautocompleter.h" -#include -#include #include -#include -#include #include -using namespace CPlusPlus; - namespace GlslEditor { namespace Internal { -GlslCompleter::GlslCompleter() -{} - -GlslCompleter::~GlslCompleter() -{} - bool GlslCompleter::contextAllowsAutoParentheses(const QTextCursor &cursor, const QString &textToInsert) const { - QChar ch; - - if (! textToInsert.isEmpty()) - ch = textToInsert.at(0); - - if (! (MatchingText::shouldInsertMatchingText(cursor) - || ch == QLatin1Char('\'') - || ch == QLatin1Char('"'))) - return false; - else if (isInComment(cursor)) - return false; - - return true; + return CPlusPlus::MatchingText::contextAllowsAutoParentheses(cursor, textToInsert); } bool GlslCompleter::contextAllowsElectricCharacters(const QTextCursor &cursor) const { - const Token tk = SimpleLexer::tokenAt(cursor.block().text(), cursor.positionInBlock(), - BackwardsScanner::previousBlockState(cursor.block()), - LanguageFeatures::defaultFeatures()); - - // XXX Duplicated from CppEditor::isInComment to avoid tokenizing twice - if (tk.isComment()) { - const unsigned pos = cursor.selectionEnd() - cursor.block().position(); - - if (pos == tk.utf16charsEnd()) { - if (tk.is(T_CPP_COMMENT) || tk.is(T_CPP_DOXY_COMMENT)) - return false; - - const int state = cursor.block().userState() & 0xFF; - if (state > 0) - return false; - } - - if (pos < tk.utf16charsEnd()) - return false; - } else if (tk.isStringLiteral() || tk.isCharLiteral()) { - const unsigned pos = cursor.selectionEnd() - cursor.block().position(); - if (pos <= tk.utf16charsEnd()) - return false; - } - - return true; + return CPlusPlus::MatchingText::contextAllowsElectricCharacters(cursor); } bool GlslCompleter::isInComment(const QTextCursor &cursor) const { - const Token tk = SimpleLexer::tokenAt(cursor.block().text(), cursor.positionInBlock(), - BackwardsScanner::previousBlockState(cursor.block()), - LanguageFeatures::defaultFeatures()); - - if (tk.isComment()) { - const unsigned pos = cursor.selectionEnd() - cursor.block().position(); - - if (pos == tk.utf16charsEnd()) { - if (tk.is(T_CPP_COMMENT) || tk.is(T_CPP_DOXY_COMMENT)) - return true; - - const int state = cursor.block().userState() & 0xFF; - if (state > 0) - return true; - } - - if (pos < tk.utf16charsEnd()) - return true; - } - - return false; + return CPlusPlus::MatchingText::isInCommentHelper(cursor); } QString GlslCompleter::insertMatchingBrace(const QTextCursor &cursor, @@ -122,12 +53,12 @@ QString GlslCompleter::insertMatchingBrace(const QTextCursor &cursor, QChar la, int *skippedChars) const { - return MatchingText::insertMatchingBrace(cursor, text, la, skippedChars); + return CPlusPlus::MatchingText::insertMatchingBrace(cursor, text, la, skippedChars); } QString GlslCompleter::insertParagraphSeparator(const QTextCursor &cursor) const { - return MatchingText::insertParagraphSeparator(cursor); + return CPlusPlus::MatchingText::insertParagraphSeparator(cursor); } } // namespace Internal diff --git a/src/plugins/glsleditor/glslautocompleter.h b/src/plugins/glsleditor/glslautocompleter.h index 8f09d242cd9..1e1d1a0f842 100644 --- a/src/plugins/glsleditor/glslautocompleter.h +++ b/src/plugins/glsleditor/glslautocompleter.h @@ -33,9 +33,6 @@ namespace Internal { class GlslCompleter : public TextEditor::AutoCompleter { public: - GlslCompleter(); - virtual ~GlslCompleter(); - virtual bool contextAllowsAutoParentheses(const QTextCursor &cursor, const QString &textToInsert = QString()) const; virtual bool contextAllowsElectricCharacters(const QTextCursor &cursor) const;