forked from qt-creator/qt-creator
ProjectExplorer: allow to avoid scanning workspace subdirectories
In order to provide file watchers for the workspace project we need a way to completely exclude subdirectory of a workspace project. Otherwise we might end up with an unnecessary amount of notifications for quickly changing subdirectories like a build dir inside the workspace project. Use the previously available "files.exclude" and fully remove the entries of the project tree and avoid the scanning of the folders in that list. Change-Id: If11f62b1eabb4a7f03e4445e5f37068466feda4d Reviewed-by: Marcus Tillmanns <marcus.tillmanns@qt.io>
This commit is contained in:
@@ -54,7 +54,7 @@ bool TreeScanner::asyncScanForFiles(const Utils::FilePath &directory)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TreeScanner::setFilter(TreeScanner::FileFilter filter)
|
void TreeScanner::setFilter(TreeScanner::Filter filter)
|
||||||
{
|
{
|
||||||
if (isFinished())
|
if (isFinished())
|
||||||
m_filter = filter;
|
m_filter = filter;
|
||||||
@@ -182,10 +182,17 @@ static DirectoryScanResult scanForFilesImpl(
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const Utils::MimeType &directoryMimeType()
|
||||||
|
{
|
||||||
|
static const Utils::MimeType mimeType = Utils::mimeTypeForName("inode/directory");
|
||||||
|
return mimeType;
|
||||||
|
}
|
||||||
|
|
||||||
static QList<FileNode *> scanForFilesHelper(
|
static QList<FileNode *> scanForFilesHelper(
|
||||||
TreeScanner::Promise &promise,
|
TreeScanner::Promise &promise,
|
||||||
const Utils::FilePath &directory,
|
const Utils::FilePath &directory,
|
||||||
QDir::Filters filter,
|
QDir::Filters dirfilter,
|
||||||
|
const TreeScanner::Filter &filter,
|
||||||
const std::function<FileNode *(const Utils::FilePath &)> &factory)
|
const std::function<FileNode *(const Utils::FilePath &)> &factory)
|
||||||
{
|
{
|
||||||
const QFuture<void> future(promise.future());
|
const QFuture<void> future(promise.future());
|
||||||
@@ -195,7 +202,7 @@ static QList<FileNode *> scanForFilesHelper(
|
|||||||
promise.setProgressRange(0, progressRange);
|
promise.setProgressRange(0, progressRange);
|
||||||
|
|
||||||
QSet<Utils::FilePath> visited;
|
QSet<Utils::FilePath> visited;
|
||||||
const DirectoryScanResult result = scanForFilesImpl(future, directory, filter, factory, versionControls);
|
const DirectoryScanResult result = scanForFilesImpl(future, directory, dirfilter, factory, versionControls);
|
||||||
QList<FileNode *> fileNodes = result.nodes;
|
QList<FileNode *> fileNodes = result.nodes;
|
||||||
const int progressIncrement = int(
|
const int progressIncrement = int(
|
||||||
progressRange / static_cast<double>(fileNodes.count() + result.subDirectories.count()));
|
progressRange / static_cast<double>(fileNodes.count() + result.subDirectories.count()));
|
||||||
@@ -203,11 +210,13 @@ static QList<FileNode *> scanForFilesHelper(
|
|||||||
QList<QPair<Utils::FilePath, int>> subDirectories;
|
QList<QPair<Utils::FilePath, int>> subDirectories;
|
||||||
auto addSubDirectories = [&](const Utils::FilePaths &subdirs, int progressIncrement) {
|
auto addSubDirectories = [&](const Utils::FilePaths &subdirs, int progressIncrement) {
|
||||||
for (const Utils::FilePath &subdir : subdirs) {
|
for (const Utils::FilePath &subdir : subdirs) {
|
||||||
if (Utils::insert(visited, subdir.canonicalPath()))
|
if (Utils::insert(visited, subdir.canonicalPath())
|
||||||
|
&& !(filter && filter(directoryMimeType(), subdir))) {
|
||||||
subDirectories.append(qMakePair(subdir, progressIncrement));
|
subDirectories.append(qMakePair(subdir, progressIncrement));
|
||||||
else
|
} else {
|
||||||
promise.setProgressValue(future.progressValue() + progressIncrement);
|
promise.setProgressValue(future.progressValue() + progressIncrement);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
addSubDirectories(result.subDirectories, progressIncrement);
|
addSubDirectories(result.subDirectories, progressIncrement);
|
||||||
|
|
||||||
@@ -218,7 +227,7 @@ static QList<FileNode *> scanForFilesHelper(
|
|||||||
|
|
||||||
auto onSetup = [&, iterator](Utils::Async<DirectoryScanResult> &task) {
|
auto onSetup = [&, iterator](Utils::Async<DirectoryScanResult> &task) {
|
||||||
task.setConcurrentCallData(
|
task.setConcurrentCallData(
|
||||||
scanForFilesImpl, future, iterator->first, filter, factory, versionControls);
|
scanForFilesImpl, future, iterator->first, dirfilter, factory, versionControls);
|
||||||
};
|
};
|
||||||
|
|
||||||
auto onDone = [&, iterator](const Utils::Async<DirectoryScanResult> &task) {
|
auto onDone = [&, iterator](const Utils::Async<DirectoryScanResult> &task) {
|
||||||
@@ -250,12 +259,12 @@ static QList<FileNode *> scanForFilesHelper(
|
|||||||
void TreeScanner::scanForFiles(
|
void TreeScanner::scanForFiles(
|
||||||
Promise &promise,
|
Promise &promise,
|
||||||
const Utils::FilePath &directory,
|
const Utils::FilePath &directory,
|
||||||
const FileFilter &filter,
|
const Filter &filter,
|
||||||
QDir::Filters dirFilter,
|
QDir::Filters dirFilter,
|
||||||
const FileTypeFactory &factory)
|
const FileTypeFactory &factory)
|
||||||
{
|
{
|
||||||
QList<FileNode *> nodes = scanForFilesHelper(
|
QList<FileNode *> nodes = scanForFilesHelper(
|
||||||
promise, directory, dirFilter, [&filter, &factory](const Utils::FilePath &fn) -> FileNode * {
|
promise, directory, dirFilter, filter, [&filter, &factory](const Utils::FilePath &fn) -> FileNode * {
|
||||||
const Utils::MimeType mimeType = Utils::mimeTypesForFileName(fn.path()).value(0);
|
const Utils::MimeType mimeType = Utils::mimeTypesForFileName(fn.path()).value(0);
|
||||||
|
|
||||||
// Skip some files during scan.
|
// Skip some files during scan.
|
||||||
|
@@ -33,7 +33,7 @@ public:
|
|||||||
using FutureWatcher = QFutureWatcher<Result>;
|
using FutureWatcher = QFutureWatcher<Result>;
|
||||||
using Promise = QPromise<Result>;
|
using Promise = QPromise<Result>;
|
||||||
|
|
||||||
using FileFilter = std::function<bool(const Utils::MimeType &, const Utils::FilePath &)>;
|
using Filter = std::function<bool(const Utils::MimeType &, const Utils::FilePath &)>;
|
||||||
using FileTypeFactory = std::function<ProjectExplorer::FileType(const Utils::MimeType &, const Utils::FilePath &)>;
|
using FileTypeFactory = std::function<ProjectExplorer::FileType(const Utils::MimeType &, const Utils::FilePath &)>;
|
||||||
|
|
||||||
explicit TreeScanner(QObject *parent = nullptr);
|
explicit TreeScanner(QObject *parent = nullptr);
|
||||||
@@ -43,7 +43,7 @@ public:
|
|||||||
bool asyncScanForFiles(const Utils::FilePath& directory);
|
bool asyncScanForFiles(const Utils::FilePath& directory);
|
||||||
|
|
||||||
// Setup filter for ignored files
|
// Setup filter for ignored files
|
||||||
void setFilter(FileFilter filter);
|
void setFilter(Filter filter);
|
||||||
|
|
||||||
// Setup dir filters for scanned folders
|
// Setup dir filters for scanned folders
|
||||||
void setDirFilter(QDir::Filters dirFilter);
|
void setDirFilter(QDir::Filters dirFilter);
|
||||||
@@ -74,12 +74,12 @@ signals:
|
|||||||
private:
|
private:
|
||||||
static void scanForFiles(Promise &fi,
|
static void scanForFiles(Promise &fi,
|
||||||
const Utils::FilePath &directory,
|
const Utils::FilePath &directory,
|
||||||
const FileFilter &filter,
|
const Filter &filter,
|
||||||
QDir::Filters dirFilter,
|
QDir::Filters dirFilter,
|
||||||
const FileTypeFactory &factory);
|
const FileTypeFactory &factory);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
FileFilter m_filter;
|
Filter m_filter;
|
||||||
QDir::Filters m_dirFilter = QDir::AllEntries | QDir::NoDotAndDotDot;
|
QDir::Filters m_dirFilter = QDir::AllEntries | QDir::NoDotAndDotDot;
|
||||||
FileTypeFactory m_factory;
|
FileTypeFactory m_factory;
|
||||||
|
|
||||||
|
@@ -49,18 +49,6 @@ const expected_str<QJsonObject> projectDefinition(const Project *project)
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool checkEnabled(FolderNode *fn)
|
|
||||||
{
|
|
||||||
if (fn->findChildFileNode([](FileNode *fn) { return fn->isEnabled(); }))
|
|
||||||
return true;
|
|
||||||
|
|
||||||
if (fn->findChildFolderNode([](FolderNode *fn) { return checkEnabled(fn); }))
|
|
||||||
return true;
|
|
||||||
|
|
||||||
fn->setEnabled(false);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
class WorkspaceBuildSystem final : public BuildSystem
|
class WorkspaceBuildSystem final : public BuildSystem
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@@ -71,15 +59,10 @@ public:
|
|||||||
auto root = std::make_unique<ProjectNode>(projectDirectory());
|
auto root = std::make_unique<ProjectNode>(projectDirectory());
|
||||||
root->setDisplayName(target()->project()->displayName());
|
root->setDisplayName(target()->project()->displayName());
|
||||||
std::vector<std::unique_ptr<FileNode>> nodePtrs
|
std::vector<std::unique_ptr<FileNode>> nodePtrs
|
||||||
= Utils::transform<std::vector>(m_scanner.release().allFiles, [this](FileNode *fn) {
|
= Utils::transform<std::vector>(m_scanner.release().allFiles, [](FileNode *fn) {
|
||||||
fn->setEnabled(!Utils::anyOf(
|
|
||||||
m_filters, [path = fn->path().path()](const QRegularExpression &filter) {
|
|
||||||
return filter.match(path).hasMatch();
|
|
||||||
}));
|
|
||||||
return std::unique_ptr<FileNode>(fn);
|
return std::unique_ptr<FileNode>(fn);
|
||||||
});
|
});
|
||||||
root->addNestedNodes(std::move(nodePtrs));
|
root->addNestedNodes(std::move(nodePtrs));
|
||||||
root->forEachFolderNode(&checkEnabled);
|
|
||||||
setRootProjectNode(std::move(root));
|
setRootProjectNode(std::move(root));
|
||||||
|
|
||||||
m_parseGuard.markAsSuccess();
|
m_parseGuard.markAsSuccess();
|
||||||
@@ -88,6 +71,11 @@ public:
|
|||||||
emitBuildSystemUpdated();
|
emitBuildSystemUpdated();
|
||||||
});
|
});
|
||||||
m_scanner.setDirFilter(QDir::AllEntries | QDir::NoDotAndDotDot | QDir::Hidden);
|
m_scanner.setDirFilter(QDir::AllEntries | QDir::NoDotAndDotDot | QDir::Hidden);
|
||||||
|
m_scanner.setFilter([&](const Utils::MimeType &, const Utils::FilePath &filePath) {
|
||||||
|
return Utils::anyOf(m_filters, [filePath](const QRegularExpression &filter) {
|
||||||
|
return filter.match(filePath.path()).hasMatch();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
connect(target()->project(),
|
connect(target()->project(),
|
||||||
&Project::projectFileIsDirty,
|
&Project::projectFileIsDirty,
|
||||||
@@ -110,8 +98,6 @@ public:
|
|||||||
for (const QJsonValue &excludeJson : excludesJson) {
|
for (const QJsonValue &excludeJson : excludesJson) {
|
||||||
if (excludeJson.isString()) {
|
if (excludeJson.isString()) {
|
||||||
FilePath absolute = projectPath.pathAppended(excludeJson.toString());
|
FilePath absolute = projectPath.pathAppended(excludeJson.toString());
|
||||||
if (absolute.isDir())
|
|
||||||
absolute = absolute.pathAppended("*");
|
|
||||||
m_filters << QRegularExpression(
|
m_filters << QRegularExpression(
|
||||||
Utils::wildcardToRegularExpression(absolute.path()),
|
Utils::wildcardToRegularExpression(absolute.path()),
|
||||||
QRegularExpression::CaseInsensitiveOption);
|
QRegularExpression::CaseInsensitiveOption);
|
||||||
|
Reference in New Issue
Block a user