diff --git a/src/libs/cplusplus/ExpressionUnderCursor.cpp b/src/libs/cplusplus/ExpressionUnderCursor.cpp index 257d14443e8587b1a2635698fa6b008d4cb592ba..9cbaeb97539dbc61a1df3d2ad014db5e4a60e99d 100644 --- a/src/libs/cplusplus/ExpressionUnderCursor.cpp +++ b/src/libs/cplusplus/ExpressionUnderCursor.cpp @@ -190,7 +190,10 @@ int ExpressionUnderCursor::previousBlockState(const QTextBlock &block) return 0; } -QString ExpressionUnderCursor::operator()(const QTextCursor &cursor) +void ExpressionUnderCursor::init(const QTextCursor &cursor, + QList<SimpleToken> *tokens, + QString *text, + int *startPosition) { enum { MAX_BLOCK_COUNT = 5 }; @@ -203,8 +206,6 @@ QString ExpressionUnderCursor::operator()(const QTextCursor &cursor) initialBlock = initialBlock.previous(); } - QString text; - QTextBlock it = initialBlock; for (; it.isValid(); it = it.next()) { QString textBlock = it.text(); @@ -212,18 +213,29 @@ QString ExpressionUnderCursor::operator()(const QTextCursor &cursor) if (it == block) textBlock = textBlock.left(cursor.position() - cursor.block().position()); - text += textBlock; + text->append(textBlock); if (it == block) break; - text += QLatin1Char('\n'); + text->append(QLatin1Char('\n')); } SimpleLexer tokenize; tokenize.setSkipComments(true); - QList<SimpleToken> tokens = tokenize(text, previousBlockState(initialBlock)); - tokens.prepend(SimpleToken()); // sentinel + tokens->append(tokenize(*text, previousBlockState(initialBlock))); + tokens->prepend(SimpleToken()); // sentinel + + if (startPosition) + *startPosition = initialBlock.position(); +} + +QString ExpressionUnderCursor::operator()(const QTextCursor &cursor) +{ + QList<SimpleToken> tokens; + QString text; + + init(cursor, &tokens, &text); _jumpedComma = false; @@ -236,3 +248,28 @@ QString ExpressionUnderCursor::operator()(const QTextCursor &cursor) - tokens.at(i).position()); } +int ExpressionUnderCursor::startOfFunctionCall(const QTextCursor &cursor) +{ + QList<SimpleToken> tokens; + QString text; + int startPosition; + + init(cursor, &tokens, &text, &startPosition); + + int index = tokens.size(); + + forever { + const SimpleToken &tk = tokens.at(index - 1); + + if (tk.is(T_EOF_SYMBOL)) + break; + else if (tk.is(T_LPAREN)) + return startPosition + tk.position(); + else if (tk.is(T_RPAREN)) + index = startOfMatchingBrace(tokens, index); + else + --index; + } + + return -1; +} diff --git a/src/libs/cplusplus/ExpressionUnderCursor.h b/src/libs/cplusplus/ExpressionUnderCursor.h index 843b679cb5ffbf82c3662aa91ca16ce11725f5a7..dda77c406c5ed5944e259b826528d8cb146305bf 100644 --- a/src/libs/cplusplus/ExpressionUnderCursor.h +++ b/src/libs/cplusplus/ExpressionUnderCursor.h @@ -50,8 +50,14 @@ public: ~ExpressionUnderCursor(); QString operator()(const QTextCursor &cursor); + int startOfFunctionCall(const QTextCursor &cursor); private: + void init(const QTextCursor &cursor, + QList<SimpleToken> *tokens, + QString *text, + int *startPosition = 0); + int startOfMatchingBrace(const QList<SimpleToken> &tk, int index); int startOfExpression(const QList<SimpleToken> &tk, int index); int previousBlockState(const QTextBlock &block); diff --git a/src/plugins/cpptools/cppcodecompletion.cpp b/src/plugins/cpptools/cppcodecompletion.cpp index 9c54d4969d39ef0d2cd8d72516e538aa6400afbc..3813744774c2f91c9a370cb3354a44d9b1ba9afd 100644 --- a/src/plugins/cpptools/cppcodecompletion.cpp +++ b/src/plugins/cpptools/cppcodecompletion.cpp @@ -77,7 +77,9 @@ class FunctionArgumentWidget : public QLabel public: FunctionArgumentWidget(); - void showFunctionHint(QList<Function *> functionSymbols, const LookupContext &context); + void showFunctionHint(QList<Function *> functionSymbols, + const LookupContext &context, + int startPosition); protected: bool eventFilter(QObject *obj, QEvent *e); @@ -96,6 +98,7 @@ private: int m_startpos; int m_currentarg; + int m_current; TextEditor::ITextEditor *m_editor; @@ -103,7 +106,6 @@ private: QFrame *m_popupFrame; QList<Function *> m_items; LookupContext m_context; - int m_current; }; class ConvertToCompletionItem: protected NameVisitor @@ -193,6 +195,7 @@ protected: using namespace CppTools::Internal; FunctionArgumentWidget::FunctionArgumentWidget(): + m_startpos(-1), m_current(0) { QObject *editorObject = Core::EditorManager::instance()->currentEditor(); @@ -243,18 +246,24 @@ FunctionArgumentWidget::FunctionArgumentWidget(): setTextFormat(Qt::RichText); setMargin(1); + + qApp->installEventFilter(this); } void FunctionArgumentWidget::showFunctionHint(QList<Function *> functionSymbols, - const LookupContext &context) + const LookupContext &context, + int startPosition) { Q_ASSERT(!functionSymbols.isEmpty()); + if (m_startpos == startPosition) + return; + m_popupFrame->hide(); m_items = functionSymbols; m_context = context; - m_startpos = m_editor->position(); + m_startpos = startPosition; m_current = 0; // update the text @@ -263,12 +272,10 @@ void FunctionArgumentWidget::showFunctionHint(QList<Function *> functionSymbols, m_pager->setVisible(functionSymbols.size() > 1); - QPoint pos = m_editor->cursorRect().topLeft(); + QPoint pos = m_editor->cursorRect(m_startpos).topLeft(); pos.setY(pos.y() - m_popupFrame->sizeHint().height() - 1); m_popupFrame->move(pos); m_popupFrame->show(); - - qApp->installEventFilter(this); } void FunctionArgumentWidget::nextPage() @@ -337,7 +344,6 @@ bool FunctionArgumentWidget::eventFilter(QObject *obj, QEvent *e) if (obj != m_editor->widget()) break; } - qDebug() << e; close(); break; case QEvent::MouseButtonPress: @@ -346,7 +352,6 @@ bool FunctionArgumentWidget::eventFilter(QObject *obj, QEvent *e) case QEvent::Wheel: { QWidget *widget = qobject_cast<QWidget *>(obj); if (! (widget == this || m_popupFrame->isAncestorOf(widget))) { - qDebug() << e << widget; close(); } } @@ -434,6 +439,9 @@ static int startOfOperator(TextEditor::ITextEditable *editor, if (ch2 != QLatin1Char('.') && ch == QLatin1Char('.')) { k = T_DOT; --start; + } else if (ch == QLatin1Char(',')) { + k = T_COMMA; + --start; } else if (wantFunctionCall && ch == QLatin1Char('(')) { k = T_LPAREN; --start; @@ -468,7 +476,6 @@ static int startOfOperator(TextEditor::ITextEditable *editor, k = T_EOF_SYMBOL; start = pos; } - else if (tk.is(T_COMMENT) || tk.isLiteral()) { k = T_EOF_SYMBOL; start = pos; @@ -520,10 +527,6 @@ int CppCodeCompletion::startCompletion(TextEditor::ITextEditable *editor) edit->convertPosition(editor->position(), &line, &column); // qDebug() << "line:" << line << "column:" << column; - ExpressionUnderCursor expressionUnderCursor; - QString expression; - - if (m_completionOperator == T_DOXY_COMMENT) { for (int i = 1; i < T_DOXY_LAST_TAG; ++i) { TextEditor::CompletionItem item(this); @@ -535,11 +538,23 @@ int CppCodeCompletion::startCompletion(TextEditor::ITextEditable *editor) return m_startPosition; } + ExpressionUnderCursor expressionUnderCursor; + QTextCursor tc(edit->document()); - if (m_completionOperator) { - QTextCursor tc(edit->document()); + if (m_completionOperator == T_COMMA) { tc.setPosition(endOfExpression); + const int start = expressionUnderCursor.startOfFunctionCall(tc); + if (start != -1) { + endOfExpression = start; + m_startPosition = start + 1; + m_completionOperator = T_LPAREN; + } + } + + QString expression; + tc.setPosition(endOfExpression); + if (m_completionOperator) { expression = expressionUnderCursor(tc); if (m_completionOperator == T_LPAREN) { @@ -553,12 +568,12 @@ int CppCodeCompletion::startCompletion(TextEditor::ITextEditable *editor) // We don't want a function completion when the cursor isn't at the opening brace expression.clear(); m_completionOperator = T_EOF_SYMBOL; + m_startPosition = editor->position(); } } } - //if (! expression.isEmpty()) - //qDebug() << "***** expression:" << expression; + //qDebug() << "***** expression:" << expression; const Snapshot snapshot = m_manager->snapshot(); @@ -702,7 +717,9 @@ bool CppCodeCompletion::completeConstructorOrFunction(const QList<TypeOfExpressi if (!m_functionArgumentWidget) m_functionArgumentWidget = new FunctionArgumentWidget; - m_functionArgumentWidget->showFunctionHint(functions, typeOfExpression.lookupContext()); + m_functionArgumentWidget->showFunctionHint(functions, + typeOfExpression.lookupContext(), + m_startPosition); } return false; @@ -1150,20 +1167,7 @@ void CppCodeCompletion::complete(const TextEditor::CompletionItem &item) if (item.m_data.isValid()) symbol = item.m_data.value<Symbol *>(); - // qDebug() << "*** complete symbol:" << symbol->fileName() << symbol->line(); - - if (m_completionOperator == T_LPAREN) { - if (symbol) { - Function *function = symbol->type()->asFunctionType(); - QTC_ASSERT(function, return); - - // Recreate if necessary - if (!m_functionArgumentWidget) - m_functionArgumentWidget = new FunctionArgumentWidget; - - m_functionArgumentWidget->showFunctionHint(QList<Function*>() << function, typeOfExpression.lookupContext()); - } - } else if (m_completionOperator == T_SIGNAL || m_completionOperator == T_SLOT) { + if (m_completionOperator == T_SIGNAL || m_completionOperator == T_SLOT) { QString toInsert = item.m_text; toInsert += QLatin1Char(')'); // Insert the remainder of the name