From 6f2598e370940503b9944509c51808ba74656860 Mon Sep 17 00:00:00 2001 From: Kubat <mael.martin31@gmail.com> Date: Thu, 2 Sep 2021 19:55:36 +0200 Subject: [PATCH] LOG: The src/Lib/Script subfolder uses the new LOG API [+REGRESSION] /!\ REGRESSION: We no longer have the line of the last lua error! --- src/Lib/Log.hh | 23 +++++- src/Lib/Script/CRTPLuaScriptObject.hh | 23 +++--- .../CRTPLuaScriptObject/FreeFunctions.cc | 2 +- .../FunctionDeclaration.cc | 4 +- .../CRTPLuaScriptObject/JobDeclaration.cc | 10 +-- .../CRTPLuaScriptObject/ModuleDeclaration.cc | 10 +-- src/Lib/Script/LuaContext.cc | 77 ++++++++++--------- src/Lib/Script/LuaContext.hh | 52 ++++++------- src/Lib/Script/ScriptStore.cc | 33 +++----- src/Lib/Script/ScriptStore.hh | 9 +-- src/UI/MainWindow.cc | 8 +- 11 files changed, 128 insertions(+), 123 deletions(-) diff --git a/src/Lib/Log.hh b/src/Lib/Log.hh index a14b5392..1aa83afa 100644 --- a/src/Lib/Log.hh +++ b/src/Lib/Log.hh @@ -3,7 +3,8 @@ #include "Utils.hh" // Create a logger with a category -#define VIVY_GET_LOGGER(sink, cat) (sink)->newLogger(std::string_view{ #cat }) +#define VIVY_GET_LOGGER(sink, cat) (sink)->newLogger(std::string_view{ #cat }) +#define VIVY_GET_LOGGER_BY_STORED_NAME(sink, cat) (sink)->newLogger(std::string_view{ cat }) // Log something in a logger #define VIVY_LOG_WITH_LEVEL(log, level) (log)->logEvent(__FILE__, __func__, __LINE__, level) @@ -27,15 +28,24 @@ #define VIVY_DCL_LOG_DISPATCH_WITH(sink, name, dispatch, ...) \ std::shared_ptr<dispatch> name{ (sink)->newDispatcher<dispatch>(__VA_ARGS__) }; -// Install logger for the object. -#define VIVY_LOGGABLE_OBJECT(sink, name, logger) \ - std::shared_ptr<Logger> logger{ VIVY_GET_LOGGER(sink, name) }; \ +#define VIVY_LOGGABLE_OBJECT_METHODS_ONLY(logger) \ LogMessage logFatal() const noexcept { return VIVY_LOG_FATAL(logger); } \ LogMessage logError() const noexcept { return VIVY_LOG_ERR(logger); } \ LogMessage logWarning() const noexcept { return VIVY_LOG_WARN(logger); } \ LogMessage logInfo() const noexcept { return VIVY_LOG_INFO(logger); } \ LogMessage logDebug() const noexcept { return VIVY_LOG_DEBUG(logger); } +// Install logger for the object. +#define VIVY_LOGGABLE_OBJECT(sink, name, logger) \ + std::shared_ptr<Logger> logger{ VIVY_GET_LOGGER(sink, name) }; \ + VIVY_LOGGABLE_OBJECT_METHODS_ONLY(logger) + +// Install logger for the object. Here `name` must be a variable that can be +// used to create a std::stding_view. +#define VIVY_LOGGABLE_OBJECT_BY_STORED_NAME(sink, name, logger) \ + std::shared_ptr<Logger> logger{ VIVY_GET_LOGGER_BY_STORED_NAME(sink, name) }; \ + VIVY_LOGGABLE_OBJECT_METHODS_ONLY(logger) + #define VIVY_LOG_CTOR() logDebug() << "<<CTOR>> " #define VIVY_LOG_DTOR() logDebug() << "<<DTOR>> " @@ -45,6 +55,11 @@ #define VIVY_APP_LOGGABLE_OBJECT(name, logger) \ VIVY_LOGGABLE_OBJECT(vivyApp->getLogSink(), name, logger) +// Install logger, use the global LogSink, with a stored name like in the +// VIVY_LOGGABLE_OBJECT_BY_STORED_NAME macro. +#define VIVY_APP_LOGGABLE_OBJECT_BY_STORED_NAME(name, logger) \ + VIVY_LOGGABLE_OBJECT_BY_STORED_NAME(vivyApp->getLogSink(), name, logger) + namespace Vivy { class LogSinkDispatcher; diff --git a/src/Lib/Script/CRTPLuaScriptObject.hh b/src/Lib/Script/CRTPLuaScriptObject.hh index 3a5a51e7..480c5695 100644 --- a/src/Lib/Script/CRTPLuaScriptObject.hh +++ b/src/Lib/Script/CRTPLuaScriptObject.hh @@ -1,5 +1,7 @@ #pragma once +#include "../../VivyApplication.hh" +#include "../../Lib/Log.hh" #include "LuaContext.hh" #include "ScriptOption.hh" @@ -20,15 +22,14 @@ namespace Vivy::Script #define method_list static constexpr inline auto -#define LUA_SCRIPTABLE_CLASS(theClassName) \ - VIVY_UNMOVABLE_OBJECT(theClassName) \ - static constexpr char className[] = #theClassName; \ - friend CRTPLuaScriptObject<theClassName>; \ - theClassName(lua_State *L) noexcept \ - { \ - err(LuaContext::getContext(L)) \ - << "Create instance of " << theClassName::className << "\n"; \ - } \ +#define LUA_SCRIPTABLE_CLASS(theClassName) \ + VIVY_UNMOVABLE_OBJECT(theClassName) \ + static constexpr char className[] = #theClassName; \ + friend CRTPLuaScriptObject<theClassName>; \ + theClassName(lua_State *L) noexcept \ + { \ + out(LuaContext::getContext(L)) << "Create instance of " << theClassName::className; \ + } \ ~theClassName() noexcept {} // The type of the thing that a job iterate over @@ -46,6 +47,8 @@ getJobIteratorTypeFromString(const std::string_view it) noexcept // CRTP to expose objects to Lua template <class Object> class CRTPLuaScriptObject { protected: + VIVY_APP_LOGGABLE_OBJECT_BY_STORED_NAME(Object::className, logger) + [[noreturn]] static void luaGlobalError(lua_State *const L, const std::string &str) noexcept { const auto *const context = LuaContext::getContext(L); @@ -90,7 +93,7 @@ protected: { const Object *const obj = reinterpret_cast<const Object *>(lua_topointer(L, 1)); auto *context = LuaContext::getContext(L); - err(context) << "Call destructor for " << Object::className << "\n"; + out(context) << "Call destructor for " << Object::className; obj->~Object(); return 0; } diff --git a/src/Lib/Script/CRTPLuaScriptObject/FreeFunctions.cc b/src/Lib/Script/CRTPLuaScriptObject/FreeFunctions.cc index 98149102..3b49778e 100644 --- a/src/Lib/Script/CRTPLuaScriptObject/FreeFunctions.cc +++ b/src/Lib/Script/CRTPLuaScriptObject/FreeFunctions.cc @@ -6,7 +6,7 @@ int FreeFunctions::print(lua_State *const L) noexcept { const std::string_view arg = CHECK_STRING_VIEW(L, 1); - out(LuaContext::getContext(L)) << "OUT: " << arg << "\n"; + out(LuaContext::getContext(L)) << "OUT: " << arg; LUA_RETURN_NOTHING(L); } diff --git a/src/Lib/Script/CRTPLuaScriptObject/FunctionDeclaration.cc b/src/Lib/Script/CRTPLuaScriptObject/FunctionDeclaration.cc index 13fd29aa..e773a13f 100644 --- a/src/Lib/Script/CRTPLuaScriptObject/FunctionDeclaration.cc +++ b/src/Lib/Script/CRTPLuaScriptObject/FunctionDeclaration.cc @@ -40,10 +40,10 @@ FunctionDeclaration::pushToRuntime(lua_State *const L) noexcept if (self->isImported) err(context) << "The function \"" << self->parentScript << "::" << self->name - << "\" is an imported function\n"; + << "\" is an imported function"; else if (context->registerDeclaration(self) == LuaContext::Code::Error) - context->setFailed("Failed to register function " + self->name); + context->failedWith("Failed to register function " + self->name); LUA_RETURN_NOTHING(L); } diff --git a/src/Lib/Script/CRTPLuaScriptObject/JobDeclaration.cc b/src/Lib/Script/CRTPLuaScriptObject/JobDeclaration.cc index f55a170b..c3761f3a 100644 --- a/src/Lib/Script/CRTPLuaScriptObject/JobDeclaration.cc +++ b/src/Lib/Script/CRTPLuaScriptObject/JobDeclaration.cc @@ -34,14 +34,14 @@ JobDeclaration::setOptions(lua_State *L) noexcept { auto *const context = LuaContext::getContext(L); JobDeclaration *const job = JobDeclaration::CHECK(L, 1); - err(context) << "Set options for job '" << job->name << "'\n"; + err(context) << "Set options for job '" << job->name << "'"; IterateOverArray(L, 2, [&context, job, L]() noexcept -> bool { OptionDeclaration *opt = OptionDeclaration::CHECK(L, -1); for (const auto &[name, value] : opt->options) { err(context) << "\tregister option \"" << name << "\" with type \"" - << value.getSignature() << "\"\n"; + << value.getSignature() << "\""; } job->options.push_back(opt); @@ -70,11 +70,11 @@ JobDeclaration::pushToRuntime(lua_State *const L) noexcept lua_settop(L, 1); if (self->isImported) - err(context) << "The job \"" << self->parentScript << "::" << self->name - << "\" is an imported job\n"; + err(context) + << "The job \"" << self->parentScript << "::" << self->name << "\" is an imported job"; else if (context->registerDeclaration(self) == LuaContext::Code::Error) - context->setFailed("Failed to register job " + self->name); + context->failedWith("Failed to register job " + self->name); LUA_RETURN_NOTHING(L); } diff --git a/src/Lib/Script/CRTPLuaScriptObject/ModuleDeclaration.cc b/src/Lib/Script/CRTPLuaScriptObject/ModuleDeclaration.cc index 5d535ea6..1a35f0ce 100644 --- a/src/Lib/Script/CRTPLuaScriptObject/ModuleDeclaration.cc +++ b/src/Lib/Script/CRTPLuaScriptObject/ModuleDeclaration.cc @@ -10,7 +10,7 @@ ModuleDeclaration::resolvModules(LuaContext *const context) noexcept if (mod) { importedModules.emplace_back(mod); } else { - context->setFailed("Failed to find needed module: " + str); + context->failedWith("Failed to find needed module: " + str); return false; } } @@ -77,7 +77,7 @@ ModuleDeclaration::exportFunction(lua_State *const L, const int tableIndex, { auto *const context = LuaContext::getContext(L); FunctionDeclaration *const func = context->getFunction(moduleName, name); - out(context) << "Export function " << moduleName << "::" << name << '\n'; + out(context) << "Export function " << moduleName << "::" << name; lua_pushinteger(L, 2); lua_gettable(L, tableIndex); @@ -100,7 +100,7 @@ ModuleDeclaration::exportJob(lua_State *const L, const int tableIndex, const std } else { - out(context) << "Export job " << moduleName << "::" << name << "{" << itTypeStr << "}\n"; + out(context) << "Export job " << moduleName << "::" << name << "{" << itTypeStr << "}"; lua_pushinteger(L, 3); lua_gettable(L, tableIndex); @@ -212,11 +212,11 @@ ModuleDeclaration::pushToRuntime(lua_State *const L) noexcept Utils::uniqAndSort<std::string>(self->importNames); // Better for all std algorithms self->validateModule(L); // May abort the LUA context - err(context) << "Register module \"" << self->moduleName << "\" in the runtime!\n"; + err(context) << "Register module " << VIVY_LOG_QUOTED(self->moduleName) << " in the runtime!"; lua_settop(L, 1); if (context->registerDeclaration(self) == LuaContext::Code::Error) - context->setFailed("Failed to register module " + self->moduleName); + context->failedWith("Failed to register module " + self->moduleName); TODO(Import needed modules here !) diff --git a/src/Lib/Script/LuaContext.cc b/src/Lib/Script/LuaContext.cc index 6d5f32e5..48ac5354 100644 --- a/src/Lib/Script/LuaContext.cc +++ b/src/Lib/Script/LuaContext.cc @@ -5,10 +5,8 @@ // LuaContext implementation using namespace Vivy::Script; -LuaContext::LuaContext(LoggerType &out, LoggerType &err) noexcept +LuaContext::LuaContext() noexcept : L(luaL_newstate()) - , streamOut(out) - , streamErr(err) { luaL_openlibs(L); @@ -56,19 +54,19 @@ LuaContext::loadDocument(std::shared_ptr<ScriptDocument> doc) noexcept const QFileInfo fileCheck(doc->getName()); if (!fileCheck.exists()) { err(this) << "File " << doc->getName().toStdString() << " for document " - << doc->getUuid().toString().toStdString() << " doesn't exists\n"; + << doc->getUuid().toString().toStdString() << " doesn't exists"; return Code::Error; } lastLoadedModule = ""; const auto rc = loadFile(fileCheck.absoluteFilePath().toStdString().c_str()); if (rc != Code::Success) { - setFailed("Failed to load the module file"); + setFailedWith("Failed to load the module file"); return rc; } if (lastLoadedModule.empty()) { - setFailed("No module was loaded"); + setFailedWith("No module was loaded"); return Code::Error; } @@ -85,7 +83,7 @@ LuaContext::Code LuaContext::exec() noexcept { if (lua_pcall(L, 0, 0, 0) != LUA_OK) { - err(this) << getLastLuaError().toStdString().c_str() << "\n"; + err(this) << getLastLuaError().toStdString().c_str(); return Code::Error; } return Code::Success; @@ -95,7 +93,7 @@ LuaContext::Code LuaContext::loadString(const char *str) noexcept { if (luaL_loadstring(L, str) != LUA_OK) { - err(this) << "Error loading string: " << getLastLuaError().toStdString() << "\n"; + err(this) << "Error loading string: " << getLastLuaError(); return Code::Error; } return exec(); @@ -106,8 +104,7 @@ LuaContext::loadFile(const char *file) noexcept { currentFile = file; if (luaL_loadfile(L, file) != LUA_OK) { - err(this) - << "Error loading file " << file << ": " << getLastLuaError().toStdString() << "\n"; + err(this) << "Error loading file " << file << ": " << getLastLuaError(); currentFile = ""; return Code::Error; } @@ -129,6 +126,32 @@ LuaContext::getLastLuaError() noexcept return ret; } +void +LuaContext::failedWith(const std::string &errorMessage) noexcept +{ + failedWith(errorMessage.c_str()); +} + +void +LuaContext::failedWith(const char *errorMessage) noexcept +{ + setFailedWith(errorMessage); + lua_error(L); + exit(EXIT_FAILURE); // Should not be there! +} + +void +LuaContext::setFailedWith(const char *errorMessage) noexcept +{ + lua_pushstring(L, errorMessage); +} + +void +LuaContext::setFailedWith(const std::string &errorMessage) noexcept +{ + setFailedWith(errorMessage.c_str()); +} + lua_State * LuaContext::getState() noexcept { @@ -136,7 +159,7 @@ LuaContext::getState() noexcept } bool -LuaContext::moduleExists(string_view mod) const noexcept +LuaContext::moduleExists(const std::string_view mod) const noexcept { return modules.count(mod) >= 1; } @@ -156,14 +179,14 @@ LuaContext::registerDeclaration(const JobDeclaration *const job) noexcept } LuaContext::Code -LuaContext::registerToMapTuple( - string_view module, string_view name, - std::map<std::tuple<string_view, string_view>, const int> *const map) noexcept +LuaContext::registerToMapTuple(const std::string_view module, const std::string_view name, + std::map<std::tuple<const std::string_view, const std::string_view>, + const int> *const map) noexcept { if (map->count({ module, name }) >= 1) return Error; - streamErr << "Register \"" << module << "::" << name << "\"\n"; + logInfo() << "Register " << module << "::" << name; // WARN: The object needs to be already checked! const int r = luaL_ref(L, LUA_REGISTRYINDEX); @@ -175,11 +198,12 @@ LuaContext::Code LuaContext::registerDeclaration(const ModuleDeclaration *const mod) noexcept { if (moduleExists(mod->moduleName)) { - streamErr << "The module \"" << mod->moduleName << "\" is already registered!"; + logError() + << "The module " << VIVY_LOG_QUOTED(mod->moduleName) << " is already registered!"; return Code::Error; } - streamErr << "Register module \"" << mod->moduleName << "\"\n"; + logInfo() << "Register module " << VIVY_LOG_QUOTED(mod->moduleName); ModuleDeclaration::CHECK(L, -1); const int r = luaL_ref(L, LUA_REGISTRYINDEX); @@ -247,25 +271,6 @@ LuaContext::getAllModuleName() const noexcept return moduleNames; } -void -LuaContext::setFailed(const std::string &msg) noexcept -{ - failureString = msg; - streamErr << "LuaContext is now in failure state: " << msg << "\n"; -} - -bool -LuaContext::isFailed() const noexcept -{ - return failureString.size() != 0; -} - -const std::string & -LuaContext::getFailureDescription() const noexcept -{ - return failureString; -} - const std::string & LuaContext::getCurrentLuaFile() const { diff --git a/src/Lib/Script/LuaContext.hh b/src/Lib/Script/LuaContext.hh index afc55e82..06da7b43 100644 --- a/src/Lib/Script/LuaContext.hh +++ b/src/Lib/Script/LuaContext.hh @@ -1,5 +1,7 @@ #pragma once +#include "../../VivyApplication.hh" +#include "../Log.hh" #include "../Utils.hh" struct lua_State; @@ -22,12 +24,7 @@ namespace Vivy::Script // New Lua script instance class LuaContext final { VIVY_UNMOVABLE_OBJECT(LuaContext) - -public: - using LoggerType = std::stringstream; - -private: - using string_view = const std::string_view; + VIVY_APP_LOGGABLE_OBJECT(LuaContext, logger) lua_State *L{ nullptr }; @@ -35,29 +32,36 @@ private: std::string currentFile{}; std::string lastLoadedModule{}; - std::map<string_view, const int> modules = {}; - std::map<std::tuple<string_view, string_view>, const int> functions = {}; - std::map<std::tuple<string_view, string_view>, const int> jobs = {}; + std::map<const std::string_view, const int> modules = {}; + std::map<std::tuple<const std::string_view, const std::string_view>, const int> functions = {}; + std::map<std::tuple<const std::string_view, const std::string_view>, const int> jobs = {}; static inline std::map<const lua_State *const, LuaContext *const> contextList = {}; - LoggerType &streamOut; - LoggerType &streamErr; - public: enum class Code { Success, Error }; static constexpr inline Code Success = Code::Success; static constexpr inline Code Error = Code::Error; - LuaContext(LoggerType &out, LoggerType &err) noexcept; + LuaContext() noexcept; ~LuaContext() noexcept; Code loadDocument(std::shared_ptr<ScriptDocument>) noexcept; + QString getLastLuaError() noexcept; + + // Fail and abort the LuaContext + [[noreturn]] void failedWith(const std::string &) noexcept; + [[noreturn]] void failedWith(const char *) noexcept; + + // Set the error message for the lua context and continue + void setFailedWith(const char *) noexcept; + void setFailedWith(const std::string &) noexcept; + lua_State *getState() noexcept; - auto &getOutputStream() noexcept { return streamOut; } - auto &getErrorStream() noexcept { return streamErr; } + decltype(auto) getOutputStream() noexcept { return logInfo(); } + decltype(auto) getErrorStream() noexcept { return logError(); } operator lua_State *() noexcept { return L; } static LuaContext *getContext(const lua_State *const) noexcept; @@ -74,12 +78,6 @@ public: JobDeclaration *getJob(const std::string_view, const std::string_view) const noexcept; const std::vector<std::string_view> getAllModuleName() const noexcept; - // Some verifications gone wrong, this is not a Lua error, this is a script - // runtime error. - void setFailed(const std::string &) noexcept; - bool isFailed() const noexcept; - const std::string &getFailureDescription() const noexcept; - // Makes only sens when called from within loadFile and loadPackagedFile const std::string &getCurrentLuaFile() const; void setLastLoadedModule(const std::string &) noexcept; @@ -92,22 +90,22 @@ private: Code loadFile(const char *) noexcept; void loadPackagedFile(const QString &) noexcept; - Code registerToMapTuple( - const std::string_view module, const std::string_view name, - std::map<std::tuple<string_view, string_view>, const int> *const mapPtr) noexcept; - bool moduleExists(string_view) const noexcept; + Code registerToMapTuple(const std::string_view module, const std::string_view name, + std::map<std::tuple<const std::string_view, const std::string_view>, + const int> *const mapPtr) noexcept; + bool moduleExists(const std::string_view) const noexcept; // Swap the env, needed before executing a user script! void swapEnv() noexcept; }; -static inline auto & +static inline decltype(auto) out(LuaContext *const context) noexcept { return context->getOutputStream(); } -static inline auto & +static inline decltype(auto) err(LuaContext *const context) noexcept { return context->getErrorStream(); diff --git a/src/Lib/Script/ScriptStore.cc b/src/Lib/Script/ScriptStore.cc index 593809f7..14ee4bc2 100644 --- a/src/Lib/Script/ScriptStore.cc +++ b/src/Lib/Script/ScriptStore.cc @@ -41,35 +41,14 @@ ScriptStore::getLoadedScripts() const noexcept void ScriptStore::resetLoadedScripts() noexcept { - luaContext.reset(new Script::LuaContext(streamOut, streamErr)); + luaContext.reset(new Script::LuaContext()); } -std::optional<std::tuple<int, std::string>> +bool ScriptStore::executeScript(Uuid id) noexcept { const auto script = documents.at(id); - const bool ok = luaContext->loadDocument(script) == Code::Success; - QString errorString; - std::string buffer; - - std::cout << "STDOUT:\n"; - while (std::getline(streamOut, buffer, '\n')) - std::cout << '\t' << buffer << '\n'; - - if (!ok) { - // /home/.../sample-spec.module:31: bad argument #1 to 'export'... - std::cout << "STDERR:\n"; - QRegExp errorDetect(QStringLiteral("^([^\\:]*)\\:(\\d+)\\:(.*)\\n?$")); - while (std::getline(streamErr, buffer, '\n')) { - std::cout << '\t' << buffer << '\n'; - if (errorDetect.indexIn(QString::fromUtf8(buffer.c_str())) != -1) { - std::string errorDesc = errorDetect.cap(3).toStdString(); - return std::tuple{ QString(errorDetect.cap(2)).toInt(), Utils::trim(errorDesc) }; - } - } - } - - return std::nullopt; + return luaContext->loadDocument(script) == Code::Success; } const std::vector<std::string_view> @@ -83,3 +62,9 @@ ScriptStore::getModule(const std::string_view str) const noexcept { return luaContext->getModule(str); } + +QString +ScriptStore::getLastLuaError() noexcept +{ + return luaContext ? luaContext->getLastLuaError() : QString(); +} diff --git a/src/Lib/Script/ScriptStore.hh b/src/Lib/Script/ScriptStore.hh index 21d0b983..636da75c 100644 --- a/src/Lib/Script/ScriptStore.hh +++ b/src/Lib/Script/ScriptStore.hh @@ -18,8 +18,7 @@ class ScriptStore final : public CRTPStore<ScriptStore, ScriptDocument> { static constexpr inline int outBufferSize = 1024; public: - using Item = std::tuple<Uuid, QString>; - using LoggerType = Script::LuaContext::LoggerType; + using Item = std::tuple<Uuid, QString>; explicit ScriptStore() noexcept; @@ -27,7 +26,9 @@ public: void resetLoadedScripts() noexcept; void loadScriptFolder(const QString &folderPath); std::vector<Item> getLoadedScripts() const noexcept; - std::optional<std::tuple<int, std::string>> executeScript(Uuid) noexcept; + bool executeScript(Uuid) noexcept; + + QString getLastLuaError() noexcept; // Get modules from scripts const std::vector<std::string_view> getLoadedModules() const noexcept; @@ -35,7 +36,5 @@ public: private: std::unique_ptr<Script::LuaContext> luaContext{ nullptr }; - LoggerType streamOut; - LoggerType streamErr; }; } diff --git a/src/UI/MainWindow.cc b/src/UI/MainWindow.cc index 0130076f..b0f5f030 100644 --- a/src/UI/MainWindow.cc +++ b/src/UI/MainWindow.cc @@ -345,12 +345,12 @@ MainWindow::openDocument() noexcept else if (fileType == Utils::DocumentType::VivyScript) { auto scriptDocument = vivyApp->scriptStore->loadDocument(filename); - auto errorTuple = vivyApp->scriptStore->executeScript(scriptDocument->getUuid()); + const bool rc = vivyApp->scriptStore->executeScript(scriptDocument->getUuid()); ScriptDocumentView *newView = new ScriptDocumentView(scriptDocument, documents); - if (errorTuple.has_value()) { - const auto &[line, desc] = errorTuple.value(); - emit newView->luaErrorFound(line, QString::fromUtf8(desc.c_str())); + if (!rc) { + const auto &[line, desc] = std::tuple{ 0, vivyApp->scriptStore->getLastLuaError() }; + emit newView->luaErrorFound(line, desc); } addTab(newView); -- GitLab