forked from qt-creator/qt-creator
CMake: Only start parsing when creator gets focus again
Rip out QFileSystemWatcher and use Qt Creators IDocument for file watching instead. The latter properly delays any action till creator gets focus again. Task-number: QTCREATORBUG-16354 Change-Id: Ibb71963416b09712a80ee95347425550453b7fd4 Reviewed-by: Tim Jenssen <tim.jenssen@theqtcompany.com>
This commit is contained in:
@@ -49,7 +49,6 @@
|
|||||||
#include <QDateTime>
|
#include <QDateTime>
|
||||||
#include <QFile>
|
#include <QFile>
|
||||||
#include <QFileInfo>
|
#include <QFileInfo>
|
||||||
#include <QFileSystemWatcher>
|
|
||||||
#include <QMessageBox>
|
#include <QMessageBox>
|
||||||
#include <QRegularExpression>
|
#include <QRegularExpression>
|
||||||
#include <QSet>
|
#include <QSet>
|
||||||
@@ -97,26 +96,14 @@ static QStringList toArguments(const CMakeConfig &config, const ProjectExplorer:
|
|||||||
// --------------------------------------------------------------------
|
// --------------------------------------------------------------------
|
||||||
|
|
||||||
BuildDirManager::BuildDirManager(CMakeBuildConfiguration *bc) :
|
BuildDirManager::BuildDirManager(CMakeBuildConfiguration *bc) :
|
||||||
m_buildConfiguration(bc),
|
m_buildConfiguration(bc)
|
||||||
m_watcher(new QFileSystemWatcher(this))
|
|
||||||
{
|
{
|
||||||
QTC_ASSERT(bc, return);
|
QTC_ASSERT(bc, return);
|
||||||
m_projectName = sourceDirectory().fileName();
|
m_projectName = sourceDirectory().fileName();
|
||||||
|
|
||||||
m_reparseTimer.setSingleShot(true);
|
m_reparseTimer.setSingleShot(true);
|
||||||
m_reparseTimer.setInterval(5000);
|
m_reparseTimer.setInterval(2000);
|
||||||
connect(&m_reparseTimer, &QTimer::timeout, this, &BuildDirManager::parse);
|
connect(&m_reparseTimer, &QTimer::timeout, this, &BuildDirManager::parse);
|
||||||
|
|
||||||
connect(m_watcher, &QFileSystemWatcher::fileChanged, this, [this]() {
|
|
||||||
if (isParsing())
|
|
||||||
return;
|
|
||||||
|
|
||||||
const CMakeTool *tool = CMakeKitInformation::cmakeTool(m_buildConfiguration->target()->kit());
|
|
||||||
if (!tool->isAutoRun())
|
|
||||||
return;
|
|
||||||
|
|
||||||
m_reparseTimer.start();
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
BuildDirManager::~BuildDirManager()
|
BuildDirManager::~BuildDirManager()
|
||||||
@@ -163,6 +150,18 @@ bool BuildDirManager::isParsing() const
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void BuildDirManager::cmakeFilesChanged()
|
||||||
|
{
|
||||||
|
if (isParsing())
|
||||||
|
return;
|
||||||
|
|
||||||
|
const CMakeTool *tool = CMakeKitInformation::cmakeTool(m_buildConfiguration->target()->kit());
|
||||||
|
if (!tool->isAutoRun())
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_reparseTimer.start();
|
||||||
|
}
|
||||||
|
|
||||||
void BuildDirManager::forceReparse()
|
void BuildDirManager::forceReparse()
|
||||||
{
|
{
|
||||||
if (m_buildConfiguration->target()->activeBuildConfiguration() != m_buildConfiguration)
|
if (m_buildConfiguration->target()->activeBuildConfiguration() != m_buildConfiguration)
|
||||||
@@ -186,13 +185,8 @@ void BuildDirManager::resetData()
|
|||||||
m_cmakeCache.clear();
|
m_cmakeCache.clear();
|
||||||
m_projectName.clear();
|
m_projectName.clear();
|
||||||
m_buildTargets.clear();
|
m_buildTargets.clear();
|
||||||
m_watchedFiles.clear();
|
|
||||||
qDeleteAll(m_files);
|
qDeleteAll(m_files);
|
||||||
m_files.clear();
|
m_files.clear();
|
||||||
|
|
||||||
const QStringList watchedFiles = m_watcher->files();
|
|
||||||
if (!watchedFiles.isEmpty())
|
|
||||||
m_watcher->removePaths(watchedFiles);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BuildDirManager::persistCMakeState()
|
bool BuildDirManager::persistCMakeState()
|
||||||
@@ -229,8 +223,8 @@ void BuildDirManager::parse()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const bool mustUpdate = m_watchedFiles.isEmpty()
|
const bool mustUpdate = m_cmakeFiles.isEmpty()
|
||||||
|| Utils::anyOf(m_watchedFiles, [&cbpFileFi](const Utils::FileName &f) {
|
|| Utils::anyOf(m_cmakeFiles, [&cbpFileFi](const Utils::FileName &f) {
|
||||||
return f.toFileInfo().lastModified() > cbpFileFi.lastModified();
|
return f.toFileInfo().lastModified() > cbpFileFi.lastModified();
|
||||||
});
|
});
|
||||||
if (mustUpdate) {
|
if (mustUpdate) {
|
||||||
@@ -257,11 +251,6 @@ void BuildDirManager::clearCache()
|
|||||||
forceReparse();
|
forceReparse();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BuildDirManager::isProjectFile(const Utils::FileName &fileName) const
|
|
||||||
{
|
|
||||||
return m_watchedFiles.contains(fileName);
|
|
||||||
}
|
|
||||||
|
|
||||||
QString BuildDirManager::projectName() const
|
QString BuildDirManager::projectName() const
|
||||||
{
|
{
|
||||||
return m_projectName;
|
return m_projectName;
|
||||||
@@ -277,6 +266,11 @@ QList<ProjectExplorer::FileNode *> BuildDirManager::files()
|
|||||||
return m_files;
|
return m_files;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QSet<Utils::FileName> BuildDirManager::cmakeFiles()
|
||||||
|
{
|
||||||
|
return m_cmakeFiles;
|
||||||
|
}
|
||||||
|
|
||||||
void BuildDirManager::clearFiles()
|
void BuildDirManager::clearFiles()
|
||||||
{
|
{
|
||||||
m_files.clear();
|
m_files.clear();
|
||||||
@@ -361,15 +355,19 @@ void BuildDirManager::extractData()
|
|||||||
|
|
||||||
m_projectName = sourceDirectory().fileName();
|
m_projectName = sourceDirectory().fileName();
|
||||||
m_files.append(new ProjectExplorer::FileNode(topCMake, ProjectExplorer::ProjectFileType, false));
|
m_files.append(new ProjectExplorer::FileNode(topCMake, ProjectExplorer::ProjectFileType, false));
|
||||||
m_watchedFiles.insert(topCMake);
|
// Do not insert topCMake into m_cmakeFiles: The project already watches that!
|
||||||
|
|
||||||
// Find cbp file
|
// Find cbp file
|
||||||
QString cbpFile = CMakeManager::findCbpFile(workDirectory().toString());
|
QString cbpFile = CMakeManager::findCbpFile(workDirectory().toString());
|
||||||
if (cbpFile.isEmpty())
|
if (cbpFile.isEmpty())
|
||||||
return;
|
return;
|
||||||
|
m_cmakeFiles.insert(Utils::FileName::fromString(cbpFile));
|
||||||
|
|
||||||
m_watcher->addPath(cbpFile);
|
// Add CMakeCache.txt file:
|
||||||
m_watcher->addPath(workDirectory().toString() + QLatin1String("/CMakeCache.txt"));
|
Utils::FileName cacheFile = workDirectory();
|
||||||
|
cacheFile.appendPath(QLatin1String("CMakeCache.txt"));
|
||||||
|
if (cacheFile.toFileInfo().exists())
|
||||||
|
m_cmakeFiles.insert(cacheFile);
|
||||||
|
|
||||||
// setFolderName
|
// setFolderName
|
||||||
CMakeCbpParser cbpparser;
|
CMakeCbpParser cbpparser;
|
||||||
@@ -380,21 +378,14 @@ void BuildDirManager::extractData()
|
|||||||
m_projectName = cbpparser.projectName();
|
m_projectName = cbpparser.projectName();
|
||||||
|
|
||||||
m_files = cbpparser.fileList();
|
m_files = cbpparser.fileList();
|
||||||
QSet<Utils::FileName> projectFiles;
|
|
||||||
if (cbpparser.hasCMakeFiles()) {
|
if (cbpparser.hasCMakeFiles()) {
|
||||||
m_files.append(cbpparser.cmakeFileList());
|
m_files.append(cbpparser.cmakeFileList());
|
||||||
foreach (const ProjectExplorer::FileNode *node, cbpparser.cmakeFileList())
|
foreach (const ProjectExplorer::FileNode *node, cbpparser.cmakeFileList())
|
||||||
projectFiles.insert(node->filePath());
|
m_cmakeFiles.insert(node->filePath());
|
||||||
} else {
|
} else {
|
||||||
m_files.append(new ProjectExplorer::FileNode(topCMake, ProjectExplorer::ProjectFileType, false));
|
m_files.append(new ProjectExplorer::FileNode(topCMake, ProjectExplorer::ProjectFileType, false));
|
||||||
projectFiles.insert(topCMake);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
m_watchedFiles = projectFiles;
|
|
||||||
const QStringList toWatch
|
|
||||||
= Utils::transform(m_watchedFiles.toList(), [](const Utils::FileName &fn) { return fn.toString(); });
|
|
||||||
m_watcher->addPaths(toWatch);
|
|
||||||
|
|
||||||
m_buildTargets = cbpparser.buildTargets();
|
m_buildTargets = cbpparser.buildTargets();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -73,6 +73,8 @@ public:
|
|||||||
const CMakeConfig intendedConfiguration() const;
|
const CMakeConfig intendedConfiguration() const;
|
||||||
bool isParsing() const;
|
bool isParsing() const;
|
||||||
|
|
||||||
|
void cmakeFilesChanged();
|
||||||
|
|
||||||
void parse();
|
void parse();
|
||||||
void clearCache();
|
void clearCache();
|
||||||
void forceReparse();
|
void forceReparse();
|
||||||
@@ -80,10 +82,10 @@ public:
|
|||||||
void resetData();
|
void resetData();
|
||||||
bool persistCMakeState();
|
bool persistCMakeState();
|
||||||
|
|
||||||
bool isProjectFile(const Utils::FileName &fileName) const;
|
|
||||||
QString projectName() const;
|
QString projectName() const;
|
||||||
QList<CMakeBuildTarget> buildTargets() const;
|
QList<CMakeBuildTarget> buildTargets() const;
|
||||||
QList<ProjectExplorer::FileNode *> files();
|
QList<ProjectExplorer::FileNode *> files();
|
||||||
|
QSet<Utils::FileName> cmakeFiles();
|
||||||
void clearFiles();
|
void clearFiles();
|
||||||
CMakeConfig parsedConfiguration() const;
|
CMakeConfig parsedConfiguration() const;
|
||||||
|
|
||||||
@@ -115,10 +117,9 @@ private:
|
|||||||
QTemporaryDir *m_tempDir = nullptr;
|
QTemporaryDir *m_tempDir = nullptr;
|
||||||
mutable CMakeConfig m_cmakeCache;
|
mutable CMakeConfig m_cmakeCache;
|
||||||
|
|
||||||
QSet<Utils::FileName> m_watchedFiles;
|
QSet<Utils::FileName> m_cmakeFiles;
|
||||||
QString m_projectName;
|
QString m_projectName;
|
||||||
QList<CMakeBuildTarget> m_buildTargets;
|
QList<CMakeBuildTarget> m_buildTargets;
|
||||||
QFileSystemWatcher *m_watcher;
|
|
||||||
QList<ProjectExplorer::FileNode *> m_files;
|
QList<ProjectExplorer::FileNode *> m_files;
|
||||||
|
|
||||||
// For error reporting:
|
// For error reporting:
|
||||||
|
@@ -71,6 +71,11 @@ CMakeBuildConfiguration::~CMakeBuildConfiguration()
|
|||||||
m_buildDirManager->deleteLater(); // Do not block while waiting for cmake...
|
m_buildDirManager->deleteLater(); // Do not block while waiting for cmake...
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CMakeBuildConfiguration::cmakeFilesChanged()
|
||||||
|
{
|
||||||
|
m_buildDirManager->cmakeFilesChanged();
|
||||||
|
}
|
||||||
|
|
||||||
bool CMakeBuildConfiguration::isEnabled() const
|
bool CMakeBuildConfiguration::isEnabled() const
|
||||||
{
|
{
|
||||||
return m_error.isEmpty();
|
return m_error.isEmpty();
|
||||||
|
@@ -52,6 +52,8 @@ public:
|
|||||||
CMakeBuildConfiguration(ProjectExplorer::Target *parent);
|
CMakeBuildConfiguration(ProjectExplorer::Target *parent);
|
||||||
~CMakeBuildConfiguration();
|
~CMakeBuildConfiguration();
|
||||||
|
|
||||||
|
void cmakeFilesChanged();
|
||||||
|
|
||||||
bool isEnabled() const override;
|
bool isEnabled() const override;
|
||||||
QString disabledReason() const override;
|
QString disabledReason() const override;
|
||||||
|
|
||||||
|
@@ -27,6 +27,8 @@
|
|||||||
#include "cmakeproject.h"
|
#include "cmakeproject.h"
|
||||||
#include "cmakeprojectconstants.h"
|
#include "cmakeprojectconstants.h"
|
||||||
|
|
||||||
|
#include <projectexplorer/target.h>
|
||||||
|
|
||||||
#include <utils/fileutils.h>
|
#include <utils/fileutils.h>
|
||||||
|
|
||||||
using namespace Utils;
|
using namespace Utils;
|
||||||
@@ -34,7 +36,7 @@ using namespace Utils;
|
|||||||
namespace CMakeProjectManager {
|
namespace CMakeProjectManager {
|
||||||
namespace Internal {
|
namespace Internal {
|
||||||
|
|
||||||
CMakeFile::CMakeFile(const FileName &fileName)
|
CMakeFile::CMakeFile(CMakeProject *project, const FileName &fileName) : m_project(project)
|
||||||
{
|
{
|
||||||
setId("Cmake.ProjectFile");
|
setId("Cmake.ProjectFile");
|
||||||
setMimeType(QLatin1String(Constants::CMAKEPROJECTMIMETYPE));
|
setMimeType(QLatin1String(Constants::CMAKEPROJECTMIMETYPE));
|
||||||
@@ -48,5 +50,15 @@ Core::IDocument::ReloadBehavior CMakeFile::reloadBehavior(ChangeTrigger state, C
|
|||||||
return BehaviorSilent;
|
return BehaviorSilent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CMakeFile::reload(QString *errorString, Core::IDocument::ReloadFlag flag, Core::IDocument::ChangeType type)
|
||||||
|
{
|
||||||
|
Q_UNUSED(errorString);
|
||||||
|
Q_UNUSED(flag);
|
||||||
|
|
||||||
|
if (type != TypePermissions)
|
||||||
|
m_project->handleCmakeFileChanged();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Internal
|
} // namespace Internal
|
||||||
} // namespace CMakeProjectManager
|
} // namespace CMakeProjectManager
|
||||||
|
@@ -35,9 +35,13 @@ namespace Internal {
|
|||||||
class CMakeFile : public Core::IDocument
|
class CMakeFile : public Core::IDocument
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CMakeFile(const Utils::FileName &fileName);
|
CMakeFile(CMakeProject *project, const Utils::FileName &fileName);
|
||||||
|
|
||||||
ReloadBehavior reloadBehavior(ChangeTrigger state, ChangeType type) const override;
|
ReloadBehavior reloadBehavior(ChangeTrigger state, ChangeType type) const override;
|
||||||
|
bool reload(QString *errorString, ReloadFlag flag, ChangeType type) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
CMakeProject *m_project;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Internal
|
} // namespace Internal
|
||||||
|
@@ -36,6 +36,7 @@
|
|||||||
#include "cmakeprojectmanager.h"
|
#include "cmakeprojectmanager.h"
|
||||||
|
|
||||||
#include <coreplugin/icore.h>
|
#include <coreplugin/icore.h>
|
||||||
|
#include <coreplugin/documentmanager.h>
|
||||||
#include <cpptools/cppmodelmanager.h>
|
#include <cpptools/cppmodelmanager.h>
|
||||||
#include <cpptools/projectinfo.h>
|
#include <cpptools/projectinfo.h>
|
||||||
#include <cpptools/projectpartbuilder.h>
|
#include <cpptools/projectpartbuilder.h>
|
||||||
@@ -88,11 +89,13 @@ CMakeProject::CMakeProject(CMakeManager *manager, const FileName &fileName)
|
|||||||
{
|
{
|
||||||
setId(Constants::CMAKEPROJECT_ID);
|
setId(Constants::CMAKEPROJECT_ID);
|
||||||
setProjectManager(manager);
|
setProjectManager(manager);
|
||||||
setDocument(new CMakeFile(fileName));
|
setDocument(new Internal::CMakeFile(this, fileName));
|
||||||
|
|
||||||
setRootProjectNode(new CMakeProjectNode(fileName));
|
setRootProjectNode(new CMakeProjectNode(fileName));
|
||||||
setProjectContext(Core::Context(CMakeProjectManager::Constants::PROJECTCONTEXT));
|
setProjectContext(Core::Context(CMakeProjectManager::Constants::PROJECTCONTEXT));
|
||||||
setProjectLanguages(Core::Context(ProjectExplorer::Constants::LANG_CXX));
|
setProjectLanguages(Core::Context(ProjectExplorer::Constants::LANG_CXX));
|
||||||
|
|
||||||
|
Core::DocumentManager::addDocument(document());
|
||||||
rootProjectNode()->setDisplayName(fileName.parentDir().fileName());
|
rootProjectNode()->setDisplayName(fileName.parentDir().fileName());
|
||||||
|
|
||||||
connect(this, &CMakeProject::activeTargetChanged, this, &CMakeProject::handleActiveTargetChanged);
|
connect(this, &CMakeProject::activeTargetChanged, this, &CMakeProject::handleActiveTargetChanged);
|
||||||
@@ -217,6 +220,29 @@ void CMakeProject::parseCMakeOutput()
|
|||||||
|
|
||||||
rootProjectNode()->setDisplayName(bdm->projectName());
|
rootProjectNode()->setDisplayName(bdm->projectName());
|
||||||
|
|
||||||
|
// Delete no longer necessary file watcher:
|
||||||
|
const QSet<Utils::FileName> currentWatched
|
||||||
|
= Utils::transform(m_watchedFiles, [](CMakeFile *cmf) { return cmf->filePath(); });
|
||||||
|
const QSet<Utils::FileName> toWatch = bdm->cmakeFiles();
|
||||||
|
QSet<Utils::FileName> toDelete = currentWatched;
|
||||||
|
toDelete.subtract(toWatch);
|
||||||
|
m_watchedFiles = Utils::filtered(m_watchedFiles, [&toDelete](Internal::CMakeFile *cmf) {
|
||||||
|
if (toDelete.contains(cmf->filePath())) {
|
||||||
|
delete cmf;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Add new file watchers:
|
||||||
|
QSet<Utils::FileName> toAdd = toWatch;
|
||||||
|
toAdd.subtract(currentWatched);
|
||||||
|
foreach (const Utils::FileName &fn, toAdd) {
|
||||||
|
CMakeFile *cm = new CMakeFile(this, fn);
|
||||||
|
Core::DocumentManager::addDocument(cm);
|
||||||
|
m_watchedFiles.insert(cm);
|
||||||
|
}
|
||||||
|
|
||||||
buildTree(static_cast<CMakeProjectNode *>(rootProjectNode()), bdm->files());
|
buildTree(static_cast<CMakeProjectNode *>(rootProjectNode()), bdm->files());
|
||||||
bdm->clearFiles(); // Some of the FileNodes in files() were deleted!
|
bdm->clearFiles(); // Some of the FileNodes in files() were deleted!
|
||||||
|
|
||||||
@@ -512,6 +538,15 @@ bool CMakeProject::setupTarget(Target *t)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CMakeProject::handleCmakeFileChanged()
|
||||||
|
{
|
||||||
|
if (Target *t = activeTarget()) {
|
||||||
|
if (auto bc = qobject_cast<CMakeBuildConfiguration *>(t->activeBuildConfiguration())) {
|
||||||
|
bc->cmakeFilesChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void CMakeProject::handleActiveTargetChanged()
|
void CMakeProject::handleActiveTargetChanged()
|
||||||
{
|
{
|
||||||
if (m_connectedTarget) {
|
if (m_connectedTarget) {
|
||||||
|
@@ -120,6 +120,8 @@ protected:
|
|||||||
bool setupTarget(ProjectExplorer::Target *t) override;
|
bool setupTarget(ProjectExplorer::Target *t) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void handleCmakeFileChanged();
|
||||||
|
|
||||||
void handleActiveTargetChanged();
|
void handleActiveTargetChanged();
|
||||||
void handleActiveBuildConfigurationChanged();
|
void handleActiveBuildConfigurationChanged();
|
||||||
void handleParsingStarted();
|
void handleParsingStarted();
|
||||||
@@ -144,7 +146,10 @@ private:
|
|||||||
QFuture<void> m_codeModelFuture;
|
QFuture<void> m_codeModelFuture;
|
||||||
QList<ProjectExplorer::ExtraCompiler *> m_extraCompilers;
|
QList<ProjectExplorer::ExtraCompiler *> m_extraCompilers;
|
||||||
|
|
||||||
|
QSet<Internal::CMakeFile *> m_watchedFiles;
|
||||||
|
|
||||||
friend class Internal::CMakeBuildConfiguration;
|
friend class Internal::CMakeBuildConfiguration;
|
||||||
|
friend class Internal::CMakeFile;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace CMakeProjectManager
|
} // namespace CMakeProjectManager
|
||||||
|
Reference in New Issue
Block a user