core: support `root:` and `root:/` paths for the config root

This works everywhere urls are accepted and rewrites them from the
config root as a qsintercept url.
This commit is contained in:
outfoxxed 2024-05-29 15:07:10 -07:00
parent 33fac67798
commit 0519acf1d6
Signed by: outfoxxed
GPG Key ID: 4C88A185FB89301E
7 changed files with 48 additions and 8 deletions

View File

@ -27,8 +27,10 @@
static QHash<QQmlEngine*, EngineGeneration*> g_generations; // NOLINT
EngineGeneration::EngineGeneration(QmlScanner scanner)
: scanner(std::move(scanner))
EngineGeneration::EngineGeneration(const QDir& rootPath, QmlScanner scanner)
: rootPath(rootPath)
, scanner(std::move(scanner))
, urlInterceptor(this->rootPath)
, interceptNetFactory(this->scanner.qmldirIntercepts)
, engine(new QQmlEngine()) {
g_generations.insert(this->engine, this);

View File

@ -1,6 +1,7 @@
#pragma once
#include <qcontainerfwd.h>
#include <qdir.h>
#include <qfilesystemwatcher.h>
#include <qobject.h>
#include <qpair.h>
@ -19,7 +20,7 @@ class EngineGeneration: public QObject {
Q_OBJECT;
public:
explicit EngineGeneration(QmlScanner scanner);
explicit EngineGeneration(const QDir& rootPath, QmlScanner scanner);
~EngineGeneration() override;
Q_DISABLE_COPY_MOVE(EngineGeneration);
@ -33,6 +34,7 @@ public:
static EngineGeneration* findObjectGeneration(QObject* object);
RootWrapper* wrapper = nullptr;
QDir rootPath;
QmlScanner scanner;
QsUrlInterceptor urlInterceptor;
QsInterceptNetworkAccessManagerFactory interceptNetFactory;

View File

@ -16,7 +16,22 @@
Q_LOGGING_CATEGORY(logQsIntercept, "quickshell.interceptor", QtWarningMsg);
QUrl QsUrlInterceptor::intercept(const QUrl& url, QQmlAbstractUrlInterceptor::DataType type) {
QUrl QsUrlInterceptor::intercept(
const QUrl& originalUrl,
QQmlAbstractUrlInterceptor::DataType type
) {
auto url = originalUrl;
if (url.scheme() == "root") {
url.setScheme("qsintercept");
auto path = url.path();
if (path.startsWith('/')) path = path.sliced(1);
url.setPath(this->configRoot.filePath(path));
qCDebug(logQsIntercept) << "Rewrote root intercept" << originalUrl << "to" << url;
}
// Some types such as Image take into account where they are loading from, and force
// asynchronous loading over a network. qsintercept is considered to be over a network.
if (type == QQmlAbstractUrlInterceptor::DataType::UrlString && url.scheme() == "qsintercept") {

View File

@ -1,5 +1,6 @@
#pragma once
#include <qdir.h>
#include <qhash.h>
#include <qloggingcategory.h>
#include <qnetworkaccessmanager.h>
@ -13,7 +14,12 @@ Q_DECLARE_LOGGING_CATEGORY(logQsIntercept);
class QsUrlInterceptor: public QQmlAbstractUrlInterceptor {
public:
QUrl intercept(const QUrl& url, QQmlAbstractUrlInterceptor::DataType type) override;
explicit QsUrlInterceptor(const QDir& configRoot): configRoot(configRoot) {}
QUrl intercept(const QUrl& originalUrl, QQmlAbstractUrlInterceptor::DataType type) override;
private:
QDir configRoot;
};
class QsInterceptDataReply: public QNetworkReply {

View File

@ -42,10 +42,11 @@ RootWrapper::~RootWrapper() {
}
void RootWrapper::reloadGraph(bool hard) {
auto scanner = QmlScanner();
auto rootPath = QFileInfo(this->rootPath).dir();
auto scanner = QmlScanner(rootPath);
scanner.scanQmlFile(this->rootPath);
auto* generation = new EngineGeneration(std::move(scanner));
auto* generation = new EngineGeneration(rootPath, std::move(scanner));
generation->wrapper = this;
// todo: move into EngineGeneration

View File

@ -103,7 +103,15 @@ bool QmlScanner::scanQmlFile(const QString& path) {
this->scanDir(currentdir.path());
for (auto& import: imports) {
auto ipath = currentdir.filePath(import);
QString ipath;
if (import.startsWith("root:")) {
auto path = import.sliced(5);
if (path.startsWith('/')) path = path.sliced(1);
ipath = this->rootPath.filePath(path);
} else {
ipath = currentdir.filePath(import);
}
auto cpath = QFileInfo(ipath).canonicalFilePath();
if (cpath.isEmpty()) {

View File

@ -1,6 +1,7 @@
#pragma once
#include <qcontainerfwd.h>
#include <qdir.h>
#include <qhash.h>
#include <qloggingcategory.h>
#include <qvector.h>
@ -10,6 +11,8 @@ Q_DECLARE_LOGGING_CATEGORY(logQmlScanner);
// expects canonical paths
class QmlScanner {
public:
QmlScanner(const QDir& rootPath): rootPath(rootPath) {}
void scanDir(const QString& path);
// returns if the file has a singleton
bool scanQmlFile(const QString& path);
@ -17,4 +20,7 @@ public:
QVector<QString> scannedDirs;
QVector<QString> scannedFiles;
QHash<QString, QString> qmldirIntercepts;
private:
QDir rootPath;
};