mirror of
https://github.com/Palm1r/QodeAssist.git
synced 2026-07-24 20:20:59 -04:00
feat: add support acp in common chat (#369)
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
add_library(Context STATIC
|
||||
DocumentContextReader.hpp DocumentContextReader.cpp
|
||||
ChangesManager.h ChangesManager.cpp
|
||||
FileEditManager.hpp FileEditManager.cpp
|
||||
ContextManager.hpp ContextManager.cpp
|
||||
ContentFile.hpp
|
||||
DocumentReaderQtCreator.hpp
|
||||
@@ -10,7 +10,6 @@ add_library(Context STATIC
|
||||
IContextManager.hpp
|
||||
IgnoreManager.hpp IgnoreManager.cpp
|
||||
ProjectUtils.hpp ProjectUtils.cpp
|
||||
RulesLoader.hpp RulesLoader.cpp
|
||||
)
|
||||
|
||||
target_link_libraries(Context
|
||||
|
||||
@@ -12,6 +12,7 @@ struct ContentFile
|
||||
{
|
||||
QString filename;
|
||||
QString content;
|
||||
QString path;
|
||||
};
|
||||
|
||||
} // namespace QodeAssist::Context
|
||||
|
||||
@@ -41,9 +41,9 @@ QString ContextManager::readFile(const QString &filePath) const
|
||||
return content;
|
||||
}
|
||||
|
||||
QList<ContentFile> ContextManager::getContentFiles(const QStringList &filePaths) const
|
||||
QStringList ContextManager::allowedPaths(const QStringList &filePaths) const
|
||||
{
|
||||
QList<ContentFile> files;
|
||||
QStringList allowed;
|
||||
for (const QString &path : filePaths) {
|
||||
auto project = ProjectExplorer::ProjectManager::projectForFile(
|
||||
Utils::FilePath::fromString(path));
|
||||
@@ -52,9 +52,16 @@ QList<ContentFile> ContextManager::getContentFiles(const QStringList &filePaths)
|
||||
continue;
|
||||
}
|
||||
|
||||
ContentFile contentFile = createContentFile(path);
|
||||
files.append(contentFile);
|
||||
allowed.append(path);
|
||||
}
|
||||
return allowed;
|
||||
}
|
||||
|
||||
QList<ContentFile> ContextManager::getContentFiles(const QStringList &filePaths) const
|
||||
{
|
||||
QList<ContentFile> files;
|
||||
for (const QString &path : allowedPaths(filePaths))
|
||||
files.append(createContentFile(path));
|
||||
return files;
|
||||
}
|
||||
|
||||
@@ -85,6 +92,7 @@ ContentFile ContextManager::createContentFile(const QString &filePath) const
|
||||
QFileInfo fileInfo(filePath);
|
||||
contentFile.filename = fileInfo.fileName();
|
||||
contentFile.content = readFile(filePath);
|
||||
contentFile.path = fileInfo.absoluteFilePath();
|
||||
return contentFile;
|
||||
}
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@ public:
|
||||
~ContextManager() override = default;
|
||||
|
||||
QString readFile(const QString &filePath) const override;
|
||||
QStringList allowedPaths(const QStringList &filePaths) const override;
|
||||
QList<ContentFile> getContentFiles(const QStringList &filePaths) const override;
|
||||
QStringList getProjectSourceFiles(ProjectExplorer::Project *project) const override;
|
||||
ContentFile createContentFile(const QString &filePath) const override;
|
||||
|
||||
@@ -10,8 +10,6 @@
|
||||
|
||||
#include "CodeCompletionSettings.hpp"
|
||||
|
||||
#include "ChangesManager.h"
|
||||
|
||||
const QRegularExpression &getYearRegex()
|
||||
{
|
||||
static const QRegularExpression yearRegex("\\b(19|20)\\d{2}\\b");
|
||||
@@ -274,10 +272,6 @@ LLMCore::ContextData DocumentContextReader::prepareContext(
|
||||
QString fileContext;
|
||||
fileContext.append("\n ").append(getLanguageAndFileInfo());
|
||||
|
||||
if (settings.useProjectChangesCache())
|
||||
fileContext.append("Recent Project Changes Context:\n ")
|
||||
.append(ChangesManager::instance().getRecentChangesContext(m_textDocument));
|
||||
|
||||
return {.prefix = contextBefore, .suffix = contextAfter, .fileContext = fileContext};
|
||||
}
|
||||
|
||||
|
||||
@@ -2,11 +2,11 @@
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
// Additional attribution terms under GPLv3 §7(b) apply — see LICENSE
|
||||
|
||||
#include "ChangesManager.h"
|
||||
#include "CodeCompletionSettings.hpp"
|
||||
#include "FileEditManager.hpp"
|
||||
|
||||
#include <coreplugin/editormanager/editormanager.h>
|
||||
#include <coreplugin/editormanager/ieditor.h>
|
||||
#include <texteditor/textdocument.h>
|
||||
#include <logger/Logger.hpp>
|
||||
#include <algorithm>
|
||||
#include <QFile>
|
||||
@@ -15,61 +15,20 @@
|
||||
|
||||
namespace QodeAssist::Context {
|
||||
|
||||
ChangesManager &ChangesManager::instance()
|
||||
FileEditManager &FileEditManager::instance()
|
||||
{
|
||||
static ChangesManager instance;
|
||||
static FileEditManager instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
ChangesManager::ChangesManager()
|
||||
FileEditManager::FileEditManager()
|
||||
: QObject(nullptr)
|
||||
, m_undoStack(new QUndoStack(this))
|
||||
{}
|
||||
|
||||
ChangesManager::~ChangesManager() {}
|
||||
FileEditManager::~FileEditManager() {}
|
||||
|
||||
void ChangesManager::addChange(
|
||||
TextEditor::TextDocument *document, int position, int charsRemoved, int charsAdded)
|
||||
{
|
||||
auto &documentQueue = m_documentChanges[document];
|
||||
|
||||
QTextBlock block = document->document()->findBlock(position);
|
||||
int lineNumber = block.blockNumber();
|
||||
QString lineContent = block.text();
|
||||
QString fileName = document->filePath().fileName();
|
||||
|
||||
ChangeInfo change{fileName, lineNumber, lineContent};
|
||||
|
||||
auto it
|
||||
= std::find_if(documentQueue.begin(), documentQueue.end(), [lineNumber](const ChangeInfo &c) {
|
||||
return c.lineNumber == lineNumber;
|
||||
});
|
||||
|
||||
if (it != documentQueue.end()) {
|
||||
it->lineContent = lineContent;
|
||||
} else {
|
||||
documentQueue.enqueue(change);
|
||||
|
||||
if (documentQueue.size() > Settings::codeCompletionSettings().maxChangesCacheSize()) {
|
||||
documentQueue.dequeue();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QString ChangesManager::getRecentChangesContext(const TextEditor::TextDocument *currentDocument) const
|
||||
{
|
||||
QString context;
|
||||
for (auto it = m_documentChanges.constBegin(); it != m_documentChanges.constEnd(); ++it) {
|
||||
if (it.key() != currentDocument) {
|
||||
for (const auto &change : it.value()) {
|
||||
context += change.lineContent + "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
return context;
|
||||
}
|
||||
|
||||
void ChangesManager::addFileEdit(
|
||||
void FileEditManager::addFileEdit(
|
||||
const QString &editId,
|
||||
const QString &filePath,
|
||||
const QString &oldContent,
|
||||
@@ -139,7 +98,44 @@ void ChangesManager::addFileEdit(
|
||||
}
|
||||
}
|
||||
|
||||
bool ChangesManager::applyFileEdit(const QString &editId)
|
||||
void FileEditManager::registerAppliedFileEdit(
|
||||
const QString &editId,
|
||||
const QString &filePath,
|
||||
const QString &oldContent,
|
||||
const QString &newContent,
|
||||
const QString &requestId)
|
||||
{
|
||||
QMutexLocker locker(&m_mutex);
|
||||
|
||||
if (m_fileEdits.contains(editId)) {
|
||||
LOG_MESSAGE(QString("File edit already exists, skipping: %1").arg(editId));
|
||||
return;
|
||||
}
|
||||
|
||||
FileEdit edit;
|
||||
edit.editId = editId;
|
||||
edit.filePath = filePath;
|
||||
edit.oldContent = oldContent;
|
||||
edit.newContent = newContent;
|
||||
edit.timestamp = QDateTime::currentDateTime();
|
||||
edit.wasAutoApplied = true;
|
||||
edit.isFromHistory = false;
|
||||
edit.status = Applied;
|
||||
edit.statusMessage = "Applied by agent";
|
||||
|
||||
m_fileEdits.insert(editId, edit);
|
||||
|
||||
if (!requestId.isEmpty())
|
||||
m_requestEdits[requestId].editIds.append(editId);
|
||||
|
||||
locker.unlock();
|
||||
emit fileEditAdded(editId);
|
||||
|
||||
LOG_MESSAGE(QString("Agent file edit registered as applied: %1 for file %2")
|
||||
.arg(editId, filePath));
|
||||
}
|
||||
|
||||
bool FileEditManager::applyFileEdit(const QString &editId)
|
||||
{
|
||||
QMutexLocker locker(&m_mutex);
|
||||
|
||||
@@ -193,7 +189,7 @@ bool ChangesManager::applyFileEdit(const QString &editId)
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ChangesManager::rejectFileEdit(const QString &editId)
|
||||
bool FileEditManager::rejectFileEdit(const QString &editId)
|
||||
{
|
||||
QMutexLocker locker(&m_mutex);
|
||||
|
||||
@@ -220,7 +216,7 @@ bool ChangesManager::rejectFileEdit(const QString &editId)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ChangesManager::undoFileEdit(const QString &editId)
|
||||
bool FileEditManager::undoFileEdit(const QString &editId)
|
||||
{
|
||||
QMutexLocker locker(&m_mutex);
|
||||
|
||||
@@ -276,13 +272,13 @@ bool ChangesManager::undoFileEdit(const QString &editId)
|
||||
return false;
|
||||
}
|
||||
|
||||
ChangesManager::FileEdit ChangesManager::getFileEdit(const QString &editId) const
|
||||
FileEditManager::FileEdit FileEditManager::getFileEdit(const QString &editId) const
|
||||
{
|
||||
QMutexLocker locker(&m_mutex);
|
||||
return m_fileEdits.value(editId);
|
||||
}
|
||||
|
||||
QList<ChangesManager::FileEdit> ChangesManager::getPendingEdits() const
|
||||
QList<FileEditManager::FileEdit> FileEditManager::getPendingEdits() const
|
||||
{
|
||||
QMutexLocker locker(&m_mutex);
|
||||
|
||||
@@ -295,7 +291,7 @@ QList<ChangesManager::FileEdit> ChangesManager::getPendingEdits() const
|
||||
return pendingEdits;
|
||||
}
|
||||
|
||||
bool ChangesManager::performFileEdit(
|
||||
bool FileEditManager::performFileEdit(
|
||||
const QString &filePath, const QString &oldContent, const QString &newContent, QString *errorMsg)
|
||||
{
|
||||
auto setError = [errorMsg](const QString &msg) {
|
||||
@@ -451,7 +447,7 @@ bool ChangesManager::performFileEdit(
|
||||
return true;
|
||||
}
|
||||
|
||||
int ChangesManager::levenshteinDistance(const QString &s1, const QString &s2) const
|
||||
int FileEditManager::levenshteinDistance(const QString &s1, const QString &s2) const
|
||||
{
|
||||
const int len1 = s1.length();
|
||||
const int len2 = s2.length();
|
||||
@@ -484,7 +480,7 @@ int ChangesManager::levenshteinDistance(const QString &s1, const QString &s2) co
|
||||
return d[len1][len2];
|
||||
}
|
||||
|
||||
QString ChangesManager::findBestMatchLineBased(
|
||||
QString FileEditManager::findBestMatchLineBased(
|
||||
const QString &fileContent,
|
||||
const QString &searchContent,
|
||||
double threshold,
|
||||
@@ -550,7 +546,7 @@ QString ChangesManager::findBestMatchLineBased(
|
||||
return bestMatch;
|
||||
}
|
||||
|
||||
QString ChangesManager::findBestMatch(const QString &fileContent, const QString &searchContent, double threshold, double *outSimilarity) const
|
||||
QString FileEditManager::findBestMatch(const QString &fileContent, const QString &searchContent, double threshold, double *outSimilarity) const
|
||||
{
|
||||
if (searchContent.isEmpty() || fileContent.isEmpty()) {
|
||||
if (outSimilarity) *outSimilarity = 0.0;
|
||||
@@ -631,7 +627,7 @@ QString ChangesManager::findBestMatch(const QString &fileContent, const QString
|
||||
return bestMatch;
|
||||
}
|
||||
|
||||
QString ChangesManager::findBestMatchWithNormalization(
|
||||
QString FileEditManager::findBestMatchWithNormalization(
|
||||
const QString &fileContent,
|
||||
const QString &searchContent,
|
||||
double *outSimilarity,
|
||||
@@ -677,7 +673,7 @@ QString ChangesManager::findBestMatchWithNormalization(
|
||||
return QString();
|
||||
}
|
||||
|
||||
bool ChangesManager::performFragmentReplacement(
|
||||
bool FileEditManager::performFragmentReplacement(
|
||||
const QString &filePath,
|
||||
const QString &searchContent,
|
||||
const QString &replaceContent,
|
||||
@@ -821,7 +817,7 @@ bool ChangesManager::performFragmentReplacement(
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ChangesManager::applyPendingEditsForRequest(const QString &requestId, QString *errorMsg)
|
||||
bool FileEditManager::applyPendingEditsForRequest(const QString &requestId, QString *errorMsg)
|
||||
{
|
||||
QMutexLocker locker(&m_mutex);
|
||||
|
||||
@@ -857,7 +853,7 @@ bool ChangesManager::applyPendingEditsForRequest(const QString &requestId, QStri
|
||||
return true;
|
||||
}
|
||||
|
||||
QList<ChangesManager::FileEdit> ChangesManager::getEditsForRequest(const QString &requestId) const
|
||||
QList<FileEditManager::FileEdit> FileEditManager::getEditsForRequest(const QString &requestId) const
|
||||
{
|
||||
QMutexLocker locker(&m_mutex);
|
||||
|
||||
@@ -877,7 +873,7 @@ QList<ChangesManager::FileEdit> ChangesManager::getEditsForRequest(const QString
|
||||
return edits;
|
||||
}
|
||||
|
||||
bool ChangesManager::undoAllEditsForRequest(const QString &requestId, QString *errorMsg)
|
||||
bool FileEditManager::undoAllEditsForRequest(const QString &requestId, QString *errorMsg)
|
||||
{
|
||||
QMutexLocker locker(&m_mutex);
|
||||
|
||||
@@ -962,7 +958,7 @@ bool ChangesManager::undoAllEditsForRequest(const QString &requestId, QString *e
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ChangesManager::reapplyAllEditsForRequest(const QString &requestId, QString *errorMsg)
|
||||
bool FileEditManager::reapplyAllEditsForRequest(const QString &requestId, QString *errorMsg)
|
||||
{
|
||||
QMutexLocker locker(&m_mutex);
|
||||
|
||||
@@ -1046,7 +1042,7 @@ bool ChangesManager::reapplyAllEditsForRequest(const QString &requestId, QString
|
||||
return true;
|
||||
}
|
||||
|
||||
void ChangesManager::archiveAllNonArchivedEdits()
|
||||
void FileEditManager::archiveAllNonArchivedEdits()
|
||||
{
|
||||
QMutexLocker locker(&m_mutex);
|
||||
|
||||
@@ -1080,7 +1076,7 @@ void ChangesManager::archiveAllNonArchivedEdits()
|
||||
}
|
||||
}
|
||||
|
||||
QString ChangesManager::readFileContent(const QString &filePath) const
|
||||
QString FileEditManager::readFileContent(const QString &filePath) const
|
||||
{
|
||||
LOG_MESSAGE(QString("Reading current file content: %1").arg(filePath));
|
||||
|
||||
@@ -1112,7 +1108,7 @@ QString ChangesManager::readFileContent(const QString &filePath) const
|
||||
return content;
|
||||
}
|
||||
|
||||
bool ChangesManager::performFileEditWithDiff(
|
||||
bool FileEditManager::performFileEditWithDiff(
|
||||
const QString &filePath,
|
||||
const DiffInfo &diffInfo,
|
||||
bool reverse,
|
||||
@@ -1244,7 +1240,7 @@ bool ChangesManager::performFileEditWithDiff(
|
||||
return true;
|
||||
}
|
||||
|
||||
ChangesManager::DiffInfo ChangesManager::createDiffInfo(
|
||||
FileEditManager::DiffInfo FileEditManager::createDiffInfo(
|
||||
const QString &originalContent,
|
||||
const QString &modifiedContent,
|
||||
const QString &filePath)
|
||||
@@ -1390,7 +1386,7 @@ ChangesManager::DiffInfo ChangesManager::createDiffInfo(
|
||||
return diffInfo;
|
||||
}
|
||||
|
||||
bool ChangesManager::findHunkLocation(
|
||||
bool FileEditManager::findHunkLocation(
|
||||
const QStringList &fileLines,
|
||||
const DiffHunk &hunk,
|
||||
int &actualStartLine,
|
||||
@@ -1537,7 +1533,7 @@ bool ChangesManager::findHunkLocation(
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ChangesManager::applyDiffToContent(
|
||||
bool FileEditManager::applyDiffToContent(
|
||||
QString &content,
|
||||
const DiffInfo &diffInfo,
|
||||
bool reverse,
|
||||
@@ -4,28 +4,22 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <texteditor/textdocument.h>
|
||||
#include <QDateTime>
|
||||
#include <QHash>
|
||||
#include <QList>
|
||||
#include <QMutex>
|
||||
#include <QQueue>
|
||||
#include <QTimer>
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
#include <QUndoStack>
|
||||
|
||||
namespace QodeAssist::Context {
|
||||
|
||||
class ChangesManager : public QObject
|
||||
class FileEditManager : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
struct ChangeInfo
|
||||
{
|
||||
QString fileName;
|
||||
int lineNumber;
|
||||
QString lineContent;
|
||||
};
|
||||
|
||||
enum FileEditStatus { Pending, Applied, Rejected, Archived };
|
||||
|
||||
struct DiffHunk
|
||||
@@ -63,11 +57,7 @@ public:
|
||||
QString statusMessage;
|
||||
};
|
||||
|
||||
static ChangesManager &instance();
|
||||
|
||||
void addChange(
|
||||
TextEditor::TextDocument *document, int position, int charsRemoved, int charsAdded);
|
||||
QString getRecentChangesContext(const TextEditor::TextDocument *currentDocument) const;
|
||||
static FileEditManager &instance();
|
||||
|
||||
void addFileEdit(
|
||||
const QString &editId,
|
||||
@@ -77,20 +67,26 @@ public:
|
||||
bool autoApply = true,
|
||||
bool isFromHistory = false,
|
||||
const QString &requestId = QString());
|
||||
void registerAppliedFileEdit(
|
||||
const QString &editId,
|
||||
const QString &filePath,
|
||||
const QString &oldContent,
|
||||
const QString &newContent,
|
||||
const QString &requestId = QString());
|
||||
bool applyFileEdit(const QString &editId);
|
||||
bool rejectFileEdit(const QString &editId);
|
||||
bool undoFileEdit(const QString &editId);
|
||||
FileEdit getFileEdit(const QString &editId) const;
|
||||
QList<FileEdit> getPendingEdits() const;
|
||||
|
||||
|
||||
bool applyPendingEditsForRequest(const QString &requestId, QString *errorMsg = nullptr);
|
||||
|
||||
|
||||
QList<FileEdit> getEditsForRequest(const QString &requestId) const;
|
||||
|
||||
|
||||
bool undoAllEditsForRequest(const QString &requestId, QString *errorMsg = nullptr);
|
||||
|
||||
|
||||
bool reapplyAllEditsForRequest(const QString &requestId, QString *errorMsg = nullptr);
|
||||
|
||||
|
||||
void archiveAllNonArchivedEdits();
|
||||
|
||||
signals:
|
||||
@@ -101,19 +97,19 @@ signals:
|
||||
void fileEditArchived(const QString &editId);
|
||||
|
||||
private:
|
||||
ChangesManager();
|
||||
~ChangesManager();
|
||||
ChangesManager(const ChangesManager &) = delete;
|
||||
ChangesManager &operator=(const ChangesManager &) = delete;
|
||||
FileEditManager();
|
||||
~FileEditManager();
|
||||
FileEditManager(const FileEditManager &) = delete;
|
||||
FileEditManager &operator=(const FileEditManager &) = delete;
|
||||
|
||||
bool performFileEdit(const QString &filePath, const QString &oldContent, const QString &newContent, QString *errorMsg = nullptr);
|
||||
bool performFileEditWithDiff(const QString &filePath, const DiffInfo &diffInfo, bool reverse, QString *errorMsg = nullptr);
|
||||
QString readFileContent(const QString &filePath) const;
|
||||
|
||||
|
||||
DiffInfo createDiffInfo(const QString &originalContent, const QString &modifiedContent, const QString &filePath);
|
||||
bool applyDiffToContent(QString &content, const DiffInfo &diffInfo, bool reverse, QString *errorMsg = nullptr);
|
||||
bool findHunkLocation(const QStringList &fileLines, const DiffHunk &hunk, int &actualStartLine, QString *debugInfo = nullptr) const;
|
||||
|
||||
|
||||
// Helper method for fragment-based apply/undo operations
|
||||
bool performFragmentReplacement(
|
||||
const QString &filePath,
|
||||
@@ -122,7 +118,7 @@ private:
|
||||
bool isAppendOperation,
|
||||
QString *errorMsg = nullptr,
|
||||
bool isUndo = false);
|
||||
|
||||
|
||||
int levenshteinDistance(const QString &s1, const QString &s2) const;
|
||||
QString findBestMatch(const QString &fileContent, const QString &searchContent, double threshold = 0.82, double *outSimilarity = nullptr) const;
|
||||
QString findBestMatchLineBased(const QString &fileContent, const QString &searchContent, double threshold = 0.82, double *outSimilarity = nullptr) const;
|
||||
@@ -134,7 +130,6 @@ private:
|
||||
bool autoApplyPending = false;
|
||||
};
|
||||
|
||||
QHash<TextEditor::TextDocument *, QQueue<ChangeInfo>> m_documentChanges;
|
||||
QHash<QString, FileEdit> m_fileEdits;
|
||||
QHash<QString, RequestEdits> m_requestEdits; // requestId → ordered edits
|
||||
QUndoStack *m_undoStack;
|
||||
@@ -23,6 +23,7 @@ public:
|
||||
virtual ~IContextManager() = default;
|
||||
|
||||
virtual QString readFile(const QString &filePath) const = 0;
|
||||
virtual QStringList allowedPaths(const QStringList &filePaths) const = 0;
|
||||
virtual QList<ContentFile> getContentFiles(const QStringList &filePaths) const = 0;
|
||||
virtual QStringList getProjectSourceFiles(ProjectExplorer::Project *project) const = 0;
|
||||
virtual ContentFile createContentFile(const QString &filePath) const = 0;
|
||||
|
||||
@@ -1,166 +0,0 @@
|
||||
// Copyright (C) 2025-2026 Petr Mironychev
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
// Additional attribution terms under GPLv3 §7(b) apply — see LICENSE
|
||||
|
||||
#include "context/RulesLoader.hpp"
|
||||
|
||||
#include <QDir>
|
||||
#include <QFile>
|
||||
|
||||
#include <coreplugin/editormanager/editormanager.h>
|
||||
#include <projectexplorer/project.h>
|
||||
#include <projectexplorer/projectmanager.h>
|
||||
|
||||
namespace QodeAssist::Context {
|
||||
|
||||
QString RulesLoader::loadRules(const QString &projectPath, RulesContext context)
|
||||
{
|
||||
if (projectPath.isEmpty()) {
|
||||
return QString();
|
||||
}
|
||||
|
||||
QString combined;
|
||||
QString basePath = projectPath + "/.qodeassist/rules";
|
||||
|
||||
switch (context) {
|
||||
case RulesContext::Completions:
|
||||
combined += loadAllMarkdownFiles(basePath + "/completions");
|
||||
break;
|
||||
case RulesContext::Chat:
|
||||
combined += loadAllMarkdownFiles(basePath + "/common");
|
||||
combined += loadAllMarkdownFiles(basePath + "/chat");
|
||||
break;
|
||||
case RulesContext::QuickRefactor:
|
||||
combined += loadAllMarkdownFiles(basePath + "/common");
|
||||
combined += loadAllMarkdownFiles(basePath + "/quickrefactor");
|
||||
break;
|
||||
}
|
||||
|
||||
return combined;
|
||||
}
|
||||
|
||||
QString RulesLoader::loadRulesForProject(ProjectExplorer::Project *project, RulesContext context)
|
||||
{
|
||||
if (!project) {
|
||||
return QString();
|
||||
}
|
||||
|
||||
QString projectPath = getProjectPath(project);
|
||||
return loadRules(projectPath, context);
|
||||
}
|
||||
|
||||
ProjectExplorer::Project *RulesLoader::getActiveProject()
|
||||
{
|
||||
auto currentEditor = Core::EditorManager::currentEditor();
|
||||
if (currentEditor && currentEditor->document()) {
|
||||
Utils::FilePath filePath = currentEditor->document()->filePath();
|
||||
auto project = ProjectExplorer::ProjectManager::projectForFile(filePath);
|
||||
if (project) {
|
||||
return project;
|
||||
}
|
||||
}
|
||||
|
||||
return ProjectExplorer::ProjectManager::startupProject();
|
||||
}
|
||||
|
||||
QString RulesLoader::loadAllMarkdownFiles(const QString &dirPath)
|
||||
{
|
||||
QString combined;
|
||||
QDir dir(dirPath);
|
||||
|
||||
if (!dir.exists()) {
|
||||
return QString();
|
||||
}
|
||||
|
||||
QStringList mdFiles = dir.entryList({"*.md"}, QDir::Files, QDir::Name);
|
||||
|
||||
for (const QString &fileName : mdFiles) {
|
||||
QFile file(dir.filePath(fileName));
|
||||
if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
||||
combined += file.readAll();
|
||||
combined += "\n\n";
|
||||
}
|
||||
}
|
||||
|
||||
return combined;
|
||||
}
|
||||
|
||||
QString RulesLoader::getProjectPath(ProjectExplorer::Project *project)
|
||||
{
|
||||
if (!project) {
|
||||
return QString();
|
||||
}
|
||||
|
||||
return project->projectDirectory().toUrlishString();
|
||||
}
|
||||
|
||||
QVector<RuleFileInfo> RulesLoader::getRuleFiles(const QString &projectPath, RulesContext context)
|
||||
{
|
||||
if (projectPath.isEmpty()) {
|
||||
return QVector<RuleFileInfo>();
|
||||
}
|
||||
|
||||
QVector<RuleFileInfo> result;
|
||||
QString basePath = projectPath + "/.qodeassist/rules";
|
||||
|
||||
// Always include common rules
|
||||
result.append(collectMarkdownFiles(basePath + "/common", "common"));
|
||||
|
||||
// Add context-specific rules
|
||||
switch (context) {
|
||||
case RulesContext::Completions:
|
||||
result.append(collectMarkdownFiles(basePath + "/completions", "completions"));
|
||||
break;
|
||||
case RulesContext::Chat:
|
||||
result.append(collectMarkdownFiles(basePath + "/chat", "chat"));
|
||||
break;
|
||||
case RulesContext::QuickRefactor:
|
||||
result.append(collectMarkdownFiles(basePath + "/quickrefactor", "quickrefactor"));
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
QVector<RuleFileInfo> RulesLoader::getRuleFilesForProject(
|
||||
ProjectExplorer::Project *project, RulesContext context)
|
||||
{
|
||||
if (!project) {
|
||||
return QVector<RuleFileInfo>();
|
||||
}
|
||||
|
||||
QString projectPath = getProjectPath(project);
|
||||
return getRuleFiles(projectPath, context);
|
||||
}
|
||||
|
||||
QString RulesLoader::loadRuleFileContent(const QString &filePath)
|
||||
{
|
||||
QFile file(filePath);
|
||||
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
||||
return QString();
|
||||
}
|
||||
|
||||
return file.readAll();
|
||||
}
|
||||
|
||||
QVector<RuleFileInfo> RulesLoader::collectMarkdownFiles(
|
||||
const QString &dirPath, const QString &category)
|
||||
{
|
||||
QVector<RuleFileInfo> result;
|
||||
QDir dir(dirPath);
|
||||
|
||||
if (!dir.exists()) {
|
||||
return result;
|
||||
}
|
||||
|
||||
QStringList mdFiles = dir.entryList({"*.md"}, QDir::Files, QDir::Name);
|
||||
|
||||
for (const QString &fileName : mdFiles) {
|
||||
QString fullPath = dir.filePath(fileName);
|
||||
result.append({fullPath, fileName, category});
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace QodeAssist::Context
|
||||
@@ -1,42 +0,0 @@
|
||||
// Copyright (C) 2025-2026 Petr Mironychev
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
// Additional attribution terms under GPLv3 §7(b) apply — see LICENSE
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QString>
|
||||
|
||||
namespace ProjectExplorer {
|
||||
class Project;
|
||||
}
|
||||
|
||||
namespace QodeAssist::Context {
|
||||
|
||||
enum class RulesContext { Completions, Chat, QuickRefactor };
|
||||
|
||||
struct RuleFileInfo
|
||||
{
|
||||
QString filePath;
|
||||
QString fileName;
|
||||
QString category; // "common", "chat", "completions", "quickrefactor"
|
||||
};
|
||||
|
||||
class RulesLoader
|
||||
{
|
||||
public:
|
||||
static QString loadRules(const QString &projectPath, RulesContext context);
|
||||
static QString loadRulesForProject(ProjectExplorer::Project *project, RulesContext context);
|
||||
static ProjectExplorer::Project *getActiveProject();
|
||||
|
||||
// New methods for getting rule files info
|
||||
static QVector<RuleFileInfo> getRuleFiles(const QString &projectPath, RulesContext context);
|
||||
static QVector<RuleFileInfo> getRuleFilesForProject(ProjectExplorer::Project *project, RulesContext context);
|
||||
static QString loadRuleFileContent(const QString &filePath);
|
||||
|
||||
private:
|
||||
static QString loadAllMarkdownFiles(const QString &dirPath);
|
||||
static QVector<RuleFileInfo> collectMarkdownFiles(const QString &dirPath, const QString &category);
|
||||
static QString getProjectPath(ProjectExplorer::Project *project);
|
||||
};
|
||||
|
||||
} // namespace QodeAssist::Context
|
||||
Reference in New Issue
Block a user