forked from quickshell/quickshell
core: synthesized qmldir files and new qml scanning strategy
This commit is contained in:
parent
1687ff3614
commit
ffbdac9977
|
@ -9,7 +9,6 @@ qt_add_library(quickshell-core STATIC
|
||||||
rootwrapper.cpp
|
rootwrapper.cpp
|
||||||
qmlglobal.cpp
|
qmlglobal.cpp
|
||||||
qmlscreen.cpp
|
qmlscreen.cpp
|
||||||
watcher.cpp
|
|
||||||
region.cpp
|
region.cpp
|
||||||
persistentprops.cpp
|
persistentprops.cpp
|
||||||
windowinterface.cpp
|
windowinterface.cpp
|
||||||
|
@ -18,6 +17,8 @@ qt_add_library(quickshell-core STATIC
|
||||||
popupwindow.cpp
|
popupwindow.cpp
|
||||||
singleton.cpp
|
singleton.cpp
|
||||||
generation.cpp
|
generation.cpp
|
||||||
|
scan.cpp
|
||||||
|
qsintercept.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
set_source_files_properties(main.cpp PROPERTIES COMPILE_DEFINITIONS GIT_REVISION="${GIT_REVISION}")
|
set_source_files_properties(main.cpp PROPERTIES COMPILE_DEFINITIONS GIT_REVISION="${GIT_REVISION}")
|
||||||
|
|
16
src/core/enginecontext.hpp
Normal file
16
src/core/enginecontext.hpp
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "qsintercept.hpp"
|
||||||
|
#include "scan.hpp"
|
||||||
|
#include "singleton.hpp"
|
||||||
|
|
||||||
|
class EngineContext {
|
||||||
|
public:
|
||||||
|
explicit EngineContext(const QmlScanner& scanner);
|
||||||
|
|
||||||
|
private:
|
||||||
|
const QmlScanner& scanner;
|
||||||
|
QQmlEngine engine;
|
||||||
|
QsInterceptNetworkAccessManagerFactory interceptFactory;
|
||||||
|
SingletonRegistry singletonRegistry;
|
||||||
|
};
|
|
@ -1,7 +1,9 @@
|
||||||
#include "generation.hpp"
|
#include "generation.hpp"
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
#include <qcontainerfwd.h>
|
#include <qcontainerfwd.h>
|
||||||
#include <qcoreapplication.h>
|
#include <qcoreapplication.h>
|
||||||
|
#include <qfilesystemwatcher.h>
|
||||||
#include <qhash.h>
|
#include <qhash.h>
|
||||||
#include <qobject.h>
|
#include <qobject.h>
|
||||||
#include <qqmlcontext.h>
|
#include <qqmlcontext.h>
|
||||||
|
@ -9,11 +11,19 @@
|
||||||
#include <qtimer.h>
|
#include <qtimer.h>
|
||||||
|
|
||||||
#include "plugin.hpp"
|
#include "plugin.hpp"
|
||||||
|
#include "qsintercept.hpp"
|
||||||
#include "reload.hpp"
|
#include "reload.hpp"
|
||||||
|
#include "scan.hpp"
|
||||||
|
|
||||||
static QHash<QQmlEngine*, EngineGeneration*> g_generations; // NOLINT
|
static QHash<QQmlEngine*, EngineGeneration*> g_generations; // NOLINT
|
||||||
|
|
||||||
EngineGeneration::EngineGeneration() { g_generations.insert(&this->engine, this); }
|
EngineGeneration::EngineGeneration(QmlScanner scanner)
|
||||||
|
: scanner(std::move(scanner))
|
||||||
|
, interceptNetFactory(this->scanner.qmldirIntercepts) {
|
||||||
|
g_generations.insert(&this->engine, this);
|
||||||
|
|
||||||
|
this->engine.setNetworkAccessManagerFactory(&this->interceptNetFactory);
|
||||||
|
}
|
||||||
|
|
||||||
EngineGeneration::~EngineGeneration() {
|
EngineGeneration::~EngineGeneration() {
|
||||||
g_generations.remove(&this->engine);
|
g_generations.remove(&this->engine);
|
||||||
|
@ -41,6 +51,30 @@ void EngineGeneration::onReload(EngineGeneration* old) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void EngineGeneration::setWatchingFiles(bool watching) {
|
||||||
|
if (watching) {
|
||||||
|
if (this->watcher == nullptr) {
|
||||||
|
this->watcher = new QFileSystemWatcher();
|
||||||
|
|
||||||
|
for (auto& file: this->scanner.scannedFiles) {
|
||||||
|
this->watcher->addPath(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
QObject::connect(
|
||||||
|
this->watcher,
|
||||||
|
&QFileSystemWatcher::fileChanged,
|
||||||
|
this,
|
||||||
|
&EngineGeneration::filesChanged
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (this->watcher != nullptr) {
|
||||||
|
delete this->watcher;
|
||||||
|
this->watcher = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
EngineGeneration* EngineGeneration::findObjectGeneration(QObject* object) {
|
EngineGeneration* EngineGeneration::findObjectGeneration(QObject* object) {
|
||||||
while (object != nullptr) {
|
while (object != nullptr) {
|
||||||
auto* context = QQmlEngine::contextForObject(object);
|
auto* context = QQmlEngine::contextForObject(object);
|
||||||
|
|
|
@ -1,23 +1,35 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <qfilesystemwatcher.h>
|
||||||
#include <qobject.h>
|
#include <qobject.h>
|
||||||
#include <qtclasshelpermacros.h>
|
#include <qtclasshelpermacros.h>
|
||||||
|
|
||||||
|
#include "qsintercept.hpp"
|
||||||
|
#include "scan.hpp"
|
||||||
#include "shell.hpp"
|
#include "shell.hpp"
|
||||||
#include "singleton.hpp"
|
#include "singleton.hpp"
|
||||||
|
|
||||||
class EngineGeneration {
|
class EngineGeneration: public QObject {
|
||||||
|
Q_OBJECT;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit EngineGeneration();
|
explicit EngineGeneration(QmlScanner scanner);
|
||||||
~EngineGeneration();
|
~EngineGeneration() override;
|
||||||
Q_DISABLE_COPY_MOVE(EngineGeneration);
|
Q_DISABLE_COPY_MOVE(EngineGeneration);
|
||||||
|
|
||||||
// assumes root has been initialized, consumes old generation
|
// assumes root has been initialized, consumes old generation
|
||||||
void onReload(EngineGeneration* old);
|
void onReload(EngineGeneration* old);
|
||||||
|
void setWatchingFiles(bool watching);
|
||||||
|
|
||||||
static EngineGeneration* findObjectGeneration(QObject* object);
|
static EngineGeneration* findObjectGeneration(QObject* object);
|
||||||
|
|
||||||
|
QmlScanner scanner;
|
||||||
|
QsInterceptNetworkAccessManagerFactory interceptNetFactory;
|
||||||
QQmlEngine engine;
|
QQmlEngine engine;
|
||||||
ShellRoot* root = nullptr;
|
ShellRoot* root = nullptr;
|
||||||
SingletonRegistry singletonRegistry;
|
SingletonRegistry singletonRegistry;
|
||||||
|
QFileSystemWatcher* watcher = nullptr;
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void filesChanged();
|
||||||
};
|
};
|
||||||
|
|
67
src/core/qsintercept.cpp
Normal file
67
src/core/qsintercept.cpp
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
#include "qsintercept.hpp"
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
#include <qhash.h>
|
||||||
|
#include <qiodevice.h>
|
||||||
|
#include <qlogging.h>
|
||||||
|
#include <qloggingcategory.h>
|
||||||
|
#include <qminmax.h>
|
||||||
|
#include <qnetworkaccessmanager.h>
|
||||||
|
#include <qnetworkrequest.h>
|
||||||
|
#include <qobject.h>
|
||||||
|
#include <qstring.h>
|
||||||
|
#include <qtypes.h>
|
||||||
|
|
||||||
|
Q_LOGGING_CATEGORY(logQsIntercept, "quickshell.interceptor", QtWarningMsg);
|
||||||
|
|
||||||
|
QsInterceptDataReply::QsInterceptDataReply(const QString& qmldir, QObject* parent)
|
||||||
|
: QNetworkReply(parent)
|
||||||
|
, content(qmldir.toUtf8()) {
|
||||||
|
this->setOpenMode(QIODevice::ReadOnly);
|
||||||
|
this->setFinished(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
qint64 QsInterceptDataReply::readData(char* data, qint64 maxSize) {
|
||||||
|
auto size = qMin(maxSize, this->content.length() - this->offset);
|
||||||
|
if (size == 0) return -1;
|
||||||
|
memcpy(data, this->content.constData() + this->offset, size); // NOLINT
|
||||||
|
this->offset += size;
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
QsInterceptNetworkAccessManager::QsInterceptNetworkAccessManager(
|
||||||
|
const QHash<QString, QString>& qmldirIntercepts,
|
||||||
|
QObject* parent
|
||||||
|
)
|
||||||
|
: QNetworkAccessManager(parent)
|
||||||
|
, qmldirIntercepts(qmldirIntercepts) {}
|
||||||
|
|
||||||
|
QNetworkReply* QsInterceptNetworkAccessManager::createRequest(
|
||||||
|
QNetworkAccessManager::Operation op,
|
||||||
|
const QNetworkRequest& req,
|
||||||
|
QIODevice* outgoingData
|
||||||
|
) {
|
||||||
|
auto url = req.url();
|
||||||
|
if (url.scheme() == "qsintercept") {
|
||||||
|
auto path = url.path();
|
||||||
|
qCDebug(logQsIntercept) << "Got intercept for" << path << "contains"
|
||||||
|
<< this->qmldirIntercepts.value(path);
|
||||||
|
auto qmldir = this->qmldirIntercepts.value(path);
|
||||||
|
if (qmldir != nullptr) {
|
||||||
|
return new QsInterceptDataReply(qmldir, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto fileReq = req;
|
||||||
|
auto fileUrl = req.url();
|
||||||
|
fileUrl.setScheme("file");
|
||||||
|
qCDebug(logQsIntercept) << "Passing through intercept" << url << "to" << fileUrl;
|
||||||
|
fileReq.setUrl(fileUrl);
|
||||||
|
return this->QNetworkAccessManager::createRequest(op, fileReq, outgoingData);
|
||||||
|
}
|
||||||
|
|
||||||
|
return this->QNetworkAccessManager::createRequest(op, req, outgoingData);
|
||||||
|
}
|
||||||
|
|
||||||
|
QNetworkAccessManager* QsInterceptNetworkAccessManagerFactory::create(QObject* parent) {
|
||||||
|
return new QsInterceptNetworkAccessManager(this->qmldirIntercepts, parent);
|
||||||
|
}
|
57
src/core/qsintercept.hpp
Normal file
57
src/core/qsintercept.hpp
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <qhash.h>
|
||||||
|
#include <qloggingcategory.h>
|
||||||
|
#include <qnetworkaccessmanager.h>
|
||||||
|
#include <qnetworkreply.h>
|
||||||
|
#include <qnetworkrequest.h>
|
||||||
|
#include <qqmlnetworkaccessmanagerfactory.h>
|
||||||
|
#include <qurl.h>
|
||||||
|
|
||||||
|
Q_DECLARE_LOGGING_CATEGORY(logQsIntercept);
|
||||||
|
|
||||||
|
class QsInterceptDataReply: public QNetworkReply {
|
||||||
|
Q_OBJECT;
|
||||||
|
|
||||||
|
public:
|
||||||
|
QsInterceptDataReply(const QString& qmldir, QObject* parent = nullptr);
|
||||||
|
|
||||||
|
qint64 readData(char* data, qint64 maxSize) override;
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void abort() override {}
|
||||||
|
|
||||||
|
private:
|
||||||
|
qint64 offset = 0;
|
||||||
|
QByteArray content;
|
||||||
|
};
|
||||||
|
|
||||||
|
class QsInterceptNetworkAccessManager: public QNetworkAccessManager {
|
||||||
|
Q_OBJECT;
|
||||||
|
|
||||||
|
public:
|
||||||
|
QsInterceptNetworkAccessManager(
|
||||||
|
const QHash<QString, QString>& qmldirIntercepts,
|
||||||
|
QObject* parent = nullptr
|
||||||
|
);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
QNetworkReply* createRequest(
|
||||||
|
QNetworkAccessManager::Operation op,
|
||||||
|
const QNetworkRequest& req,
|
||||||
|
QIODevice* outgoingData = nullptr
|
||||||
|
) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
const QHash<QString, QString>& qmldirIntercepts;
|
||||||
|
};
|
||||||
|
|
||||||
|
class QsInterceptNetworkAccessManagerFactory: public QQmlNetworkAccessManagerFactory {
|
||||||
|
public:
|
||||||
|
QsInterceptNetworkAccessManagerFactory(const QHash<QString, QString>& qmldirIntercepts)
|
||||||
|
: qmldirIntercepts(qmldirIntercepts) {}
|
||||||
|
QNetworkAccessManager* create(QObject* parent) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
const QHash<QString, QString>& qmldirIntercepts;
|
||||||
|
};
|
|
@ -12,8 +12,8 @@
|
||||||
|
|
||||||
#include "generation.hpp"
|
#include "generation.hpp"
|
||||||
#include "qmlglobal.hpp"
|
#include "qmlglobal.hpp"
|
||||||
|
#include "scan.hpp"
|
||||||
#include "shell.hpp"
|
#include "shell.hpp"
|
||||||
#include "watcher.hpp"
|
|
||||||
|
|
||||||
RootWrapper::RootWrapper(QString rootPath)
|
RootWrapper::RootWrapper(QString rootPath)
|
||||||
: QObject(nullptr)
|
: QObject(nullptr)
|
||||||
|
@ -42,7 +42,10 @@ RootWrapper::~RootWrapper() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void RootWrapper::reloadGraph(bool hard) {
|
void RootWrapper::reloadGraph(bool hard) {
|
||||||
auto* generation = new EngineGeneration();
|
auto scanner = QmlScanner();
|
||||||
|
scanner.scanQmlFile(this->rootPath);
|
||||||
|
|
||||||
|
auto* generation = new EngineGeneration(std::move(scanner));
|
||||||
|
|
||||||
// todo: move into EngineGeneration
|
// todo: move into EngineGeneration
|
||||||
if (this->generation != nullptr) {
|
if (this->generation != nullptr) {
|
||||||
|
@ -51,7 +54,10 @@ void RootWrapper::reloadGraph(bool hard) {
|
||||||
|
|
||||||
QDir::setCurrent(this->originalWorkingDirectory);
|
QDir::setCurrent(this->originalWorkingDirectory);
|
||||||
|
|
||||||
auto component = QQmlComponent(&generation->engine, QUrl::fromLocalFile(this->rootPath));
|
auto url = QUrl::fromLocalFile(this->rootPath);
|
||||||
|
// unless the original file comes from the qsintercept scheme
|
||||||
|
url.setScheme("qsintercept");
|
||||||
|
auto component = QQmlComponent(&generation->engine, url);
|
||||||
|
|
||||||
auto* obj = component.beginCreate(generation->engine.rootContext());
|
auto* obj = component.beginCreate(generation->engine.rootContext());
|
||||||
|
|
||||||
|
@ -80,25 +86,20 @@ void RootWrapper::reloadGraph(bool hard) {
|
||||||
|
|
||||||
qInfo() << "Configuration Loaded";
|
qInfo() << "Configuration Loaded";
|
||||||
|
|
||||||
|
QObject::connect(
|
||||||
|
this->generation,
|
||||||
|
&EngineGeneration::filesChanged,
|
||||||
|
this,
|
||||||
|
&RootWrapper::onWatchedFilesChanged
|
||||||
|
);
|
||||||
|
|
||||||
this->onWatchFilesChanged();
|
this->onWatchFilesChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
void RootWrapper::onWatchFilesChanged() {
|
void RootWrapper::onWatchFilesChanged() {
|
||||||
auto watchFiles = QuickshellSettings::instance()->watchFiles();
|
auto watchFiles = QuickshellSettings::instance()->watchFiles();
|
||||||
|
if (this->generation != nullptr) {
|
||||||
if (watchFiles && this->configWatcher == nullptr) {
|
this->generation->setWatchingFiles(watchFiles);
|
||||||
this->configWatcher = new FiletreeWatcher();
|
|
||||||
this->configWatcher->addPath(QFileInfo(this->rootPath).dir().path());
|
|
||||||
|
|
||||||
QObject::connect(
|
|
||||||
this->configWatcher,
|
|
||||||
&FiletreeWatcher::fileChanged,
|
|
||||||
this,
|
|
||||||
&RootWrapper::onWatchedFilesChanged
|
|
||||||
);
|
|
||||||
} else if (!watchFiles && this->configWatcher != nullptr) {
|
|
||||||
this->configWatcher->deleteLater();
|
|
||||||
this->configWatcher = nullptr;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,6 @@
|
||||||
#include <qurl.h>
|
#include <qurl.h>
|
||||||
|
|
||||||
#include "generation.hpp"
|
#include "generation.hpp"
|
||||||
#include "watcher.hpp"
|
|
||||||
|
|
||||||
class RootWrapper: public QObject {
|
class RootWrapper: public QObject {
|
||||||
Q_OBJECT;
|
Q_OBJECT;
|
||||||
|
@ -26,6 +25,5 @@ private slots:
|
||||||
private:
|
private:
|
||||||
QString rootPath;
|
QString rootPath;
|
||||||
EngineGeneration* generation = nullptr;
|
EngineGeneration* generation = nullptr;
|
||||||
FiletreeWatcher* configWatcher = nullptr;
|
|
||||||
QString originalWorkingDirectory;
|
QString originalWorkingDirectory;
|
||||||
};
|
};
|
||||||
|
|
119
src/core/scan.cpp
Normal file
119
src/core/scan.cpp
Normal file
|
@ -0,0 +1,119 @@
|
||||||
|
#include "scan.hpp"
|
||||||
|
|
||||||
|
#include <qcontainerfwd.h>
|
||||||
|
#include <qdir.h>
|
||||||
|
#include <qfileinfo.h>
|
||||||
|
#include <qlogging.h>
|
||||||
|
#include <qloggingcategory.h>
|
||||||
|
#include <qstring.h>
|
||||||
|
#include <qtextstream.h>
|
||||||
|
|
||||||
|
Q_LOGGING_CATEGORY(logQmlScanner, "quickshell.qmlscanner", QtWarningMsg);
|
||||||
|
|
||||||
|
void QmlScanner::scanDir(const QString& path) {
|
||||||
|
if (this->scannedDirs.contains(path)) return;
|
||||||
|
this->scannedDirs.push_back(path);
|
||||||
|
|
||||||
|
qCDebug(logQmlScanner) << "Scanning directory" << path;
|
||||||
|
auto dir = QDir(path);
|
||||||
|
|
||||||
|
bool seenQmldir = false;
|
||||||
|
auto singletons = QVector<QString>();
|
||||||
|
auto entries = QVector<QString>();
|
||||||
|
for (auto& entry: dir.entryList(QDir::Files | QDir::NoDotAndDotDot)) {
|
||||||
|
if (entry == "qmldir") {
|
||||||
|
qCDebug(logQmlScanner
|
||||||
|
) << "Found qmldir file, qmldir synthesization will be disabled for directory"
|
||||||
|
<< path;
|
||||||
|
seenQmldir = true;
|
||||||
|
} else if (entry.at(0).isUpper() && entry.endsWith(".qml")) {
|
||||||
|
if (this->scanQmlFile(dir.filePath(entry))) {
|
||||||
|
singletons.push_back(entry);
|
||||||
|
} else {
|
||||||
|
entries.push_back(entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Due to the qsintercept:// protocol a qmldir is always required, even without singletons.
|
||||||
|
if (!seenQmldir) {
|
||||||
|
qCDebug(logQmlScanner) << "Synthesizing qmldir for directory" << path << "singletons"
|
||||||
|
<< singletons;
|
||||||
|
|
||||||
|
QString qmldir;
|
||||||
|
auto stream = QTextStream(&qmldir);
|
||||||
|
|
||||||
|
for (auto& singleton: singletons) {
|
||||||
|
stream << "singleton " << singleton.sliced(0, singleton.length() - 4) << " 1.0 " << singleton
|
||||||
|
<< "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto& entry: entries) {
|
||||||
|
stream << entry.sliced(0, entry.length() - 4) << " 1.0 " << entry << "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
qCDebug(logQmlScanner) << "Synthesized qmldir for" << path << qPrintable("\n" + qmldir);
|
||||||
|
this->qmldirIntercepts.insert(QDir(path).filePath("qmldir"), qmldir);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool QmlScanner::scanQmlFile(const QString& path) {
|
||||||
|
if (this->scannedFiles.contains(path)) return false;
|
||||||
|
this->scannedFiles.push_back(path);
|
||||||
|
|
||||||
|
qCDebug(logQmlScanner) << "Scanning qml file" << path;
|
||||||
|
|
||||||
|
auto file = QFile(path);
|
||||||
|
if (!file.open(QFile::ReadOnly | QFile::Text)) {
|
||||||
|
qCWarning(logQmlScanner) << "Failed to open file" << path;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto stream = QTextStream(&file);
|
||||||
|
auto imports = QVector<QString>();
|
||||||
|
|
||||||
|
bool singleton = false;
|
||||||
|
|
||||||
|
while (!stream.atEnd()) {
|
||||||
|
auto line = stream.readLine().trimmed();
|
||||||
|
if (!singleton && line == "pragma Singleton") {
|
||||||
|
qCDebug(logQmlScanner) << "Discovered singleton" << path;
|
||||||
|
singleton = true;
|
||||||
|
} else if (line.startsWith("import")) {
|
||||||
|
|
||||||
|
auto startQuot = line.indexOf('"');
|
||||||
|
if (startQuot == -1 || line.length() < startQuot + 3) continue;
|
||||||
|
auto endQuot = line.indexOf('"', startQuot + 1);
|
||||||
|
if (endQuot == -1) continue;
|
||||||
|
|
||||||
|
auto name = line.sliced(startQuot + 1, endQuot - startQuot - 1);
|
||||||
|
imports.push_back(name);
|
||||||
|
} else if (line.contains('{')) break;
|
||||||
|
}
|
||||||
|
|
||||||
|
file.close();
|
||||||
|
|
||||||
|
if (logQmlScanner().isDebugEnabled() && !imports.isEmpty()) {
|
||||||
|
qCDebug(logQmlScanner) << "Found imports" << imports;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto currentdir = QDir(QFileInfo(path).canonicalPath());
|
||||||
|
|
||||||
|
// the root can never be a singleton so it dosent matter if we skip it
|
||||||
|
this->scanDir(currentdir.path());
|
||||||
|
|
||||||
|
for (auto& import: imports) {
|
||||||
|
auto ipath = currentdir.filePath(import);
|
||||||
|
auto cpath = QFileInfo(ipath).canonicalFilePath();
|
||||||
|
|
||||||
|
if (cpath.isEmpty()) {
|
||||||
|
qCWarning(logQmlScanner) << "Ignoring unresolvable import" << ipath << "from" << path;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (import.endsWith(".js")) this->scannedFiles.push_back(cpath);
|
||||||
|
else this->scanDir(cpath);
|
||||||
|
}
|
||||||
|
|
||||||
|
return singleton;
|
||||||
|
}
|
20
src/core/scan.hpp
Normal file
20
src/core/scan.hpp
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <qcontainerfwd.h>
|
||||||
|
#include <qhash.h>
|
||||||
|
#include <qloggingcategory.h>
|
||||||
|
#include <qvector.h>
|
||||||
|
|
||||||
|
Q_DECLARE_LOGGING_CATEGORY(logQmlScanner);
|
||||||
|
|
||||||
|
// expects canonical paths
|
||||||
|
class QmlScanner {
|
||||||
|
public:
|
||||||
|
void scanDir(const QString& path);
|
||||||
|
// returns if the file has a singleton
|
||||||
|
bool scanQmlFile(const QString& path);
|
||||||
|
|
||||||
|
QVector<QString> scannedDirs;
|
||||||
|
QVector<QString> scannedFiles;
|
||||||
|
QHash<QString, QString> qmldirIntercepts;
|
||||||
|
};
|
|
@ -1,11 +1,10 @@
|
||||||
#include "singleton.hpp"
|
#include "singleton.hpp"
|
||||||
|
|
||||||
|
#include <qhash.h>
|
||||||
#include <qlogging.h>
|
#include <qlogging.h>
|
||||||
#include <qmap.h>
|
|
||||||
#include <qobject.h>
|
#include <qobject.h>
|
||||||
#include <qqmlcontext.h>
|
#include <qqmlcontext.h>
|
||||||
#include <qqmlengine.h>
|
#include <qqmlengine.h>
|
||||||
#include <qurl.h>
|
|
||||||
|
|
||||||
#include "generation.hpp"
|
#include "generation.hpp"
|
||||||
#include "reload.hpp"
|
#include "reload.hpp"
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <qhash.h>
|
||||||
#include <qobject.h>
|
#include <qobject.h>
|
||||||
|
#include <qqmlengine.h>
|
||||||
#include <qqmlintegration.h>
|
#include <qqmlintegration.h>
|
||||||
#include <qtclasshelpermacros.h>
|
|
||||||
#include <qtmetamacros.h>
|
#include <qtmetamacros.h>
|
||||||
|
#include <qtypes.h>
|
||||||
#include <qurl.h>
|
#include <qurl.h>
|
||||||
|
|
||||||
#include "reload.hpp"
|
#include "reload.hpp"
|
||||||
|
@ -26,5 +28,5 @@ public:
|
||||||
void onReload(SingletonRegistry* old);
|
void onReload(SingletonRegistry* old);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QMap<QUrl, Singleton*> registry;
|
QHash<QUrl, Singleton*> registry;
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,38 +0,0 @@
|
||||||
#include "watcher.hpp"
|
|
||||||
|
|
||||||
#include <qdir.h>
|
|
||||||
#include <qfileinfo.h>
|
|
||||||
#include <qfilesystemwatcher.h>
|
|
||||||
#include <qobject.h>
|
|
||||||
#include <qtmetamacros.h>
|
|
||||||
|
|
||||||
FiletreeWatcher::FiletreeWatcher(QObject* parent): QObject(parent) {
|
|
||||||
QObject::connect(
|
|
||||||
&this->watcher,
|
|
||||||
&QFileSystemWatcher::fileChanged,
|
|
||||||
this,
|
|
||||||
&FiletreeWatcher::onFileChanged
|
|
||||||
);
|
|
||||||
|
|
||||||
QObject::connect(
|
|
||||||
&this->watcher,
|
|
||||||
&QFileSystemWatcher::directoryChanged,
|
|
||||||
this,
|
|
||||||
&FiletreeWatcher::onDirectoryChanged
|
|
||||||
);
|
|
||||||
}
|
|
||||||
void FiletreeWatcher::addPath(const QString& path) {
|
|
||||||
this->watcher.addPath(path);
|
|
||||||
|
|
||||||
if (QFileInfo(path).isDir()) {
|
|
||||||
auto dir = QDir(path);
|
|
||||||
|
|
||||||
for (auto& entry: dir.entryList(QDir::AllEntries | QDir::NoDotAndDotDot)) {
|
|
||||||
this->addPath(dir.filePath(entry));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void FiletreeWatcher::onDirectoryChanged(const QString& path) { this->addPath(path); }
|
|
||||||
|
|
||||||
void FiletreeWatcher::onFileChanged(const QString& path) { emit this->fileChanged(path); }
|
|
|
@ -1,24 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <qdir.h>
|
|
||||||
#include <qfilesystemwatcher.h>
|
|
||||||
#include <qobject.h>
|
|
||||||
|
|
||||||
class FiletreeWatcher: public QObject {
|
|
||||||
Q_OBJECT;
|
|
||||||
|
|
||||||
public:
|
|
||||||
explicit FiletreeWatcher(QObject* parent = nullptr);
|
|
||||||
|
|
||||||
void addPath(const QString& path);
|
|
||||||
|
|
||||||
signals:
|
|
||||||
void fileChanged(const QString& path);
|
|
||||||
|
|
||||||
private slots:
|
|
||||||
void onDirectoryChanged(const QString& path);
|
|
||||||
void onFileChanged(const QString& path);
|
|
||||||
|
|
||||||
private:
|
|
||||||
QFileSystemWatcher watcher;
|
|
||||||
};
|
|
Loading…
Reference in a new issue