Editor: Simplify TextDocumentManipulator

The TextDocumentManipulatorInterface was introduced to decouple
modification operations from QTextDocument. But nowadays all tests and
production code usages are backed by a QTextDocument, so we can remove
this abstraction layer again. The first step is to merge the interface
and all manipulator implementations.

Change-Id: Idd1609df549d3b120dd516d5161af9aa8aa571ca
Reviewed-by: Christian Kandeler <christian.kandeler@qt.io>
This commit is contained in:
David Schulz
2024-06-26 12:38:17 +02:00
parent ef3a4fd9e3
commit 39a448c62e
32 changed files with 113 additions and 193 deletions

View File

@@ -54,7 +54,7 @@
#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/textdocumentmanipulatorinterface.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

@@ -74,8 +74,7 @@ class ClangdCompletionItem : public LanguageClientCompletionItem
{ {
public: public:
using LanguageClientCompletionItem::LanguageClientCompletionItem; using LanguageClientCompletionItem::LanguageClientCompletionItem;
void apply(TextDocumentManipulatorInterface &manipulator, void apply(TextDocumentManipulator &manipulator, int basePosition) const override;
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);
@@ -247,7 +246,7 @@ bool ClangdCompletionAssistProvider::isInCommentOrString(const AssistInterface *
return CppEditor::isInCommentOrString(interface, features); return CppEditor::isInCommentOrString(interface, features);
} }
void ClangdCompletionItem::apply(TextDocumentManipulatorInterface &manipulator, void ClangdCompletionItem::apply(TextDocumentManipulator &manipulator,
int /*basePosition*/) const int /*basePosition*/) const
{ {
const CompletionItem item = this->item(); const CompletionItem item = this->item();

View File

@@ -28,7 +28,7 @@ bool ClangPreprocessorAssistProposalItem::implicitlyApplies() const
return true; return true;
} }
void ClangPreprocessorAssistProposalItem::apply(TextEditor::TextDocumentManipulatorInterface &manipulator, void ClangPreprocessorAssistProposalItem::apply(TextEditor::TextDocumentManipulator &manipulator,
int basePosition) const int basePosition) const
{ {
// TODO move in an extra class under tests // TODO move in an extra class under tests

View File

@@ -17,8 +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::TextDocumentManipulatorInterface &manipulator, void apply(TextEditor::TextDocumentManipulator &manipulator, int basePosition) const final;
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/textdocumentmanipulatorinterface.h> #include <texteditor/codeassist/textdocumentmanipulator.h>
#include <cplusplus/SimpleLexer.h> #include <cplusplus/SimpleLexer.h>
#include <utils/algorithm.h> #include <utils/algorithm.h>
@@ -303,8 +303,7 @@ const QStringList globalClangOptions()
} }
// 7.3.3: using typename(opt) nested-name-specifier unqualified-id ; // 7.3.3: using typename(opt) nested-name-specifier unqualified-id ;
bool isAtUsingDeclaration(TextEditor::TextDocumentManipulatorInterface &manipulator, bool isAtUsingDeclaration(TextEditor::TextDocumentManipulator &manipulator, int basePosition)
int basePosition)
{ {
using namespace CPlusPlus; using namespace CPlusPlus;
SimpleLexer lexer; SimpleLexer lexer;
@@ -322,7 +321,7 @@ bool isAtUsingDeclaration(TextEditor::TextDocumentManipulatorInterface &manipula
return contains(tokens, [](const Token &token) { return token.kind() == T_USING; }); return contains(tokens, [](const Token &token) { return token.kind() == T_USING; });
} }
QString textUntilPreviousStatement(TextEditor::TextDocumentManipulatorInterface &manipulator, QString textUntilPreviousStatement(TextEditor::TextDocumentManipulator &manipulator,
int startPosition) int startPosition)
{ {
static const QString stopCharacters(";{}#"); static const QString stopCharacters(";{}#");

View File

@@ -22,7 +22,7 @@ class ClangDiagnosticConfig;
class CppEditorDocumentHandle; class CppEditorDocumentHandle;
} }
namespace TextEditor { class TextDocumentManipulatorInterface; } namespace TextEditor { class TextDocumentManipulator; }
namespace ProjectExplorer { class Project; } namespace ProjectExplorer { class Project; }
@@ -126,11 +126,10 @@ bool matchPreviousWord(const CharacterProvider &provider, QTextCursor cursor, QS
return pattern.isEmpty(); return pattern.isEmpty();
} }
QString textUntilPreviousStatement(TextEditor::TextDocumentManipulatorInterface &manipulator, QString textUntilPreviousStatement(
int startPosition); TextEditor::TextDocumentManipulator &manipulator, int startPosition);
bool isAtUsingDeclaration(TextEditor::TextDocumentManipulatorInterface &manipulator, bool isAtUsingDeclaration(TextEditor::TextDocumentManipulator &manipulator, int basePosition);
int basePosition);
class ClangSourceRange class ClangSourceRange
{ {

View File

@@ -30,7 +30,7 @@
#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/textdocumentmanipulatorinterface.h> #include <texteditor/codeassist/textdocumentmanipulator.h>
#include <texteditor/semantichighlighter.h> #include <texteditor/semantichighlighter.h>
#include <texteditor/textmark.h> #include <texteditor/textmark.h>
@@ -1530,76 +1530,6 @@ void ClangdTestHighlighting::testIfdefedOutBlocks()
} }
class Manipulator final : public TextDocumentManipulatorInterface
{
public:
Manipulator()
{
const auto textEditor = static_cast<BaseTextEditor *>(EditorManager::currentEditor());
QVERIFY(textEditor);
m_doc = textEditor->textDocument()->document();
m_cursor = textEditor->editorWidget()->textCursor();
}
int currentPosition() const override { return m_cursor.position(); }
int positionAt(TextPositionOperation) const override { return 0; }
QChar characterAt(int position) const override { return m_doc->characterAt(position); }
QString textAt(int position, int length) const override
{
return m_doc->toPlainText().mid(position, length);
}
QTextCursor textCursorAt(int position) const override
{
QTextCursor cursor(m_doc);
cursor.setPosition(position);
return cursor;
}
void setCursorPosition(int position) override { m_cursor.setPosition(position); }
void setAutoCompleteSkipPosition(int position) override { m_skipPos = position; }
bool replace(int position, int length, const QString &text) override
{
QTextCursor cursor = textCursorAt(position);
cursor.setPosition(position + length, QTextCursor::KeepAnchor);
cursor.insertText(text);
return true;
}
void insertCodeSnippet(int pos, const QString &text, const SnippetParser &parser) override
{
const auto parseResult = parser(text);
if (const auto snippet = std::get_if<ParsedSnippet>(&parseResult)) {
if (!snippet->parts.isEmpty())
textCursorAt(pos).insertText(snippet->parts.first().text);
}
}
void paste() override {}
void encourageApply() override {}
void autoIndent(int, int) override {}
QString getLine(int line) const { return m_doc->findBlockByNumber(line - 1).text(); }
QPair<int, int> cursorPos() const
{
const int pos = currentPosition();
QPair<int, int> lineAndColumn;
Text::convertPosition(m_doc, pos, &lineAndColumn.first, &lineAndColumn.second);
return lineAndColumn;
}
int skipPos() const { return m_skipPos; }
private:
QTextDocument *m_doc;
QTextCursor m_cursor;
int m_skipPos = -1;
};
class ClangdTestCompletion final : public ClangdTest class ClangdTestCompletion final : public ClangdTest
{ {
Q_OBJECT Q_OBJECT
@@ -1723,10 +1653,10 @@ void ClangdTestCompletion::testCompleteGlobals()
const AssistProposalItemInterface * const item = getItem(proposal, " globalFunction()", "void"); const AssistProposalItemInterface * const item = getItem(proposal, " globalFunction()", "void");
QVERIFY(item); QVERIFY(item);
Manipulator manipulator; TextDocumentManipulator manipulator(TextEditorWidget::currentTextEditorWidget());
item->apply(manipulator, cursorPos); item->apply(manipulator, cursorPos);
QCOMPARE(manipulator.getLine(7), " globalFunction() /* COMPLETE HERE */"); QCOMPARE(manipulator.getLine(7), " globalFunction() /* COMPLETE HERE */");
QCOMPARE(manipulator.cursorPos(), qMakePair(7, 19)); QCOMPARE(manipulator.cursorPos(), Text::Position(7, 19));
QCOMPARE(manipulator.skipPos(), -1); QCOMPARE(manipulator.skipPos(), -1);
} }
@@ -1743,10 +1673,10 @@ void ClangdTestCompletion::testCompleteMembers()
const AssistProposalItemInterface * const item = getItem(proposal, " member", "int"); const AssistProposalItemInterface * const item = getItem(proposal, " member", "int");
QVERIFY(item); QVERIFY(item);
Manipulator manipulator; TextDocumentManipulator manipulator(TextEditorWidget::currentTextEditorWidget());
item->apply(manipulator, cursorPos); item->apply(manipulator, cursorPos);
QCOMPARE(manipulator.getLine(7), " s.member /* COMPLETE HERE */"); QCOMPARE(manipulator.getLine(7), " s.member /* COMPLETE HERE */");
QCOMPARE(manipulator.cursorPos(), qMakePair(7, 12)); QCOMPARE(manipulator.cursorPos(), Text::Position(7, 12));
QCOMPARE(manipulator.skipPos(), -1); QCOMPARE(manipulator.skipPos(), -1);
} }
@@ -1761,10 +1691,10 @@ void ClangdTestCompletion::testCompleteMembersFromInside()
const AssistProposalItemInterface * const item = getItem(proposal, " privateFunc()", "void"); const AssistProposalItemInterface * const item = getItem(proposal, " privateFunc()", "void");
QVERIFY(item); QVERIFY(item);
Manipulator manipulator; TextDocumentManipulator manipulator(TextEditorWidget::currentTextEditorWidget());
item->apply(manipulator, cursorPos); item->apply(manipulator, cursorPos);
QCOMPARE(manipulator.getLine(4), " privateFunc() /* COMPLETE HERE */"); QCOMPARE(manipulator.getLine(4), " privateFunc() /* COMPLETE HERE */");
QCOMPARE(manipulator.cursorPos(), qMakePair(4, 21)); QCOMPARE(manipulator.cursorPos(), Text::Position(4, 21));
QCOMPARE(manipulator.skipPos(), -1); QCOMPARE(manipulator.skipPos(), -1);
} }
@@ -1779,10 +1709,10 @@ void ClangdTestCompletion::testCompleteMembersFromOutside()
const AssistProposalItemInterface * const item = getItem(proposal, " publicFunc()", "void"); const AssistProposalItemInterface * const item = getItem(proposal, " publicFunc()", "void");
QVERIFY(item); QVERIFY(item);
Manipulator manipulator; TextDocumentManipulator manipulator(TextEditorWidget::currentTextEditorWidget());
item->apply(manipulator, cursorPos); item->apply(manipulator, cursorPos);
QCOMPARE(manipulator.getLine(13), " c.publicFunc() /* COMPLETE HERE */"); QCOMPARE(manipulator.getLine(13), " c.publicFunc() /* COMPLETE HERE */");
QCOMPARE(manipulator.cursorPos(), qMakePair(13, 18)); QCOMPARE(manipulator.cursorPos(), Text::Position(13, 18));
QCOMPARE(manipulator.skipPos(), -1); QCOMPARE(manipulator.skipPos(), -1);
} }
@@ -1797,10 +1727,10 @@ void ClangdTestCompletion::testCompleteMembersFromFriend()
const AssistProposalItemInterface * const item = getItem(proposal, " privateFunc()", "void"); const AssistProposalItemInterface * const item = getItem(proposal, " privateFunc()", "void");
QVERIFY(item); QVERIFY(item);
Manipulator manipulator; TextDocumentManipulator manipulator(TextEditorWidget::currentTextEditorWidget());
item->apply(manipulator, cursorPos); item->apply(manipulator, cursorPos);
QCOMPARE(manipulator.getLine(14), " C().privateFunc() /* COMPLETE HERE */"); QCOMPARE(manipulator.getLine(14), " C().privateFunc() /* COMPLETE HERE */");
QCOMPARE(manipulator.cursorPos(), qMakePair(14, 21)); QCOMPARE(manipulator.cursorPos(), Text::Position(14, 21));
QCOMPARE(manipulator.skipPos(), -1); QCOMPARE(manipulator.skipPos(), -1);
} }
@@ -1814,10 +1744,10 @@ void ClangdTestCompletion::testFunctionAddress()
const AssistProposalItemInterface * const item = getItem(proposal, " memberFunc()", "void"); const AssistProposalItemInterface * const item = getItem(proposal, " memberFunc()", "void");
QVERIFY(item); QVERIFY(item);
Manipulator manipulator; TextDocumentManipulator manipulator(TextEditorWidget::currentTextEditorWidget());
item->apply(manipulator, cursorPos); item->apply(manipulator, cursorPos);
QCOMPARE(manipulator.getLine(7), " const auto p = &S::memberFunc /* COMPLETE HERE */;"); QCOMPARE(manipulator.getLine(7), " const auto p = &S::memberFunc /* COMPLETE HERE */;");
QCOMPARE(manipulator.cursorPos(), qMakePair(7, 33)); QCOMPARE(manipulator.cursorPos(), Text::Position(7, 33));
QCOMPARE(manipulator.skipPos(), -1); QCOMPARE(manipulator.skipPos(), -1);
} }
@@ -1878,10 +1808,10 @@ 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);
Manipulator manipulator; TextDocumentManipulator manipulator(TextEditorWidget::currentTextEditorWidget());
item->apply(manipulator, cursorPos); item->apply(manipulator, cursorPos);
QCOMPARE(manipulator.getLine(7), " Foo( /* COMPLETE HERE */"); QCOMPARE(manipulator.getLine(7), " Foo( /* COMPLETE HERE */");
QCOMPARE(manipulator.cursorPos(), qMakePair(7, 8)); QCOMPARE(manipulator.cursorPos(), Text::Position(7, 8));
QCOMPARE(manipulator.skipPos(), -1); QCOMPARE(manipulator.skipPos(), -1);
} }
@@ -1905,10 +1835,10 @@ 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);
Manipulator manipulator; TextDocumentManipulator manipulator(TextEditorWidget::currentTextEditorWidget());
item->apply(manipulator, cursorPos); item->apply(manipulator, cursorPos);
QCOMPARE(manipulator.getLine(4), " bar->member /* COMPLETE HERE */"); QCOMPARE(manipulator.getLine(4), " bar->member /* COMPLETE HERE */");
QCOMPARE(manipulator.cursorPos(), qMakePair(4, 15)); QCOMPARE(manipulator.cursorPos(), Text::Position(4, 15));
QCOMPARE(manipulator.skipPos(), -1); QCOMPARE(manipulator.skipPos(), -1);
} }
@@ -1936,10 +1866,10 @@ 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);
Manipulator manipulator; TextDocumentManipulator manipulator(TextEditorWidget::currentTextEditorWidget());
item->apply(manipulator, cursorPos); item->apply(manipulator, cursorPos);
QCOMPARE(manipulator.getLine(34), " ui->setupUi( /* COMPLETE HERE */"); QCOMPARE(manipulator.getLine(34), " ui->setupUi( /* COMPLETE HERE */");
QCOMPARE(manipulator.cursorPos(), qMakePair(34, 16)); QCOMPARE(manipulator.cursorPos(), Text::Position(34, 16));
QCOMPARE(manipulator.skipPos(), -1); QCOMPARE(manipulator.skipPos(), -1);
} }

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(TextDocumentManipulatorInterface &manipulator, int basePosition) const override; void applyContextualContent(TextDocumentManipulator &manipulator, 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,7 +143,7 @@ bool CppAssistProposalItem::prematurelyApplies(const QChar &typedChar) const
return false; return false;
} }
static bool isDereferenced(TextDocumentManipulatorInterface &manipulator, int basePosition) static bool isDereferenced(TextDocumentManipulator &manipulator, int basePosition)
{ {
QTextCursor cursor = manipulator.textCursorAt(basePosition); QTextCursor cursor = manipulator.textCursorAt(basePosition);
cursor.setPosition(basePosition); cursor.setPosition(basePosition);
@@ -173,7 +173,7 @@ quint64 CppAssistProposalItem::hash() const
return 0; return 0;
} }
void CppAssistProposalItem::applyContextualContent(TextDocumentManipulatorInterface &manipulator, int basePosition) const void CppAssistProposalItem::applyContextualContent(TextDocumentManipulator &manipulator, int basePosition) const
{ {
Symbol *symbol = nullptr; Symbol *symbol = nullptr;

View File

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

View File

@@ -16,8 +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::TextDocumentManipulatorInterface &manipulator, void apply(TextEditor::TextDocumentManipulator &manipulator, int basePosition) const override;
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(TextDocumentManipulatorInterface &, int) const override void applyContextualContent(TextDocumentManipulator &, 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

@@ -53,7 +53,7 @@ bool LanguageClientCompletionItem::prematurelyApplies(const QChar &typedCharacte
return false; return false;
} }
void LanguageClientCompletionItem::apply(TextDocumentManipulatorInterface &manipulator, void LanguageClientCompletionItem::apply(TextDocumentManipulator &manipulator,
int /*basePosition*/) const int /*basePosition*/) const
{ {
if (auto edit = m_item.textEdit()) { if (auto edit = m_item.textEdit()) {

View File

@@ -18,7 +18,7 @@
namespace TextEditor { namespace TextEditor {
class IAssistProposal; class IAssistProposal;
class TextDocumentManipulatorInterface; class TextDocumentManipulator;
} }
namespace LanguageClient { namespace LanguageClient {
@@ -97,8 +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::TextDocumentManipulatorInterface &manipulator, void apply(TextEditor::TextDocumentManipulator &manipulator, int basePosition) const override;
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,7 @@
#include <coreplugin/messagemanager.h> #include <coreplugin/messagemanager.h>
#include <coreplugin/progressmanager/progressmanager.h> #include <coreplugin/progressmanager/progressmanager.h>
#include <texteditor/codeassist/textdocumentmanipulatorinterface.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,7 +100,7 @@ bool applyTextEdits(const Client *client,
return file->apply(editsToChangeSet(edits, file->document())); return file->apply(editsToChangeSet(edits, file->document()));
} }
void applyTextEdit(TextDocumentManipulatorInterface &manipulator, void applyTextEdit(TextDocumentManipulator &manipulator,
const TextEdit &edit, const TextEdit &edit,
bool newTextIsSnippet) bool newTextIsSnippet)
{ {

View File

@@ -15,7 +15,7 @@ namespace Core { class IEditor; }
namespace TextEditor { namespace TextEditor {
class TextDocument; class TextDocument;
class TextDocumentManipulatorInterface; class TextDocumentManipulator;
} // namespace TextEditor } // namespace TextEditor
namespace LanguageClient { namespace LanguageClient {
@@ -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::TextDocumentManipulatorInterface &manipulator, void LANGUAGECLIENT_EXPORT applyTextEdit(TextEditor::TextDocumentManipulator &manipulator,
const LanguageServerProtocol::TextEdit &edit, const LanguageServerProtocol::TextEdit &edit,
bool newTextIsSnippet = false); bool newTextIsSnippet = false);
void LANGUAGECLIENT_EXPORT void LANGUAGECLIENT_EXPORT

View File

@@ -355,7 +355,7 @@ bool QmlJSAssistProposalItem::prematurelyApplies(const QChar &c) const
|| (text().endsWith(QLatin1Char('.')) && c == QLatin1Char('.')); || (text().endsWith(QLatin1Char('.')) && c == QLatin1Char('.'));
} }
void QmlJSAssistProposalItem::applyContextualContent(TextEditor::TextDocumentManipulatorInterface &manipulator, void QmlJSAssistProposalItem::applyContextualContent(TextEditor::TextDocumentManipulator &manipulator,
int basePosition) const int basePosition) const
{ {
const int currentPosition = manipulator.currentPosition(); const int currentPosition = manipulator.currentPosition();

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::TextDocumentManipulatorInterface &manipulator, void applyContextualContent(TextEditor::TextDocumentManipulator &manipulator,
int basePosition) const final; int basePosition) const final;
}; };

View File

@@ -42,7 +42,6 @@ add_qtc_plugin(TextEditor
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 codeassist/textdocumentmanipulator.cpp codeassist/textdocumentmanipulator.h
codeassist/textdocumentmanipulatorinterface.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,7 +37,7 @@ public:
setText(text); setText(text);
} }
void apply(TextDocumentManipulatorInterface &manipulator, int /*basePosition*/) const final void apply(TextDocumentManipulator &manipulator, int /*basePosition*/) const final
{ {
//Move to last in circular clipboard //Move to last in circular clipboard

View File

@@ -105,7 +105,7 @@ bool AssistProposalItem::prematurelyApplies(const QChar &c) const
return false; return false;
} }
void AssistProposalItem::apply(TextDocumentManipulatorInterface &manipulator, int basePosition) const void AssistProposalItem::apply(TextDocumentManipulator &manipulator, int basePosition) const
{ {
if (data().canConvert<QString>()) { if (data().canConvert<QString>()) {
applySnippet(manipulator, basePosition); applySnippet(manipulator, basePosition);
@@ -117,19 +117,19 @@ void AssistProposalItem::apply(TextDocumentManipulatorInterface &manipulator, in
} }
} }
void AssistProposalItem::applyContextualContent(TextDocumentManipulatorInterface &manipulator, int basePosition) const void AssistProposalItem::applyContextualContent(TextDocumentManipulator &manipulator, int basePosition) const
{ {
const int currentPosition = manipulator.currentPosition(); const int currentPosition = manipulator.currentPosition();
manipulator.replace(basePosition, currentPosition - basePosition, text()); manipulator.replace(basePosition, currentPosition - basePosition, text());
} }
void AssistProposalItem::applySnippet(TextDocumentManipulatorInterface &manipulator, int basePosition) const void AssistProposalItem::applySnippet(TextDocumentManipulator &manipulator, int basePosition) const
{ {
manipulator.insertCodeSnippet(basePosition, data().toString(), &Snippet::parse); manipulator.insertCodeSnippet(basePosition, data().toString(), &Snippet::parse);
} }
void AssistProposalItem::applyQuickFix(TextDocumentManipulatorInterface &manipulator, int basePosition) const void AssistProposalItem::applyQuickFix(TextDocumentManipulator &manipulator, int basePosition) const
{ {
Q_UNUSED(manipulator) Q_UNUSED(manipulator)
Q_UNUSED(basePosition) Q_UNUSED(basePosition)

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(TextDocumentManipulatorInterface &manipulator, int basePosition) const override; void apply(TextDocumentManipulator &manipulator, 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(TextDocumentManipulatorInterface &manipulator, int basePosition) const; virtual void applyContextualContent(TextDocumentManipulator &manipulator, int basePosition) const;
virtual void applySnippet(TextDocumentManipulatorInterface &manipulator, int basePosition) const; virtual void applySnippet(TextDocumentManipulator &manipulator, int basePosition) const;
virtual void applyQuickFix(TextDocumentManipulatorInterface &manipulator, int basePosition) const; virtual void applyQuickFix(TextDocumentManipulator &manipulator, int basePosition) const;
private: private:
QIcon m_icon; QIcon m_icon;

View File

@@ -3,7 +3,7 @@
#pragma once #pragma once
#include "textdocumentmanipulatorinterface.h" #include "textdocumentmanipulator.h"
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
class QIcon; class QIcon;
@@ -36,7 +36,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(TextDocumentManipulatorInterface &manipulator, int basePosition) const = 0; virtual void apply(TextDocumentManipulator &manipulator, 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(TextDocumentManipulatorInterface &, int) const final void apply(TextDocumentManipulator &, 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

@@ -72,7 +72,7 @@ bool KeywordsAssistProposalItem::prematurelyApplies(const QChar &c) const
return c == QLatin1Char('(') && m_isFunction; return c == QLatin1Char('(') && m_isFunction;
} }
void KeywordsAssistProposalItem::applyContextualContent(TextDocumentManipulatorInterface &manipulator, void KeywordsAssistProposalItem::applyContextualContent(TextDocumentManipulator &manipulator,
int basePosition) const int basePosition) const
{ {
const CompletionSettings &settings = TextEditorSettings::completionSettings(); const CompletionSettings &settings = TextEditorSettings::completionSettings();

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(TextDocumentManipulatorInterface &manipulator, int basePosition) const final; void applyContextualContent(TextDocumentManipulator &manipulator, int basePosition) const final;
private: private:
bool m_isFunction; bool m_isFunction;
}; };

View File

@@ -112,6 +112,22 @@ void TextDocumentManipulator::autoIndent(int position, int length)
} }
} }
QString TextDocumentManipulator::getLine(int line) const
{
return m_textEditorWidget->document()->findBlockByNumber(line - 1).text();
}
Utils::Text::Position TextDocumentManipulator::cursorPos() const
{
return Utils::Text::Position::fromCursor(m_textEditorWidget->textCursor());
}
int TextDocumentManipulator::skipPos() const
{
const QList<QTextCursor> highlights = m_textEditorWidget->autoCompleteHighlightPositions();
return highlights.isEmpty() ? -1 : highlights.first().position();
}
bool TextDocumentManipulator::textIsDifferentAt(int position, int length, const QString &text) const bool TextDocumentManipulator::textIsDifferentAt(int position, int length, const QString &text) const
{ {
const auto textToBeReplaced = m_textEditorWidget->textAt(position, length); const auto textToBeReplaced = m_textEditorWidget->textAt(position, length);

View File

@@ -3,30 +3,45 @@
#pragma once #pragma once
#include "textdocumentmanipulatorinterface.h" #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 { namespace TextEditor {
class TextEditorWidget; class TextEditorWidget;
class TextDocumentManipulator final : public TextDocumentManipulatorInterface class TEXTEDITOR_EXPORT TextDocumentManipulator
{ {
public: public:
TextDocumentManipulator(TextEditorWidget *textEditorWidget); TextDocumentManipulator(TextEditorWidget *textEditorWidget);
int currentPosition() const final; int currentPosition() const;
int positionAt(TextPositionOperation textPositionOperation) const final; int positionAt(TextPositionOperation textPositionOperation) const;
QChar characterAt(int position) const final; QChar characterAt(int position) const;
QString textAt(int position, int length) const final; QString textAt(int position, int length) const;
QTextCursor textCursorAt(int position) const final; QTextCursor textCursorAt(int position) const;
void setCursorPosition(int position) final; void setCursorPosition(int position);
void setAutoCompleteSkipPosition(int position) final; void setAutoCompleteSkipPosition(int position);
bool replace(int position, int length, const QString &text) final; bool replace(int position, int length, const QString &text);
void insertCodeSnippet(int position, const QString &text, const SnippetParser &parse) final; void insertCodeSnippet(int position, const QString &text, const SnippetParser &parse);
void paste() final; void paste();
void encourageApply() final; void encourageApply();
void autoIndent(int position, int length) override; void autoIndent(int position, int length);
QString getLine(int line) const;
Utils::Text::Position cursorPos() const;
int skipPos() const;
private: private:
bool textIsDifferentAt(int position, int length, const QString &text) const; bool textIsDifferentAt(int position, int length, const QString &text) const;

View File

@@ -1,39 +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>
QT_BEGIN_NAMESPACE
class QChar;
class QString;
class QTextCursor;
QT_END_NAMESPACE
namespace TextEditor {
class TEXTEDITOR_EXPORT TextDocumentManipulatorInterface
{
public:
virtual ~TextDocumentManipulatorInterface() = default;
virtual int currentPosition() const = 0;
virtual int positionAt(TextPositionOperation textPositionOperation) const = 0;
virtual QChar characterAt(int position) const = 0;
virtual QString textAt(int position, int length) const = 0;
virtual QTextCursor textCursorAt(int position) const = 0;
virtual void setCursorPosition(int position) = 0;
virtual void setAutoCompleteSkipPosition(int position) = 0;
virtual bool replace(int position, int length, const QString &text) = 0;
virtual void insertCodeSnippet(int position,
const QString &text,
const SnippetParser &parse) = 0;
virtual void paste() = 0;
virtual void encourageApply() = 0;
virtual void autoIndent(int position, int length) = 0;
};
} // namespace TextEditor

View File

@@ -24,7 +24,7 @@ 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(TextDocumentManipulatorInterface &manipulator, int basePosition) const override void apply(TextDocumentManipulator &manipulator, int basePosition) const override
{ {
manipulator.insertCodeSnippet(basePosition, m_snippet.content(), &Snippet::parse); manipulator.insertCodeSnippet(basePosition, m_snippet.content(), &Snippet::parse);
} }

View File

@@ -7037,6 +7037,11 @@ TextEditorWidget::SuggestionBlocker TextEditorWidget::blockSuggestions()
return d->m_suggestionBlocker; return d->m_suggestionBlocker;
} }
QList<QTextCursor> TextEditorWidget::autoCompleteHighlightPositions() const
{
return d->m_autoCompleteHighlightPos;
}
#ifdef WITH_TESTS #ifdef WITH_TESTS
void TextEditorWidget::processTooltipRequest(const QTextCursor &c) void TextEditorWidget::processTooltipRequest(const QTextCursor &c)
{ {

View File

@@ -518,6 +518,8 @@ public:
// Returns an object that blocks suggestions until it is destroyed. // Returns an object that blocks suggestions until it is destroyed.
SuggestionBlocker blockSuggestions(); SuggestionBlocker blockSuggestions();
QList<QTextCursor> autoCompleteHighlightPositions() const;
#ifdef WITH_TESTS #ifdef WITH_TESTS
void processTooltipRequest(const QTextCursor &c); void processTooltipRequest(const QTextCursor &c);
#endif #endif

View File

@@ -199,7 +199,6 @@ QtcPlugin {
"keywordscompletionassist.h", "keywordscompletionassist.h",
"textdocumentmanipulator.cpp", "textdocumentmanipulator.cpp",
"textdocumentmanipulator.h", "textdocumentmanipulator.h",
"textdocumentmanipulatorinterface.h",
] ]
} }