From 287ae7ae61fa211fd4ee1b545b4d1d9a13e5f0f8 Mon Sep 17 00:00:00 2001 From: Ivan Donchevskii Date: Wed, 28 Jun 2017 09:51:53 +0200 Subject: [PATCH] Completion: improve complete in the middle Apply clang fix to the old code model Do not replace the text after cursor if the proposal does not contain it or if proposal matches 100% the text after it Task-number: QTCREATORBUG-18471 Change-Id: I662cb6e48a9e0ee14065594f5c823f114fff2474 Reviewed-by: Nikolai Kosjar --- .../clangassistproposalitem.cpp | 11 +++++-- src/plugins/cpptools/cppcompletionassist.cpp | 31 +++++++------------ .../texteditor/codeassist/codeassistant.cpp | 15 ++++++++- 3 files changed, 35 insertions(+), 22 deletions(-) diff --git a/src/plugins/clangcodemodel/clangassistproposalitem.cpp b/src/plugins/clangcodemodel/clangassistproposalitem.cpp index 012ac9af5e1..75dc40c6710 100644 --- a/src/plugins/clangcodemodel/clangassistproposalitem.cpp +++ b/src/plugins/clangcodemodel/clangassistproposalitem.cpp @@ -76,6 +76,7 @@ void ClangAssistProposalItem::apply(TextEditor::TextDocumentManipulatorInterface int extraLength = 0; int cursorOffset = 0; bool setAutoCompleteSkipPos = false; + int currentPosition = manipulator.currentPosition(); bool autoParenthesesEnabled = true; if (m_completionOperator == T_SIGNAL || m_completionOperator == T_SLOT) { @@ -124,7 +125,7 @@ void ClangAssistProposalItem::apply(TextEditor::TextDocumentManipulatorInterface // If the function doesn't return anything, automatically place the semicolon, // unless we're doing a scope completion (then it might be function definition). - const QChar characterAtCursor = manipulator.characterAt(manipulator.currentPosition()); + const QChar characterAtCursor = manipulator.characterAt(currentPosition); bool endWithSemicolon = m_typedCharacter == QLatin1Char(';')/* || (function->returnType()->isVoidType() && m_completionOperator != T_COLON_COLON)*/; //### const QChar semicolon = m_typedCharacter.isNull() ? QLatin1Char(';') : m_typedCharacter; @@ -181,7 +182,13 @@ void ClangAssistProposalItem::apply(TextEditor::TextDocumentManipulatorInterface // Avoid inserting characters that are already there QTextCursor cursor = manipulator.textCursorAt(basePosition); cursor.movePosition(QTextCursor::EndOfWord); - const int currentPosition = cursor.position(); + const QString textAfterCursor = manipulator.textAt(currentPosition, + cursor.position() - currentPosition); + + if (textToBeInserted != textAfterCursor + && textToBeInserted.indexOf(textAfterCursor, currentPosition - basePosition) >= 0) { + currentPosition = cursor.position(); + } for (int i = 0; i < extraCharacters.length(); ++i) { const QChar a = extraCharacters.at(i); diff --git a/src/plugins/cpptools/cppcompletionassist.cpp b/src/plugins/cpptools/cppcompletionassist.cpp index 0a31d52b848..26b139e6478 100644 --- a/src/plugins/cpptools/cppcompletionassist.cpp +++ b/src/plugins/cpptools/cppcompletionassist.cpp @@ -309,28 +309,20 @@ void CppAssistProposalItem::applyContextualContent(TextDocumentManipulatorInterf --cursorOffset; } - // Determine the length of characters that should just be kept on the editor, but do - // not consider content that ends as an identifier (which could be undesired). - const int lineEnd = manipulator.positionAt(EndOfLinePosition); - const QString inEditor = manipulator.textAt(manipulator.currentPosition(), - lineEnd - manipulator.currentPosition()); - int preserveLength = 0; - if (!inEditor.isEmpty()) { - preserveLength = toInsert.length() - (manipulator.currentPosition() - basePosition); - const int inEditorLength = inEditor.length(); - while (preserveLength > 0) { - if (inEditor.startsWith(toInsert.right(preserveLength)) - && (inEditorLength == preserveLength - || !CppTools::isValidIdentifierChar(inEditor.at(preserveLength)))) { - break; - } - --preserveLength; - } + // Avoid inserting characters that are already there + int currentPosition = manipulator.currentPosition(); + QTextCursor cursor = manipulator.textCursorAt(basePosition); + cursor.movePosition(QTextCursor::EndOfWord); + const QString textAfterCursor = manipulator.textAt(currentPosition, + cursor.position() - currentPosition); + if (toInsert != textAfterCursor + && toInsert.indexOf(textAfterCursor, currentPosition - basePosition) >= 0) { + currentPosition = cursor.position(); } for (int i = 0; i < extraChars.length(); ++i) { const QChar a = extraChars.at(i); - const QChar b = manipulator.characterAt(manipulator.currentPosition() + i + preserveLength); + const QChar b = manipulator.characterAt(currentPosition + i); if (a == b) ++extraLength; else @@ -340,8 +332,9 @@ void CppAssistProposalItem::applyContextualContent(TextDocumentManipulatorInterf toInsert += extraChars; // Insert the remainder of the name - const int length = manipulator.currentPosition() - basePosition + preserveLength + extraLength; + const int length = currentPosition - basePosition + extraLength; manipulator.replace(basePosition, length, toInsert); + manipulator.setCursorPosition(basePosition + toInsert.length()); if (cursorOffset) manipulator.setCursorPosition(manipulator.currentPosition() + cursorOffset); if (setAutoCompleteSkipPos) diff --git a/src/plugins/texteditor/codeassist/codeassistant.cpp b/src/plugins/texteditor/codeassist/codeassistant.cpp index caff27918df..0622f29f10d 100644 --- a/src/plugins/texteditor/codeassist/codeassistant.cpp +++ b/src/plugins/texteditor/codeassist/codeassistant.cpp @@ -365,8 +365,21 @@ void CodeAssistantPrivate::handlePrefixExpansion(const QString &newPrefix) cursor.setPosition(m_proposal->basePosition()); cursor.movePosition(QTextCursor::EndOfWord); + int currentPosition = m_editorWidget->position(); + const QString textAfterCursor = m_editorWidget->textAt(currentPosition, + cursor.position() - currentPosition); + if (!textAfterCursor.startsWith(newPrefix)) { + if (newPrefix.indexOf(textAfterCursor, currentPosition - m_proposal->basePosition()) >= 0) + currentPosition = cursor.position(); + const QStringRef prefixAddition = + newPrefix.midRef(currentPosition - m_proposal->basePosition()); + // If remaining string starts with the prefix addition + if (textAfterCursor.startsWith(prefixAddition)) + currentPosition += prefixAddition.size(); + } + m_editorWidget->setCursorPosition(m_proposal->basePosition()); - m_editorWidget->replace(cursor.position() - m_proposal->basePosition(), newPrefix); + m_editorWidget->replace(currentPosition - m_proposal->basePosition(), newPrefix); notifyChange(); }