diff --git a/ChatView/ChatRootView.cpp b/ChatView/ChatRootView.cpp index 0da8195..da95963 100644 --- a/ChatView/ChatRootView.cpp +++ b/ChatView/ChatRootView.cpp @@ -464,12 +464,12 @@ void ChatRootView::updateInputTokensCount() } if (!m_attachmentFiles.isEmpty()) { - auto attachFiles = Context::ContextManager::instance().getContentFiles(m_attachmentFiles); + auto attachFiles = m_clientInterface->contextManager()->getContentFiles(m_attachmentFiles); inputTokens += Context::TokenUtils::estimateFilesTokens(attachFiles); } if (!m_linkedFiles.isEmpty()) { - auto linkFiles = Context::ContextManager::instance().getContentFiles(m_linkedFiles); + auto linkFiles = m_clientInterface->contextManager()->getContentFiles(m_linkedFiles); inputTokens += Context::TokenUtils::estimateFilesTokens(linkFiles); } diff --git a/ChatView/ClientInterface.cpp b/ChatView/ClientInterface.cpp index 774069e..0d7f4e3 100644 --- a/ChatView/ClientInterface.cpp +++ b/ChatView/ClientInterface.cpp @@ -33,7 +33,6 @@ #include #include "ChatAssistantSettings.hpp" -#include "ContextManager.hpp" #include "GeneralSettings.hpp" #include "Logger.hpp" #include "ProvidersManager.hpp" @@ -46,6 +45,7 @@ ClientInterface::ClientInterface( , m_requestHandler(new LLMCore::RequestHandler(this)) , m_chatModel(chatModel) , m_promptProvider(promptProvider) + , m_contextManager(new Context::ContextManager(this)) { connect( m_requestHandler, @@ -73,7 +73,7 @@ void ClientInterface::sendMessage( { cancelRequest(); - auto attachFiles = Context::ContextManager::instance().getContentFiles(attachments); + auto attachFiles = m_contextManager->getContentFiles(attachments); m_chatModel->addMessage(message, ChatModel::ChatRole::User, "", attachFiles); auto &chatAssistantSettings = Settings::chatAssistantSettings(); @@ -200,7 +200,7 @@ QString ClientInterface::getSystemPromptWithLinkedFiles( if (!linkedFiles.isEmpty()) { updatedPrompt += "\n\nLinked files for reference:\n"; - auto contentFiles = Context::ContextManager::instance().getContentFiles(linkedFiles); + auto contentFiles = m_contextManager->getContentFiles(linkedFiles); for (const auto &file : contentFiles) { updatedPrompt += QString("\nFile: %1\nContent:\n%2\n").arg(file.filename, file.content); } @@ -209,4 +209,9 @@ QString ClientInterface::getSystemPromptWithLinkedFiles( return updatedPrompt; } +Context::ContextManager *ClientInterface::contextManager() const +{ + return m_contextManager; +} + } // namespace QodeAssist::Chat diff --git a/ChatView/ClientInterface.hpp b/ChatView/ClientInterface.hpp index 1e56c36..39a1f3e 100644 --- a/ChatView/ClientInterface.hpp +++ b/ChatView/ClientInterface.hpp @@ -26,6 +26,7 @@ #include "ChatModel.hpp" #include "RequestHandler.hpp" #include "llmcore/IPromptProvider.hpp" +#include namespace QodeAssist::Chat { @@ -45,6 +46,8 @@ public: void clearMessages(); void cancelRequest(); + Context::ContextManager *contextManager() const; + signals: void errorOccurred(const QString &error); void messageReceivedCompletely(); @@ -58,6 +61,7 @@ private: LLMCore::IPromptProvider *m_promptProvider = nullptr; ChatModel *m_chatModel; LLMCore::RequestHandler *m_requestHandler; + Context::ContextManager *m_contextManager; }; } // namespace QodeAssist::Chat diff --git a/LLMClientInterface.cpp b/LLMClientInterface.cpp index c3190a4..9ae69f7 100644 --- a/LLMClientInterface.cpp +++ b/LLMClientInterface.cpp @@ -24,7 +24,6 @@ #include #include "CodeHandler.hpp" -#include "context/ContextManager.hpp" #include "context/DocumentContextReader.hpp" #include "context/Utils.hpp" #include "llmcore/PromptTemplateManager.hpp" @@ -51,6 +50,7 @@ LLMClientInterface::LLMClientInterface( , m_requestHandler(requestHandler) , m_documentReader(documentReader) , m_performanceLogger(performanceLogger) + , m_contextManager(new Context::ContextManager(this)) { connect( &m_requestHandler, @@ -170,8 +170,7 @@ void LLMClientInterface::handleCompletion(const QJsonObject &request) auto updatedContext = prepareContext(request, documentInfo); - bool isPreset1Active - = Context::ContextManager::isSpecifyCompletion(documentInfo, m_generalSettings); + bool isPreset1Active = m_contextManager->isSpecifyCompletion(documentInfo); const auto providerName = !isPreset1Active ? m_generalSettings.ccProvider() : m_generalSettings.ccPreset1Provider(); @@ -282,8 +281,7 @@ void LLMClientInterface::sendCompletionToClient( { auto filePath = Context::extractFilePathFromRequest(request); auto documentInfo = m_documentReader.readDocument(filePath); - bool isPreset1Active - = Context::ContextManager::isSpecifyCompletion(documentInfo, m_generalSettings); + bool isPreset1Active = m_contextManager->isSpecifyCompletion(documentInfo); auto templateName = !isPreset1Active ? m_generalSettings.ccTemplate() : m_generalSettings.ccPreset1Template(); diff --git a/LLMClientInterface.hpp b/LLMClientInterface.hpp index 122c4ed..9728ba6 100644 --- a/LLMClientInterface.hpp +++ b/LLMClientInterface.hpp @@ -22,6 +22,7 @@ #include #include +#include #include #include #include @@ -84,6 +85,7 @@ private: Context::IDocumentReader &m_documentReader; IRequestPerformanceLogger &m_performanceLogger; QElapsedTimer m_completionTimer; + Context::ContextManager *m_contextManager; }; } // namespace QodeAssist diff --git a/context/CMakeLists.txt b/context/CMakeLists.txt index 8d569ac..5c9212f 100644 --- a/context/CMakeLists.txt +++ b/context/CMakeLists.txt @@ -7,6 +7,7 @@ add_library(Context STATIC IDocumentReader.hpp TokenUtils.hpp TokenUtils.cpp ProgrammingLanguage.hpp ProgrammingLanguage.cpp + IContextManager.hpp ) target_link_libraries(Context diff --git a/context/ContextManager.cpp b/context/ContextManager.cpp index bffa6e8..1e59cc3 100644 --- a/context/ContextManager.cpp +++ b/context/ContextManager.cpp @@ -24,17 +24,14 @@ #include #include -#include "GeneralSettings.hpp" +#include "settings/GeneralSettings.hpp" +#include +#include + #include "Logger.hpp" namespace QodeAssist::Context { -ContextManager &ContextManager::instance() -{ - static ContextManager manager; - return manager; -} - ContextManager::ContextManager(QObject *parent) : QObject(parent) {} @@ -59,6 +56,27 @@ QList ContextManager::getContentFiles(const QStringList &filePaths) return files; } +QStringList ContextManager::getProjectSourceFiles(ProjectExplorer::Project *project) const +{ + QStringList sourceFiles; + if (!project) + return sourceFiles; + + auto projectNode = project->rootProjectNode(); + if (!projectNode) + return sourceFiles; + + projectNode->forEachNode( + [&sourceFiles, this](ProjectExplorer::FileNode *fileNode) { + if (fileNode /*&& shouldProcessFile(fileNode->filePath().toString())*/) { + sourceFiles.append(fileNode->filePath().toUrlishString()); + } + }, + nullptr); + + return sourceFiles; +} + ContentFile ContextManager::createContentFile(const QString &filePath) const { ContentFile contentFile; @@ -68,7 +86,7 @@ ContentFile ContextManager::createContentFile(const QString &filePath) const return contentFile; } -ProgrammingLanguage ContextManager::getDocumentLanguage(const DocumentInfo &documentInfo) +ProgrammingLanguage ContextManager::getDocumentLanguage(const DocumentInfo &documentInfo) const { if (!documentInfo.document) { LOG_MESSAGE("Error: Document is not available for" + documentInfo.filePath); @@ -78,9 +96,10 @@ ProgrammingLanguage ContextManager::getDocumentLanguage(const DocumentInfo &docu return Context::ProgrammingLanguageUtils::fromMimeType(documentInfo.mimeType); } -bool ContextManager::isSpecifyCompletion( - const DocumentInfo &documentInfo, const Settings::GeneralSettings &generalSettings) +bool ContextManager::isSpecifyCompletion(const DocumentInfo &documentInfo) const { + const auto &generalSettings = Settings::generalSettings(); + Context::ProgrammingLanguage documentLanguage = getDocumentLanguage(documentInfo); Context::ProgrammingLanguage preset1Language = Context::ProgrammingLanguageUtils::fromString( generalSettings.preset1Language.displayForIndex(generalSettings.preset1Language())); diff --git a/context/ContextManager.hpp b/context/ContextManager.hpp index 260959d..f09256c 100644 --- a/context/ContextManager.hpp +++ b/context/ContextManager.hpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2024 Petr Mironychev + * Copyright (C) 2025 Petr Mironychev * * This file is part of QodeAssist. * @@ -23,31 +23,30 @@ #include #include "ContentFile.hpp" -#include "IDocumentReader.hpp" +#include "IContextManager.hpp" #include "ProgrammingLanguage.hpp" -#include "settings/GeneralSettings.hpp" + +namespace ProjectExplorer { +class Project; +} namespace QodeAssist::Context { -class ContextManager : public QObject +class ContextManager : public QObject, public IContextManager { Q_OBJECT public: - static ContextManager &instance(); - QString readFile(const QString &filePath) const; - QList getContentFiles(const QStringList &filePaths) const; - - static ProgrammingLanguage getDocumentLanguage(const DocumentInfo &documentInfo); - static bool isSpecifyCompletion( - const DocumentInfo &documentInfo, const Settings::GeneralSettings &generalSettings); - -private: explicit ContextManager(QObject *parent = nullptr); - ~ContextManager() = default; - ContextManager(const ContextManager &) = delete; - ContextManager &operator=(const ContextManager &) = delete; - ContentFile createContentFile(const QString &filePath) const; + ~ContextManager() override = default; + + QString readFile(const QString &filePath) const override; + QList getContentFiles(const QStringList &filePaths) const override; + QStringList getProjectSourceFiles(ProjectExplorer::Project *project) const override; + ContentFile createContentFile(const QString &filePath) const override; + + ProgrammingLanguage getDocumentLanguage(const DocumentInfo &documentInfo) const override; + bool isSpecifyCompletion(const DocumentInfo &documentInfo) const override; }; } // namespace QodeAssist::Context diff --git a/context/IContextManager.hpp b/context/IContextManager.hpp new file mode 100644 index 0000000..4dd1375 --- /dev/null +++ b/context/IContextManager.hpp @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2025 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 +#include + +#include "ContentFile.hpp" +#include "IDocumentReader.hpp" +#include "ProgrammingLanguage.hpp" + +namespace ProjectExplorer { +class Project; +} + +namespace QodeAssist::Context { + +class IContextManager +{ +public: + virtual ~IContextManager() = default; + + virtual QString readFile(const QString &filePath) const = 0; + virtual QList getContentFiles(const QStringList &filePaths) const = 0; + virtual QStringList getProjectSourceFiles(ProjectExplorer::Project *project) const = 0; + virtual ContentFile createContentFile(const QString &filePath) const = 0; + + virtual ProgrammingLanguage getDocumentLanguage(const DocumentInfo &documentInfo) const = 0; + virtual bool isSpecifyCompletion(const DocumentInfo &documentInfo) const = 0; +}; + +} // namespace QodeAssist::Context