From a324df8dbfd47d304a2372335943862a22e3aa40 Mon Sep 17 00:00:00 2001 From: Petr Mironychev <9195189+Palm1r@users.noreply.github.com> Date: Tue, 27 Aug 2024 23:03:22 +0200 Subject: [PATCH] Fix reading context --- CMakeLists.txt | 1 + DocumentContextReader.cpp | 126 ++++++++++++++++++++++++++++++++++++++ DocumentContextReader.hpp | 43 +++++++++++++ LLMClientInterface.cpp | 75 +++++------------------ 4 files changed, 187 insertions(+), 58 deletions(-) create mode 100644 DocumentContextReader.cpp create mode 100644 DocumentContextReader.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 9620b59..66fe792 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -45,4 +45,5 @@ add_qtc_plugin(QodeAssist QodeAssistHoverHandler.hpp QodeAssistHoverHandler.cpp QodeAssistClient.hpp QodeAssistClient.cpp QodeAssistUtils.hpp + DocumentContextReader.hpp DocumentContextReader.cpp ) diff --git a/DocumentContextReader.cpp b/DocumentContextReader.cpp new file mode 100644 index 0000000..2718d92 --- /dev/null +++ b/DocumentContextReader.cpp @@ -0,0 +1,126 @@ +/* + * Copyright (C) 2024 Petr Mironychev + * + * This file is part of QodeAssist. + * + * QodeAssist is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * QodeAssist is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with QodeAssist. If not, see . + */ + +#include "DocumentContextReader.hpp" + +#include + +namespace QodeAssist { + +QString DocumentContextReader::getLineText(int lineNumber, int cursorPosition) const +{ + if (!m_document || lineNumber < 0) + return QString(); + + QTextBlock block = m_document->begin(); + int currentLine = 0; + + while (block.isValid()) { + if (currentLine == lineNumber) { + QString text = block.text(); + if (cursorPosition >= 0 && cursorPosition <= text.length()) { + text = text.left(cursorPosition); + } + return text; + } + + block = block.next(); + currentLine++; + } + + return QString(); +} + +QString DocumentContextReader::getContextBefore(int lineNumber, + int cursorPosition, + int linesCount) const +{ + QString context; + for (int i = qMax(0, lineNumber - linesCount); i <= lineNumber; ++i) { + QString line = getLineText(i, i == lineNumber ? cursorPosition : -1); + context += line; + if (i < lineNumber) + context += "\n"; + } + return context; +} + +QString DocumentContextReader::getContextAfter(int lineNumber, + int cursorPosition, + int linesCount) const +{ + QString context; + int maxLine = lineNumber + linesCount; + for (int i = lineNumber; i <= maxLine; ++i) { + QString line = getLineText(i); + if (i == lineNumber && cursorPosition >= 0) { + line = line.mid(cursorPosition); + } + context += line; + if (i < maxLine && !line.isEmpty()) + context += "\n"; + } + return context; +} + +QString DocumentContextReader::readWholeFileBefore(int lineNumber, int cursorPosition) const +{ + QString content; + QTextBlock block = m_document->begin(); + int currentLine = 0; + + while (block.isValid() && currentLine <= lineNumber) { + if (currentLine == lineNumber) { + content += block.text().left(cursorPosition); + break; + } else { + content += block.text() + "\n"; + } + block = block.next(); + currentLine++; + } + + return content; +} + +QString DocumentContextReader::readWholeFileAfter(int lineNumber, int cursorPosition) const +{ + QString content; + QTextBlock block = m_document->begin(); + int currentLine = 0; + + while (block.isValid() && currentLine < lineNumber) { + block = block.next(); + currentLine++; + } + + while (block.isValid()) { + if (currentLine == lineNumber) { + content += block.text().mid(cursorPosition) + "\n"; + } else { + content += block.text() + "\n"; + } + block = block.next(); + currentLine++; + } + + return content.trimmed(); +} + +} // namespace QodeAssist diff --git a/DocumentContextReader.hpp b/DocumentContextReader.hpp new file mode 100644 index 0000000..5c473ec --- /dev/null +++ b/DocumentContextReader.hpp @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2024 Petr Mironychev + * + * This file is part of QodeAssist. + * + * QodeAssist is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * QodeAssist is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with QodeAssist. If not, see . + */ + +#pragma once + +#include + +namespace QodeAssist { + +class DocumentContextReader +{ +public: + DocumentContextReader(QTextDocument *doc) + : m_document(doc) + {} + + QString getLineText(int lineNumber, int cursorPosition = -1) const; + QString getContextBefore(int lineNumber, int cursorPosition, int linesCount) const; + QString getContextAfter(int lineNumber, int cursorPosition, int linesCount) const; + QString readWholeFileBefore(int lineNumber, int cursorPosition) const; + QString readWholeFileAfter(int lineNumber, int cursorPosition) const; + +private: + QTextDocument *m_document; +}; + +} // namespace QodeAssist diff --git a/LLMClientInterface.cpp b/LLMClientInterface.cpp index 5ad9c71..9689d70 100644 --- a/LLMClientInterface.cpp +++ b/LLMClientInterface.cpp @@ -25,6 +25,7 @@ #include +#include "DocumentContextReader.hpp" #include "LLMProvidersManager.hpp" #include "PromptTemplateManager.hpp" #include "QodeAssistSettings.hpp" @@ -98,38 +99,18 @@ QString LLMClientInterface::сontextBefore(TextEditor::TextEditorWidget *widget, return QString(); QTextDocument *doc = widget->document(); - int totalLines = doc->blockCount(); - QTextBlock currentBlock = doc->findBlockByLineNumber(lineNumber); + DocumentContextReader reader(doc); - QString beforeCursor; - - if (settings().readFullFile() && totalLines < settings().maxFileThreshold()) { - // Read all content from the beginning of the file to the cursor - QTextBlock block = doc->begin(); - while (block.isValid() && block.blockNumber() <= lineNumber) { - if (block.blockNumber() == lineNumber) { - beforeCursor += block.text().left(cursorPosition); - break; - } else { - beforeCursor += block.text() + "\n"; - } - block = block.next(); - } + QString contextBefore; + if (settings().readFullFile()) { + contextBefore = reader.readWholeFileBefore(lineNumber, cursorPosition); } else { - // Read only the specified number of lines before the cursor - int contextLinesBefore = settings().readStringsBeforeCursor(); - QTextBlock block = currentBlock; - for (int i = 0; i < contextLinesBefore && block.isValid(); ++i) { - if (block.blockNumber() == lineNumber) { - beforeCursor = block.text().left(cursorPosition) + beforeCursor; - } else { - beforeCursor = block.text() + "\n" + beforeCursor; - } - block = block.previous(); - } + contextBefore = reader.getContextBefore(lineNumber, + cursorPosition, + settings().readStringsBeforeCursor()); } - return beforeCursor; + return contextBefore; } QString LLMClientInterface::сontextAfter(TextEditor::TextEditorWidget *widget, @@ -140,40 +121,18 @@ QString LLMClientInterface::сontextAfter(TextEditor::TextEditorWidget *widget, return QString(); QTextDocument *doc = widget->document(); - int totalLines = doc->blockCount(); - QTextBlock currentBlock = doc->findBlockByLineNumber(lineNumber); + DocumentContextReader reader(doc); - QString afterCursor; - - if (settings().readFullFile() && totalLines < settings().maxFileThreshold()) { - // Read all content from the cursor to the end of the file - QTextBlock block = currentBlock; - bool isFirstBlock = true; - while (block.isValid()) { - if (isFirstBlock) { - afterCursor += block.text().mid(cursorPosition) + "\n"; - isFirstBlock = false; - } else { - afterCursor += block.text() + "\n"; - } - block = block.next(); - } + QString contextAfter; + if (settings().readFullFile()) { + contextAfter = reader.readWholeFileAfter(lineNumber, cursorPosition); } else { - // Read only the specified number of lines after the cursor - int contextLinesAfter = settings().readStringsAfterCursor(); - QTextBlock block = currentBlock; - for (int i = 0; i < contextLinesAfter && block.isValid(); ++i) { - if (block.blockNumber() == lineNumber) { - afterCursor += block.text().mid(cursorPosition); - } else { - afterCursor += block.text(); - } - afterCursor += "\n"; - block = block.next(); - } + contextAfter = reader.getContextAfter(lineNumber, + cursorPosition, + settings().readStringsAfterCursor()); } - return afterCursor; + return contextAfter; } void LLMClientInterface::handleInitialize(const QJsonObject &request)