diff options
author | David Schulz <[email protected]> | 2023-03-27 07:28:48 +0200 |
---|---|---|
committer | David Schulz <[email protected]> | 2023-03-29 07:43:19 +0000 |
commit | 8a1e34f084f24f45d61e0011a2b6486aadc34218 (patch) | |
tree | 0f5b0b5d52df71a23a75e453b0f1fbf804bae2c6 | |
parent | 1ee46580ac8afda64e63b3dd816b4acbfad5dfaa (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.cpp | 10 | ||||
-rw-r--r-- | src/libs/languageserverprotocol/lsptypes.h | 2 | ||||
-rw-r--r-- | src/libs/languageserverprotocol/lsputils.h | 7 | ||||
-rw-r--r-- | src/plugins/copilot/copilotclient.cpp | 46 | ||||
-rw-r--r-- | src/plugins/texteditor/textdocument.cpp | 15 | ||||
-rw-r--r-- | src/plugins/texteditor/textdocument.h | 2 | ||||
-rw-r--r-- | src/plugins/texteditor/textdocumentlayout.cpp | 90 | ||||
-rw-r--r-- | src/plugins/texteditor/textdocumentlayout.h | 40 | ||||
-rw-r--r-- | src/plugins/texteditor/texteditor.cpp | 110 | ||||
-rw-r--r-- | src/plugins/texteditor/texteditor.h | 15 |
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; |