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