Nim: Introduce a NimBuildSystem

Change-Id: Ib9bdf52939c88f01fe861308d0c08b5c69efa624
Reviewed-by: Christian Kandeler <christian.kandeler@qt.io>
This commit is contained in:
Tobias Hunger
2019-08-19 12:31:25 +02:00
parent fb21b78444
commit 67349baded
12 changed files with 304 additions and 162 deletions

View File

@@ -8,6 +8,7 @@ add_qtc_plugin(Nim
nim.qrc
nimconstants.h
nimplugin.cpp nimplugin.h
project/nimbuildsystem.cpp project/nimbuildsystem.h
project/nimbuildconfiguration.cpp project/nimbuildconfiguration.h
project/nimcompilerbuildstep.cpp project/nimcompilerbuildstep.h
project/nimcompilerbuildstepconfigwidget.cpp project/nimcompilerbuildstepconfigwidget.h project/nimcompilerbuildstepconfigwidget.ui

View File

@@ -16,6 +16,7 @@ HEADERS += \
editor/nimindenter.h \
tools/nimlexer.h \
tools/sourcecodestream.h \
project/nimbuildsystem.h \
project/nimproject.h \
project/nimprojectnode.h \
project/nimbuildconfiguration.h \
@@ -45,6 +46,7 @@ SOURCES += \
editor/nimhighlighter.cpp \
editor/nimindenter.cpp \
tools/nimlexer.cpp \
project/nimbuildsystem.cpp \
project/nimproject.cpp \
project/nimprojectnode.cpp \
project/nimbuildconfiguration.cpp \

View File

@@ -36,6 +36,7 @@ QtcPlugin {
name: "Project"
prefix: "project/"
files: [
"nimbuildsystem.cpp", "nimbuildsystem.h",
"nimbuildconfiguration.h", "nimbuildconfiguration.cpp",
"nimcompilerbuildstep.h", "nimcompilerbuildstep.cpp",
"nimcompilerbuildstepconfigwidget.h", "nimcompilerbuildstepconfigwidget.cpp", "nimcompilerbuildstepconfigwidget.ui",

View File

@@ -24,9 +24,7 @@
****************************************************************************/
#include "nimbuildconfiguration.h"
#include "nimcompilerbuildstep.h"
#include "nimproject.h"
#include "nimbuildconfiguration.h"
#include "nimbuildsystem.h"
#include "nimcompilerbuildstep.h"
#include "nimproject.h"
@@ -80,12 +78,12 @@ void NimBuildConfiguration::initialize()
{
BuildConfiguration::initialize();
auto project = qobject_cast<NimProject *>(target()->project());
QTC_ASSERT(project, return);
auto bs = qobject_cast<NimBuildSystem *>(project()->buildSystem());
QTC_ASSERT(bs, return );
// Create the build configuration and initialize it from build info
setBuildDirectory(defaultBuildDirectory(target()->kit(),
project->projectFilePath(),
project()->projectFilePath(),
displayName(),
buildType()));
@@ -106,7 +104,7 @@ void NimBuildConfiguration::initialize()
break;
}
nimCompilerBuildStep->setDefaultCompilerOptions(defaultOption);
Utils::FilePathList nimFiles = project->nimFiles();
Utils::FilePathList nimFiles = bs->nimFiles();
if (!nimFiles.isEmpty())
nimCompilerBuildStep->setTargetNimFile(nimFiles.first());
buildSteps->appendStep(nimCompilerBuildStep);

View File

@@ -0,0 +1,177 @@
/****************************************************************************
**
** Copyright (C) Filippo Cucchetto <filippocucchetto@gmail.com>
** Contact: http://www.qt.io/licensing
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "nimbuildsystem.h"
#include "nimproject.h"
#include "nimprojectnode.h"
#include <utils/algorithm.h>
#include <utils/fileutils.h>
#include <utils/qtcassert.h>
#include <QVariantMap>
#if 0
#include "nimbuildconfiguration.h"
#include "nimtoolchain.h"
#include "../nimconstants.h"
#include <coreplugin/icontext.h>
#include <coreplugin/progressmanager/progressmanager.h>
#include <coreplugin/iversioncontrol.h>
#include <coreplugin/vcsmanager.h>
#include <projectexplorer/buildconfiguration.h>
#include <projectexplorer/kit.h>
#include <projectexplorer/projectexplorerconstants.h>
#include <projectexplorer/projectnodes.h>
#include <projectexplorer/target.h>
#include <projectexplorer/toolchain.h>
#include <projectexplorer/kitinformation.h>
#include <texteditor/textdocument.h>
#include <utils/runextensions.h>
#include <coreplugin/editormanager/editormanager.h>
#include <coreplugin/editormanager/ieditor.h>
#include <QFileInfo>
#include <QQueue>
#endif
using namespace ProjectExplorer;
using namespace Utils;
namespace Nim {
const char SETTINGS_KEY[] = "Nim.BuildSystem";
const char EXCLUDED_FILES_KEY[] = "ExcludedFiles";
NimBuildSystem::NimBuildSystem(Project *project)
: BuildSystem(project)
{
connect(project, &Project::settingsLoaded, this, &NimBuildSystem::loadSettings);
connect(project, &Project::aboutToSaveSettings, this, &NimBuildSystem::saveSettings);
connect(&m_scanner, &TreeScanner::finished, this, &NimBuildSystem::updateProject);
m_scanner.setFilter([this](const Utils::MimeType &, const Utils::FilePath &fp) {
const QString path = fp.toString();
return excludedFiles().contains(path) || path.endsWith(".nimproject")
|| path.contains(".nimproject.user");
});
connect(&m_directoryWatcher, &FileSystemWatcher::directoryChanged, this, [this]() {
requestParse();
});
}
bool NimBuildSystem::addFiles(const QStringList &filePaths)
{
m_excludedFiles = Utils::filtered(m_excludedFiles, [&](const QString & f) {
return !filePaths.contains(f);
});
requestParse();
return true;
}
bool NimBuildSystem::removeFiles(const QStringList &filePaths)
{
m_excludedFiles.append(filePaths);
m_excludedFiles = Utils::filteredUnique(m_excludedFiles);
requestParse();
return true;
}
bool NimBuildSystem::renameFile(const QString &filePath, const QString &newFilePath)
{
Q_UNUSED(filePath)
m_excludedFiles.removeOne(newFilePath);
requestParse();
return true;
}
void NimBuildSystem::setExcludedFiles(const QStringList &list)
{
m_excludedFiles = list;
}
QStringList NimBuildSystem::excludedFiles()
{
return m_excludedFiles;
}
void NimBuildSystem::parseProject(BuildSystem::ParsingContext &&ctx)
{
QTC_ASSERT(!m_currentContext.project, return );
m_currentContext = std::move(ctx);
QTC_CHECK(m_currentContext.project);
m_scanner.asyncScanForFiles(m_currentContext.project->projectDirectory());
}
const FilePathList NimBuildSystem::nimFiles() const
{
return project()->files(
[](const Node *n) { return Project::AllFiles(n) && n->path().endsWith(".nim"); });
}
void NimBuildSystem::loadSettings()
{
QVariantMap settings = project()->namedSettings(SETTINGS_KEY).toMap();
if (settings.contains(EXCLUDED_FILES_KEY))
m_excludedFiles = settings.value(EXCLUDED_FILES_KEY, m_excludedFiles).toStringList();
requestParse();
}
void NimBuildSystem::saveSettings()
{
QVariantMap settings;
settings.insert(EXCLUDED_FILES_KEY, m_excludedFiles);
project()->setNamedSettings(SETTINGS_KEY, settings);
}
void NimBuildSystem::updateProject()
{
auto newRoot = std::make_unique<NimProjectNode>(project()->projectDirectory());
QSet<QString> directories;
for (FileNode *node : m_scanner.release()) {
directories.insert(node->directory());
newRoot->addNestedNode(std::unique_ptr<FileNode>(node));
}
newRoot->setDisplayName(project()->displayName());
project()->setRootProjectNode(std::move(newRoot));
m_directoryWatcher.addDirectories(directories.toList(), FileSystemWatcher::WatchAllChanges);
m_currentContext.guard.markAsSuccess();
m_currentContext = {};
}
} // namespace Nim

View File

@@ -0,0 +1,69 @@
/****************************************************************************
**
** Copyright (C) Filippo Cucchetto <filippocucchetto@gmail.com>
** Contact: http://www.qt.io/licensing
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include <projectexplorer/buildsystem.h>
#include <projectexplorer/treescanner.h>
#include <utils/filesystemwatcher.h>
namespace Nim {
class NimBuildSystem : public ProjectExplorer::BuildSystem
{
Q_OBJECT
public:
explicit NimBuildSystem(ProjectExplorer::Project *project);
bool addFiles(const QStringList &filePaths);
bool removeFiles(const QStringList &filePaths);
bool renameFile(const QString &filePath, const QString &newFilePath);
void setExcludedFiles(const QStringList &list); // Keep for compatibility with Qt Creator 4.10
QStringList excludedFiles(); // Make private when no longer supporting Qt Creator 4.10
void parseProject(ParsingContext &&ctx) final;
const Utils::FilePathList nimFiles() const;
private:
void loadSettings();
void saveSettings();
void collectProjectFiles();
void updateProject();
QStringList m_excludedFiles;
ProjectExplorer::TreeScanner m_scanner;
ParsingContext m_currentContext;
Utils::FileSystemWatcher m_directoryWatcher;
};
} // namespace Nim

View File

@@ -25,9 +25,9 @@
#include "nimcompilerbuildstep.h"
#include "nimbuildconfiguration.h"
#include "nimconstants.h"
#include "nimbuildsystem.h"
#include "nimcompilerbuildstepconfigwidget.h"
#include "nimproject.h"
#include "nimconstants.h"
#include "nimtoolchain.h"
#include <projectexplorer/buildconfiguration.h>
@@ -271,7 +271,8 @@ void NimCompilerBuildStep::updateTargetNimFile()
{
if (!m_targetNimFile.isEmpty())
return;
const Utils::FilePathList nimFiles = static_cast<NimProject *>(project())->nimFiles();
const Utils::FilePathList nimFiles = static_cast<NimBuildSystem *>(project()->buildSystem())
->nimFiles();
if (!nimFiles.isEmpty())
setTargetNimFile(nimFiles.at(0));
}

View File

@@ -24,10 +24,11 @@
****************************************************************************/
#include "nimcompilerbuildstepconfigwidget.h"
#include "ui_nimcompilerbuildstepconfigwidget.h"
#include "nimbuildconfiguration.h"
#include "nimbuildsystem.h"
#include "nimcompilerbuildstep.h"
#include "nimproject.h"
#include "ui_nimcompilerbuildstepconfigwidget.h"
#include "../nimconstants.h"
@@ -52,9 +53,10 @@ NimCompilerBuildStepConfigWidget::NimCompilerBuildStepConfigWidget(NimCompilerBu
setSummaryText(tr(Constants::C_NIMCOMPILERBUILDSTEPWIDGET_SUMMARY));
// Connect the project signals
auto project = static_cast<NimProject *>(m_buildStep->project());
connect(project, &NimProject::fileListChanged,
this, &NimCompilerBuildStepConfigWidget::updateUi);
connect(m_buildStep->project(),
&Project::fileListChanged,
this,
&NimCompilerBuildStepConfigWidget::updateUi);
// Connect build step signals
connect(m_buildStep, &NimCompilerBuildStep::processParametersChanged,
@@ -114,12 +116,12 @@ void NimCompilerBuildStepConfigWidget::updateTargetComboBox()
{
QTC_ASSERT(m_buildStep, return );
auto project = qobject_cast<NimProject *>(m_buildStep->project());
QTC_ASSERT(project, return);
const auto bs = qobject_cast<NimBuildSystem *>(m_buildStep->project()->buildSystem());
QTC_ASSERT(bs, return );
// Re enter the files
m_ui->targetComboBox->clear();
foreach (const FilePath &file, project->nimFiles())
for (const FilePath &file : bs->nimFiles())
m_ui->targetComboBox->addItem(file.fileName(), file.toString());
const int index = m_ui->targetComboBox->findData(m_buildStep->targetNimFile().toString());

View File

@@ -24,42 +24,20 @@
****************************************************************************/
#include "nimproject.h"
#include "nimbuildconfiguration.h"
#include "nimprojectnode.h"
#include "nimtoolchain.h"
#include "../nimconstants.h"
#include "nimbuildsystem.h"
#include "nimtoolchain.h"
#include <coreplugin/icontext.h>
#include <coreplugin/progressmanager/progressmanager.h>
#include <coreplugin/iversioncontrol.h>
#include <coreplugin/vcsmanager.h>
#include <projectexplorer/buildconfiguration.h>
#include <projectexplorer/kit.h>
#include <projectexplorer/projectexplorerconstants.h>
#include <projectexplorer/projectnodes.h>
#include <projectexplorer/target.h>
#include <projectexplorer/toolchain.h>
#include <projectexplorer/kitinformation.h>
#include <texteditor/textdocument.h>
#include <utils/algorithm.h>
#include <utils/qtcassert.h>
#include <utils/runextensions.h>
#include <coreplugin/editormanager/editormanager.h>
#include <coreplugin/editormanager/ieditor.h>
#include <QFileInfo>
#include <QQueue>
#include <projectexplorer/projectexplorerconstants.h>
using namespace ProjectExplorer;
using namespace Utils;
namespace Nim {
const int MIN_TIME_BETWEEN_PROJECT_SCANS = 4500;
NimProject::NimProject(const FilePath &fileName) : Project(Constants::C_NIM_MIMETYPE, fileName)
{
setId(Constants::C_NIMPROJECT_ID);
@@ -67,87 +45,7 @@ NimProject::NimProject(const FilePath &fileName) : Project(Constants::C_NIM_MIME
// ensure debugging is enabled (Nim plugin translates nim code to C code)
setProjectLanguages(Core::Context(ProjectExplorer::Constants::CXX_LANGUAGE_ID));
m_projectScanTimer.setSingleShot(true);
connect(&m_projectScanTimer, &QTimer::timeout, this, &NimProject::collectProjectFiles);
connect(this, &Project::settingsLoaded, this, &NimProject::collectProjectFiles);
connect(&m_futureWatcher, &QFutureWatcher<QList<FileNode *>>::finished, this,
&NimProject::updateProject);
}
void NimProject::scheduleProjectScan()
{
auto elapsedTime = m_lastProjectScan.elapsed();
if (elapsedTime < MIN_TIME_BETWEEN_PROJECT_SCANS) {
if (!m_projectScanTimer.isActive()) {
m_projectScanTimer.setInterval(MIN_TIME_BETWEEN_PROJECT_SCANS - elapsedTime);
m_projectScanTimer.start();
}
} else {
collectProjectFiles();
}
}
bool NimProject::addFiles(const QStringList &filePaths)
{
m_excludedFiles = Utils::filtered(m_excludedFiles, [&](const QString & f) {
return !filePaths.contains(f);
});
scheduleProjectScan();
return true;
}
bool NimProject::removeFiles(const QStringList &filePaths)
{
m_excludedFiles.append(filePaths);
m_excludedFiles = Utils::filteredUnique(m_excludedFiles);
scheduleProjectScan();
return true;
}
bool NimProject::renameFile(const QString &filePath, const QString &newFilePath)
{
Q_UNUSED(filePath)
m_excludedFiles.removeOne(newFilePath);
scheduleProjectScan();
return true;
}
void NimProject::collectProjectFiles()
{
m_lastProjectScan.start();
QTC_ASSERT(!m_futureWatcher.future().isRunning(), return);
FilePath prjDir = projectDirectory();
QFuture<QList<ProjectExplorer::FileNode *>> future = Utils::runAsync([prjDir,
excluded = m_excludedFiles] {
return FileNode::scanForFiles(prjDir, [excluded](const FilePath & fn) -> FileNode * {
const QString fileName = fn.fileName();
if (excluded.contains(fn.toString())
|| fileName.endsWith(".nimproject", HostOsInfo::fileNameCaseSensitivity())
|| fileName.contains(".nimproject.user", HostOsInfo::fileNameCaseSensitivity()))
return nullptr;
return new FileNode(fn, FileType::Source);
});
});
m_futureWatcher.setFuture(future);
Core::ProgressManager::addTask(future, tr("Scanning for Nim files"), "Nim.Project.Scan");
}
void NimProject::updateProject()
{
ParseGuard guard = guardParsingRun();
auto newRoot = std::make_unique<NimProjectNode>(*this, projectDirectory());
QList<FileNode *> files = m_futureWatcher.future().result();
for (FileNode *node : files)
newRoot->addNestedNode(std::unique_ptr<FileNode>(node));
newRoot->setDisplayName(displayName());
setRootProjectNode(std::move(newRoot));
guard.markAsSuccess();
setBuildSystem(std::make_unique<NimBuildSystem>(this));
}
Tasks NimProject::projectIssues(const Kit *k) const
@@ -164,24 +62,20 @@ Tasks NimProject::projectIssues(const Kit *k) const
return result;
}
FilePathList NimProject::nimFiles() const
{
return files([](const ProjectExplorer::Node *n) {
return AllFiles(n) && n->filePath().endsWith(".nim");
});
}
QVariantMap NimProject::toMap() const
{
QVariantMap result = Project::toMap();
result[Constants::C_NIMPROJECT_EXCLUDEDFILES] = m_excludedFiles;
result[Constants::C_NIMPROJECT_EXCLUDEDFILES] = static_cast<NimBuildSystem *>(buildSystem())
->excludedFiles();
return result;
}
Project::RestoreResult NimProject::fromMap(const QVariantMap &map, QString *errorMessage)
{
m_excludedFiles = map.value(Constants::C_NIMPROJECT_EXCLUDEDFILES).toStringList();
return Project::fromMap(map, errorMessage);
auto result = Project::fromMap(map, errorMessage);
static_cast<NimBuildSystem *>(buildSystem())
->setExcludedFiles(map.value(Constants::C_NIMPROJECT_EXCLUDEDFILES).toStringList());
return result;
}
} // namespace Nim

View File

@@ -34,6 +34,8 @@
namespace Nim {
class NimBuildSystem;
class NimProject : public ProjectExplorer::Project
{
Q_OBJECT
@@ -42,25 +44,13 @@ public:
explicit NimProject(const Utils::FilePath &fileName);
ProjectExplorer::Tasks projectIssues(const ProjectExplorer::Kit *k) const final;
Utils::FilePathList nimFiles() const;
// Keep for compatibility with Qt Creator 4.10
QVariantMap toMap() const final;
bool addFiles(const QStringList &filePaths);
bool removeFiles(const QStringList &filePaths);
bool renameFile(const QString &filePath, const QString &newFilePath);
protected:
// Keep for compatibility with Qt Creator 4.10
RestoreResult fromMap(const QVariantMap &map, QString *errorMessage) final;
private:
void scheduleProjectScan();
void collectProjectFiles();
void updateProject();
QStringList m_excludedFiles;
QFutureWatcher<QList<ProjectExplorer::FileNode *>> m_futureWatcher;
QElapsedTimer m_lastProjectScan;
QTimer m_projectScanTimer;
};
}
} // namespace Nim

View File

@@ -24,17 +24,18 @@
****************************************************************************/
#include "nimprojectnode.h"
#include "nimproject.h"
#include "nimbuildsystem.h"
#include <projectexplorer/projecttree.h>
using namespace ProjectExplorer;
using namespace Utils;
namespace Nim {
NimProjectNode::NimProjectNode(NimProject &project,
const FilePath &projectFilePath)
NimProjectNode::NimProjectNode(const FilePath &projectFilePath)
: ProjectNode(projectFilePath)
, m_project(project)
{}
bool NimProjectNode::supportsAction(ProjectAction action, const Node *node) const
@@ -53,13 +54,13 @@ bool NimProjectNode::supportsAction(ProjectAction action, const Node *node) cons
bool NimProjectNode::addFiles(const QStringList &filePaths, QStringList *)
{
return m_project.addFiles(filePaths);
return buildSystem()->addFiles(filePaths);
}
RemovedFilesFromProject NimProjectNode::removeFiles(const QStringList &filePaths,
QStringList *)
{
return m_project.removeFiles(filePaths) ? RemovedFilesFromProject::Ok
return buildSystem()->removeFiles(filePaths) ? RemovedFilesFromProject::Ok
: RemovedFilesFromProject::Error;
}
@@ -70,7 +71,13 @@ bool NimProjectNode::deleteFiles(const QStringList &)
bool NimProjectNode::renameFile(const QString &filePath, const QString &newFilePath)
{
return m_project.renameFile(filePath, newFilePath);
return buildSystem()->renameFile(filePath, newFilePath);
}
NimBuildSystem *NimProjectNode::buildSystem() const
{
return qobject_cast<NimBuildSystem *>(
ProjectTree::instance()->projectForNode(this)->buildSystem());
}
} // namespace Nim

View File

@@ -31,12 +31,12 @@ namespace Utils { class FilePath; }
namespace Nim {
class NimProject;
class NimBuildSystem;
class NimProjectNode : public ProjectExplorer::ProjectNode
{
public:
NimProjectNode(NimProject &project, const Utils::FilePath &projectFilePath);
NimProjectNode(const Utils::FilePath &projectFilePath);
bool supportsAction(ProjectExplorer::ProjectAction action, const Node *node) const override;
bool addFiles(const QStringList &filePaths, QStringList *) override;
@@ -46,7 +46,7 @@ public:
bool renameFile(const QString &filePath, const QString &newFilePath) override;
private:
NimProject &m_project;
NimBuildSystem *buildSystem() const;
};
}