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/iassistprocessor.h>
#include <texteditor/codeassist/iassistprovider.h>
#include <texteditor/codeassist/textdocumentmanipulator.h>
#include <texteditor/texteditor.h>
#include <utils/algorithm.h>
#include <utils/async.h>

View File

@@ -18,6 +18,7 @@
#include <cppeditor/projectpart.h>
#include <cplusplus/Icons.h>
#include <cplusplus/MatchingText.h>
#include <cplusplus/SimpleLexer.h>
#include <languageclient/languageclientfunctionhint.h>
@@ -26,6 +27,7 @@
#include <texteditor/codeassist/assistinterface.h>
#include <texteditor/codeassist/genericproposal.h>
#include <texteditor/codeassist/genericproposalmodel.h>
#include <texteditor/texteditor.h>
#include <texteditor/texteditorsettings.h>
#include <utils/mimeconstants.h>
@@ -44,6 +46,83 @@ namespace ClangCodeModel::Internal {
static Q_LOGGING_CATEGORY(clangdLogCompletion, "qtc.clangcodemodel.clangd.completion",
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 };
class CustomAssistProcessor : public IAssistProcessor
@@ -74,7 +153,7 @@ class ClangdCompletionItem : public LanguageClientCompletionItem
{
public:
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 };
static SpecialQtType getQtType(const CompletionItem &item);
@@ -246,9 +325,11 @@ bool ClangdCompletionAssistProvider::isInCommentOrString(const AssistInterface *
return CppEditor::isInCommentOrString(interface, features);
}
void ClangdCompletionItem::apply(TextDocumentManipulator &manipulator,
void ClangdCompletionItem::apply(TextEditorWidget *editorWidget,
int /*basePosition*/) const
{
QTC_ASSERT(editorWidget, return);
const CompletionItem item = this->item();
QChar typedChar = triggeredCommitCharacter();
const auto edit = item.textEdit();
@@ -287,8 +368,8 @@ void ClangdCompletionItem::apply(TextDocumentManipulator &manipulator,
int extraLength = 0;
int cursorOffset = 0;
bool setAutoCompleteSkipPos = false;
int currentPos = manipulator.currentPosition();
const QTextDocument * const doc = manipulator.document();
int currentPos = editorWidget->position();
const QTextDocument * const doc = editorWidget->document();
const Range range = edit->range();
const int rangeStart = range.start().toPositionInDocument(doc);
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
// inserted closing parenthesis.
const bool skipClosingParenthesis = typedChar != '(';
QTextCursor cursor = manipulator.textCursorAt(rangeStart);
QTextCursor cursor = editorWidget->textCursorAt(rangeStart);
bool abandonParen = false;
if (matchPreviousWord(manipulator, cursor, "&")) {
moveToPreviousWord(manipulator, cursor);
moveToPreviousChar(manipulator, cursor);
const QChar prevChar = manipulator.characterAt(cursor.position());
if (matchPreviousWord(editorWidget, cursor, "&")) {
moveToPreviousWord(editorWidget, cursor);
moveToPreviousChar(editorWidget, cursor);
const QChar prevChar = editorWidget->characterAt(cursor.position());
cursor.setPosition(rangeStart);
abandonParen = QString("(;,{}=").contains(prevChar);
}
if (!abandonParen)
abandonParen = isAtUsingDeclaration(manipulator, rangeStart);
if (!abandonParen && !isMacroCall && matchPreviousWord(manipulator, cursor, detail))
abandonParen = isAtUsingDeclaration(editorWidget, rangeStart);
if (!abandonParen && !isMacroCall && matchPreviousWord(editorWidget, cursor, detail))
abandonParen = true; // function definition
if (!abandonParen) {
if (completionSettings.m_spaceAfterFunctionName)
@@ -319,7 +400,7 @@ void ClangdCompletionItem::apply(TextDocumentManipulator &manipulator,
// 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(currentPos);
const QChar characterAtCursor = editorWidget->characterAt(currentPos);
bool endWithSemicolon = typedChar == ';';
const QChar semicolon = typedChar.isNull() ? QLatin1Char(';') : typedChar;
if (endWithSemicolon && characterAtCursor == semicolon) {
@@ -335,7 +416,7 @@ void ClangdCompletionItem::apply(TextDocumentManipulator &manipulator,
typedChar = {};
}
} else {
const QChar lookAhead = manipulator.characterAt(currentPos + 1);
const QChar lookAhead = editorWidget->characterAt(currentPos + 1);
if (MatchingText::shouldInsertMatchingText(lookAhead)) {
extraCharacters += ')';
--cursorOffset;
@@ -360,13 +441,13 @@ void ClangdCompletionItem::apply(TextDocumentManipulator &manipulator,
// Avoid inserting characters that are already there
// For include file completions, also consider a possibly pre-existing
// closing quote or angle bracket.
QTextCursor cursor = manipulator.textCursorAt(rangeStart);
QTextCursor cursor = editorWidget->textCursorAt(rangeStart);
cursor.movePosition(QTextCursor::EndOfWord);
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);
}
const QString textAfterCursor = manipulator.textAt(currentPos, cursor.position() - currentPos);
const QString textAfterCursor = editorWidget->textAt(currentPos, cursor.position() - currentPos);
if (currentPos < cursor.position()
&& textToBeInserted != textAfterCursor
&& textToBeInserted.indexOf(textAfterCursor, currentPos - rangeStart) >= 0) {
@@ -374,7 +455,7 @@ void ClangdCompletionItem::apply(TextDocumentManipulator &manipulator,
}
for (int i = 0; i < extraCharacters.length(); ++i) {
const QChar a = extraCharacters.at(i);
const QChar b = manipulator.characterAt(currentPos + i);
const QChar b = editorWidget->characterAt(currentPos + i);
if (a == b)
++extraLength;
else
@@ -383,19 +464,19 @@ void ClangdCompletionItem::apply(TextDocumentManipulator &manipulator,
textToBeInserted += extraCharacters;
const int length = currentPos - rangeStart + extraLength;
const int oldRevision = manipulator.document()->revision();
manipulator.replace(rangeStart, length, textToBeInserted);
manipulator.setCursorPosition(rangeStart + textToBeInserted.length());
if (manipulator.document()->revision() != oldRevision) {
const int oldRevision = editorWidget->document()->revision();
editorWidget->replace(rangeStart, length, textToBeInserted);
editorWidget->setCursorPosition(rangeStart + textToBeInserted.length());
if (editorWidget->document()->revision() != oldRevision) {
if (cursorOffset)
manipulator.setCursorPosition(manipulator.currentPosition() + cursorOffset);
editorWidget->setCursorPosition(editorWidget->position() + cursorOffset);
if (setAutoCompleteSkipPos)
manipulator.addAutoCompleteSkipPosition();
editorWidget->setAutoCompleteSkipPosition(editorWidget->textCursor());
}
if (auto additionalEdits = item.additionalTextEdits()) {
for (const auto &edit : *additionalEdits)
applyTextEdit(manipulator, edit);
applyTextEdit(editorWidget, edit);
}
}

View File

@@ -28,10 +28,11 @@ bool ClangPreprocessorAssistProposalItem::implicitlyApplies() const
return true;
}
void ClangPreprocessorAssistProposalItem::apply(TextEditor::TextDocumentManipulator &manipulator,
void ClangPreprocessorAssistProposalItem::apply(TextEditor::TextEditorWidget *editorWidget,
int basePosition) const
{
// TODO move in an extra class under tests
QTC_ASSERT(editorWidget, return);
QString textToBeInserted = text();
@@ -51,13 +52,13 @@ void ClangPreprocessorAssistProposalItem::apply(TextEditor::TextDocumentManipula
extraCharacters += m_typedCharacter;
// Avoid inserting characters that are already there
QTextCursor c = manipulator.textCursor();
QTextCursor c = editorWidget->textCursor();
c.movePosition(QTextCursor::EndOfBlock, QTextCursor::KeepAnchor);
const QString existingText = c.selectedText();
int existLength = 0;
if (!existingText.isEmpty()) {
// 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))) {
if (--existLength == 0)
break;
@@ -65,7 +66,7 @@ void ClangPreprocessorAssistProposalItem::apply(TextEditor::TextDocumentManipula
}
for (int i = 0; i < extraCharacters.length(); ++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)
++extraLength;
else
@@ -75,9 +76,9 @@ void ClangPreprocessorAssistProposalItem::apply(TextEditor::TextDocumentManipula
textToBeInserted += extraCharacters;
// 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)

View File

@@ -17,7 +17,7 @@ public:
~ClangPreprocessorAssistProposalItem() noexcept override = default;
bool prematurelyApplies(const QChar &typedChar) 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);
QString text() const final;

View File

@@ -20,7 +20,7 @@
#include <projectexplorer/kitaspects.h>
#include <projectexplorer/projectexplorerconstants.h>
#include <projectexplorer/target.h>
#include <texteditor/codeassist/textdocumentmanipulator.h>
#include <texteditor/texteditor.h>
#include <cplusplus/SimpleLexer.h>
#include <utils/algorithm.h>
@@ -302,41 +302,6 @@ const QStringList globalClangOptions()
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,
const ClangDiagnosticConfig &warningsConfig,
const FilePath &clangIncludeDir,

View File

@@ -22,8 +22,6 @@ class ClangDiagnosticConfig;
class CppEditorDocumentHandle;
}
namespace TextEditor { class TextDocumentManipulator; }
namespace ProjectExplorer { class Project; }
namespace ClangCodeModel {
@@ -81,56 +79,6 @@ private:
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
{
public:

View File

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

View File

@@ -64,7 +64,7 @@ class CppAssistProposalItem final : public AssistProposalItem
public:
~CppAssistProposalItem() noexcept override = default;
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; }
void markAsOverloaded() { m_isOverloaded = true; }
@@ -143,9 +143,9 @@ bool CppAssistProposalItem::prematurelyApplies(const QChar &typedChar) const
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);
BackwardsScanner scanner(cursor, LanguageFeatures());
@@ -173,8 +173,10 @@ quint64 CppAssistProposalItem::hash() const
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;
if (data().isValid())
@@ -224,7 +226,7 @@ void CppAssistProposalItem::applyContextualContent(TextDocumentManipulator &mani
if (function->argumentCount() == 0)
extraChars += QLatin1Char('<');
#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,
// in which case it would be annoying if we put the cursor after the already automatically
// inserted closing parenthesis.
@@ -238,7 +240,7 @@ void CppAssistProposalItem::applyContextualContent(TextDocumentManipulator &mani
// 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 = editorWidget->characterAt(editorWidget->position());
bool endWithSemicolon = m_typedChar == QLatin1Char(';')
|| (function->returnType()->asVoidType() && m_completionOperator != T_COLON_COLON);
const QChar semicolon = m_typedChar.isNull() ? QLatin1Char(';') : m_typedChar;
@@ -256,7 +258,7 @@ void CppAssistProposalItem::applyContextualContent(TextDocumentManipulator &mani
m_typedChar = QChar();
}
} else if (autoParenthesesEnabled) {
const QChar lookAhead = manipulator.characterAt(manipulator.currentPosition() + 1);
const QChar lookAhead = editorWidget->characterAt(editorWidget->position() + 1);
if (MatchingText::shouldInsertMatchingText(lookAhead)) {
extraChars += QLatin1Char(')');
--cursorOffset;
@@ -294,10 +296,10 @@ void CppAssistProposalItem::applyContextualContent(TextDocumentManipulator &mani
}
// Avoid inserting characters that are already there
int currentPosition = manipulator.currentPosition();
QTextCursor cursor = manipulator.textCursorAt(basePosition);
int currentPosition = editorWidget->position();
QTextCursor cursor = editorWidget->textCursorAt(basePosition);
cursor.movePosition(QTextCursor::EndOfWord);
const QString textAfterCursor = manipulator.textAt(currentPosition,
const QString textAfterCursor = editorWidget->textAt(currentPosition,
cursor.position() - currentPosition);
if (toInsert != textAfterCursor
&& toInsert.indexOf(textAfterCursor, currentPosition - basePosition) >= 0) {
@@ -306,7 +308,7 @@ void CppAssistProposalItem::applyContextualContent(TextDocumentManipulator &mani
for (int i = 0; i < extraChars.length(); ++i) {
const QChar a = extraChars.at(i);
const QChar b = manipulator.characterAt(currentPosition + i);
const QChar b = editorWidget->characterAt(currentPosition + i);
if (a == b)
++extraLength;
else
@@ -317,12 +319,12 @@ void CppAssistProposalItem::applyContextualContent(TextDocumentManipulator &mani
// Insert the remainder of the name
const int length = currentPosition - basePosition + extraLength;
manipulator.replace(basePosition, length, toInsert);
manipulator.setCursorPosition(basePosition + toInsert.length());
editorWidget->replace(basePosition, length, toInsert);
editorWidget->setCursorPosition(basePosition + toInsert.length());
if (cursorOffset)
manipulator.setCursorPosition(manipulator.currentPosition() + cursorOffset);
editorWidget->setCursorPosition(editorWidget->position() + cursorOffset);
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())
return;

View File

@@ -16,7 +16,7 @@ public:
VirtualFunctionProposalItem(const Utils::Link &link,
bool openInSplit = true);
~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
private:

View File

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

View File

@@ -15,6 +15,7 @@
#include <texteditor/snippets/snippet.h>
#include <texteditor/snippets/snippetassistcollector.h>
#include <texteditor/textdocument.h>
#include <texteditor/texteditor.h>
#include <texteditor/texteditorsettings.h>
#include <utils/algorithm.h>
#include <utils/textutils.h>
@@ -53,23 +54,24 @@ bool LanguageClientCompletionItem::prematurelyApplies(const QChar &typedCharacte
return false;
}
void LanguageClientCompletionItem::apply(TextDocumentManipulator &manipulator,
void LanguageClientCompletionItem::apply(TextEditorWidget *editorWidget,
int /*basePosition*/) const
{
QTC_ASSERT(editorWidget, return);
if (auto edit = m_item.textEdit()) {
applyTextEdit(manipulator, *edit, isSnippet());
applyTextEdit(editorWidget, *edit, isSnippet());
} else {
const int pos = manipulator.currentPosition();
const int pos = editorWidget->position();
const QString textToInsert(m_item.insertText().value_or(text()));
int length = 0;
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;
break;
}
++length;
}
QTextCursor cursor = manipulator.textCursorAt(pos);
QTextCursor cursor = editorWidget->textCursorAt(pos);
cursor.movePosition(QTextCursor::StartOfLine, QTextCursor::KeepAnchor);
const QString blockTextUntilPosition = cursor.selectedText();
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;
length = qMax(length, matchLength);
if (isSnippet()) {
manipulator.replace(pos - length, length, {});
manipulator.insertCodeSnippet(pos - length, textToInsert, &parseSnippet);
editorWidget->replace(pos - length, length, {});
editorWidget->insertCodeSnippet(pos - length, textToInsert, &parseSnippet);
} else {
manipulator.replace(pos - length, length, textToInsert);
editorWidget->replace(pos - length, length, textToInsert);
}
}
if (auto additionalEdits = m_item.additionalTextEdits()) {
for (const auto &edit : *additionalEdits)
applyTextEdit(manipulator, edit);
applyTextEdit(editorWidget, edit);
}
if (!m_triggeredCommitCharacter.isNull())
manipulator.insertCodeSnippet(manipulator.currentPosition(),
editorWidget->insertCodeSnippet(editorWidget->position(),
m_triggeredCommitCharacter,
&Snippet::parse);
}

View File

@@ -97,7 +97,7 @@ public:
QString filterText() const override;
bool implicitlyApplies() 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;
QString detail() const override;
bool isSnippet() const override;

View File

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

View File

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

View File

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

View File

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

View File

@@ -37,8 +37,9 @@ public:
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
if (CircularClipboard * clipboard = CircularClipboard::instance()) {
@@ -51,7 +52,7 @@ public:
TextEditorWidget::duplicateMimeData(m_mimeData.get()));
//Paste
manipulator.editor()->paste();
editorWidget->paste();
}
private:

View File

@@ -105,33 +105,35 @@ bool AssistProposalItem::prematurelyApplies(const QChar &c) const
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>()) {
applySnippet(manipulator, basePosition);
applySnippet(editorWidget, basePosition);
} else if (data().canConvert<QuickFixOperation::Ptr>()) {
applyQuickFix(manipulator, basePosition);
applyQuickFix(editorWidget, basePosition);
} else {
applyContextualContent(manipulator, basePosition);
manipulator.editor()->encourageApply();
applyContextualContent(editorWidget, basePosition);
editorWidget->encourageApply();
}
}
void AssistProposalItem::applyContextualContent(TextDocumentManipulator &manipulator, int basePosition) const
void AssistProposalItem::applyContextualContent(TextEditorWidget *editorWidget, int basePosition) const
{
const int currentPosition = manipulator.currentPosition();
manipulator.replace(basePosition, currentPosition - basePosition, text());
QTC_ASSERT(editorWidget, return);
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)
QuickFixOperation::Ptr op = data().value<QuickFixOperation::Ptr>();

View File

@@ -20,7 +20,7 @@ public:
QString text() const override;
bool implicitlyApplies() 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);
QIcon icon() const final;
@@ -37,9 +37,9 @@ public:
bool isValid() const final;
quint64 hash() const override;
virtual void applyContextualContent(TextDocumentManipulator &manipulator, int basePosition) const;
virtual void applySnippet(TextDocumentManipulator &manipulator, int basePosition) const;
virtual void applyQuickFix(TextDocumentManipulator &manipulator, int basePosition) const;
virtual void applyContextualContent(TextEditorWidget *editorWidget, int basePosition) const;
virtual void applySnippet(TextEditorWidget *editorWidget, int basePosition) const;
virtual void applyQuickFix(TextEditorWidget *editorWidget, int basePosition) const;
private:
QIcon m_icon;

View File

@@ -3,7 +3,7 @@
#pragma once
#include "textdocumentmanipulator.h"
#include <texteditor/texteditor_global.h>
QT_BEGIN_NAMESPACE
class QIcon;
@@ -14,6 +14,8 @@ QT_END_NAMESPACE
namespace TextEditor {
class TextEditorWidget;
class TEXTEDITOR_EXPORT AssistProposalItemInterface
{
public:
@@ -36,7 +38,7 @@ public:
virtual QString filterText() const { return text(); }
virtual bool implicitlyApplies() 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 QString detail() const = 0;
virtual bool isKeyword() const { return false; }

View File

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

View File

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

View File

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

View File

@@ -40,7 +40,7 @@ public:
KeywordsAssistProposalItem(bool isFunction);
bool prematurelyApplies(const QChar &c) const final;
void applyContextualContent(TextDocumentManipulator &manipulator, int basePosition) const final;
void applyContextualContent(TextEditorWidget *editorWidget, int basePosition) const final;
private:
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 <texteditor/texteditorconstants.h>
#include <texteditor/texteditor.h>
#include <texteditor/codeassist/assistproposalitem.h>
using namespace TextEditor;
@@ -24,9 +25,10 @@ public:
}
bool implicitlyApplies() 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; }
QString detail() const override { return m_snippet.generateTip(); }

View File

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