From 7dec58dbb9fd394e98413bae38ce3f0dfcd39adf Mon Sep 17 00:00:00 2001 From: David Schulz Date: Wed, 28 Aug 2024 15:23:06 +0200 Subject: [PATCH] Copilot: Allow applying suggestions over line breaks Task-number: QTCREATORBUG-31418 Change-Id: I90b2b53ad57ee1dea5789d02159f4a93fd641c1f Reviewed-by: Marcus Tillmanns --- src/plugins/copilot/copilotsuggestion.cpp | 23 +++++++++++++++---- src/plugins/copilot/requests/getcompletions.h | 8 +++++++ src/plugins/texteditor/textdocumentlayout.cpp | 4 ++-- src/plugins/texteditor/texteditor.cpp | 1 + 4 files changed, 29 insertions(+), 7 deletions(-) diff --git a/src/plugins/copilot/copilotsuggestion.cpp b/src/plugins/copilot/copilotsuggestion.cpp index 8fcac6ee663..c97e65fb8b8 100644 --- a/src/plugins/copilot/copilotsuggestion.cpp +++ b/src/plugins/copilot/copilotsuggestion.cpp @@ -30,7 +30,6 @@ CopilotSuggestion::CopilotSuggestion(const QList &completions, document()->setPlainText(text); m_start = completion.position().toTextCursor(origin); m_start.setKeepPositionOnInsert(true); - setCurrentPosition(m_start.position()); } bool CopilotSuggestion::apply() @@ -44,8 +43,9 @@ bool CopilotSuggestion::apply() bool CopilotSuggestion::applyWord(TextEditorWidget *widget) { - const Completion completion = m_completions.value(m_currentCompletion); - const QTextCursor cursor = completion.range().toSelection(m_start.document()); + Completion completion = m_completions.value(m_currentCompletion); + const Range range = completion.range(); + const QTextCursor cursor = range.toSelection(m_start.document()); QTextCursor currentCursor = widget->textCursor(); const QString text = completion.text(); const int startPos = currentCursor.positionInBlock() - cursor.positionInBlock() @@ -55,13 +55,26 @@ bool CopilotSuggestion::applyWord(TextEditorWidget *widget) if (next == -1) return apply(); - // TODO: Allow adding more than one line QString subText = text.mid(startPos, next - startPos); - subText = subText.left(subText.indexOf('\n')); if (subText.isEmpty()) return false; currentCursor.insertText(subText); + if (const int seperatorPos = subText.lastIndexOf('\n'); seperatorPos >= 0) { + const QString newCompletionText = text.mid(startPos + seperatorPos + 1); + if (!newCompletionText.isEmpty()) { + completion.setText(newCompletionText); + const Position newStart(range.start().line() + subText.count('\n'), 0); + int nextSeperatorPos = newCompletionText.indexOf('\n'); + if (nextSeperatorPos == -1) + nextSeperatorPos = newCompletionText.size(); + const Position newEnd(newStart.line(), nextSeperatorPos); + completion.setRange(Range(newStart, newEnd)); + completion.setPosition(newStart); + widget->insertSuggestion(std::make_unique( + QList{completion}, widget->document(), 0)); + } + } return false; } diff --git a/src/plugins/copilot/requests/getcompletions.h b/src/plugins/copilot/requests/getcompletions.h index 3630c086cd1..65e73e14994 100644 --- a/src/plugins/copilot/requests/getcompletions.h +++ b/src/plugins/copilot/requests/getcompletions.h @@ -22,10 +22,18 @@ public: { return typedValue(LanguageServerProtocol::positionKey); } + void setPosition(const LanguageServerProtocol::Position &position) + { + insert(LanguageServerProtocol::positionKey, position); + } LanguageServerProtocol::Range range() const { return typedValue(LanguageServerProtocol::rangeKey); } + void setRange(const LanguageServerProtocol::Range &range) + { + insert(LanguageServerProtocol::rangeKey, range); + } QString text() const { return typedValue(LanguageServerProtocol::textKey); } void setText(const QString &text) { insert(LanguageServerProtocol::textKey, text); } QString uuid() const { return typedValue(uuidKey); } diff --git a/src/plugins/texteditor/textdocumentlayout.cpp b/src/plugins/texteditor/textdocumentlayout.cpp index 639a36e11e0..27c2a059ac5 100644 --- a/src/plugins/texteditor/textdocumentlayout.cpp +++ b/src/plugins/texteditor/textdocumentlayout.cpp @@ -613,9 +613,9 @@ bool TextDocumentLayout::updateSuggestion(const QTextBlock &block, const FontSettings &fontSettings) { if (TextSuggestion *suggestion = TextDocumentLayout::suggestion(block)) { - auto positionInBlock = position - block.position(); - if (position < suggestion->position()) + if (position < suggestion->currentPosition()) return false; + const int 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(); diff --git a/src/plugins/texteditor/texteditor.cpp b/src/plugins/texteditor/texteditor.cpp index 6b606f0e170..ba15f0b68f8 100644 --- a/src/plugins/texteditor/texteditor.cpp +++ b/src/plugins/texteditor/texteditor.cpp @@ -1823,6 +1823,7 @@ void TextEditorWidgetPrivate::insertSuggestion(std::unique_ptr & return; auto cursor = q->textCursor(); + suggestion->setCurrentPosition(cursor.position()); cursor.setPosition(suggestion->position()); QTextOption option = suggestion->document()->defaultTextOption(); option.setTabStopDistance(charWidth() * m_document->tabSettings().m_tabSize);