diff --git a/src/plugins/lua/bindings/fetch.cpp b/src/plugins/lua/bindings/fetch.cpp index 31e67e6ae5c..35e3255943f 100644 --- a/src/plugins/lua/bindings/fetch.cpp +++ b/src/plugins/lua/bindings/fetch.cpp @@ -39,6 +39,8 @@ void addFetchModule() { LuaEngine::registerProvider( "Fetch", [](sol::state_view lua) -> sol::object { + const ScriptPluginSpec *pluginSpec = lua.get("PluginSpec"); + sol::table async = lua.script("return require('async')", "_fetch_").get(); sol::function wrap = async["wrap"]; @@ -58,9 +60,10 @@ void addFetchModule() .arg(r->error()); }); - fetch["fetch_cb"] = [](const sol::table &options, - const sol::function &callback, - const sol::this_state &thisState) { + fetch["fetch_cb"] = [guard = pluginSpec->connectionGuard.get()]( + const sol::table &options, + const sol::function &callback, + const sol::this_state &thisState) { auto url = options.get("url"); auto method = (options.get_or("method", "GET")).toLower(); @@ -85,10 +88,7 @@ void addFetchModule() if (convertToTable) { QObject::connect( - reply, - &QNetworkReply::finished, - &LuaEngine::instance(), - [reply, thisState, callback]() { + reply, &QNetworkReply::finished, guard, [reply, thisState, callback]() { reply->deleteLater(); if (reply->error() != QNetworkReply::NoError) { @@ -120,7 +120,7 @@ void addFetchModule() } else { QObject::connect( - reply, &QNetworkReply::finished, &LuaEngine::instance(), [reply, callback]() { + reply, &QNetworkReply::finished, guard, [reply, callback]() { // We don't want the network reply to be deleted by the manager, but // by the Lua GC reply->setParent(nullptr); diff --git a/src/plugins/lua/bindings/install.cpp b/src/plugins/lua/bindings/install.cpp index 59e8720d133..75fb3cadb14 100644 --- a/src/plugins/lua/bindings/install.cpp +++ b/src/plugins/lua/bindings/install.cpp @@ -253,12 +253,12 @@ void addInstallModule() sol::function wrap = async["wrap"]; sol::table install = lua.create_table(); - const ScriptPluginSpec pluginSpec = lua.get("PluginSpec"); + const ScriptPluginSpec *pluginSpec = lua.get("PluginSpec"); install["packageInfo"] = [pluginSpec](const QString &name, sol::this_state l) -> sol::optional { expected_str obj - = getInstalledPackageInfo(pluginSpec.appDataPath, name); + = getInstalledPackageInfo(pluginSpec->appDataPath, name); if (!obj) throw sol::error(obj.error().toStdString()); @@ -302,7 +302,7 @@ void addInstallModule() } const Utils::Id infoBarId = Utils::Id::fromString( - "Install" + pluginSpec.name + QString::number(qHash(installOptionsList))); + "Install" + pluginSpec->name + QString::number(qHash(installOptionsList))); InfoBarEntry entry(infoBarId, msg, InfoBarEntry::GlobalSuppression::Enabled); @@ -315,7 +315,7 @@ void addInstallModule() progress->setDisplayName(Tr::tr("Installing package(s) %1").arg("...")); tree->setRecipe( - installRecipe(pluginSpec.appDataPath, installOptionsList, callback)); + installRecipe(pluginSpec->appDataPath, installOptionsList, callback)); tree->start(); Core::ICore::infoBar()->removeInfo(infoBarId); @@ -327,7 +327,7 @@ void addInstallModule() const QString markdown = Tr::tr("The plugin \"**%1**\" would like to install the following " "package(s):\n\n") - .arg(pluginSpec.name) + .arg(pluginSpec->name) + Utils::transform(installOptionsList, [](const InstallOptions &options) { return QString("* %1 - %2 (from: [%3](%3))") .arg(options.name, options.version, options.url.toString()); diff --git a/src/plugins/lua/bindings/layout.cpp b/src/plugins/lua/bindings/layout.cpp index 4fca3ed7ef6..f7ef311afc9 100644 --- a/src/plugins/lua/bindings/layout.cpp +++ b/src/plugins/lua/bindings/layout.cpp @@ -89,7 +89,7 @@ HAS_MEM_FUNC(setTitle, hasSetTitle); HAS_MEM_FUNC(setValue, hasSetValue); template -void setProperties(std::unique_ptr &item, const sol::table &children) +void setProperties(std::unique_ptr &item, const sol::table &children, QObject *guard) { if constexpr (hasOnTextChanged::value) { sol::optional onTextChanged @@ -100,7 +100,7 @@ void setProperties(std::unique_ptr &item, const sol::table &children) auto res = LuaEngine::void_safe_call(f, text); QTC_CHECK_EXPECTED(res); }, - &LuaEngine::instance()); + guard); } } if constexpr (hasOnClicked &, QObject *guard)>::value) { @@ -112,7 +112,7 @@ void setProperties(std::unique_ptr &item, const sol::table &children) auto res = LuaEngine::void_safe_call(f); QTC_CHECK_EXPECTED(res); }, - &LuaEngine::instance()); + guard); } } if constexpr (hasSetText::value) { @@ -129,11 +129,11 @@ void setProperties(std::unique_ptr &item, const sol::table &children) } template -std::unique_ptr constructWidgetType(const sol::table &children) +std::unique_ptr constructWidgetType(const sol::table &children, QObject *guard) { std::unique_ptr item(new T({})); constructWidget(item, children); - setProperties(item, children); + setProperties(item, children, guard); return item; } @@ -143,10 +143,10 @@ std::unique_ptr constructTab(const QString &tabName, const Layout &layout) return item; } -std::unique_ptr constructTabWidget(const sol::table &children) +std::unique_ptr constructTabWidget(const sol::table &children, QObject *guard) { std::unique_ptr item(new TabWidget({})); - setProperties(item, children); + setProperties(item, children, guard); for (size_t i = 1; i < children.size(); ++i) { const auto &child = children[i]; if (child.is()) @@ -177,6 +177,9 @@ std::unique_ptr constructSplitter(const sol::table &children) void addLayoutModule() { LuaEngine::registerProvider("Layout", [](sol::state_view l) -> sol::object { + const ScriptPluginSpec *pluginSpec = l.get("PluginSpec"); + QObject *guard = pluginSpec->connectionGuard.get(); + sol::table layout = l.create_table(); layout.new_usertype( @@ -225,14 +228,18 @@ void addLayoutModule() layout.new_usertype( "PushButton", sol::call_constructor, - sol::factories(&constructWidgetType), + sol::factories([guard](const sol::table &children) { + return constructWidgetType(children, guard); + }), sol::base_classes, sol::bases()); layout.new_usertype( "Widget", sol::call_constructor, - sol::factories(&constructWidgetType), + sol::factories([guard](const sol::table &children) { + return constructWidgetType(children, guard); + }), "show", &Widget::show, "resize", @@ -243,7 +250,9 @@ void addLayoutModule() layout.new_usertype( "Stack", sol::call_constructor, - sol::factories(&constructWidgetType), + sol::factories([guard](const sol::table &children) { + return constructWidgetType(children, guard); + }), sol::base_classes, sol::bases()); @@ -257,14 +266,18 @@ void addLayoutModule() layout.new_usertype( "TextEdit", sol::call_constructor, - sol::factories(&constructWidgetType), + sol::factories([guard](const sol::table &children) { + return constructWidgetType(children, guard); + }), sol::base_classes, sol::bases()); layout.new_usertype( "SpinBox", sol::call_constructor, - sol::factories(&constructWidgetType), + sol::factories([guard](const sol::table &children) { + return constructWidgetType(children, guard); + }), sol::base_classes, sol::bases()); layout.new_usertype( @@ -276,20 +289,26 @@ void addLayoutModule() layout.new_usertype( "ToolBar", sol::call_constructor, - sol::factories(&constructWidgetType), + sol::factories([guard](const sol::table &children) { + return constructWidgetType(children, guard); + }), sol::base_classes, sol::bases()); layout.new_usertype( "TabWidget", sol::call_constructor, - sol::factories(&constructTabWidget), + sol::factories([guard](const sol::table &children) { + return constructTabWidget(children, guard); + }), sol::base_classes, sol::bases()); layout.new_usertype( "Group", sol::call_constructor, - sol::factories(&constructWidgetType), + sol::factories([guard](const sol::table &children) { + return constructWidgetType(children, guard); + }), sol::base_classes, sol::bases()); @@ -300,22 +319,6 @@ void addLayoutModule() layout["noMargin"] = &noMargin; layout["normalMargin"] = &normalMargin; - //layout["customMargin"] = [](int left, int top, int right, int bottom) { - // return customMargin(QMargins(left, top, right, bottom)); - //}; - // layout["withFormAlignment"] = &withFormAlignment; - // layout["columnStretch"] = &columnStretch; - // layout["spacing"] = &spacing; - // layout["windowTitle"] = &windowTitle; - // layout["fieldGrowthPolicy"] = &fieldGrowthPolicy; - // layout["id"] = &id; - layout["onTextChanged"] = [](const sol::function &f) { - return onTextChanged([f](const QString &text) { - auto res = LuaEngine::void_safe_call(f, text); - QTC_CHECK_EXPECTED(res); - }); - }; - return layout; }); } diff --git a/src/plugins/lua/bindings/qtcprocess.cpp b/src/plugins/lua/bindings/qtcprocess.cpp index 93d3af2e0ac..c1b4a4eccdd 100644 --- a/src/plugins/lua/bindings/qtcprocess.cpp +++ b/src/plugins/lua/bindings/qtcprocess.cpp @@ -12,30 +12,31 @@ namespace Lua::Internal { void addProcessModule() { - LuaEngine::registerProvider( - "Process", [](sol::state_view lua) -> sol::object { - sol::table async = lua.script("return require('async')", "_process_").get(); - sol::function wrap = async["wrap"]; + LuaEngine::registerProvider("Process", [](sol::state_view lua) -> sol::object { + const ScriptPluginSpec *pluginSpec = lua.get("PluginSpec"); - sol::table process = lua.create_table(); + sol::table async = lua.script("return require('async')", "_process_").get(); + sol::function wrap = async["wrap"]; - process["runInTerminal_cb"] = [](const QString &cmdline, const sol::function &cb) { + sol::table process = lua.create_table(); + + process["runInTerminal_cb"] = + [guard + = pluginSpec->connectionGuard.get()](const QString &cmdline, const sol::function &cb) { Process *p = new Process; p->setTerminalMode(TerminalMode::Run); p->setCommand(CommandLine::fromUserInput((cmdline))); p->setEnvironment(Environment::systemEnvironment()); - QObject::connect(p, &Process::done, &LuaEngine::instance(), [p, cb]() { - cb(p->exitCode()); - }); + QObject::connect(p, &Process::done, guard, [p, cb]() { cb(p->exitCode()); }); p->start(); }; - process["runInTerminal"] = wrap(process["runInTerminal_cb"]); + process["runInTerminal"] = wrap(process["runInTerminal_cb"]); - return process; - }); + return process; + }); } } // namespace Lua::Internal diff --git a/src/plugins/lua/bindings/utils.cpp b/src/plugins/lua/bindings/utils.cpp index cbf4e3e0784..2ed5a4601e5 100644 --- a/src/plugins/lua/bindings/utils.cpp +++ b/src/plugins/lua/bindings/utils.cpp @@ -19,16 +19,19 @@ void addUtilsModule() LuaEngine::registerProvider( "Utils", [futureSync = Utils::FutureSynchronizer()](sol::state_view lua) mutable -> sol::object { + const ScriptPluginSpec *pluginSpec = lua.get("PluginSpec"); + auto async = lua.script("return require('async')", "_utils_").get(); sol::table utils = lua.create_table(); - utils.set_function("waitms_cb", [](int ms, const sol::function &cb) { - QTimer::singleShot(ms, &LuaEngine::instance(), [cb]() { cb(); }); + utils.set_function("waitms_cb", [guard = pluginSpec->connectionGuard.get()](int ms, const sol::function &cb) { + QTimer::singleShot(ms, guard, [cb]() { cb(); }); }); auto dirEntries_cb = - [&futureSync](const FilePath &p, const sol::table &options, const sol::function &cb) { + [&futureSync, guard = pluginSpec->connectionGuard.get()]( + const FilePath &p, const sol::table &options, const sol::function &cb) { const QStringList nameFilters = options.get_or("nameFilters", {}); QDir::Filters fileFilters = (QDir::Filters) options.get_or("fileFilters", QDir::NoFilter); @@ -53,22 +56,22 @@ void addUtilsModule() futureSync.addFuture(future); - Utils::onFinished( - future, &LuaEngine::instance(), [cb](const QFuture &future) { - cb(future.results()); - }); + Utils::onFinished(future, guard, [cb](const QFuture &future) { + cb(future.results()); + }); }; - auto searchInPath_cb = [&futureSync](const FilePath &p, const sol::function &cb) { + auto searchInPath_cb = [&futureSync, + guard = pluginSpec->connectionGuard + .get()](const FilePath &p, const sol::function &cb) { QFuture future = Utils::asyncRun( [p](QPromise &promise) { promise.addResult(p.searchInPath()); }); futureSync.addFuture(future); - Utils::onFinished( - future, &LuaEngine::instance(), [cb](const QFuture &future) { - cb(future.result()); - }); + Utils::onFinished(future, guard, [cb](const QFuture &future) { + cb(future.result()); + }); }; utils.set_function("__dirEntries_cb__", dirEntries_cb); diff --git a/src/plugins/lua/luaengine.cpp b/src/plugins/lua/luaengine.cpp index 14925f0d6bb..be589a3b146 100644 --- a/src/plugins/lua/luaengine.cpp +++ b/src/plugins/lua/luaengine.cpp @@ -156,14 +156,13 @@ expected_str LuaEngine::prepareSetup( const FilePath appDataPath = Core::ICore::userResourcePath() / "plugin-data" / "lua" / pluginSpec.location().fileName(); - sol::environment env(lua, sol::create, lua.globals()); - lua.new_usertype( "PluginSpec", sol::no_constructor, "name", sol::property([](ScriptPluginSpec &self) { return self.name; })); - lua["PluginSpec"] = ScriptPluginSpec{pluginSpec.name(), appDataPath}; + lua["PluginSpec"] + = ScriptPluginSpec{pluginSpec.name(), appDataPath, std::make_unique()}; // TODO: only register what the plugin requested for (const auto &[name, func] : d->m_providers.asKeyValueRange()) { diff --git a/src/plugins/lua/luaengine.h b/src/plugins/lua/luaengine.h index 8fff4c0b278..ef51bbc9b0a 100644 --- a/src/plugins/lua/luaengine.h +++ b/src/plugins/lua/luaengine.h @@ -37,6 +37,7 @@ struct ScriptPluginSpec { QString name; Utils::FilePath appDataPath; + std::unique_ptr connectionGuard; }; class LUA_EXPORT LuaEngine final : public QObject