From 9bcbaca9a1758c58f232ef41cddf1e56f110acaf Mon Sep 17 00:00:00 2001 From: David Schulz Date: Fri, 6 Sep 2024 14:39:13 +0200 Subject: [PATCH] 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 --- src/plugins/projectexplorer/treescanner.cpp | 25 ++++++++++++------ src/plugins/projectexplorer/treescanner.h | 8 +++--- .../projectexplorer/workspaceproject.cpp | 26 +++++-------------- 3 files changed, 27 insertions(+), 32 deletions(-) diff --git a/src/plugins/projectexplorer/treescanner.cpp b/src/plugins/projectexplorer/treescanner.cpp index 42fab5d0bad..369f2b56523 100644 --- a/src/plugins/projectexplorer/treescanner.cpp +++ b/src/plugins/projectexplorer/treescanner.cpp @@ -54,7 +54,7 @@ bool TreeScanner::asyncScanForFiles(const Utils::FilePath &directory) return true; } -void TreeScanner::setFilter(TreeScanner::FileFilter filter) +void TreeScanner::setFilter(TreeScanner::Filter filter) { if (isFinished()) m_filter = filter; @@ -182,10 +182,17 @@ static DirectoryScanResult scanForFilesImpl( return result; } +static const Utils::MimeType &directoryMimeType() +{ + static const Utils::MimeType mimeType = Utils::mimeTypeForName("inode/directory"); + return mimeType; +} + static QList scanForFilesHelper( TreeScanner::Promise &promise, const Utils::FilePath &directory, - QDir::Filters filter, + QDir::Filters dirfilter, + const TreeScanner::Filter &filter, const std::function &factory) { const QFuture future(promise.future()); @@ -195,7 +202,7 @@ static QList scanForFilesHelper( promise.setProgressRange(0, progressRange); QSet visited; - const DirectoryScanResult result = scanForFilesImpl(future, directory, filter, factory, versionControls); + const DirectoryScanResult result = scanForFilesImpl(future, directory, dirfilter, factory, versionControls); QList fileNodes = result.nodes; const int progressIncrement = int( progressRange / static_cast(fileNodes.count() + result.subDirectories.count())); @@ -203,10 +210,12 @@ static QList scanForFilesHelper( QList> subDirectories; auto addSubDirectories = [&](const Utils::FilePaths &subdirs, int progressIncrement) { 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)); - else + } else { promise.setProgressValue(future.progressValue() + progressIncrement); + } } }; addSubDirectories(result.subDirectories, progressIncrement); @@ -218,7 +227,7 @@ static QList scanForFilesHelper( auto onSetup = [&, iterator](Utils::Async &task) { task.setConcurrentCallData( - scanForFilesImpl, future, iterator->first, filter, factory, versionControls); + scanForFilesImpl, future, iterator->first, dirfilter, factory, versionControls); }; auto onDone = [&, iterator](const Utils::Async &task) { @@ -250,12 +259,12 @@ static QList scanForFilesHelper( void TreeScanner::scanForFiles( Promise &promise, const Utils::FilePath &directory, - const FileFilter &filter, + const Filter &filter, QDir::Filters dirFilter, const FileTypeFactory &factory) { QList 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); // Skip some files during scan. diff --git a/src/plugins/projectexplorer/treescanner.h b/src/plugins/projectexplorer/treescanner.h index bc4dbe0b069..ca98b2a1e26 100644 --- a/src/plugins/projectexplorer/treescanner.h +++ b/src/plugins/projectexplorer/treescanner.h @@ -33,7 +33,7 @@ public: using FutureWatcher = QFutureWatcher; using Promise = QPromise; - using FileFilter = std::function; + using Filter = std::function; using FileTypeFactory = std::function; explicit TreeScanner(QObject *parent = nullptr); @@ -43,7 +43,7 @@ public: bool asyncScanForFiles(const Utils::FilePath& directory); // Setup filter for ignored files - void setFilter(FileFilter filter); + void setFilter(Filter filter); // Setup dir filters for scanned folders void setDirFilter(QDir::Filters dirFilter); @@ -74,12 +74,12 @@ signals: private: static void scanForFiles(Promise &fi, const Utils::FilePath &directory, - const FileFilter &filter, + const Filter &filter, QDir::Filters dirFilter, const FileTypeFactory &factory); private: - FileFilter m_filter; + Filter m_filter; QDir::Filters m_dirFilter = QDir::AllEntries | QDir::NoDotAndDotDot; FileTypeFactory m_factory; diff --git a/src/plugins/projectexplorer/workspaceproject.cpp b/src/plugins/projectexplorer/workspaceproject.cpp index fc1925b97dc..7510c3246a8 100644 --- a/src/plugins/projectexplorer/workspaceproject.cpp +++ b/src/plugins/projectexplorer/workspaceproject.cpp @@ -49,18 +49,6 @@ const expected_str projectDefinition(const Project *project) 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 { public: @@ -71,15 +59,10 @@ public: auto root = std::make_unique(projectDirectory()); root->setDisplayName(target()->project()->displayName()); std::vector> nodePtrs - = Utils::transform(m_scanner.release().allFiles, [this](FileNode *fn) { - fn->setEnabled(!Utils::anyOf( - m_filters, [path = fn->path().path()](const QRegularExpression &filter) { - return filter.match(path).hasMatch(); - })); + = Utils::transform(m_scanner.release().allFiles, [](FileNode *fn) { return std::unique_ptr(fn); }); root->addNestedNodes(std::move(nodePtrs)); - root->forEachFolderNode(&checkEnabled); setRootProjectNode(std::move(root)); m_parseGuard.markAsSuccess(); @@ -88,6 +71,11 @@ public: emitBuildSystemUpdated(); }); 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(), &Project::projectFileIsDirty, @@ -110,8 +98,6 @@ public: for (const QJsonValue &excludeJson : excludesJson) { if (excludeJson.isString()) { FilePath absolute = projectPath.pathAppended(excludeJson.toString()); - if (absolute.isDir()) - absolute = absolute.pathAppended("*"); m_filters << QRegularExpression( Utils::wildcardToRegularExpression(absolute.path()), QRegularExpression::CaseInsensitiveOption);