diff --git a/CMakeLists.txt b/CMakeLists.txt index 7633f4f..81e896f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,8 +1,6 @@ cmake_minimum_required(VERSION 3.20) project(quickshell VERSION "0.2.1" LANGUAGES CXX C) -set(UNRELEASED_FEATURES) - set(QT_MIN_VERSION "6.6.0") set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_STANDARD_REQUIRED ON) diff --git a/changelog/next.md b/changelog/next.md index 30e998b..cab03e6 100644 --- a/changelog/next.md +++ b/changelog/next.md @@ -23,7 +23,6 @@ set shell id. - Added initial support for network management. - Added support for grabbing focus from popup windows. - Added support for IPC signal listeners. -- Added Quickshell version checking and version gated preprocessing. ## Other Changes diff --git a/src/build/build.hpp.in b/src/build/build.hpp.in index 66fb664..075abd1 100644 --- a/src/build/build.hpp.in +++ b/src/build/build.hpp.in @@ -1,11 +1,6 @@ #pragma once // NOLINTBEGIN -#define QS_VERSION "@quickshell_VERSION@" -#define QS_VERSION_MAJOR @quickshell_VERSION_MAJOR@ -#define QS_VERSION_MINOR @quickshell_VERSION_MINOR@ -#define QS_VERSION_PATCH @quickshell_VERSION_PATCH@ -#define QS_UNRELEASED_FEATURES "@UNRELEASED_FEATURES@" #define GIT_REVISION "@GIT_REVISION@" #define DISTRIBUTOR "@DISTRIBUTOR@" #define DISTRIBUTOR_DEBUGINFO_AVAILABLE @DEBUGINFO_AVAILABLE@ diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index fb63f40..bbfb8c4 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -12,7 +12,6 @@ qt_add_library(quickshell-core STATIC singleton.cpp generation.cpp scan.cpp - scanenv.cpp qsintercept.cpp incubator.cpp lazyloader.cpp @@ -52,7 +51,7 @@ qt_add_qml_module(quickshell-core install_qml_module(quickshell-core) -target_link_libraries(quickshell-core PRIVATE Qt::Quick Qt::QuickPrivate Qt::Widgets quickshell-build) +target_link_libraries(quickshell-core PRIVATE Qt::Quick Qt::QuickPrivate Qt::Widgets) qs_module_pch(quickshell-core SET large) diff --git a/src/core/qmlglobal.cpp b/src/core/qmlglobal.cpp index 03fb818..07238f6 100644 --- a/src/core/qmlglobal.cpp +++ b/src/core/qmlglobal.cpp @@ -29,7 +29,6 @@ #include "paths.hpp" #include "qmlscreen.hpp" #include "rootwrapper.hpp" -#include "scanenv.hpp" QuickshellSettings::QuickshellSettings() { QObject::connect( @@ -314,14 +313,6 @@ QString QuickshellGlobal::iconPath(const QString& icon, const QString& fallback) return IconImageProvider::requestString(icon, "", fallback); } -bool QuickshellGlobal::hasVersion(qint32 major, qint32 minor, const QStringList& features) { - return qs::scan::env::PreprocEnv::hasVersion(major, minor, features); -} - -bool QuickshellGlobal::hasVersion(qint32 major, qint32 minor) { - return QuickshellGlobal::hasVersion(major, minor, QStringList()); -} - QuickshellGlobal* QuickshellGlobal::create(QQmlEngine* engine, QJSEngine* /*unused*/) { auto* qsg = new QuickshellGlobal(); auto* generation = EngineGeneration::findEngineGeneration(engine); diff --git a/src/core/qmlglobal.hpp b/src/core/qmlglobal.hpp index 3ca70be..1fc363b 100644 --- a/src/core/qmlglobal.hpp +++ b/src/core/qmlglobal.hpp @@ -217,21 +217,6 @@ public: /// /// The popup can also be blocked by setting `QS_NO_RELOAD_POPUP=1`. Q_INVOKABLE void inhibitReloadPopup() { this->mInhibitReloadPopup = true; } - /// Check if Quickshell's version is at least `major.minor` and the listed - /// unreleased features are available. If Quickshell is newer than the given version - /// it is assumed that all unreleased features are present. The unreleased feature list - /// may be omitted. - /// - /// > [!NOTE] You can feature gate code blocks using Quickshell's preprocessor which - /// > has the same function available. - /// > - /// > ```qml - /// > //@ if hasVersion(0, 3, ["feature"]) - /// > ... - /// > //@ endif - /// > ``` - Q_INVOKABLE static bool hasVersion(qint32 major, qint32 minor, const QStringList& features); - Q_INVOKABLE static bool hasVersion(qint32 major, qint32 minor); void clearReloadPopupInhibit() { this->mInhibitReloadPopup = false; } [[nodiscard]] bool isReloadPopupInhibited() const { return this->mInhibitReloadPopup; } diff --git a/src/core/rootwrapper.cpp b/src/core/rootwrapper.cpp index 1e75819..25c46cc 100644 --- a/src/core/rootwrapper.cpp +++ b/src/core/rootwrapper.cpp @@ -63,6 +63,9 @@ void RootWrapper::reloadGraph(bool hard) { qs::core::QmlToolingSupport::updateTooling(rootPath, scanner); this->configDirWatcher.addPath(rootPath.path()); + auto* generation = new EngineGeneration(rootPath, std::move(scanner)); + generation->wrapper = this; + // todo: move into EngineGeneration if (this->generation != nullptr) { qInfo() << "Reloading configuration..."; @@ -71,33 +74,6 @@ void RootWrapper::reloadGraph(bool hard) { QDir::setCurrent(this->originalWorkingDirectory); - if (!scanner.scanErrors.isEmpty()) { - qCritical() << "Failed to load configuration"; - QString errorString = "Failed to load configuration"; - for (auto& error: scanner.scanErrors) { - const auto& file = error.file; - QString rel; - if (file.startsWith(rootPath.path() % '/')) { - rel = '@' % file.sliced(rootPath.path().length() + 1); - } else { - rel = file; - } - - auto msg = " error in " % rel % '[' % QString::number(error.line) % ":0]: " % error.message; - errorString += '\n' % msg; - qCritical().noquote() << msg; - } - - if (this->generation != nullptr && this->generation->qsgInstance != nullptr) { - emit this->generation->qsgInstance->reloadFailed(errorString); - } - - return; - } - - auto* generation = new EngineGeneration(rootPath, std::move(scanner)); - generation->wrapper = this; - QUrl url; url.setScheme("qs"); url.setPath("@/qs/" % rootFile.fileName()); diff --git a/src/core/scan.cpp b/src/core/scan.cpp index 37b0fac..453b7dc 100644 --- a/src/core/scan.cpp +++ b/src/core/scan.cpp @@ -1,11 +1,9 @@ #include "scan.hpp" #include -#include #include #include #include -#include #include #include #include @@ -17,7 +15,6 @@ #include #include "logcat.hpp" -#include "scanenv.hpp" QS_LOGGING_CATEGORY(logQmlScanner, "quickshell.qmlscanner", QtWarningMsg); @@ -118,113 +115,51 @@ bool QmlScanner::scanQmlFile(const QString& path, bool& singleton, bool& interna auto stream = QTextStream(&file); auto imports = QVector(); - bool inHeader = true; - auto ifScopes = QVector(); - bool sourceMasked = false; - int lineNum = 0; - QString overrideText; - bool isOverridden = false; - - auto pragmaEngine = QJSEngine(); - pragmaEngine.globalObject().setPrototype( - pragmaEngine.newQObject(new qs::scan::env::PreprocEnv()) - ); - - auto postError = [&, this](QString error) { - this->scanErrors.append({.file = path, .message = std::move(error), .line = lineNum}); - }; - while (!stream.atEnd()) { - ++lineNum; - bool hideMask = false; - auto rawLine = stream.readLine(); - auto line = rawLine.trimmed(); - if (!sourceMasked && inHeader) { - if (!singleton && line == "pragma Singleton") { - singleton = true; - } else if (line.startsWith("import")) { - // we dont care about "import qs" as we always load the root folder - if (auto importCursor = line.indexOf(" qs."); importCursor != -1) { - importCursor += 4; - QString path; + auto line = stream.readLine().trimmed(); + if (!singleton && line == "pragma Singleton") { + singleton = true; + } else if (!internal && line == "//@ pragma Internal") { + internal = true; + } else if (line.startsWith("import")) { + // we dont care about "import qs" as we always load the root folder + if (auto importCursor = line.indexOf(" qs."); importCursor != -1) { + importCursor += 4; + QString path; - while (importCursor != line.length()) { - auto c = line.at(importCursor); - if (c == '.') c = '/'; - else if (c == ' ') break; - else if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') - || c == '_') - { - } else { - qCWarning(logQmlScanner) << "Import line contains invalid characters: " << line; - goto next; - } - - path.append(c); - importCursor += 1; + while (importCursor != line.length()) { + auto c = line.at(importCursor); + if (c == '.') c = '/'; + else if (c == ' ') break; + else if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') + || c == '_') + { + } else { + qCWarning(logQmlScanner) << "Import line contains invalid characters: " << line; + goto next; } - imports.append(this->rootPath.filePath(path)); - } else if (auto startQuot = line.indexOf('"'); - startQuot != -1 && line.length() >= startQuot + 3) - { - auto endQuot = line.indexOf('"', startQuot + 1); - if (endQuot == -1) continue; - - auto name = line.sliced(startQuot + 1, endQuot - startQuot - 1); - imports.push_back(name); + path.append(c); + importCursor += 1; } - } else if (!internal && line == "//@ pragma Internal") { - internal = true; - } else if (line.contains('{')) { - inHeader = false; + + imports.append(this->rootPath.filePath(path)); + } else if (auto startQuot = line.indexOf('"'); + startQuot != -1 && line.length() >= startQuot + 3) + { + auto endQuot = line.indexOf('"', startQuot + 1); + if (endQuot == -1) continue; + + auto name = line.sliced(startQuot + 1, endQuot - startQuot - 1); + imports.push_back(name); } - } - - if (line.startsWith("//@ if ")) { - auto code = line.sliced(7); - auto value = pragmaEngine.evaluate(code, path, 1234); - bool mask = true; - - if (value.isError()) { - postError(QString("Evaluating if: %0").arg(value.toString())); - } else if (!value.isBool()) { - postError(QString("If expression \"%0\" is not a boolean").arg(value.toString())); - } else if (value.toBool()) { - mask = false; - } - if (!sourceMasked && mask) hideMask = true; - mask = sourceMasked || mask; // cant unmask if a nested if passes - ifScopes.append(mask); - if (mask) isOverridden = true; - sourceMasked = mask; - } else if (line.startsWith("//@ endif")) { - if (ifScopes.isEmpty()) { - postError("endif without matching if"); - } else { - ifScopes.pop_back(); - - if (ifScopes.isEmpty()) sourceMasked = false; - else sourceMasked = ifScopes.last(); - } - } - - if (!hideMask && sourceMasked) overrideText.append("// MASKED: " % rawLine % '\n'); - else overrideText.append(rawLine % '\n'); + } else if (line.contains('{')) break; next:; } - if (!ifScopes.isEmpty()) { - postError("unclosed preprocessor if block"); - } - file.close(); - if (isOverridden) { - this->fileIntercepts.insert(path, overrideText); - } - if (logQmlScanner().isDebugEnabled() && !imports.isEmpty()) { qCDebug(logQmlScanner) << "Found imports" << imports; } diff --git a/src/core/scan.hpp b/src/core/scan.hpp index 29f8f6a..2dc8c3c 100644 --- a/src/core/scan.hpp +++ b/src/core/scan.hpp @@ -23,14 +23,6 @@ public: QVector scannedFiles; QHash fileIntercepts; - struct ScanError { - QString file; - QString message; - int line; - }; - - QVector scanErrors; - private: QDir rootPath; diff --git a/src/core/scanenv.cpp b/src/core/scanenv.cpp deleted file mode 100644 index b8c514c..0000000 --- a/src/core/scanenv.cpp +++ /dev/null @@ -1,22 +0,0 @@ -#include "scanenv.hpp" - -#include - -#include "build.hpp" - -namespace qs::scan::env { - -bool PreprocEnv::hasVersion(int major, int minor, const QStringList& features) { - if (QS_VERSION_MAJOR > major) return true; - if (QS_VERSION_MAJOR == major && QS_VERSION_MINOR > minor) return true; - - auto availFeatures = QString(QS_UNRELEASED_FEATURES).split(';'); - - for (const auto& feature: features) { - if (!availFeatures.contains(feature)) return false; - } - - return QS_VERSION_MAJOR == major && QS_VERSION_MINOR == minor; -} - -} // namespace qs::scan::env diff --git a/src/core/scanenv.hpp b/src/core/scanenv.hpp deleted file mode 100644 index 0abde2e..0000000 --- a/src/core/scanenv.hpp +++ /dev/null @@ -1,17 +0,0 @@ -#pragma once - -#include -#include -#include - -namespace qs::scan::env { - -class PreprocEnv: public QObject { - Q_OBJECT; - -public: - Q_INVOKABLE static bool - hasVersion(int major, int minor, const QStringList& features = QStringList()); -}; - -} // namespace qs::scan::env diff --git a/src/launch/command.cpp b/src/launch/command.cpp index 151fc24..d867584 100644 --- a/src/launch/command.cpp +++ b/src/launch/command.cpp @@ -519,8 +519,8 @@ int runCommand(int argc, char** argv, QCoreApplication* coreApplication) { } if (state.misc.printVersion) { - qCInfo(logBare).noquote().nospace() << "quickshell " << QS_VERSION << ", revision " - << GIT_REVISION << ", distributed by: " << DISTRIBUTOR; + qCInfo(logBare).noquote().nospace() + << "quickshell 0.2.1, revision " << GIT_REVISION << ", distributed by: " << DISTRIBUTOR; if (state.log.verbosity > 1) { qCInfo(logBare).noquote() << "\nBuildtime Qt Version:" << QT_VERSION_STR;