aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Schulz <[email protected]>2023-03-27 07:28:48 +0200
committerDavid Schulz <[email protected]>2023-03-29 07:43:19 +0000
commit8a1e34f084f24f45d61e0011a2b6486aadc34218 (patch)
tree0f5b0b5d52df71a23a75e453b0f1fbf804bae2c6
parent1ee46580ac8afda64e63b3dd816b4acbfad5dfaa (diff)
TextEditor: introduce text suggestion interface
And also a copilot suggestion implementing that interface that allows reverting all changes done to a suggestion as well as applying it. Change-Id: I236c1fc5e5844d19ac606672af54e273e9c42e1c Reviewed-by: Marcus Tillmanns <[email protected]>
-rw-r--r--src/libs/languageserverprotocol/lsptypes.cpp10
-rw-r--r--src/libs/languageserverprotocol/lsptypes.h2
-rw-r--r--src/libs/languageserverprotocol/lsputils.h7
-rw-r--r--src/plugins/copilot/copilotclient.cpp46
-rw-r--r--src/plugins/texteditor/textdocument.cpp15
-rw-r--r--src/plugins/texteditor/textdocument.h2
-rw-r--r--src/plugins/texteditor/textdocumentlayout.cpp90
-rw-r--r--src/plugins/texteditor/textdocumentlayout.h40
-rw-r--r--src/plugins/texteditor/texteditor.cpp110
-rw-r--r--src/plugins/texteditor/texteditor.h15
10 files changed, 190 insertions, 147 deletions
diff --git a/src/libs/languageserverprotocol/lsptypes.cpp b/src/libs/languageserverprotocol/lsptypes.cpp
index 4bf3f3746e2..bd7798dcef9 100644
--- a/src/libs/languageserverprotocol/lsptypes.cpp
+++ b/src/libs/languageserverprotocol/lsptypes.cpp
@@ -311,6 +311,16 @@ bool Range::overlaps(const Range &range) const
return !isLeftOf(range) && !range.isLeftOf(*this);
}
+QTextCursor Range::toSelection(QTextDocument *doc) const
+{
+ QTC_ASSERT(doc, return {});
+ if (!isValid())
+ return {};
+ QTextCursor cursor = start().toTextCursor(doc);
+ cursor.setPosition(end().toPositionInDocument(doc), QTextCursor::KeepAnchor);
+ return cursor;
+}
+
QString expressionForGlob(QString globPattern)
{
const QString anySubDir("qtc_anysubdir_id");
diff --git a/src/libs/languageserverprotocol/lsptypes.h b/src/libs/languageserverprotocol/lsptypes.h
index 4adc35aa105..3a9adb1b0d8 100644
--- a/src/libs/languageserverprotocol/lsptypes.h
+++ b/src/libs/languageserverprotocol/lsptypes.h
@@ -117,6 +117,8 @@ public:
bool isLeftOf(const Range &other) const
{ return isEmpty() || other.isEmpty() ? end() < other.start() : end() <= other.start(); }
+ QTextCursor toSelection(QTextDocument *doc) const;
+
bool isValid() const override
{ return JsonObject::contains(startKey) && JsonObject::contains(endKey); }
};
diff --git a/src/libs/languageserverprotocol/lsputils.h b/src/libs/languageserverprotocol/lsputils.h
index 5515b515767..0c815bafd8a 100644
--- a/src/libs/languageserverprotocol/lsputils.h
+++ b/src/libs/languageserverprotocol/lsputils.h
@@ -87,6 +87,13 @@ public:
return QJsonValue();
}
+ QList<T> toListOrEmpty() const
+ {
+ if (std::holds_alternative<QList<T>>(*this))
+ return std::get<QList<T>>(*this);
+ return {};
+ }
+
QList<T> toList() const
{
QTC_ASSERT(std::holds_alternative<QList<T>>(*this), return {});
diff --git a/src/plugins/copilot/copilotclient.cpp b/src/plugins/copilot/copilotclient.cpp
index d245e68eaa3..27bcbacf476 100644
--- a/src/plugins/copilot/copilotclient.cpp
+++ b/src/plugins/copilot/copilotclient.cpp
@@ -11,6 +11,7 @@
#include <utils/filepath.h>
+#include <texteditor/textdocumentlayout.h>
#include <texteditor/texteditor.h>
#include <languageserverprotocol/lsptypes.h>
@@ -128,6 +129,39 @@ void CopilotClient::requestCompletions(TextEditorWidget *editor)
sendMessage(request);
}
+class CopilotSuggestion final : public TextEditor::TextSuggestion
+{
+public:
+ CopilotSuggestion(const Completion &completion, QTextDocument *origin)
+ : m_completion(completion)
+ {
+ document()->setPlainText(completion.text());
+ m_start = completion.position().toTextCursor(origin);
+ m_start.setKeepPositionOnInsert(true);
+ setCurrentPosition(m_start.position());
+ }
+
+ bool apply() final
+ {
+ reset();
+ QTextCursor cursor = m_completion.range().toSelection(m_start.document());
+ cursor.insertText(m_completion.text());
+ return true;
+ }
+ void reset() final
+ {
+ m_start.removeSelectedText();
+ }
+ int position() final
+ {
+ return m_start.position();
+ }
+
+private:
+ Completion m_completion;
+ QTextCursor m_start;
+};
+
void CopilotClient::handleCompletions(const GetCompletionRequest::Response &response,
TextEditorWidget *editor)
{
@@ -142,19 +176,15 @@ void CopilotClient::handleCompletions(const GetCompletionRequest::Response &resp
if (cursors.hasMultipleCursors())
return;
- const QTextCursor cursor = cursors.mainCursor();
if (cursors.hasSelection() || cursors.mainCursor().position() != requestPosition)
return;
if (const std::optional<GetCompletionResponse> result = response.result()) {
- LanguageClientArray<Completion> completions = result->completions();
- if (completions.isNull() || completions.toList().isEmpty())
+ QList<Completion> completions = result->completions().toListOrEmpty();
+ if (completions.isEmpty())
return;
-
- const Completion firstCompletion = completions.toList().first();
- const QString content = firstCompletion.text().mid(firstCompletion.position().character());
-
- editor->insertSuggestion(content);
+ editor->insertSuggestion(
+ std::make_unique<CopilotSuggestion>(completions.first(), editor->document()));
}
}
diff --git a/src/plugins/texteditor/textdocument.cpp b/src/plugins/texteditor/textdocument.cpp
index 966edd4e7d8..4a7e80f52ce 100644
--- a/src/plugins/texteditor/textdocument.cpp
+++ b/src/plugins/texteditor/textdocument.cpp
@@ -373,16 +373,13 @@ QAction *TextDocument::createDiffAgainstCurrentFileAction(
return diffAction;
}
-void TextDocument::insertSuggestion(const QString &text, const QTextCursor &cursor)
+void TextDocument::insertSuggestion(std::unique_ptr<TextSuggestion> &&suggestion)
{
+ QTextCursor cursor(&d->m_document);
+ cursor.setPosition(suggestion->position());
const QTextBlock block = cursor.block();
- const QString blockText = block.text();
- QString replacement = blockText.left(cursor.positionInBlock()) + text;
- if (!text.contains('\n'))
- replacement.append(blockText.mid(cursor.positionInBlock()));
- TextDocumentLayout::userData(block)->setReplacement(replacement);
- TextDocumentLayout::userData(block)->setReplacementPosition(cursor.positionInBlock());
- TextDocumentLayout::updateReplacementFormats(block, fontSettings());
+ TextDocumentLayout::userData(block)->insertSuggestion(std::move(suggestion));
+ TextDocumentLayout::updateSuggestionFormats(block, fontSettings());
updateLayout();
}
@@ -434,7 +431,7 @@ void TextDocument::applyFontSettings()
d->m_fontSettingsNeedsApply = false;
QTextBlock block = document()->firstBlock();
while (block.isValid()) {
- TextDocumentLayout::updateReplacementFormats(block, fontSettings());
+ TextDocumentLayout::updateSuggestionFormats(block, fontSettings());
block = block.next();
}
updateLayout();
diff --git a/src/plugins/texteditor/textdocument.h b/src/plugins/texteditor/textdocument.h
index 9ef556503fd..d1f686f6a0c 100644
--- a/src/plugins/texteditor/textdocument.h
+++ b/src/plugins/texteditor/textdocument.h
@@ -37,6 +37,7 @@ class SyntaxHighlighter;
class TabSettings;
class TextDocumentPrivate;
class TextMark;
+class TextSuggestion;
class TypingSettings;
using TextMarks = QList<TextMark *>;
@@ -145,6 +146,7 @@ public:
const std::function<Utils::FilePath()> &filePath);
void insertSuggestion(const QString &text, const QTextCursor &cursor);
+ void insertSuggestion(std::unique_ptr<TextSuggestion> &&suggestion);
#ifdef WITH_TESTS
void setSilentReload();
diff --git a/src/plugins/texteditor/textdocumentlayout.cpp b/src/plugins/texteditor/textdocumentlayout.cpp
index 9c257d3a257..a80a1b77515 100644
--- a/src/plugins/texteditor/textdocumentlayout.cpp
+++ b/src/plugins/texteditor/textdocumentlayout.cpp
@@ -345,22 +345,19 @@ void TextBlockUserData::setCodeFormatterData(CodeFormatterData *data)
m_codeFormatterData = data;
}
-void TextBlockUserData::setReplacement(const QString &replacement)
+void TextBlockUserData::insertSuggestion(std::unique_ptr<TextSuggestion> &&suggestion)
{
- m_replacement.reset(new QTextDocument(replacement));
- m_replacement->setDocumentLayout(new TextDocumentLayout(m_replacement.get()));
- m_replacement->setDocumentMargin(0);
+ m_suggestion = std::move(suggestion);
}
-void TextBlockUserData::setReplacementPosition(int replacementPosition)
+TextSuggestion *TextBlockUserData::suggestion() const
{
- m_replacementPosition = replacementPosition;
+ return m_suggestion.get();
}
-void TextBlockUserData::clearReplacement()
+void TextBlockUserData::clearSuggestion()
{
- m_replacement.reset();
- m_replacementPosition = -1;
+ m_suggestion.release();
}
void TextBlockUserData::addMark(TextMark *mark)
@@ -536,21 +533,29 @@ QByteArray TextDocumentLayout::expectedRawStringSuffix(const QTextBlock &block)
return {};
}
-void TextDocumentLayout::updateReplacementFormats(const QTextBlock &block,
+TextSuggestion *TextDocumentLayout::suggestion(const QTextBlock &block)
+{
+ if (TextBlockUserData *userData = textUserData(block))
+ return userData->suggestion();
+ return nullptr;
+}
+
+void TextDocumentLayout::updateSuggestionFormats(const QTextBlock &block,
const FontSettings &fontSettings)
{
- if (QTextDocument *replacement = replacementDocument(block)) {
+ if (TextSuggestion *suggestion = TextDocumentLayout::suggestion(block)) {
+ QTextDocument *suggestionDoc = suggestion->document();
const QTextCharFormat replacementFormat = fontSettings.toTextCharFormat(
TextStyles{C_TEXT, {C_DISABLED_CODE}});
QList<QTextLayout::FormatRange> formats = block.layout()->formats();
- QTextCursor cursor(replacement);
+ QTextCursor cursor(suggestionDoc);
cursor.select(QTextCursor::Document);
cursor.setCharFormat(fontSettings.toTextCharFormat(C_TEXT));
- const int position = replacementPosition(block);
+ const int position = suggestion->currentPosition() - block.position();
cursor.setPosition(position);
const QString trailingText = block.text().mid(position);
if (!trailingText.isEmpty()) {
- const int trailingIndex = replacement->firstBlock().text().indexOf(trailingText,
+ const int trailingIndex = suggestionDoc->firstBlock().text().indexOf(trailingText,
position);
if (trailingIndex >= 0) {
cursor.setPosition(trailingIndex, QTextCursor::KeepAnchor);
@@ -581,45 +586,22 @@ void TextDocumentLayout::updateReplacementFormats(const QTextBlock &block,
}
cursor.movePosition(QTextCursor::End, QTextCursor::KeepAnchor);
cursor.setCharFormat(replacementFormat);
- replacement->firstBlock().layout()->setFormats(formats);
- }
-}
-
-QString TextDocumentLayout::replacement(const QTextBlock &block)
-{
- if (QTextDocument *replacement = replacementDocument(block)) {
- QTextCursor cursor(replacement);
- const int position = replacementPosition(block);
- cursor.setPosition(position);
- cursor.movePosition(QTextCursor::End, QTextCursor::KeepAnchor);
- return cursor.selectedText();
+ suggestionDoc->firstBlock().layout()->setFormats(formats);
}
- return {};
-}
-
-QTextDocument *TextDocumentLayout::replacementDocument(const QTextBlock &block)
-{
- TextBlockUserData *userData = textUserData(block);
- return userData ? userData->replacement() : nullptr;
-}
-
-int TextDocumentLayout::replacementPosition(const QTextBlock &block)
-{
- TextBlockUserData *userData = textUserData(block);
- return userData ? userData->replacementPosition() : -1;
}
-bool TextDocumentLayout::updateReplacement(const QTextBlock &block,
- int position,
- const FontSettings &fontSettings)
+bool TextDocumentLayout::updateSuggestion(const QTextBlock &block,
+ int position,
+ const FontSettings &fontSettings)
{
- if (QTextDocument *replacementDocument = TextDocumentLayout::replacementDocument(block)) {
- const QString start = block.text().left(position);
- const QString end = block.text().mid(position);
- const QString replacement = replacementDocument->firstBlock().text();
- if (replacement.startsWith(start) && replacement.endsWith(end)) {
- userData(block)->setReplacementPosition(position);
- TextDocumentLayout::updateReplacementFormats(block, fontSettings);
+ if (TextSuggestion *suggestion = TextDocumentLayout::suggestion(block)) {
+ auto positionInBlock = position - block.position();
+ const QString start = block.text().left(positionInBlock);
+ const QString end = block.text().mid(positionInBlock);
+ const QString replacement = suggestion->document()->firstBlock().text();
+ if (replacement.startsWith(start) && replacement.indexOf(end, start.size()) >= 0) {
+ suggestion->setCurrentPosition(position);
+ TextDocumentLayout::updateSuggestionFormats(block, fontSettings);
return true;
}
}
@@ -756,11 +738,11 @@ static QRectF replacementBoundingRect(const QTextDocument *replacement)
QRectF TextDocumentLayout::blockBoundingRect(const QTextBlock &block) const
{
- if (QTextDocument *replacement = replacementDocument(block)) {
+ if (TextSuggestion *suggestion = TextDocumentLayout::suggestion(block)) {
// since multiple code paths expects that we have a valid block layout after requesting the
// block bounding rect explicitly create that layout here
ensureBlockLayout(block);
- return replacementBoundingRect(replacement);
+ return replacementBoundingRect(suggestion->document());
}
QRectF boundingRect = QPlainTextDocumentLayout::blockBoundingRect(block);
@@ -851,4 +833,10 @@ void insertSorted(Parentheses &list, const Parenthesis &elem)
list.insert(it, elem);
}
+TextSuggestion::TextSuggestion()
+{
+ m_replacementDocument.setDocumentLayout(new TextDocumentLayout(&m_replacementDocument));
+ m_replacementDocument.setDocumentMargin(0);
+}
+
} // namespace TextEditor
diff --git a/src/plugins/texteditor/textdocumentlayout.h b/src/plugins/texteditor/textdocumentlayout.h
index 97fa5992abb..e02615b1063 100644
--- a/src/plugins/texteditor/textdocumentlayout.h
+++ b/src/plugins/texteditor/textdocumentlayout.h
@@ -42,6 +42,24 @@ public:
virtual ~CodeFormatterData();
};
+class TEXTEDITOR_EXPORT TextSuggestion
+{
+public:
+ TextSuggestion();
+ virtual bool apply() = 0;
+ virtual void reset() = 0;
+ virtual int position() = 0;
+
+ int currentPosition() const { return m_currentPosition; }
+ void setCurrentPosition(int position) { m_currentPosition = position; }
+
+ QTextDocument *document() { return &m_replacementDocument; }
+
+private:
+ QTextDocument m_replacementDocument;
+ int m_currentPosition = -1;
+};
+
class TEXTEDITOR_EXPORT TextBlockUserData : public QTextBlockUserData
{
public:
@@ -126,11 +144,9 @@ public:
QByteArray expectedRawStringSuffix() { return m_expectedRawStringSuffix; }
void setExpectedRawStringSuffix(const QByteArray &suffix) { m_expectedRawStringSuffix = suffix; }
- void setReplacement(const QString &replacement);
- void setReplacementPosition(int replacementPosition);
- void clearReplacement();
- QTextDocument *replacement() const { return m_replacement.get(); }
- int replacementPosition() const { return m_replacementPosition; }
+ void insertSuggestion(std::unique_ptr<TextSuggestion> &&suggestion);
+ TextSuggestion *suggestion() const;
+ void clearSuggestion();
private:
TextMarks m_marks;
@@ -146,7 +162,7 @@ private:
KSyntaxHighlighting::State m_syntaxState;
QByteArray m_expectedRawStringSuffix; // A bit C++-specific, but let's be pragmatic.
std::unique_ptr<QTextDocument> m_replacement;
- int m_replacementPosition = -1;
+ std::unique_ptr<TextSuggestion> m_suggestion;
};
@@ -180,14 +196,12 @@ public:
static void setFolded(const QTextBlock &block, bool folded);
static void setExpectedRawStringSuffix(const QTextBlock &block, const QByteArray &suffix);
static QByteArray expectedRawStringSuffix(const QTextBlock &block);
- static void updateReplacementFormats(const QTextBlock &block,
+ static TextSuggestion *suggestion(const QTextBlock &block);
+ static void updateSuggestionFormats(const QTextBlock &block,
const FontSettings &fontSettings);
- static QString replacement(const QTextBlock &block);
- static QTextDocument *replacementDocument(const QTextBlock &block);
- static int replacementPosition(const QTextBlock &block);
- static bool updateReplacement(const QTextBlock &block,
- int position,
- const FontSettings &fontSettings);
+ static bool updateSuggestion(const QTextBlock &block,
+ int position,
+ const FontSettings &fontSettings);
class TEXTEDITOR_EXPORT FoldValidator
{
diff --git a/src/plugins/texteditor/texteditor.cpp b/src/plugins/texteditor/texteditor.cpp
index ccbdb0467d0..c5783acb919 100644
--- a/src/plugins/texteditor/texteditor.cpp
+++ b/src/plugins/texteditor/texteditor.cpp
@@ -820,7 +820,7 @@ public:
QList<int> m_visualIndentCache;
int m_visualIndentOffset = 0;
- void insertSuggestion(const QString &suggestion);
+ void insertSuggestion(std::unique_ptr<TextSuggestion> &&suggestion);
void updateSuggestion();
void clearCurrentSuggestion();
QTextBlock m_suggestionBlock;
@@ -1651,12 +1651,13 @@ void TextEditorWidgetPrivate::handleMoveBlockSelection(QTextCursor::MoveOperatio
q->setMultiTextCursor(MultiTextCursor(cursors));
}
-void TextEditorWidgetPrivate::insertSuggestion(const QString &suggestion)
+void TextEditorWidgetPrivate::insertSuggestion(std::unique_ptr<TextSuggestion> &&suggestion)
{
clearCurrentSuggestion();
auto cursor = q->textCursor();
+ cursor.setPosition(suggestion->position());
m_suggestionBlock = cursor.block();
- m_document->insertSuggestion(suggestion, cursor);
+ m_document->insertSuggestion(std::move(suggestion));
}
void TextEditorWidgetPrivate::updateSuggestion()
@@ -1666,10 +1667,9 @@ void TextEditorWidgetPrivate::updateSuggestion()
if (m_cursors.mainCursor().block() != m_suggestionBlock) {
clearCurrentSuggestion();
} else {
- const int position = m_cursors.mainCursor().position() - m_suggestionBlock.position();
- if (!TextDocumentLayout::updateReplacement(m_suggestionBlock,
- position,
- m_document->fontSettings())) {
+ if (!TextDocumentLayout::updateSuggestion(m_suggestionBlock,
+ m_cursors.mainCursor().position(),
+ m_document->fontSettings())) {
clearCurrentSuggestion();
}
}
@@ -1678,7 +1678,7 @@ void TextEditorWidgetPrivate::updateSuggestion()
void TextEditorWidgetPrivate::clearCurrentSuggestion()
{
if (TextBlockUserData *userData = TextDocumentLayout::textUserData(m_suggestionBlock)) {
- userData->clearReplacement();
+ userData->clearSuggestion();
m_document->updateLayout();
}
m_suggestionBlock = QTextBlock();
@@ -2689,25 +2689,18 @@ void TextEditorWidget::keyPressEvent(QKeyEvent *e)
case Qt::Key_Tab:
case Qt::Key_Backtab: {
if (ro) break;
- if (d->m_suggestionBlock.isValid()) {
- const int position = TextDocumentLayout::replacementPosition(d->m_suggestionBlock);
- if (position >= 0) {
- QTextCursor cursor(d->m_suggestionBlock);
- cursor.setPosition(d->m_suggestionBlock.position() + position);
- cursor.movePosition(QTextCursor::EndOfBlock, QTextCursor::KeepAnchor);
- cursor.insertText(TextDocumentLayout::replacement(d->m_suggestionBlock));
- setTextCursor(cursor);
- }
- d->clearCurrentSuggestion();
- e->accept();
- return;
- }
if (d->m_snippetOverlay->isVisible() && !d->m_snippetOverlay->isEmpty()) {
d->snippetTabOrBacktab(e->key() == Qt::Key_Tab);
e->accept();
return;
}
QTextCursor cursor = textCursor();
+ if (TextSuggestion *suggestion = TextDocumentLayout::suggestion(d->m_suggestionBlock)) {
+ suggestion->apply();
+ d->clearCurrentSuggestion();
+ e->accept();
+ return;
+ }
if (d->m_skipAutoCompletedText && e->key() == Qt::Key_Tab) {
bool skippedAutoCompletedText = false;
while (!d->m_autoCompleteHighlightPos.isEmpty()
@@ -4067,10 +4060,10 @@ static TextMarks availableMarks(const TextMarks &marks,
QRectF TextEditorWidgetPrivate::getLastLineLineRect(const QTextBlock &block)
{
QTextLayout *layout = nullptr;
- if (block != m_suggestionBlock)
+ if (TextSuggestion *suggestion = TextDocumentLayout::suggestion(block))
+ layout = suggestion->document()->firstBlock().layout();
+ else
layout = block.layout();
- else if (QTextDocument *replacement = TextDocumentLayout::replacementDocument(block))
- layout = replacement->firstBlock().layout();
QTC_ASSERT(layout, layout = block.layout());
const int lineCount = layout->lineCount();
@@ -4467,18 +4460,18 @@ void TextEditorWidgetPrivate::paintAdditionalVisualWhitespaces(PaintEventData &d
visualArrow);
}
if (!nextBlockIsValid) { // paint EOF symbol
- if (m_suggestionBlock.isValid() && data.block == m_suggestionBlock) {
- if (QTextDocument *replacement = TextDocumentLayout::replacementDocument(
- m_suggestionBlock)) {
- const QTextBlock lastReplacementBlock = replacement->lastBlock();
- for (QTextBlock block = replacement->firstBlock();
- block != lastReplacementBlock && block.isValid();
- block = block.next()) {
- top += replacement->documentLayout()->blockBoundingRect(block).height();
- }
- layout = lastReplacementBlock.layout();
- lineCount = layout->lineCount();
+ if (TextSuggestion *suggestion = TextDocumentLayout::suggestion(data.block)) {
+ const QTextBlock lastReplacementBlock = suggestion->document()->lastBlock();
+ for (QTextBlock block = suggestion->document()->firstBlock();
+ block != lastReplacementBlock && block.isValid();
+ block = block.next()) {
+ top += suggestion->document()
+ ->documentLayout()
+ ->blockBoundingRect(block)
+ .height();
}
+ layout = lastReplacementBlock.layout();
+ lineCount = layout->lineCount();
}
QTextLine line = layout->lineAt(lineCount - 1);
QRectF lineRect = line.naturalTextRect().translated(data.offset.x(), top);
@@ -4739,17 +4732,14 @@ void TextEditorWidgetPrivate::setupSelections(const PaintEventData &data,
int deltaPos = -1;
int delta = 0;
- if (m_suggestionBlock == data.block) {
- if (QTextDocument *replacement = TextDocumentLayout::replacementDocument(
- m_suggestionBlock)) {
- deltaPos = TextDocumentLayout::replacementPosition(data.block);
- const QString trailingText = data.block.text().mid(deltaPos);
- if (!trailingText.isEmpty()) {
- const int trailingIndex = replacement->firstBlock().text().indexOf(trailingText,
- deltaPos);
- if (trailingIndex >= 0)
- delta = std::max(trailingIndex - deltaPos, 0);
- }
+ if (TextSuggestion *suggestion = TextDocumentLayout::suggestion(data.block)) {
+ deltaPos = suggestion->currentPosition() - data.block.position();
+ const QString trailingText = data.block.text().mid(deltaPos);
+ if (!trailingText.isEmpty()) {
+ const int trailingIndex
+ = suggestion->document()->firstBlock().text().indexOf(trailingText, deltaPos);
+ if (trailingIndex >= 0)
+ delta = std::max(trailingIndex - deltaPos, 0);
}
}
@@ -4994,21 +4984,23 @@ void TextEditorWidget::paintBlock(QPainter *painter,
const QVector<QTextLayout::FormatRange> &selections,
const QRect &clipRect) const
{
- if (QTextDocument *replacement = TextDocumentLayout::replacementDocument(block)) {
- QTextBlock replacementBlock = replacement->firstBlock();
- QPointF replacementOffset = offset;
- replacementOffset.rx() += document()->documentMargin();
- while (replacementBlock.isValid()) {
+ if (TextSuggestion *suggestion = TextDocumentLayout::suggestion(block)) {
+ QTextBlock suggestionBlock = suggestion->document()->firstBlock();
+ QPointF suggestionOffset = offset;
+ suggestionOffset.rx() += document()->documentMargin();
+ while (suggestionBlock.isValid()) {
const QVector<QTextLayout::FormatRange> blockSelections
- = replacementBlock.blockNumber() == 0 ? selections
+ = suggestionBlock.blockNumber() == 0 ? selections
: QVector<QTextLayout::FormatRange>{};
- replacementBlock.layout()->draw(painter,
- replacementOffset,
+ suggestionBlock.layout()->draw(painter,
+ suggestionOffset,
blockSelections,
clipRect);
- replacementOffset.ry()
- += replacement->documentLayout()->blockBoundingRect(replacementBlock).height();
- replacementBlock = replacementBlock.next();
+ suggestionOffset.ry() += suggestion->document()
+ ->documentLayout()
+ ->blockBoundingRect(suggestionBlock)
+ .height();
+ suggestionBlock = suggestionBlock.next();
}
return;
}
@@ -5992,9 +5984,9 @@ void TextEditorWidget::removeHoverHandler(BaseHoverHandler *handler)
d->m_hoverHandlerRunner.handlerRemoved(handler);
}
-void TextEditorWidget::insertSuggestion(const QString &suggestion)
+void TextEditorWidget::insertSuggestion(std::unique_ptr<TextSuggestion> &&suggestion)
{
- d->insertSuggestion(suggestion);
+ d->insertSuggestion(std::move(suggestion));
}
void TextEditorWidget::clearSuggestion()
diff --git a/src/plugins/texteditor/texteditor.h b/src/plugins/texteditor/texteditor.h
index 4234645d50a..8c6bbb688e3 100644
--- a/src/plugins/texteditor/texteditor.h
+++ b/src/plugins/texteditor/texteditor.h
@@ -42,15 +42,16 @@ class HighlightScrollBarController;
}
namespace TextEditor {
-class TextDocument;
-class TextMark;
-class BaseHoverHandler;
-class RefactorOverlay;
-class SyntaxHighlighter;
class AssistInterface;
+class BaseHoverHandler;
+class CompletionAssistProvider;
class IAssistProvider;
class ICodeStylePreferences;
-class CompletionAssistProvider;
+class RefactorOverlay;
+class SyntaxHighlighter;
+class TextDocument;
+class TextMark;
+class TextSuggestion;
using RefactorMarkers = QList<RefactorMarker>;
using TextMarks = QList<TextMark *>;
@@ -470,7 +471,7 @@ public:
void addHoverHandler(BaseHoverHandler *handler);
void removeHoverHandler(BaseHoverHandler *handler);
- void insertSuggestion(const QString &suggestion);
+ void insertSuggestion(std::unique_ptr<TextSuggestion> &&suggestion);
void clearSuggestion();
bool suggestionVisible() const;