fix: Remove files and folder watches

This commit is contained in:
Petr Mironychev
2026-06-29 15:11:40 +02:00
parent d66c714a28
commit 86135d0c13
9 changed files with 23 additions and 111 deletions

View File

@@ -16,11 +16,9 @@
#include <utils/filepath.h> #include <utils/filepath.h>
#include <utils/theme/theme.h> #include <utils/theme/theme.h>
#include <QDateTime>
#include <QDesktopServices> #include <QDesktopServices>
#include <QDir> #include <QDir>
#include <QFile> #include <QFile>
#include <QFileSystemWatcher>
#include <QFont> #include <QFont>
#include <QFontMetrics> #include <QFontMetrics>
#include <QFrame> #include <QFrame>
@@ -153,26 +151,6 @@ public:
&AgentListPane::selectByName); &AgentListPane::selectByName);
} }
m_reloadDebounce = new QTimer(this);
m_reloadDebounce->setSingleShot(true);
m_reloadDebounce->setInterval(300);
connect(m_reloadDebounce, &QTimer::timeout, this, [this] {
constexpr qint64 kSelfWriteIgnoreMs = 1500;
if (QDateTime::currentMSecsSinceEpoch() - m_lastSelfWriteMs < kSelfWriteIgnoreMs) {
armWatcher();
return;
}
reloadFromDisk();
});
m_watcher = new QFileSystemWatcher(this);
connect(m_watcher, &QFileSystemWatcher::directoryChanged, this, [this](const QString &) {
m_reloadDebounce->start();
});
connect(m_watcher, &QFileSystemWatcher::fileChanged, this, [this](const QString &) {
m_reloadDebounce->start();
});
reloadFromDisk(); reloadFromDisk();
if (m_navigator) { if (m_navigator) {
@@ -194,21 +172,6 @@ private:
m_agentFactory->reload(); m_agentFactory->reload();
updateUserPathLabel(); updateUserPathLabel();
m_listPane->refresh(); m_listPane->refresh();
armWatcher();
}
void armWatcher()
{
if (!m_watcher)
return;
const QStringList watched = m_watcher->files() + m_watcher->directories();
if (!watched.isEmpty())
m_watcher->removePaths(watched);
const QString dir = QodeAssist::AgentFactory::userAgentsDir();
m_watcher->addPath(dir);
const QDir userDir(dir);
for (const QString &f : userDir.entryList({QStringLiteral("*.toml")}, QDir::Files))
m_watcher->addPath(userDir.filePath(f));
} }
void updateUserPathLabel() void updateUserPathLabel()
@@ -246,7 +209,6 @@ private:
void customizeAgent(const AgentConfig &parent) void customizeAgent(const AgentConfig &parent)
{ {
m_lastSelfWriteMs = QDateTime::currentMSecsSinceEpoch();
const AgentDuplicateResult res = duplicateAgentInUserDir(parent, *m_agentFactory); const AgentDuplicateResult res = duplicateAgentInUserDir(parent, *m_agentFactory);
if (!res.ok) { if (!res.ok) {
QMessageBox::warning(this, tr("Duplicate"), res.error); QMessageBox::warning(this, tr("Duplicate"), res.error);
@@ -272,7 +234,6 @@ private:
QMessageBox::No) QMessageBox::No)
!= QMessageBox::Yes) != QMessageBox::Yes)
return; return;
m_lastSelfWriteMs = QDateTime::currentMSecsSinceEpoch();
if (!QFile::remove(sourcePath)) { if (!QFile::remove(sourcePath)) {
QMessageBox::warning( QMessageBox::warning(
this, this,
@@ -296,9 +257,6 @@ private:
AgentListPane *m_listPane = nullptr; AgentListPane *m_listPane = nullptr;
QScrollArea *m_detailScroll = nullptr; QScrollArea *m_detailScroll = nullptr;
AgentDetailPane *m_detail = nullptr; AgentDetailPane *m_detail = nullptr;
QFileSystemWatcher *m_watcher = nullptr;
QTimer *m_reloadDebounce = nullptr;
qint64 m_lastSelfWriteMs = 0;
}; };
class AgentsSettingsPage : public Core::IOptionsPage class AgentsSettingsPage : public Core::IOptionsPage

View File

@@ -11,6 +11,7 @@
#include <QLabel> #include <QLabel>
#include <QListWidget> #include <QListWidget>
#include <QPushButton>
#include "ProjectSettings.hpp" #include "ProjectSettings.hpp"
#include "SettingsConstants.hpp" #include "SettingsConstants.hpp"
@@ -90,6 +91,9 @@ static ProjectSettingsWidget *createProjectPanel(Project *project)
QObject::connect( QObject::connect(
&settings->projectSkillDirs, &Utils::BaseAspect::changed, skillsList, refreshSkills); &settings->projectSkillDirs, &Utils::BaseAspect::changed, skillsList, refreshSkills);
auto *reloadSkillsButton = new QPushButton(Tr::tr("Reload"));
QObject::connect(reloadSkillsButton, &QPushButton::clicked, skillsList, refreshSkills);
Column{ Column{
generalWidget, generalWidget,
Space{8}, Space{8},
@@ -97,7 +101,7 @@ static ProjectSettingsWidget *createProjectPanel(Project *project)
title(Tr::tr("Skills")), title(Tr::tr("Skills")),
Column{ Column{
settings->projectSkillDirs, settings->projectSkillDirs,
new QLabel(Tr::tr("Discovered project skills:")), Row{new QLabel(Tr::tr("Discovered project skills:")), st, reloadSkillsButton},
skillsList, skillsList,
}, },
}, },

View File

@@ -86,6 +86,13 @@ public:
headerRow->setSpacing(8); headerRow->setSpacing(8);
headerRow->addWidget(m_titleLabel, 1); headerRow->addWidget(m_titleLabel, 1);
auto *reloadButton = new QPushButton(tr("Reload from disk"), this);
connect(reloadButton, &QPushButton::clicked, this, [this] {
if (m_factory)
m_factory->reload();
});
headerRow->addWidget(reloadButton);
auto *headerSep = new QFrame(this); auto *headerSep = new QFrame(this);
headerSep->setFrameShape(QFrame::HLine); headerSep->setFrameShape(QFrame::HLine);
headerSep->setFrameShadow(QFrame::Sunken); headerSep->setFrameShadow(QFrame::Sunken);

View File

@@ -14,6 +14,14 @@
<file>openai_chat_responses.toml</file> <file>openai_chat_responses.toml</file>
<file>google_base_chat.toml</file> <file>google_base_chat.toml</file>
<file>google_chat.toml</file> <file>google_chat.toml</file>
<file>mistral_base_chat.toml</file>
<file>mistral_chat.toml</file>
<file>mistral_chat_reasoning.toml</file>
<file>mistral_compression.toml</file>
<file>mistral_quick_refactor.toml</file>
<file>codestral_base_fim.toml</file>
<file>codestral_completion_fim.toml</file>
<file>mistral_completion_codestral_fim.toml</file>
<file>ollama_base_chat.toml</file> <file>ollama_base_chat.toml</file>
<file>ollama_chat_simple.toml</file> <file>ollama_chat_simple.toml</file>
<file>ollama_chat_thinking.toml</file> <file>ollama_chat_thinking.toml</file>

View File

@@ -5,12 +5,9 @@
#include "ProviderInstanceFactory.hpp" #include "ProviderInstanceFactory.hpp"
#include <QDir> #include <QDir>
#include <QFileInfo>
#include <QFileSystemWatcher>
#include <QLoggingCategory> #include <QLoggingCategory>
#include <QSet> #include <QSet>
#include <QThread> #include <QThread>
#include <QTimer>
#include <coreplugin/icore.h> #include <coreplugin/icore.h>
@@ -39,15 +36,6 @@ ProviderInstanceFactory::ProviderInstanceFactory(QObject *parent)
{ {
::initProviderInstancesResource(); ::initProviderInstancesResource();
m_watcher = new QFileSystemWatcher(this);
m_reloadDebounce = new QTimer(this);
m_reloadDebounce->setSingleShot(true);
m_reloadDebounce->setInterval(150);
connect(m_reloadDebounce, &QTimer::timeout, this, [this] { reload(); });
auto kick = [this](const QString &) { m_reloadDebounce->start(); };
connect(m_watcher, &QFileSystemWatcher::fileChanged, this, kick);
connect(m_watcher, &QFileSystemWatcher::directoryChanged, this, kick);
reload(); reload();
} }
@@ -65,6 +53,7 @@ void ProviderInstanceFactory::reload()
Q_FUNC_INFO, "ProviderInstanceFactory must be used from its owner thread"); Q_FUNC_INFO, "ProviderInstanceFactory must be used from its owner thread");
clear(); clear();
QDir().mkpath(userInstancesDir());
auto result = ProviderInstanceLoader::load(instanceQrcPrefix(), userInstancesDir()); auto result = ProviderInstanceLoader::load(instanceQrcPrefix(), userInstancesDir());
for (const QString &err : result.errors) for (const QString &err : result.errors)
LOG_MESSAGE(QString("[ProviderInstances] error: %1").arg(err)); LOG_MESSAGE(QString("[ProviderInstances] error: %1").arg(err));
@@ -83,7 +72,6 @@ void ProviderInstanceFactory::reload()
m_warnings = std::move(result.warnings); m_warnings = std::move(result.warnings);
rebuildIndexes(); rebuildIndexes();
rewatchUserDir();
emit instancesReloaded(); emit instancesReloaded();
} }
@@ -113,23 +101,6 @@ void ProviderInstanceFactory::rebuildIndexes()
}); });
} }
void ProviderInstanceFactory::rewatchUserDir()
{
if (!m_watcher)
return;
const QStringList stale = m_watcher->files() + m_watcher->directories();
if (!stale.isEmpty())
m_watcher->removePaths(stale);
const QString userDir = userInstancesDir();
QDir().mkpath(userDir);
m_watcher->addPath(userDir);
QDir d(userDir);
for (const QFileInfo &fi : d.entryInfoList({"*.toml"}, QDir::Files))
m_watcher->addPath(fi.absoluteFilePath());
}
const ProviderInstance *ProviderInstanceFactory::instanceByName(const QString &name) const const ProviderInstance *ProviderInstanceFactory::instanceByName(const QString &name) const
{ {
const auto it = m_nameIndex.constFind(name.toCaseFolded()); const auto it = m_nameIndex.constFind(name.toCaseFolded());

View File

@@ -13,9 +13,6 @@
#include "ProviderInstance.hpp" #include "ProviderInstance.hpp"
class QFileSystemWatcher;
class QTimer;
namespace QodeAssist::Providers { namespace QodeAssist::Providers {
class ProviderInstanceFactory : public QObject class ProviderInstanceFactory : public QObject
@@ -47,7 +44,6 @@ signals:
void instancesReloaded(); void instancesReloaded();
private: private:
void rewatchUserDir();
void rebuildIndexes(); void rebuildIndexes();
std::vector<ProviderInstance> m_instances; std::vector<ProviderInstance> m_instances;
@@ -55,10 +51,6 @@ private:
QStringList m_knownClientApisCache; QStringList m_knownClientApisCache;
QStringList m_errors; QStringList m_errors;
QStringList m_warnings; QStringList m_warnings;
QFileSystemWatcher *m_watcher = nullptr;
QTimer *m_reloadDebounce = nullptr;
}; };
} // namespace QodeAssist::Providers } // namespace QodeAssist::Providers

View File

@@ -2,7 +2,7 @@ schema_version = 1
name = "Mistral AI" name = "Mistral AI"
client_api = "Mistral AI" client_api = "Mistral AI"
description = "Cloud (Mistral). Mistral chat/instruct models, incl. the Magistral reasoning model. For Mistral's FIM code model, use Codestral." description = "Cloud (Mistral). Mistral chat/instruct models, the Magistral reasoning model, and the Codestral code model — including native FIM via /v1/fim/completions. The dedicated Codestral provider (codestral.mistral.ai) has its own key and endpoint."
url = "https://api.mistral.ai" url = "https://api.mistral.ai"
api_key_ref = "qodeassist/providers/Mistral AI" api_key_ref = "qodeassist/providers/Mistral AI"

View File

@@ -5,7 +5,6 @@
#include "SkillsManager.hpp" #include "SkillsManager.hpp"
#include <QDir> #include <QDir>
#include <QFileSystemWatcher>
#include "SkillsLoader.hpp" #include "SkillsLoader.hpp"
@@ -13,10 +12,7 @@ namespace QodeAssist::Skills {
SkillsManager::SkillsManager(QObject *parent) SkillsManager::SkillsManager(QObject *parent)
: QObject(parent) : QObject(parent)
, m_watcher(new QFileSystemWatcher(this)) {}
{
connect(m_watcher, &QFileSystemWatcher::directoryChanged, this, [this] { reload(); });
}
void SkillsManager::configure( void SkillsManager::configure(
const QString &projectPath, const QString &projectPath,
@@ -61,28 +57,9 @@ void SkillsManager::reload()
{ {
const QStringList roots = resolveRoots(m_projectPath, m_globalRoots, m_projectSubdirs); const QStringList roots = resolveRoots(m_projectPath, m_globalRoots, m_projectSubdirs);
m_skills = SkillsLoader::scan(roots); m_skills = SkillsLoader::scan(roots);
updateWatcher(roots);
emit skillsChanged(); emit skillsChanged();
} }
void SkillsManager::updateWatcher(const QStringList &roots)
{
const QStringList watched = m_watcher->directories();
if (!watched.isEmpty())
m_watcher->removePaths(watched);
QStringList toWatch;
for (const QString &root : roots) {
if (QDir(root).exists())
toWatch << root;
}
for (const AgentSkill &skill : m_skills)
toWatch << skill.skillDir;
if (!toWatch.isEmpty())
m_watcher->addPaths(toWatch);
}
QVector<AgentSkill> SkillsManager::skills() const QVector<AgentSkill> SkillsManager::skills() const
{ {
return m_skills; return m_skills;

View File

@@ -13,8 +13,6 @@
#include "AgentSkill.hpp" #include "AgentSkill.hpp"
class QFileSystemWatcher;
namespace QodeAssist::Skills { namespace QodeAssist::Skills {
class SkillsManager : public QObject class SkillsManager : public QObject
@@ -48,13 +46,10 @@ signals:
void skillsChanged(); void skillsChanged();
private: private:
void updateWatcher(const QStringList &roots);
QString m_projectPath; QString m_projectPath;
QStringList m_globalRoots; QStringList m_globalRoots;
QStringList m_projectSubdirs; QStringList m_projectSubdirs;
QVector<AgentSkill> m_skills; QVector<AgentSkill> m_skills;
QFileSystemWatcher *m_watcher = nullptr;
}; };
} // namespace QodeAssist::Skills } // namespace QodeAssist::Skills