// Copyright (C) 2023 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "copilotsuggestion.h" #include #include using namespace Utils; using namespace TextEditor; using namespace LanguageServerProtocol; namespace Copilot::Internal { CopilotSuggestion::CopilotSuggestion(const QList &completions, QTextDocument *origin, int currentCompletion) : m_completions(completions) , m_currentCompletion(currentCompletion) { const Completion completion = completions.value(currentCompletion); const Position start = completion.range().start(); const Position end = completion.range().end(); QString text = start.toTextCursor(origin).block().text(); int length = text.length() - start.character(); if (start.line() == end.line()) length = end.character() - start.character(); text.replace(start.character(), length, completion.text()); document()->setPlainText(text); m_start = completion.position().toTextCursor(origin); m_start.setKeepPositionOnInsert(true); } bool CopilotSuggestion::apply() { reset(); const Completion completion = m_completions.value(m_currentCompletion); QTextCursor cursor = completion.range().toSelection(m_start.document()); cursor.insertText(completion.text()); return true; } bool CopilotSuggestion::applyWord(TextEditorWidget *widget) { return applyPart(Word, widget); } bool CopilotSuggestion::applyLine(TextEditor::TextEditorWidget *widget) { return applyPart(Line, widget); } void CopilotSuggestion::reset() { m_start.removeSelectedText(); } int CopilotSuggestion::position() { return m_start.selectionEnd(); } bool CopilotSuggestion::applyPart(Part part, TextEditor::TextEditorWidget *widget) { 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() + (cursor.selectionEnd() - cursor.selectionStart()); int next = part == Word ? endOfNextWord(text, startPos) : text.indexOf('\n', startPos); if (next == -1) return apply(); if (part == Line) ++next; QString subText = text.mid(startPos, next - startPos); 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; } } // namespace Copilot::Internal