forked from qt-creator/qt-creator
Editor: remove TextDocumentManipulator
Change-Id: Iacd7cd40ace77c79eecca3e4e699eb308d0c27de Reviewed-by: Christian Kandeler <christian.kandeler@qt.io>
This commit is contained in:
@@ -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>
|
||||
|
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -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)
|
||||
|
@@ -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;
|
||||
|
@@ -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,
|
||||
|
@@ -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:
|
||||
|
@@ -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()
|
||||
|
@@ -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());
|
||||
}
|
||||
|
||||
// --------------------
|
||||
|
@@ -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;
|
||||
|
@@ -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:
|
||||
|
@@ -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()));
|
||||
|
@@ -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);
|
||||
}
|
||||
|
@@ -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;
|
||||
|
@@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -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
|
||||
|
@@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -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;
|
||||
};
|
||||
|
||||
|
@@ -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
|
||||
|
@@ -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:
|
||||
|
@@ -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>();
|
||||
|
@@ -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;
|
||||
|
@@ -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; }
|
||||
|
@@ -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);
|
||||
|
@@ -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())
|
||||
|
@@ -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());
|
||||
}
|
||||
|
||||
// -------------------------
|
||||
|
@@ -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;
|
||||
};
|
||||
|
@@ -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
|
@@ -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
|
@@ -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(); }
|
||||
|
@@ -197,8 +197,6 @@ QtcPlugin {
|
||||
"ifunctionhintproposalmodel.h",
|
||||
"keywordscompletionassist.cpp",
|
||||
"keywordscompletionassist.h",
|
||||
"textdocumentmanipulator.cpp",
|
||||
"textdocumentmanipulator.h",
|
||||
]
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user