Editor: remove TextDocumentManipulator

Change-Id: Iacd7cd40ace77c79eecca3e4e699eb308d0c27de
Reviewed-by: Christian Kandeler <christian.kandeler@qt.io>
This commit is contained in:
David Schulz
2024-06-28 11:29:38 +02:00
parent 9ad0a5a641
commit ccdc293697
30 changed files with 250 additions and 386 deletions

View File

@@ -54,7 +54,6 @@
#include <texteditor/codeassist/assistinterface.h> #include <texteditor/codeassist/assistinterface.h>
#include <texteditor/codeassist/iassistprocessor.h> #include <texteditor/codeassist/iassistprocessor.h>
#include <texteditor/codeassist/iassistprovider.h> #include <texteditor/codeassist/iassistprovider.h>
#include <texteditor/codeassist/textdocumentmanipulator.h>
#include <texteditor/texteditor.h> #include <texteditor/texteditor.h>
#include <utils/algorithm.h> #include <utils/algorithm.h>
#include <utils/async.h> #include <utils/async.h>

View File

@@ -18,6 +18,7 @@
#include <cppeditor/projectpart.h> #include <cppeditor/projectpart.h>
#include <cplusplus/Icons.h> #include <cplusplus/Icons.h>
#include <cplusplus/MatchingText.h> #include <cplusplus/MatchingText.h>
#include <cplusplus/SimpleLexer.h>
#include <languageclient/languageclientfunctionhint.h> #include <languageclient/languageclientfunctionhint.h>
@@ -26,6 +27,7 @@
#include <texteditor/codeassist/assistinterface.h> #include <texteditor/codeassist/assistinterface.h>
#include <texteditor/codeassist/genericproposal.h> #include <texteditor/codeassist/genericproposal.h>
#include <texteditor/codeassist/genericproposalmodel.h> #include <texteditor/codeassist/genericproposalmodel.h>
#include <texteditor/texteditor.h>
#include <texteditor/texteditorsettings.h> #include <texteditor/texteditorsettings.h>
#include <utils/mimeconstants.h> #include <utils/mimeconstants.h>
@@ -44,6 +46,83 @@ namespace ClangCodeModel::Internal {
static Q_LOGGING_CATEGORY(clangdLogCompletion, "qtc.clangcodemodel.clangd.completion", static Q_LOGGING_CATEGORY(clangdLogCompletion, "qtc.clangcodemodel.clangd.completion",
QtWarningMsg); QtWarningMsg);
static void moveToPreviousChar(TextEditor::TextEditorWidget *editorWidget, QTextCursor &cursor)
{
cursor.movePosition(QTextCursor::PreviousCharacter);
while (editorWidget->characterAt(cursor.position()).isSpace())
cursor.movePosition(QTextCursor::PreviousCharacter);
}
static bool matchPreviousWord(TextEditor::TextEditorWidget *editorWidget, QTextCursor cursor, QString pattern)
{
cursor.movePosition(QTextCursor::PreviousWord);
while (editorWidget->characterAt(cursor.position()) == ':')
cursor.movePosition(QTextCursor::PreviousWord, QTextCursor::MoveAnchor, 2);
int previousWordStart = cursor.position();
cursor.movePosition(QTextCursor::NextWord);
moveToPreviousChar(editorWidget, cursor);
QString toMatch = editorWidget->textAt(previousWordStart, cursor.position() - previousWordStart + 1);
pattern = pattern.simplified();
while (!pattern.isEmpty() && pattern.endsWith(toMatch)) {
pattern.chop(toMatch.length());
if (pattern.endsWith(' '))
pattern.chop(1);
if (!pattern.isEmpty()) {
cursor.movePosition(QTextCursor::StartOfWord);
cursor.movePosition(QTextCursor::PreviousWord);
previousWordStart = cursor.position();
cursor.movePosition(QTextCursor::NextWord);
moveToPreviousChar(editorWidget, cursor);
toMatch = editorWidget->textAt(previousWordStart, cursor.position() - previousWordStart + 1);
}
}
return pattern.isEmpty();
}
static QString textUntilPreviousStatement(TextEditor::TextEditorWidget *editorWidget,
int startPosition)
{
static const QString stopCharacters(";{}#");
int endPosition = 0;
for (int i = startPosition; i >= 0 ; --i) {
if (stopCharacters.contains(editorWidget->characterAt(i))) {
endPosition = i + 1;
break;
}
}
return editorWidget->textAt(endPosition, startPosition - endPosition);
}
// 7.3.3: using typename(opt) nested-name-specifier unqualified-id ;
static bool isAtUsingDeclaration(TextEditor::TextEditorWidget *editorWidget, int basePosition)
{
using namespace CPlusPlus;
SimpleLexer lexer;
lexer.setLanguageFeatures(LanguageFeatures::defaultFeatures());
const QString textToLex = textUntilPreviousStatement(editorWidget, basePosition);
const Tokens tokens = lexer(textToLex);
if (tokens.empty())
return false;
// The nested-name-specifier always ends with "::", so check for this first.
const Token lastToken = tokens[tokens.size() - 1];
if (lastToken.kind() != T_COLON_COLON)
return false;
return contains(tokens, [](const Token &token) { return token.kind() == T_USING; });
}
static void moveToPreviousWord(TextEditor::TextEditorWidget *editorWidget, QTextCursor &cursor)
{
cursor.movePosition(QTextCursor::PreviousWord);
while (editorWidget->characterAt(cursor.position()) == ':')
cursor.movePosition(QTextCursor::PreviousWord, QTextCursor::MoveAnchor, 2);
}
enum class CustomAssistMode { Preprocessor, IncludePath }; enum class CustomAssistMode { Preprocessor, IncludePath };
class CustomAssistProcessor : public IAssistProcessor class CustomAssistProcessor : public IAssistProcessor
@@ -74,7 +153,7 @@ class ClangdCompletionItem : public LanguageClientCompletionItem
{ {
public: public:
using LanguageClientCompletionItem::LanguageClientCompletionItem; using LanguageClientCompletionItem::LanguageClientCompletionItem;
void apply(TextDocumentManipulator &manipulator, int basePosition) const override; void apply(TextEditorWidget *editorWidget, int basePosition) const override;
enum class SpecialQtType { Signal, Slot, None }; enum class SpecialQtType { Signal, Slot, None };
static SpecialQtType getQtType(const CompletionItem &item); static SpecialQtType getQtType(const CompletionItem &item);
@@ -246,9 +325,11 @@ bool ClangdCompletionAssistProvider::isInCommentOrString(const AssistInterface *
return CppEditor::isInCommentOrString(interface, features); return CppEditor::isInCommentOrString(interface, features);
} }
void ClangdCompletionItem::apply(TextDocumentManipulator &manipulator, void ClangdCompletionItem::apply(TextEditorWidget *editorWidget,
int /*basePosition*/) const int /*basePosition*/) const
{ {
QTC_ASSERT(editorWidget, return);
const CompletionItem item = this->item(); const CompletionItem item = this->item();
QChar typedChar = triggeredCommitCharacter(); QChar typedChar = triggeredCommitCharacter();
const auto edit = item.textEdit(); const auto edit = item.textEdit();
@@ -287,8 +368,8 @@ void ClangdCompletionItem::apply(TextDocumentManipulator &manipulator,
int extraLength = 0; int extraLength = 0;
int cursorOffset = 0; int cursorOffset = 0;
bool setAutoCompleteSkipPos = false; bool setAutoCompleteSkipPos = false;
int currentPos = manipulator.currentPosition(); int currentPos = editorWidget->position();
const QTextDocument * const doc = manipulator.document(); const QTextDocument * const doc = editorWidget->document();
const Range range = edit->range(); const Range range = edit->range();
const int rangeStart = range.start().toPositionInDocument(doc); const int rangeStart = range.start().toPositionInDocument(doc);
if (isFunctionLike && completionSettings.m_autoInsertBrackets) { if (isFunctionLike && completionSettings.m_autoInsertBrackets) {
@@ -296,19 +377,19 @@ void ClangdCompletionItem::apply(TextDocumentManipulator &manipulator,
// in which case it would be annoying if we put the cursor after the already automatically // in which case it would be annoying if we put the cursor after the already automatically
// inserted closing parenthesis. // inserted closing parenthesis.
const bool skipClosingParenthesis = typedChar != '('; const bool skipClosingParenthesis = typedChar != '(';
QTextCursor cursor = manipulator.textCursorAt(rangeStart); QTextCursor cursor = editorWidget->textCursorAt(rangeStart);
bool abandonParen = false; bool abandonParen = false;
if (matchPreviousWord(manipulator, cursor, "&")) { if (matchPreviousWord(editorWidget, cursor, "&")) {
moveToPreviousWord(manipulator, cursor); moveToPreviousWord(editorWidget, cursor);
moveToPreviousChar(manipulator, cursor); moveToPreviousChar(editorWidget, cursor);
const QChar prevChar = manipulator.characterAt(cursor.position()); const QChar prevChar = editorWidget->characterAt(cursor.position());
cursor.setPosition(rangeStart); cursor.setPosition(rangeStart);
abandonParen = QString("(;,{}=").contains(prevChar); abandonParen = QString("(;,{}=").contains(prevChar);
} }
if (!abandonParen) if (!abandonParen)
abandonParen = isAtUsingDeclaration(manipulator, rangeStart); abandonParen = isAtUsingDeclaration(editorWidget, rangeStart);
if (!abandonParen && !isMacroCall && matchPreviousWord(manipulator, cursor, detail)) if (!abandonParen && !isMacroCall && matchPreviousWord(editorWidget, cursor, detail))
abandonParen = true; // function definition abandonParen = true; // function definition
if (!abandonParen) { if (!abandonParen) {
if (completionSettings.m_spaceAfterFunctionName) if (completionSettings.m_spaceAfterFunctionName)
@@ -319,7 +400,7 @@ void ClangdCompletionItem::apply(TextDocumentManipulator &manipulator,
// If the function doesn't return anything, automatically place the semicolon, // If the function doesn't return anything, automatically place the semicolon,
// unless we're doing a scope completion (then it might be function definition). // unless we're doing a scope completion (then it might be function definition).
const QChar characterAtCursor = manipulator.characterAt(currentPos); const QChar characterAtCursor = editorWidget->characterAt(currentPos);
bool endWithSemicolon = typedChar == ';'; bool endWithSemicolon = typedChar == ';';
const QChar semicolon = typedChar.isNull() ? QLatin1Char(';') : typedChar; const QChar semicolon = typedChar.isNull() ? QLatin1Char(';') : typedChar;
if (endWithSemicolon && characterAtCursor == semicolon) { if (endWithSemicolon && characterAtCursor == semicolon) {
@@ -335,7 +416,7 @@ void ClangdCompletionItem::apply(TextDocumentManipulator &manipulator,
typedChar = {}; typedChar = {};
} }
} else { } else {
const QChar lookAhead = manipulator.characterAt(currentPos + 1); const QChar lookAhead = editorWidget->characterAt(currentPos + 1);
if (MatchingText::shouldInsertMatchingText(lookAhead)) { if (MatchingText::shouldInsertMatchingText(lookAhead)) {
extraCharacters += ')'; extraCharacters += ')';
--cursorOffset; --cursorOffset;
@@ -360,13 +441,13 @@ void ClangdCompletionItem::apply(TextDocumentManipulator &manipulator,
// Avoid inserting characters that are already there // Avoid inserting characters that are already there
// For include file completions, also consider a possibly pre-existing // For include file completions, also consider a possibly pre-existing
// closing quote or angle bracket. // closing quote or angle bracket.
QTextCursor cursor = manipulator.textCursorAt(rangeStart); QTextCursor cursor = editorWidget->textCursorAt(rangeStart);
cursor.movePosition(QTextCursor::EndOfWord); cursor.movePosition(QTextCursor::EndOfWord);
if (kind == CompletionItemKind::File && !textToBeInserted.isEmpty() if (kind == CompletionItemKind::File && !textToBeInserted.isEmpty()
&& textToBeInserted.right(1) == manipulator.textAt(cursor.position(), 1)) { && textToBeInserted.right(1) == editorWidget->textAt(cursor.position(), 1)) {
cursor.setPosition(cursor.position() + 1); cursor.setPosition(cursor.position() + 1);
} }
const QString textAfterCursor = manipulator.textAt(currentPos, cursor.position() - currentPos); const QString textAfterCursor = editorWidget->textAt(currentPos, cursor.position() - currentPos);
if (currentPos < cursor.position() if (currentPos < cursor.position()
&& textToBeInserted != textAfterCursor && textToBeInserted != textAfterCursor
&& textToBeInserted.indexOf(textAfterCursor, currentPos - rangeStart) >= 0) { && textToBeInserted.indexOf(textAfterCursor, currentPos - rangeStart) >= 0) {
@@ -374,7 +455,7 @@ void ClangdCompletionItem::apply(TextDocumentManipulator &manipulator,
} }
for (int i = 0; i < extraCharacters.length(); ++i) { for (int i = 0; i < extraCharacters.length(); ++i) {
const QChar a = extraCharacters.at(i); const QChar a = extraCharacters.at(i);
const QChar b = manipulator.characterAt(currentPos + i); const QChar b = editorWidget->characterAt(currentPos + i);
if (a == b) if (a == b)
++extraLength; ++extraLength;
else else
@@ -383,19 +464,19 @@ void ClangdCompletionItem::apply(TextDocumentManipulator &manipulator,
textToBeInserted += extraCharacters; textToBeInserted += extraCharacters;
const int length = currentPos - rangeStart + extraLength; const int length = currentPos - rangeStart + extraLength;
const int oldRevision = manipulator.document()->revision(); const int oldRevision = editorWidget->document()->revision();
manipulator.replace(rangeStart, length, textToBeInserted); editorWidget->replace(rangeStart, length, textToBeInserted);
manipulator.setCursorPosition(rangeStart + textToBeInserted.length()); editorWidget->setCursorPosition(rangeStart + textToBeInserted.length());
if (manipulator.document()->revision() != oldRevision) { if (editorWidget->document()->revision() != oldRevision) {
if (cursorOffset) if (cursorOffset)
manipulator.setCursorPosition(manipulator.currentPosition() + cursorOffset); editorWidget->setCursorPosition(editorWidget->position() + cursorOffset);
if (setAutoCompleteSkipPos) if (setAutoCompleteSkipPos)
manipulator.addAutoCompleteSkipPosition(); editorWidget->setAutoCompleteSkipPosition(editorWidget->textCursor());
} }
if (auto additionalEdits = item.additionalTextEdits()) { if (auto additionalEdits = item.additionalTextEdits()) {
for (const auto &edit : *additionalEdits) for (const auto &edit : *additionalEdits)
applyTextEdit(manipulator, edit); applyTextEdit(editorWidget, edit);
} }
} }

View File

@@ -28,10 +28,11 @@ bool ClangPreprocessorAssistProposalItem::implicitlyApplies() const
return true; return true;
} }
void ClangPreprocessorAssistProposalItem::apply(TextEditor::TextDocumentManipulator &manipulator, void ClangPreprocessorAssistProposalItem::apply(TextEditor::TextEditorWidget *editorWidget,
int basePosition) const int basePosition) const
{ {
// TODO move in an extra class under tests // TODO move in an extra class under tests
QTC_ASSERT(editorWidget, return);
QString textToBeInserted = text(); QString textToBeInserted = text();
@@ -51,13 +52,13 @@ void ClangPreprocessorAssistProposalItem::apply(TextEditor::TextDocumentManipula
extraCharacters += m_typedCharacter; extraCharacters += m_typedCharacter;
// Avoid inserting characters that are already there // Avoid inserting characters that are already there
QTextCursor c = manipulator.textCursor(); QTextCursor c = editorWidget->textCursor();
c.movePosition(QTextCursor::EndOfBlock, QTextCursor::KeepAnchor); c.movePosition(QTextCursor::EndOfBlock, QTextCursor::KeepAnchor);
const QString existingText = c.selectedText(); const QString existingText = c.selectedText();
int existLength = 0; int existLength = 0;
if (!existingText.isEmpty()) { if (!existingText.isEmpty()) {
// Calculate the exist length in front of the extra chars // Calculate the exist length in front of the extra chars
existLength = textToBeInserted.length() - (manipulator.currentPosition() - basePosition); existLength = textToBeInserted.length() - (editorWidget->position() - basePosition);
while (!existingText.startsWith(textToBeInserted.right(existLength))) { while (!existingText.startsWith(textToBeInserted.right(existLength))) {
if (--existLength == 0) if (--existLength == 0)
break; break;
@@ -65,7 +66,7 @@ void ClangPreprocessorAssistProposalItem::apply(TextEditor::TextDocumentManipula
} }
for (int i = 0; i < extraCharacters.length(); ++i) { for (int i = 0; i < extraCharacters.length(); ++i) {
const QChar a = extraCharacters.at(i); const QChar a = extraCharacters.at(i);
const QChar b = manipulator.characterAt(manipulator.currentPosition() + i + existLength); const QChar b = editorWidget->characterAt(editorWidget->position() + i + existLength);
if (a == b) if (a == b)
++extraLength; ++extraLength;
else else
@@ -75,9 +76,9 @@ void ClangPreprocessorAssistProposalItem::apply(TextEditor::TextDocumentManipula
textToBeInserted += extraCharacters; textToBeInserted += extraCharacters;
// Insert the remainder of the name // Insert the remainder of the name
const int length = manipulator.currentPosition() - basePosition + existLength + extraLength; const int length = editorWidget->position() - basePosition + existLength + extraLength;
manipulator.replace(basePosition, length, textToBeInserted); editorWidget->replace(basePosition, length, textToBeInserted);
} }
void ClangPreprocessorAssistProposalItem::setText(const QString &text) void ClangPreprocessorAssistProposalItem::setText(const QString &text)

View File

@@ -17,7 +17,7 @@ public:
~ClangPreprocessorAssistProposalItem() noexcept override = default; ~ClangPreprocessorAssistProposalItem() noexcept override = default;
bool prematurelyApplies(const QChar &typedChar) const final; bool prematurelyApplies(const QChar &typedChar) const final;
bool implicitlyApplies() const final; bool implicitlyApplies() const final;
void apply(TextEditor::TextDocumentManipulator &manipulator, int basePosition) const final; void apply(TextEditor::TextEditorWidget *editorWidget, int basePosition) const final;
void setText(const QString &text); void setText(const QString &text);
QString text() const final; QString text() const final;

View File

@@ -20,7 +20,7 @@
#include <projectexplorer/kitaspects.h> #include <projectexplorer/kitaspects.h>
#include <projectexplorer/projectexplorerconstants.h> #include <projectexplorer/projectexplorerconstants.h>
#include <projectexplorer/target.h> #include <projectexplorer/target.h>
#include <texteditor/codeassist/textdocumentmanipulator.h> #include <texteditor/texteditor.h>
#include <cplusplus/SimpleLexer.h> #include <cplusplus/SimpleLexer.h>
#include <utils/algorithm.h> #include <utils/algorithm.h>
@@ -302,41 +302,6 @@ const QStringList globalClangOptions()
return ClangDiagnosticConfigsModel::globalDiagnosticOptions(); return ClangDiagnosticConfigsModel::globalDiagnosticOptions();
} }
// 7.3.3: using typename(opt) nested-name-specifier unqualified-id ;
bool isAtUsingDeclaration(TextEditor::TextDocumentManipulator &manipulator, int basePosition)
{
using namespace CPlusPlus;
SimpleLexer lexer;
lexer.setLanguageFeatures(LanguageFeatures::defaultFeatures());
const QString textToLex = textUntilPreviousStatement(manipulator, basePosition);
const Tokens tokens = lexer(textToLex);
if (tokens.empty())
return false;
// The nested-name-specifier always ends with "::", so check for this first.
const Token lastToken = tokens[tokens.size() - 1];
if (lastToken.kind() != T_COLON_COLON)
return false;
return contains(tokens, [](const Token &token) { return token.kind() == T_USING; });
}
QString textUntilPreviousStatement(TextEditor::TextDocumentManipulator &manipulator,
int startPosition)
{
static const QString stopCharacters(";{}#");
int endPosition = 0;
for (int i = startPosition; i >= 0 ; --i) {
if (stopCharacters.contains(manipulator.characterAt(i))) {
endPosition = i + 1;
break;
}
}
return manipulator.textAt(endPosition, startPosition - endPosition);
}
CompilerOptionsBuilder clangOptionsBuilder(const ProjectPart &projectPart, CompilerOptionsBuilder clangOptionsBuilder(const ProjectPart &projectPart,
const ClangDiagnosticConfig &warningsConfig, const ClangDiagnosticConfig &warningsConfig,
const FilePath &clangIncludeDir, const FilePath &clangIncludeDir,

View File

@@ -22,8 +22,6 @@ class ClangDiagnosticConfig;
class CppEditorDocumentHandle; class CppEditorDocumentHandle;
} }
namespace TextEditor { class TextDocumentManipulator; }
namespace ProjectExplorer { class Project; } namespace ProjectExplorer { class Project; }
namespace ClangCodeModel { namespace ClangCodeModel {
@@ -81,56 +79,6 @@ private:
const int m_squareBracketStartIndex; const int m_squareBracketStartIndex;
}; };
template <class CharacterProvider>
void moveToPreviousChar(const CharacterProvider &provider, QTextCursor &cursor)
{
cursor.movePosition(QTextCursor::PreviousCharacter);
while (provider.characterAt(cursor.position()).isSpace())
cursor.movePosition(QTextCursor::PreviousCharacter);
}
template <class CharacterProvider>
void moveToPreviousWord(CharacterProvider &provider, QTextCursor &cursor)
{
cursor.movePosition(QTextCursor::PreviousWord);
while (provider.characterAt(cursor.position()) == ':')
cursor.movePosition(QTextCursor::PreviousWord, QTextCursor::MoveAnchor, 2);
}
template <class CharacterProvider>
bool matchPreviousWord(const CharacterProvider &provider, QTextCursor cursor, QString pattern)
{
cursor.movePosition(QTextCursor::PreviousWord);
while (provider.characterAt(cursor.position()) == ':')
cursor.movePosition(QTextCursor::PreviousWord, QTextCursor::MoveAnchor, 2);
int previousWordStart = cursor.position();
cursor.movePosition(QTextCursor::NextWord);
moveToPreviousChar(provider, cursor);
QString toMatch = provider.textAt(previousWordStart, cursor.position() - previousWordStart + 1);
pattern = pattern.simplified();
while (!pattern.isEmpty() && pattern.endsWith(toMatch)) {
pattern.chop(toMatch.length());
if (pattern.endsWith(' '))
pattern.chop(1);
if (!pattern.isEmpty()) {
cursor.movePosition(QTextCursor::StartOfWord);
cursor.movePosition(QTextCursor::PreviousWord);
previousWordStart = cursor.position();
cursor.movePosition(QTextCursor::NextWord);
moveToPreviousChar(provider, cursor);
toMatch = provider.textAt(previousWordStart, cursor.position() - previousWordStart + 1);
}
}
return pattern.isEmpty();
}
QString textUntilPreviousStatement(
TextEditor::TextDocumentManipulator &manipulator, int startPosition);
bool isAtUsingDeclaration(TextEditor::TextDocumentManipulator &manipulator, int basePosition);
class ClangSourceRange class ClangSourceRange
{ {
public: public:

View File

@@ -30,7 +30,6 @@
#include <texteditor/codeassist/assistproposaliteminterface.h> #include <texteditor/codeassist/assistproposaliteminterface.h>
#include <texteditor/codeassist/genericproposal.h> #include <texteditor/codeassist/genericproposal.h>
#include <texteditor/codeassist/ifunctionhintproposalmodel.h> #include <texteditor/codeassist/ifunctionhintproposalmodel.h>
#include <texteditor/codeassist/textdocumentmanipulator.h>
#include <texteditor/semantichighlighter.h> #include <texteditor/semantichighlighter.h>
#include <texteditor/textmark.h> #include <texteditor/textmark.h>
@@ -1655,11 +1654,11 @@ void ClangdTestCompletion::testCompleteGlobals()
const AssistProposalItemInterface * const item = getItem(proposal, " globalFunction()", "void"); const AssistProposalItemInterface * const item = getItem(proposal, " globalFunction()", "void");
QVERIFY(item); QVERIFY(item);
TextDocumentManipulator manipulator(TextEditorWidget::currentTextEditorWidget()); auto editor = TextEditorWidget::currentTextEditorWidget();
item->apply(manipulator, cursorPos); item->apply(editor, cursorPos);
QCOMPARE(manipulator.getLine(7), " globalFunction() /* COMPLETE HERE */"); QCOMPARE(editor->textDocument()->blockText(6), " globalFunction() /* COMPLETE HERE */");
QCOMPARE(manipulator.cursorPos(), Text::Position({7, 19})); QCOMPARE(editor->lineColumn(), Text::Position({7, 19}));
QVERIFY(manipulator.editor()->autoCompleteHighlightPositions().isEmpty()); QVERIFY(editor->autoCompleteHighlightPositions().isEmpty());
} }
void ClangdTestCompletion::testCompleteMembers() void ClangdTestCompletion::testCompleteMembers()
@@ -1675,11 +1674,11 @@ void ClangdTestCompletion::testCompleteMembers()
const AssistProposalItemInterface * const item = getItem(proposal, " member", "int"); const AssistProposalItemInterface * const item = getItem(proposal, " member", "int");
QVERIFY(item); QVERIFY(item);
TextDocumentManipulator manipulator(TextEditorWidget::currentTextEditorWidget()); auto editor = TextEditorWidget::currentTextEditorWidget();
item->apply(manipulator, cursorPos); item->apply(editor, cursorPos);
QCOMPARE(manipulator.getLine(7), " s.member /* COMPLETE HERE */"); QCOMPARE(editor->textDocument()->blockText(6), " s.member /* COMPLETE HERE */");
QCOMPARE(manipulator.cursorPos(), Text::Position({7, 12})); QCOMPARE(editor->lineColumn(), Text::Position({7, 12}));
QVERIFY(manipulator.editor()->autoCompleteHighlightPositions().isEmpty()); QVERIFY(editor->autoCompleteHighlightPositions().isEmpty());
} }
void ClangdTestCompletion::testCompleteMembersFromInside() void ClangdTestCompletion::testCompleteMembersFromInside()
@@ -1693,11 +1692,11 @@ void ClangdTestCompletion::testCompleteMembersFromInside()
const AssistProposalItemInterface * const item = getItem(proposal, " privateFunc()", "void"); const AssistProposalItemInterface * const item = getItem(proposal, " privateFunc()", "void");
QVERIFY(item); QVERIFY(item);
TextDocumentManipulator manipulator(TextEditorWidget::currentTextEditorWidget()); auto editor = TextEditorWidget::currentTextEditorWidget();
item->apply(manipulator, cursorPos); item->apply(editor, cursorPos);
QCOMPARE(manipulator.getLine(4), " privateFunc() /* COMPLETE HERE */"); QCOMPARE(editor->textDocument()->blockText(3), " privateFunc() /* COMPLETE HERE */");
QCOMPARE(manipulator.cursorPos(), Text::Position({4, 21})); QCOMPARE(editor->lineColumn(), Text::Position({4, 21}));
QVERIFY(manipulator.editor()->autoCompleteHighlightPositions().isEmpty()); QVERIFY(editor->autoCompleteHighlightPositions().isEmpty());
} }
void ClangdTestCompletion::testCompleteMembersFromOutside() void ClangdTestCompletion::testCompleteMembersFromOutside()
@@ -1711,11 +1710,11 @@ void ClangdTestCompletion::testCompleteMembersFromOutside()
const AssistProposalItemInterface * const item = getItem(proposal, " publicFunc()", "void"); const AssistProposalItemInterface * const item = getItem(proposal, " publicFunc()", "void");
QVERIFY(item); QVERIFY(item);
TextDocumentManipulator manipulator(TextEditorWidget::currentTextEditorWidget()); auto editor = TextEditorWidget::currentTextEditorWidget();
item->apply(manipulator, cursorPos); item->apply(editor, cursorPos);
QCOMPARE(manipulator.getLine(13), " c.publicFunc() /* COMPLETE HERE */"); QCOMPARE(editor->textDocument()->blockText(12), " c.publicFunc() /* COMPLETE HERE */");
QCOMPARE(manipulator.cursorPos(), Text::Position({13, 18})); QCOMPARE(editor->lineColumn(), Text::Position({13, 18}));
QVERIFY(manipulator.editor()->autoCompleteHighlightPositions().isEmpty()); QVERIFY(editor->autoCompleteHighlightPositions().isEmpty());
} }
void ClangdTestCompletion::testCompleteMembersFromFriend() void ClangdTestCompletion::testCompleteMembersFromFriend()
@@ -1729,11 +1728,11 @@ void ClangdTestCompletion::testCompleteMembersFromFriend()
const AssistProposalItemInterface * const item = getItem(proposal, " privateFunc()", "void"); const AssistProposalItemInterface * const item = getItem(proposal, " privateFunc()", "void");
QVERIFY(item); QVERIFY(item);
TextDocumentManipulator manipulator(TextEditorWidget::currentTextEditorWidget()); auto editor = TextEditorWidget::currentTextEditorWidget();
item->apply(manipulator, cursorPos); item->apply(editor, cursorPos);
QCOMPARE(manipulator.getLine(14), " C().privateFunc() /* COMPLETE HERE */"); QCOMPARE(editor->textDocument()->blockText(13), " C().privateFunc() /* COMPLETE HERE */");
QCOMPARE(manipulator.cursorPos(), Text::Position({14, 21})); QCOMPARE(editor->lineColumn(), Text::Position({14, 21}));
QVERIFY(manipulator.editor()->autoCompleteHighlightPositions().isEmpty()); QVERIFY(editor->autoCompleteHighlightPositions().isEmpty());
} }
void ClangdTestCompletion::testFunctionAddress() void ClangdTestCompletion::testFunctionAddress()
@@ -1746,11 +1745,11 @@ void ClangdTestCompletion::testFunctionAddress()
const AssistProposalItemInterface * const item = getItem(proposal, " memberFunc()", "void"); const AssistProposalItemInterface * const item = getItem(proposal, " memberFunc()", "void");
QVERIFY(item); QVERIFY(item);
TextDocumentManipulator manipulator(TextEditorWidget::currentTextEditorWidget()); auto editor = TextEditorWidget::currentTextEditorWidget();
item->apply(manipulator, cursorPos); item->apply(editor, cursorPos);
QCOMPARE(manipulator.getLine(7), " const auto p = &S::memberFunc /* COMPLETE HERE */;"); QCOMPARE(editor->textDocument()->blockText(6), " const auto p = &S::memberFunc /* COMPLETE HERE */;");
QCOMPARE(manipulator.cursorPos(), Text::Position({7, 33})); QCOMPARE(editor->lineColumn(), Text::Position({7, 33}));
QVERIFY(manipulator.editor()->autoCompleteHighlightPositions().isEmpty()); QVERIFY(editor->autoCompleteHighlightPositions().isEmpty());
} }
void ClangdTestCompletion::testFunctionHints() void ClangdTestCompletion::testFunctionHints()
@@ -1810,11 +1809,11 @@ void ClangdTestCompletion::testCompleteClassAndConstructor()
const AssistProposalItemInterface * const item const AssistProposalItemInterface * const item
= getItem(proposal, QString::fromUtf8(" Foo(…)"), "[2 overloads]"); = getItem(proposal, QString::fromUtf8(" Foo(…)"), "[2 overloads]");
QVERIFY(item); QVERIFY(item);
TextDocumentManipulator manipulator(TextEditorWidget::currentTextEditorWidget()); auto editor = TextEditorWidget::currentTextEditorWidget();
item->apply(manipulator, cursorPos); item->apply(editor, cursorPos);
QCOMPARE(manipulator.getLine(7), " Foo( /* COMPLETE HERE */"); QCOMPARE(editor->textDocument()->blockText(6), " Foo( /* COMPLETE HERE */");
QCOMPARE(manipulator.cursorPos(), Text::Position({7, 8})); QCOMPARE(editor->lineColumn(), Text::Position({7, 8}));
QVERIFY(manipulator.editor()->autoCompleteHighlightPositions().isEmpty()); QVERIFY(editor->autoCompleteHighlightPositions().isEmpty());
} }
void ClangdTestCompletion::testCompletePrivateFunctionDefinition() void ClangdTestCompletion::testCompletePrivateFunctionDefinition()
@@ -1837,11 +1836,11 @@ void ClangdTestCompletion::testCompleteWithDotToArrowCorrection()
QVERIFY(proposal); QVERIFY(proposal);
const AssistProposalItemInterface * const item = getItem(proposal, " member", "int"); const AssistProposalItemInterface * const item = getItem(proposal, " member", "int");
QVERIFY(item); QVERIFY(item);
TextDocumentManipulator manipulator(TextEditorWidget::currentTextEditorWidget()); auto editor = TextEditorWidget::currentTextEditorWidget();
item->apply(manipulator, cursorPos); item->apply(editor, cursorPos);
QCOMPARE(manipulator.getLine(4), " bar->member /* COMPLETE HERE */"); QCOMPARE(editor->textDocument()->blockText(3), " bar->member /* COMPLETE HERE */");
QCOMPARE(manipulator.cursorPos(), Text::Position({4, 15})); QCOMPARE(editor->lineColumn(), Text::Position({4, 15}));
QVERIFY(manipulator.editor()->autoCompleteHighlightPositions().isEmpty()); QVERIFY(editor->autoCompleteHighlightPositions().isEmpty());
} }
void ClangdTestCompletion::testDontCompleteWithDotToArrowCorrectionForFloats() void ClangdTestCompletion::testDontCompleteWithDotToArrowCorrectionForFloats()
@@ -1868,11 +1867,11 @@ void ClangdTestCompletion::testCompleteCodeInGeneratedUiFile()
const AssistProposalItemInterface * const item = getItem( const AssistProposalItemInterface * const item = getItem(
proposal, " setupUi(QMainWindow *MainWindow)", "void"); proposal, " setupUi(QMainWindow *MainWindow)", "void");
QVERIFY(item); QVERIFY(item);
TextDocumentManipulator manipulator(TextEditorWidget::currentTextEditorWidget()); auto editor = TextEditorWidget::currentTextEditorWidget();
item->apply(manipulator, cursorPos); item->apply(editor, cursorPos);
QCOMPARE(manipulator.getLine(34), " ui->setupUi( /* COMPLETE HERE */"); QCOMPARE(editor->textDocument()->blockText(33), " ui->setupUi( /* COMPLETE HERE */");
QCOMPARE(manipulator.cursorPos(), Text::Position({34, 16})); QCOMPARE(editor->lineColumn(), Text::Position({34, 16}));
QVERIFY(manipulator.editor()->autoCompleteHighlightPositions().isEmpty()); QVERIFY(editor->autoCompleteHighlightPositions().isEmpty());
} }
void ClangdTestCompletion::testSignalCompletion_data() void ClangdTestCompletion::testSignalCompletion_data()

View File

@@ -64,7 +64,7 @@ class CppAssistProposalItem final : public AssistProposalItem
public: public:
~CppAssistProposalItem() noexcept override = default; ~CppAssistProposalItem() noexcept override = default;
bool prematurelyApplies(const QChar &c) const override; bool prematurelyApplies(const QChar &c) const override;
void applyContextualContent(TextDocumentManipulator &manipulator, int basePosition) const override; void applyContextualContent(TextEditorWidget *editorWidget, int basePosition) const override;
bool isOverloaded() const { return m_isOverloaded; } bool isOverloaded() const { return m_isOverloaded; }
void markAsOverloaded() { m_isOverloaded = true; } void markAsOverloaded() { m_isOverloaded = true; }
@@ -143,9 +143,9 @@ bool CppAssistProposalItem::prematurelyApplies(const QChar &typedChar) const
return false; return false;
} }
static bool isDereferenced(TextDocumentManipulator &manipulator, int basePosition) static bool isDereferenced(TextEditorWidget *editorWidget, int basePosition)
{ {
QTextCursor cursor = manipulator.textCursorAt(basePosition); QTextCursor cursor = editorWidget->textCursorAt(basePosition);
cursor.setPosition(basePosition); cursor.setPosition(basePosition);
BackwardsScanner scanner(cursor, LanguageFeatures()); BackwardsScanner scanner(cursor, LanguageFeatures());
@@ -173,8 +173,10 @@ quint64 CppAssistProposalItem::hash() const
return 0; return 0;
} }
void CppAssistProposalItem::applyContextualContent(TextDocumentManipulator &manipulator, int basePosition) const void CppAssistProposalItem::applyContextualContent(TextEditorWidget *editorWidget, int basePosition) const
{ {
QTC_ASSERT(editorWidget, return);
Symbol *symbol = nullptr; Symbol *symbol = nullptr;
if (data().isValid()) if (data().isValid())
@@ -224,7 +226,7 @@ void CppAssistProposalItem::applyContextualContent(TextDocumentManipulator &mani
if (function->argumentCount() == 0) if (function->argumentCount() == 0)
extraChars += QLatin1Char('<'); extraChars += QLatin1Char('<');
#endif #endif
} else if (!isDereferenced(manipulator, basePosition) && !function->isAmbiguous()) { } else if (!isDereferenced(editorWidget, basePosition) && !function->isAmbiguous()) {
// When the user typed the opening parenthesis, he'll likely also type the closing one, // When the user typed the opening parenthesis, he'll likely also type the closing one,
// in which case it would be annoying if we put the cursor after the already automatically // in which case it would be annoying if we put the cursor after the already automatically
// inserted closing parenthesis. // inserted closing parenthesis.
@@ -238,7 +240,7 @@ void CppAssistProposalItem::applyContextualContent(TextDocumentManipulator &mani
// If the function doesn't return anything, automatically place the semicolon, // If the function doesn't return anything, automatically place the semicolon,
// unless we're doing a scope completion (then it might be function definition). // unless we're doing a scope completion (then it might be function definition).
const QChar characterAtCursor = manipulator.characterAt(manipulator.currentPosition()); const QChar characterAtCursor = editorWidget->characterAt(editorWidget->position());
bool endWithSemicolon = m_typedChar == QLatin1Char(';') bool endWithSemicolon = m_typedChar == QLatin1Char(';')
|| (function->returnType()->asVoidType() && m_completionOperator != T_COLON_COLON); || (function->returnType()->asVoidType() && m_completionOperator != T_COLON_COLON);
const QChar semicolon = m_typedChar.isNull() ? QLatin1Char(';') : m_typedChar; const QChar semicolon = m_typedChar.isNull() ? QLatin1Char(';') : m_typedChar;
@@ -256,7 +258,7 @@ void CppAssistProposalItem::applyContextualContent(TextDocumentManipulator &mani
m_typedChar = QChar(); m_typedChar = QChar();
} }
} else if (autoParenthesesEnabled) { } else if (autoParenthesesEnabled) {
const QChar lookAhead = manipulator.characterAt(manipulator.currentPosition() + 1); const QChar lookAhead = editorWidget->characterAt(editorWidget->position() + 1);
if (MatchingText::shouldInsertMatchingText(lookAhead)) { if (MatchingText::shouldInsertMatchingText(lookAhead)) {
extraChars += QLatin1Char(')'); extraChars += QLatin1Char(')');
--cursorOffset; --cursorOffset;
@@ -294,10 +296,10 @@ void CppAssistProposalItem::applyContextualContent(TextDocumentManipulator &mani
} }
// Avoid inserting characters that are already there // Avoid inserting characters that are already there
int currentPosition = manipulator.currentPosition(); int currentPosition = editorWidget->position();
QTextCursor cursor = manipulator.textCursorAt(basePosition); QTextCursor cursor = editorWidget->textCursorAt(basePosition);
cursor.movePosition(QTextCursor::EndOfWord); cursor.movePosition(QTextCursor::EndOfWord);
const QString textAfterCursor = manipulator.textAt(currentPosition, const QString textAfterCursor = editorWidget->textAt(currentPosition,
cursor.position() - currentPosition); cursor.position() - currentPosition);
if (toInsert != textAfterCursor if (toInsert != textAfterCursor
&& toInsert.indexOf(textAfterCursor, currentPosition - basePosition) >= 0) { && toInsert.indexOf(textAfterCursor, currentPosition - basePosition) >= 0) {
@@ -306,7 +308,7 @@ void CppAssistProposalItem::applyContextualContent(TextDocumentManipulator &mani
for (int i = 0; i < extraChars.length(); ++i) { for (int i = 0; i < extraChars.length(); ++i) {
const QChar a = extraChars.at(i); const QChar a = extraChars.at(i);
const QChar b = manipulator.characterAt(currentPosition + i); const QChar b = editorWidget->characterAt(currentPosition + i);
if (a == b) if (a == b)
++extraLength; ++extraLength;
else else
@@ -317,12 +319,12 @@ void CppAssistProposalItem::applyContextualContent(TextDocumentManipulator &mani
// Insert the remainder of the name // Insert the remainder of the name
const int length = currentPosition - basePosition + extraLength; const int length = currentPosition - basePosition + extraLength;
manipulator.replace(basePosition, length, toInsert); editorWidget->replace(basePosition, length, toInsert);
manipulator.setCursorPosition(basePosition + toInsert.length()); editorWidget->setCursorPosition(basePosition + toInsert.length());
if (cursorOffset) if (cursorOffset)
manipulator.setCursorPosition(manipulator.currentPosition() + cursorOffset); editorWidget->setCursorPosition(editorWidget->position() + cursorOffset);
if (setAutoCompleteSkipPos) if (setAutoCompleteSkipPos)
manipulator.addAutoCompleteSkipPosition(); editorWidget->setAutoCompleteSkipPosition(editorWidget->textCursor());
} }
// -------------------- // --------------------

View File

@@ -15,7 +15,7 @@ VirtualFunctionProposalItem::VirtualFunctionProposalItem(
{ {
} }
void VirtualFunctionProposalItem::apply(TextEditor::TextDocumentManipulator &, int) const void VirtualFunctionProposalItem::apply(TextEditor::TextEditorWidget *, int) const
{ {
if (!m_link.hasValidTarget()) if (!m_link.hasValidTarget())
return; return;

View File

@@ -16,7 +16,7 @@ public:
VirtualFunctionProposalItem(const Utils::Link &link, VirtualFunctionProposalItem(const Utils::Link &link,
bool openInSplit = true); bool openInSplit = true);
~VirtualFunctionProposalItem() noexcept override = default; ~VirtualFunctionProposalItem() noexcept override = default;
void apply(TextEditor::TextDocumentManipulator &manipulator, int basePosition) const override; void apply(TextEditor::TextEditorWidget *editorWidget, int basePosition) const override;
Utils::Link link() const { return m_link; } // Exposed for tests Utils::Link link() const { return m_link; } // Exposed for tests
private: private:

View File

@@ -893,7 +893,7 @@ public:
return text() == m_provider->needle(); return text() == m_provider->needle();
} }
void applyContextualContent(TextDocumentManipulator &, int) const override void applyContextualContent(TextEditorWidget *, int) const override
{ {
QTC_ASSERT(m_provider->handler(), return); QTC_ASSERT(m_provider->handler(), return);
m_provider->handler()->handleReplay(text().mid(m_provider->needle().size())); m_provider->handler()->handleReplay(text().mid(m_provider->needle().size()));

View File

@@ -15,6 +15,7 @@
#include <texteditor/snippets/snippet.h> #include <texteditor/snippets/snippet.h>
#include <texteditor/snippets/snippetassistcollector.h> #include <texteditor/snippets/snippetassistcollector.h>
#include <texteditor/textdocument.h> #include <texteditor/textdocument.h>
#include <texteditor/texteditor.h>
#include <texteditor/texteditorsettings.h> #include <texteditor/texteditorsettings.h>
#include <utils/algorithm.h> #include <utils/algorithm.h>
#include <utils/textutils.h> #include <utils/textutils.h>
@@ -53,23 +54,24 @@ bool LanguageClientCompletionItem::prematurelyApplies(const QChar &typedCharacte
return false; return false;
} }
void LanguageClientCompletionItem::apply(TextDocumentManipulator &manipulator, void LanguageClientCompletionItem::apply(TextEditorWidget *editorWidget,
int /*basePosition*/) const int /*basePosition*/) const
{ {
QTC_ASSERT(editorWidget, return);
if (auto edit = m_item.textEdit()) { if (auto edit = m_item.textEdit()) {
applyTextEdit(manipulator, *edit, isSnippet()); applyTextEdit(editorWidget, *edit, isSnippet());
} else { } else {
const int pos = manipulator.currentPosition(); const int pos = editorWidget->position();
const QString textToInsert(m_item.insertText().value_or(text())); const QString textToInsert(m_item.insertText().value_or(text()));
int length = 0; int length = 0;
for (auto it = textToInsert.crbegin(), end = textToInsert.crend(); it != end; ++it) { for (auto it = textToInsert.crbegin(), end = textToInsert.crend(); it != end; ++it) {
if (it->toLower() != manipulator.characterAt(pos - length - 1).toLower()) { if (it->toLower() != editorWidget->characterAt(pos - length - 1).toLower()) {
length = 0; length = 0;
break; break;
} }
++length; ++length;
} }
QTextCursor cursor = manipulator.textCursorAt(pos); QTextCursor cursor = editorWidget->textCursorAt(pos);
cursor.movePosition(QTextCursor::StartOfLine, QTextCursor::KeepAnchor); cursor.movePosition(QTextCursor::StartOfLine, QTextCursor::KeepAnchor);
const QString blockTextUntilPosition = cursor.selectedText(); const QString blockTextUntilPosition = cursor.selectedText();
static QRegularExpression identifier("[a-zA-Z_][a-zA-Z0-9_]*$"); static QRegularExpression identifier("[a-zA-Z_][a-zA-Z0-9_]*$");
@@ -77,19 +79,19 @@ void LanguageClientCompletionItem::apply(TextDocumentManipulator &manipulator,
int matchLength = match.hasMatch() ? match.capturedLength(0) : 0; int matchLength = match.hasMatch() ? match.capturedLength(0) : 0;
length = qMax(length, matchLength); length = qMax(length, matchLength);
if (isSnippet()) { if (isSnippet()) {
manipulator.replace(pos - length, length, {}); editorWidget->replace(pos - length, length, {});
manipulator.insertCodeSnippet(pos - length, textToInsert, &parseSnippet); editorWidget->insertCodeSnippet(pos - length, textToInsert, &parseSnippet);
} else { } else {
manipulator.replace(pos - length, length, textToInsert); editorWidget->replace(pos - length, length, textToInsert);
} }
} }
if (auto additionalEdits = m_item.additionalTextEdits()) { if (auto additionalEdits = m_item.additionalTextEdits()) {
for (const auto &edit : *additionalEdits) for (const auto &edit : *additionalEdits)
applyTextEdit(manipulator, edit); applyTextEdit(editorWidget, edit);
} }
if (!m_triggeredCommitCharacter.isNull()) if (!m_triggeredCommitCharacter.isNull())
manipulator.insertCodeSnippet(manipulator.currentPosition(), editorWidget->insertCodeSnippet(editorWidget->position(),
m_triggeredCommitCharacter, m_triggeredCommitCharacter,
&Snippet::parse); &Snippet::parse);
} }

View File

@@ -97,7 +97,7 @@ public:
QString filterText() const override; QString filterText() const override;
bool implicitlyApplies() const override; bool implicitlyApplies() const override;
bool prematurelyApplies(const QChar &typedCharacter) const override; bool prematurelyApplies(const QChar &typedCharacter) const override;
void apply(TextEditor::TextDocumentManipulator &manipulator, int basePosition) const override; void apply(TextEditor::TextEditorWidget *editorWidget, int basePosition) const override;
QIcon icon() const override; QIcon icon() const override;
QString detail() const override; QString detail() const override;
bool isSnippet() const override; bool isSnippet() const override;

View File

@@ -15,7 +15,6 @@
#include <coreplugin/messagemanager.h> #include <coreplugin/messagemanager.h>
#include <coreplugin/progressmanager/progressmanager.h> #include <coreplugin/progressmanager/progressmanager.h>
#include <texteditor/codeassist/textdocumentmanipulator.h>
#include <texteditor/refactoringchanges.h> #include <texteditor/refactoringchanges.h>
#include <texteditor/textdocument.h> #include <texteditor/textdocument.h>
#include <texteditor/texteditor.h> #include <texteditor/texteditor.h>
@@ -100,19 +99,17 @@ bool applyTextEdits(const Client *client,
return file->apply(editsToChangeSet(edits, file->document())); return file->apply(editsToChangeSet(edits, file->document()));
} }
void applyTextEdit(TextDocumentManipulator &manipulator, void applyTextEdit(TextEditorWidget *editorWidget, const TextEdit &edit, bool newTextIsSnippet)
const TextEdit &edit,
bool newTextIsSnippet)
{ {
const Range range = edit.range(); const Range range = edit.range();
const QTextDocument *doc = manipulator.document(); const QTextDocument *doc = editorWidget->document();
const int start = Text::positionInText(doc, range.start().line() + 1, range.start().character() + 1); const int start = Text::positionInText(doc, range.start().line() + 1, range.start().character() + 1);
const int end = Text::positionInText(doc, range.end().line() + 1, range.end().character() + 1); const int end = Text::positionInText(doc, range.end().line() + 1, range.end().character() + 1);
if (newTextIsSnippet) { if (newTextIsSnippet) {
manipulator.replace(start, end - start, {}); editorWidget->replace(start, end - start, {});
manipulator.insertCodeSnippet(start, edit.newText(), &parseSnippet); editorWidget->insertCodeSnippet(start, edit.newText(), &parseSnippet);
} else { } else {
manipulator.replace(start, end - start, edit.newText()); editorWidget->replace(start, end - start, edit.newText());
} }
} }

View File

@@ -37,7 +37,7 @@ bool LANGUAGECLIENT_EXPORT applyTextEdits(const Client *client,
const QList<LanguageServerProtocol::TextEdit> &edits); const QList<LanguageServerProtocol::TextEdit> &edits);
bool LANGUAGECLIENT_EXPORT applyDocumentChange(const Client *client, bool LANGUAGECLIENT_EXPORT applyDocumentChange(const Client *client,
const LanguageServerProtocol::DocumentChange &change); const LanguageServerProtocol::DocumentChange &change);
void LANGUAGECLIENT_EXPORT applyTextEdit(TextEditor::TextDocumentManipulator &manipulator, void LANGUAGECLIENT_EXPORT applyTextEdit(TextEditor::TextEditorWidget *editorWidget,
const LanguageServerProtocol::TextEdit &edit, const LanguageServerProtocol::TextEdit &edit,
bool newTextIsSnippet = false); bool newTextIsSnippet = false);
void LANGUAGECLIENT_EXPORT void LANGUAGECLIENT_EXPORT

View File

@@ -355,11 +355,12 @@ bool QmlJSAssistProposalItem::prematurelyApplies(const QChar &c) const
|| (text().endsWith(QLatin1Char('.')) && c == QLatin1Char('.')); || (text().endsWith(QLatin1Char('.')) && c == QLatin1Char('.'));
} }
void QmlJSAssistProposalItem::applyContextualContent(TextEditor::TextDocumentManipulator &manipulator, void QmlJSAssistProposalItem::applyContextualContent(TextEditorWidget *editorWidget,
int basePosition) const int basePosition) const
{ {
const int currentPosition = manipulator.currentPosition(); QTC_ASSERT(editorWidget, return);
manipulator.replace(basePosition, currentPosition - basePosition, QString()); const int currentPosition = editorWidget->position();
editorWidget->replace(basePosition, currentPosition - basePosition, QString());
QString content = text(); QString content = text();
int cursorOffset = 0; int cursorOffset = 0;
@@ -378,17 +379,17 @@ void QmlJSAssistProposalItem::applyContextualContent(TextEditor::TextDocumentMan
int replacedLength = 0; int replacedLength = 0;
for (int i = 0; i < replaceable.length(); ++i) { for (int i = 0; i < replaceable.length(); ++i) {
const QChar a = replaceable.at(i); const QChar a = replaceable.at(i);
const QChar b = manipulator.characterAt(manipulator.currentPosition() + i); const QChar b = editorWidget->characterAt(editorWidget->position() + i);
if (a == b) if (a == b)
++replacedLength; ++replacedLength;
else else
break; break;
} }
const int length = manipulator.currentPosition() - basePosition + replacedLength; const int length = editorWidget->position() - basePosition + replacedLength;
manipulator.replace(basePosition, length, content); editorWidget->replace(basePosition, length, content);
if (cursorOffset) { if (cursorOffset) {
manipulator.setCursorPosition(manipulator.currentPosition() + cursorOffset); editorWidget->setCursorPosition(editorWidget->position() + cursorOffset);
manipulator.addAutoCompleteSkipPosition(); editorWidget->setAutoCompleteSkipPosition(editorWidget->textCursor());
} }
} }

View File

@@ -32,7 +32,7 @@ class QmlJSAssistProposalItem final : public TextEditor::AssistProposalItem
{ {
public: public:
bool prematurelyApplies(const QChar &c) const final; bool prematurelyApplies(const QChar &c) const final;
void applyContextualContent(TextEditor::TextDocumentManipulator &manipulator, void applyContextualContent(TextEditor::TextEditorWidget *editorWidget,
int basePosition) const final; int basePosition) const final;
}; };

View File

@@ -41,7 +41,6 @@ add_qtc_plugin(TextEditor
codeassist/iassistprovider.cpp codeassist/iassistprovider.h codeassist/iassistprovider.cpp codeassist/iassistprovider.h
codeassist/ifunctionhintproposalmodel.cpp codeassist/ifunctionhintproposalmodel.h codeassist/ifunctionhintproposalmodel.cpp codeassist/ifunctionhintproposalmodel.h
codeassist/keywordscompletionassist.cpp codeassist/keywordscompletionassist.h codeassist/keywordscompletionassist.cpp codeassist/keywordscompletionassist.h
codeassist/textdocumentmanipulator.cpp codeassist/textdocumentmanipulator.h
codecchooser.cpp codecchooser.h codecchooser.cpp codecchooser.h
codestyleeditor.cpp codestyleeditor.h codestyleeditor.cpp codestyleeditor.h
codestylepool.cpp codestylepool.h codestylepool.cpp codestylepool.h

View File

@@ -37,8 +37,9 @@ public:
setText(text); setText(text);
} }
void apply(TextDocumentManipulator &manipulator, int /*basePosition*/) const final void apply(TextEditorWidget *editorWidget, int /*basePosition*/) const final
{ {
QTC_ASSERT(editorWidget, return);
//Move to last in circular clipboard //Move to last in circular clipboard
if (CircularClipboard * clipboard = CircularClipboard::instance()) { if (CircularClipboard * clipboard = CircularClipboard::instance()) {
@@ -51,7 +52,7 @@ public:
TextEditorWidget::duplicateMimeData(m_mimeData.get())); TextEditorWidget::duplicateMimeData(m_mimeData.get()));
//Paste //Paste
manipulator.editor()->paste(); editorWidget->paste();
} }
private: private:

View File

@@ -105,33 +105,35 @@ bool AssistProposalItem::prematurelyApplies(const QChar &c) const
return false; return false;
} }
void AssistProposalItem::apply(TextDocumentManipulator &manipulator, int basePosition) const void AssistProposalItem::apply(TextEditorWidget *editorWidget, int basePosition) const
{ {
QTC_ASSERT(editorWidget, return);
if (data().canConvert<QString>()) { if (data().canConvert<QString>()) {
applySnippet(manipulator, basePosition); applySnippet(editorWidget, basePosition);
} else if (data().canConvert<QuickFixOperation::Ptr>()) { } else if (data().canConvert<QuickFixOperation::Ptr>()) {
applyQuickFix(manipulator, basePosition); applyQuickFix(editorWidget, basePosition);
} else { } else {
applyContextualContent(manipulator, basePosition); applyContextualContent(editorWidget, basePosition);
manipulator.editor()->encourageApply(); editorWidget->encourageApply();
} }
} }
void AssistProposalItem::applyContextualContent(TextDocumentManipulator &manipulator, int basePosition) const void AssistProposalItem::applyContextualContent(TextEditorWidget *editorWidget, int basePosition) const
{ {
const int currentPosition = manipulator.currentPosition(); QTC_ASSERT(editorWidget, return);
manipulator.replace(basePosition, currentPosition - basePosition, text()); const int currentPosition = editorWidget->position();
editorWidget->replace(basePosition, currentPosition - basePosition, text());
} }
void AssistProposalItem::applySnippet(TextDocumentManipulator &manipulator, int basePosition) const void AssistProposalItem::applySnippet(TextEditorWidget *editorWidget, int basePosition) const
{ {
manipulator.insertCodeSnippet(basePosition, data().toString(), &Snippet::parse); QTC_ASSERT(editorWidget, return);
editorWidget->insertCodeSnippet(basePosition, data().toString(), &Snippet::parse);
} }
void AssistProposalItem::applyQuickFix(TextDocumentManipulator &manipulator, int basePosition) const void AssistProposalItem::applyQuickFix(TextEditorWidget *editorWidget, int basePosition) const
{ {
Q_UNUSED(manipulator) Q_UNUSED(editorWidget)
Q_UNUSED(basePosition) Q_UNUSED(basePosition)
QuickFixOperation::Ptr op = data().value<QuickFixOperation::Ptr>(); QuickFixOperation::Ptr op = data().value<QuickFixOperation::Ptr>();

View File

@@ -20,7 +20,7 @@ public:
QString text() const override; QString text() const override;
bool implicitlyApplies() const override; bool implicitlyApplies() const override;
bool prematurelyApplies(const QChar &c) const override; bool prematurelyApplies(const QChar &c) const override;
void apply(TextDocumentManipulator &manipulator, int basePosition) const override; void apply(TextEditorWidget *editorWidget, int basePosition) const override;
void setIcon(const QIcon &icon); void setIcon(const QIcon &icon);
QIcon icon() const final; QIcon icon() const final;
@@ -37,9 +37,9 @@ public:
bool isValid() const final; bool isValid() const final;
quint64 hash() const override; quint64 hash() const override;
virtual void applyContextualContent(TextDocumentManipulator &manipulator, int basePosition) const; virtual void applyContextualContent(TextEditorWidget *editorWidget, int basePosition) const;
virtual void applySnippet(TextDocumentManipulator &manipulator, int basePosition) const; virtual void applySnippet(TextEditorWidget *editorWidget, int basePosition) const;
virtual void applyQuickFix(TextDocumentManipulator &manipulator, int basePosition) const; virtual void applyQuickFix(TextEditorWidget *editorWidget, int basePosition) const;
private: private:
QIcon m_icon; QIcon m_icon;

View File

@@ -3,7 +3,7 @@
#pragma once #pragma once
#include "textdocumentmanipulator.h" #include <texteditor/texteditor_global.h>
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
class QIcon; class QIcon;
@@ -14,6 +14,8 @@ QT_END_NAMESPACE
namespace TextEditor { namespace TextEditor {
class TextEditorWidget;
class TEXTEDITOR_EXPORT AssistProposalItemInterface class TEXTEDITOR_EXPORT AssistProposalItemInterface
{ {
public: public:
@@ -36,7 +38,7 @@ public:
virtual QString filterText() const { return text(); } virtual QString filterText() const { return text(); }
virtual bool implicitlyApplies() const = 0; virtual bool implicitlyApplies() const = 0;
virtual bool prematurelyApplies(const QChar &typedCharacter) const = 0; virtual bool prematurelyApplies(const QChar &typedCharacter) const = 0;
virtual void apply(TextDocumentManipulator &manipulator, int basePosition) const = 0; virtual void apply(TextEditorWidget *editorWidget, int basePosition) const = 0;
virtual QIcon icon() const = 0; virtual QIcon icon() const = 0;
virtual QString detail() const = 0; virtual QString detail() const = 0;
virtual bool isKeyword() const { return false; } virtual bool isKeyword() const { return false; }

View File

@@ -46,7 +46,7 @@ public:
class OpenEditorItem final : public TestProposalItem class OpenEditorItem final : public TestProposalItem
{ {
public: public:
void apply(TextDocumentManipulator &, int) const final void apply(TextEditorWidget *, int) const final
{ {
m_openedEditor = Core::EditorManager::openEditor(m_filePath, m_openedEditor = Core::EditorManager::openEditor(m_filePath,
Core::Constants::K_DEFAULT_TEXT_EDITOR_ID); Core::Constants::K_DEFAULT_TEXT_EDITOR_ID);

View File

@@ -9,7 +9,6 @@
#include "iassistproposalwidget.h" #include "iassistproposalwidget.h"
#include "assistinterface.h" #include "assistinterface.h"
#include "assistproposalitem.h" #include "assistproposalitem.h"
#include "textdocumentmanipulator.h"
#include <texteditor/textdocument.h> #include <texteditor/textdocument.h>
#include <texteditor/texteditor.h> #include <texteditor/texteditor.h>
@@ -302,8 +301,7 @@ void CodeAssistantPrivate::displayProposal(IAssistProposal *newProposal, AssistR
void CodeAssistantPrivate::processProposalItem(AssistProposalItemInterface *proposalItem) void CodeAssistantPrivate::processProposalItem(AssistProposalItemInterface *proposalItem)
{ {
QTC_ASSERT(m_proposalWidget, return); QTC_ASSERT(m_proposalWidget, return);
TextDocumentManipulator manipulator(m_editorWidget); proposalItem->apply(m_editorWidget, m_proposalWidget->basePosition());
proposalItem->apply(manipulator, m_proposalWidget->basePosition());
destroyContext(); destroyContext();
m_editorWidget->encourageApply(); m_editorWidget->encourageApply();
if (!proposalItem->isSnippet()) if (!proposalItem->isSnippet())

View File

@@ -72,20 +72,21 @@ bool KeywordsAssistProposalItem::prematurelyApplies(const QChar &c) const
return c == QLatin1Char('(') && m_isFunction; return c == QLatin1Char('(') && m_isFunction;
} }
void KeywordsAssistProposalItem::applyContextualContent(TextDocumentManipulator &manipulator, void KeywordsAssistProposalItem::applyContextualContent(TextEditorWidget *editorWidget,
int basePosition) const int basePosition) const
{ {
QTC_ASSERT(editorWidget, return);
const CompletionSettings &settings = TextEditorSettings::completionSettings(); const CompletionSettings &settings = TextEditorSettings::completionSettings();
int replaceLength = manipulator.currentPosition() - basePosition; int replaceLength = editorWidget->position() - basePosition;
QString toInsert = text(); QString toInsert = text();
int cursorOffset = 0; int cursorOffset = 0;
const QChar characterAtCurrentPosition = manipulator.characterAt(manipulator.currentPosition()); const QChar characterAtCurrentPosition = editorWidget->characterAt(editorWidget->position());
bool setAutoCompleteSkipPosition = false; bool setAutoCompleteSkipPosition = false;
if (m_isFunction && settings.m_autoInsertBrackets) { if (m_isFunction && settings.m_autoInsertBrackets) {
if (settings.m_spaceAfterFunctionName) { if (settings.m_spaceAfterFunctionName) {
if (manipulator.textAt(manipulator.currentPosition(), 2) == QLatin1String(" (")) { if (editorWidget->textAt(editorWidget->position(), 2) == QLatin1String(" (")) {
cursorOffset = 2; cursorOffset = 2;
} else if ( characterAtCurrentPosition == QLatin1Char('(') } else if ( characterAtCurrentPosition == QLatin1Char('(')
|| characterAtCurrentPosition == QLatin1Char(' ')) { || characterAtCurrentPosition == QLatin1Char(' ')) {
@@ -107,11 +108,11 @@ void KeywordsAssistProposalItem::applyContextualContent(TextDocumentManipulator
} }
} }
manipulator.replace(basePosition, replaceLength, toInsert); editorWidget->replace(basePosition, replaceLength, toInsert);
if (cursorOffset) if (cursorOffset)
manipulator.setCursorPosition(manipulator.currentPosition() + cursorOffset); editorWidget->setCursorPosition(editorWidget->position() + cursorOffset);
if (setAutoCompleteSkipPosition) if (setAutoCompleteSkipPosition)
manipulator.addAutoCompleteSkipPosition(); editorWidget->setAutoCompleteSkipPosition(editorWidget->textCursor());
} }
// ------------------------- // -------------------------

View File

@@ -40,7 +40,7 @@ public:
KeywordsAssistProposalItem(bool isFunction); KeywordsAssistProposalItem(bool isFunction);
bool prematurelyApplies(const QChar &c) const final; bool prematurelyApplies(const QChar &c) const final;
void applyContextualContent(TextDocumentManipulator &manipulator, int basePosition) const final; void applyContextualContent(TextEditorWidget *editorWidget, int basePosition) const final;
private: private:
bool m_isFunction; bool m_isFunction;
}; };

View File

@@ -1,83 +0,0 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include "textdocumentmanipulator.h"
#include <texteditor/texteditor.h>
#include <texteditor/textdocument.h>
namespace TextEditor {
TextDocumentManipulator::TextDocumentManipulator(TextEditorWidget *textEditorWidget)
: m_textEditorWidget(textEditorWidget)
{
}
int TextDocumentManipulator::currentPosition() const
{
return m_textEditorWidget->position();
}
QChar TextDocumentManipulator::characterAt(int position) const
{
return m_textEditorWidget->characterAt(position);
}
QString TextDocumentManipulator::textAt(int position, int length) const
{
return m_textEditorWidget->textAt(position, length);
}
QTextCursor TextDocumentManipulator::textCursor() const
{
return m_textEditorWidget->textCursor();
}
QTextCursor TextDocumentManipulator::textCursorAt(int position) const
{
return m_textEditorWidget->textCursorAt(position);
}
QTextDocument *TextDocumentManipulator::document() const
{
return m_textEditorWidget->document();
}
TextEditorWidget *TextDocumentManipulator::editor() const
{
return m_textEditorWidget;
}
void TextDocumentManipulator::setCursorPosition(int position)
{
m_textEditorWidget->setCursorPosition(position);
}
void TextDocumentManipulator::addAutoCompleteSkipPosition()
{
m_textEditorWidget->setAutoCompleteSkipPosition(m_textEditorWidget->textCursor());
}
void TextDocumentManipulator::replace(int position, int length, const QString &text)
{
m_textEditorWidget->replace(position, length, text);
}
void TextDocumentManipulator::insertCodeSnippet(int position,
const QString &text,
const SnippetParser &parse)
{
m_textEditorWidget->insertCodeSnippet(position, text, parse);
}
QString TextDocumentManipulator::getLine(int line) const
{
return m_textEditorWidget->textDocument()->blockText(line - 1);
}
Utils::Text::Position TextDocumentManipulator::cursorPos() const
{
return m_textEditorWidget->lineColumn();
}
} // namespace TextEditor

View File

@@ -1,51 +0,0 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#pragma once
#include <texteditor/snippets/snippetparser.h>
#include <texteditor/texteditor_global.h>
#include <utils/textutils.h>
QT_BEGIN_NAMESPACE
class QChar;
class QString;
class QTextCursor;
QT_END_NAMESPACE
namespace TextEditor {
class TextEditorWidget;
class TEXTEDITOR_EXPORT TextDocumentManipulator
{
public:
TextDocumentManipulator(TextEditorWidget *textEditorWidget);
int currentPosition() const;
QChar characterAt(int position) const;
QString textAt(int position, int length) const;
QTextCursor textCursor() const;
QTextCursor textCursorAt(int position) const;
QTextDocument *document() const;
TextEditorWidget *editor() const;
void setCursorPosition(int position);
void addAutoCompleteSkipPosition();
void replace(int position, int length, const QString &text);
void insertCodeSnippet(int position, const QString &text, const SnippetParser &parse);
QString getLine(int line) const;
Utils::Text::Position cursorPos() const;
private:
bool textIsDifferentAt(int position, int length, const QString &text) const;
void replaceWithoutCheck(int position, int length, const QString &text);
private:
TextEditorWidget *m_textEditorWidget;
};
} // namespace TextEditor

View File

@@ -5,6 +5,7 @@
#include "snippetscollection.h" #include "snippetscollection.h"
#include <texteditor/texteditorconstants.h> #include <texteditor/texteditorconstants.h>
#include <texteditor/texteditor.h>
#include <texteditor/codeassist/assistproposalitem.h> #include <texteditor/codeassist/assistproposalitem.h>
using namespace TextEditor; using namespace TextEditor;
@@ -24,9 +25,10 @@ public:
} }
bool implicitlyApplies() const override { return false; } bool implicitlyApplies() const override { return false; }
bool prematurelyApplies(const QChar &) const override { return false; } bool prematurelyApplies(const QChar &) const override { return false; }
void apply(TextDocumentManipulator &manipulator, int basePosition) const override void apply(TextEditorWidget *editorWidget, int basePosition) const override
{ {
manipulator.insertCodeSnippet(basePosition, m_snippet.content(), &Snippet::parse); QTC_ASSERT(editorWidget, return);
editorWidget->insertCodeSnippet(basePosition, m_snippet.content(), &Snippet::parse);
} }
QIcon icon() const override { return m_icon; } QIcon icon() const override { return m_icon; }
QString detail() const override { return m_snippet.generateTip(); } QString detail() const override { return m_snippet.generateTip(); }

View File

@@ -197,8 +197,6 @@ QtcPlugin {
"ifunctionhintproposalmodel.h", "ifunctionhintproposalmodel.h",
"keywordscompletionassist.cpp", "keywordscompletionassist.cpp",
"keywordscompletionassist.h", "keywordscompletionassist.h",
"textdocumentmanipulator.cpp",
"textdocumentmanipulator.h",
] ]
} }