diff --git a/rsc/lua/lib.lua b/rsc/lua/lib.lua index fb3f7efe7338c8f7be4aa9da7976dccdb82a1aac..084d70b46074618c191081e8a300d3af42bec12a 100644 --- a/rsc/lua/lib.lua +++ b/rsc/lua/lib.lua @@ -83,6 +83,11 @@ function Vivy:newColor (colorString) return false end +function Vivy:start () return Vivy.___Fun:start() end +function Vivy:finish () return Vivy.___Fun:finish() end +function Vivy:width () return Vivy.___Fun:width() end +function Vivy:height () return Vivy.___Fun:height() end + -- In case we are able to do the _ENV <- Vivy one day... Vivy["Vivy"] = Vivy diff --git a/src/Lib/Script/CRTPLuaScriptObject.hh b/src/Lib/Script/CRTPLuaScriptObject.hh index 480c569595e985fd42dc1137c2f9d678c34e3582..6772bb5a779fd79e8354e9c37499a71a47494b7f 100644 --- a/src/Lib/Script/CRTPLuaScriptObject.hh +++ b/src/Lib/Script/CRTPLuaScriptObject.hh @@ -17,24 +17,34 @@ namespace Vivy::Script #define LUA_RETURN_NOTHING(L) { lua_settop(L, 0); return 0; } // clang-format on +#define method_list static constexpr inline auto #define script_class(theClassName) \ class theClassName final : public CRTPLuaScriptObject<theClassName> -#define method_list static constexpr inline auto +#define LUA_DECL_GETTER(type, luaName, value) \ + static int luaName(lua_State *const L) noexcept \ + { \ + return luaPushValue<type>(L, CHECK(L, 1)->value); \ + } -#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; \ - } \ +#define LUA_SCRIPTABLE_CLASS_MANUAL_CTOR(theClassName) \ + VIVY_UNMOVABLE_OBJECT(theClassName) \ + static constexpr char className[] = #theClassName; \ + friend CRTPLuaScriptObject<theClassName>; \ ~theClassName() noexcept {} +#define LUA_SCRIPTABLE_CLASS(theClassName) \ + LUA_SCRIPTABLE_CLASS_MANUAL_CTOR(theClassName) \ + theClassName(lua_State *L) noexcept \ + { \ + err(LuaContext::getContext(L)) \ + << "Create instance of " << theClassName::className << "\n"; \ + } + // The type of the thing that a job iterate over enum class JobIteratorType { Line = 1, Syllabe = 2 }; -static inline JobIteratorType + +[[maybe_unused]] static inline JobIteratorType getJobIteratorTypeFromString(const std::string_view it) noexcept { if (it == "LINE") @@ -57,6 +67,30 @@ protected: exit(EXIT_FAILURE); // lua_error should not return anything } + // Push something onto the stack, must be specialized + template <typename T> static int luaPushValue(lua_State *const L, const T &thing) noexcept; + using std_str = std::string; + using std_strv = std::string_view; + + template <> static int luaPushValue<int>(lua_State *const L, const int &thing) noexcept + { + lua_pushinteger(L, thing); + return 1; + } + + template <> + static int luaPushValue<std_strv>(lua_State *const L, const std_strv &thing) noexcept + { + lua_pushlstring(L, thing.data(), thing.size()); + return 1; + } + + template <> static int luaPushValue<std_str>(lua_State *const L, const std_str &thing) noexcept + { + lua_pushstring(L, thing.c_str()); + return 1; + } + static bool PushFunctionFromRegistry(lua_State *const L, const int key) noexcept { if (key >= 0) { @@ -324,17 +358,28 @@ public: // Holds all the free functions (well, not really free functions here...) script_class (FreeFunctions) { - LUA_SCRIPTABLE_CLASS(FreeFunctions) + LUA_SCRIPTABLE_CLASS_MANUAL_CTOR(FreeFunctions) + + FreeFunctions(lua_State *const) noexcept; static int print(lua_State *const) noexcept; static int getModule(lua_State *const) noexcept; - static int start(lua_State *const) noexcept; - static int finish(lua_State *const) noexcept; + + LUA_DECL_GETTER(int, start, audioStart) + LUA_DECL_GETTER(int, finish, audioFinish) + LUA_DECL_GETTER(int, width, videoWidth) + LUA_DECL_GETTER(int, height, videoHeight) method_list metaMethods = { luaRegDefaultGC }; method_list methods = { LUA_DECL_METHOD(FreeFunctions, getModule), LUA_DECL_METHOD(FreeFunctions, start), LUA_DECL_METHOD(FreeFunctions, finish), - LUA_DECL_METHOD(FreeFunctions, print), LUA_DECL_CREATE(FreeFunctions) }; + LUA_DECL_METHOD(FreeFunctions, width), + LUA_DECL_METHOD(FreeFunctions, height), + LUA_DECL_METHOD(FreeFunctions, print), + LUA_DECL_CREATE(FreeFunctions) }; + + int videoWidth{ 0 }, videoHeight{ 0 }; + int audioStart{ 0 }, audioFinish{ 0 }; }; } diff --git a/src/Lib/Script/CRTPLuaScriptObject/FreeFunctions.cc b/src/Lib/Script/CRTPLuaScriptObject/FreeFunctions.cc index 3b49778e26aa4accd499e8dd03deaf4054face67..36c9cee70d84ed5ad0de6ccae9d6c000d0358bfe 100644 --- a/src/Lib/Script/CRTPLuaScriptObject/FreeFunctions.cc +++ b/src/Lib/Script/CRTPLuaScriptObject/FreeFunctions.cc @@ -1,7 +1,43 @@ #include "../CRTPLuaScriptObject.hh" +#include "../LuaContext.hh" +#include "../../Document/CRTPSubDocument.hh" +#include "../../Document/VivyDocument.hh" +#include "../../Audio.hh" +#include "../../Video.hh" +#include "../../../VivyApplication.hh" using namespace Vivy::Script; +FreeFunctions::FreeFunctions(lua_State *const L) noexcept +{ + const auto *const context = LuaContext::getContext(L); + out(context) << "Creating the FreeFunctions lua object!"; + + std::shared_ptr<VivyDocument> vivyDoc = context->getAttachedVivyDocument(); + if (vivyDoc) { + if (!(vivyDoc->checkDocumentCapabilities(VivyDocument::AudioAble) && + vivyDoc->checkDocumentCapabilities(VivyDocument::AssAble) && + vivyDoc->checkDocumentCapabilities(VivyDocument::AudioAble))) { + err(context) << "The VivyDocument is not a complete document, " + << "can't load it for scripting"; + luaGlobalError(L, "Attached VivyDocument is not complete"); + } + + out(context) << "Initializing the FreeFunctions lua object with the VivyDocument"; + std::shared_ptr<VideoStream> video = vivyDoc->getVideoSubDocument()->getDefaultStream(); + [[maybe_unused]] std::shared_ptr<AudioStream> audio = + vivyDoc->getAudioSubDocument()->getDefaultStream(); + + videoWidth = video->getWidth(); + videoHeight = video->getWidth(); + TODO(Set getters values for audio) + } + + else { + out(context) << "No attached Vivy document in the Lua context"; + } +} + int FreeFunctions::print(lua_State *const L) noexcept { @@ -18,19 +54,3 @@ FreeFunctions::getModule(lua_State *const L) noexcept [[maybe_unused]] const ModuleDeclaration *const mod = context->getModule(modName); return 1; } - -int -FreeFunctions::start(lua_State *const L) noexcept -{ - lua_settop(L, 0); - lua_pushinteger(L, 0); - return 1; -} - -int -FreeFunctions::finish(lua_State *const L) noexcept -{ - lua_settop(L, 0); - lua_pushinteger(L, 0); - return 1; -} diff --git a/src/Lib/Script/LuaContext.cc b/src/Lib/Script/LuaContext.cc index 48ac5354729be15bbe4e597dc78e7d5a4924e7b9..52c00dd7d2ded0365192014bbc7feea9c9fd518c 100644 --- a/src/Lib/Script/LuaContext.cc +++ b/src/Lib/Script/LuaContext.cc @@ -1,6 +1,7 @@ #include "CRTPLuaScriptObject.hh" #include "ScriptDocument.hh" #include "LuaContext.hh" +#include "../Document/VivyDocument.hh" // LuaContext implementation using namespace Vivy::Script; @@ -48,6 +49,15 @@ LuaContext::getContext(const lua_State *const state) noexcept return contextList.contains(state) ? contextList.at(state) : nullptr; } +LuaContext::Code +LuaContext::loadDocument(std::shared_ptr<Vivy::VivyDocument> doc) noexcept +{ + if (attachedVivyDocument != nullptr) + return Error; + attachedVivyDocument = doc; + return Success; +} + LuaContext::Code LuaContext::loadDocument(std::shared_ptr<ScriptDocument> doc) noexcept { @@ -158,6 +168,12 @@ LuaContext::getState() noexcept return L; } +std::shared_ptr<Vivy::VivyDocument> +LuaContext::getAttachedVivyDocument() const noexcept +{ + return attachedVivyDocument; +} + bool LuaContext::moduleExists(const std::string_view mod) const noexcept { diff --git a/src/Lib/Script/LuaContext.hh b/src/Lib/Script/LuaContext.hh index 06da7b4318d42a683802bfbdc7f4fa577160649d..318751abaeb7ad0e7cbf53616a20b7aad56a8a0b 100644 --- a/src/Lib/Script/LuaContext.hh +++ b/src/Lib/Script/LuaContext.hh @@ -9,6 +9,7 @@ struct lua_State; namespace Vivy { class ScriptDocument; +class VivyDocument; } namespace Vivy::Script @@ -27,6 +28,7 @@ class LuaContext final { VIVY_APP_LOGGABLE_OBJECT(LuaContext, logger) lua_State *L{ nullptr }; + std::shared_ptr<Vivy::VivyDocument> attachedVivyDocument{ nullptr }; std::string failureString{}; std::string currentFile{}; @@ -47,6 +49,7 @@ public: ~LuaContext() noexcept; Code loadDocument(std::shared_ptr<ScriptDocument>) noexcept; + Code loadDocument(std::shared_ptr<Vivy::VivyDocument>) noexcept; QString getLastLuaError() noexcept; @@ -59,9 +62,10 @@ public: void setFailedWith(const std::string &) noexcept; lua_State *getState() noexcept; + std::shared_ptr<Vivy::VivyDocument> getAttachedVivyDocument() const noexcept; - decltype(auto) getOutputStream() noexcept { return logInfo(); } - decltype(auto) getErrorStream() noexcept { return logError(); } + decltype(auto) getOutputStream() const noexcept { return logInfo(); } + decltype(auto) getErrorStream() const noexcept { return logError(); } operator lua_State *() noexcept { return L; } static LuaContext *getContext(const lua_State *const) noexcept; @@ -99,14 +103,14 @@ private: void swapEnv() noexcept; }; -static inline decltype(auto) -out(LuaContext *const context) noexcept +[[maybe_unused]] static inline decltype(auto) +out(const LuaContext *const context) noexcept { return context->getOutputStream(); } -static inline decltype(auto) -err(LuaContext *const context) noexcept +[[maybe_unused]] static inline decltype(auto) +err(const LuaContext *const context) noexcept { return context->getErrorStream(); } diff --git a/src/Lib/Script/ScriptStore.cc b/src/Lib/Script/ScriptStore.cc index 14ee4bc27d8a7e94c854e99c1df62be71c8fa929..44b8e5d16652b9ac658debbdd7ec40c7ea1bfeba 100644 --- a/src/Lib/Script/ScriptStore.cc +++ b/src/Lib/Script/ScriptStore.cc @@ -47,10 +47,22 @@ ScriptStore::resetLoadedScripts() noexcept bool ScriptStore::executeScript(Uuid id) noexcept { - const auto script = documents.at(id); + const auto &script = documents.at(id); return luaContext->loadDocument(script) == Code::Success; } +bool +ScriptStore::executeScript(Uuid id, std::shared_ptr<Vivy::VivyDocument> doc) noexcept +{ + if (doc == nullptr) + return false; + if (luaContext->loadDocument(doc) != Script::LuaContext::Success) { + luaContext->setFailedWith("A VivyDocument is already loaded, can't attach a new one"); + return false; + } + return executeScript(id); +} + const std::vector<std::string_view> ScriptStore::getLoadedModules() const noexcept { diff --git a/src/Lib/Script/ScriptStore.hh b/src/Lib/Script/ScriptStore.hh index 636da75c11c3eec908e695e5d3529f062999b101..0a1968a6d3b2579843e248605191eca7e534690c 100644 --- a/src/Lib/Script/ScriptStore.hh +++ b/src/Lib/Script/ScriptStore.hh @@ -1,6 +1,7 @@ #pragma once #include "../CRTPStore.hh" +#include "../Document/VivyDocument.hh" #include "ScriptDocument.hh" #include "LuaContext.hh" @@ -27,6 +28,7 @@ public: void loadScriptFolder(const QString &folderPath); std::vector<Item> getLoadedScripts() const noexcept; bool executeScript(Uuid) noexcept; + bool executeScript(Uuid, std::shared_ptr<Vivy::VivyDocument>) noexcept; QString getLastLuaError() noexcept; diff --git a/src/VivyApplication.cc b/src/VivyApplication.cc index f511fe9d3f34a840508a268651b7a4658639c04f..d474fca4c21e01152380f3f4b5ff196d013d1cfa 100644 --- a/src/VivyApplication.cc +++ b/src/VivyApplication.cc @@ -2,7 +2,9 @@ #include "UI/MainWindow.hh" #include "UI/DockWidgetTitleBar.hh" #include "Lib/Document/VivyDocumentStore.hh" +#include "Lib/Document/VivyDocument.hh" #include "Lib/Script/ScriptStore.hh" +#include "Lib/Script/ScriptDocument.hh" using namespace Vivy; @@ -14,7 +16,25 @@ VivyApplication::VivyApplication(int &argc, char **argv) VIVY_LOG_CTOR() << "Construction is OK"; if (argc >= 2) { - selectedDoc = scriptStore->loadDocument(QString::fromUtf8(argv[1])); + for (int i = 1; i < argc; ++i) { + const QString passedFileName(QString::fromUtf8(argv[1])); + const QFileInfo passedArgumentFile(passedFileName); + Utils::DocumentType passedFileType; + if (Utils::detectDocumentType(passedArgumentFile, &passedFileType)) { + if (passedFileType == Utils::DocumentType::Vivy) { + selectedVivyDoc = documentStore->loadDocument(passedFileName); + logInfo() << "Select vivy document " << passedFileName; + } else if (passedFileType == Utils::DocumentType::VivyScript) { + selectedScriptDoc = scriptStore->loadDocument(passedFileName); + logInfo() << "Select script document " << passedFileName; + } else { + logError() << "Not handled file type for file " << passedFileName; + } + } else { + logError() << "Unrecognized file type for file " << passedFileName; + } + } + selectedType = ApplicationType::CLI; VIVY_LOG_CTOR() << "Select the ApplicationType::CLI"; } @@ -70,9 +90,12 @@ VivyApplication::exec() noexcept switch (selectedType) { case ApplicationType::CLI: { - if ((selectedDoc == nullptr) || (!scriptStore->executeScript(selectedDoc->getUuid()))) + if ((selectedVivyDoc == nullptr) || (selectedScriptDoc == nullptr)) return 1; + if (!scriptStore->executeScript(selectedScriptDoc->getUuid(), selectedVivyDoc)) + return 2; + for (const auto &str : scriptStore->getLoadedModules()) { std::cout << "Module " << str << " was loaded!\n"; [[maybe_unused]] const auto *mod = scriptStore->getModule(str); diff --git a/src/VivyApplication.hh b/src/VivyApplication.hh index 7317c7ea752bfea182e02d36a48bcf82281dd74a..654989b1805c41220045f297bfeca642a51f3632 100644 --- a/src/VivyApplication.hh +++ b/src/VivyApplication.hh @@ -16,8 +16,8 @@ #define VIVY_APP_LOGGABLE_OBJECT_BY_STORED_NAME(name, logger) \ VIVY_LOGGABLE_OBJECT_BY_STORED_NAME(vivyApp->getLogSink(), name, logger) -#define currentVivyDocument() dynamic_cast<::Vivy::VivyDocument *>(vivyApp->getCurrentDocument()) -#define currentScriptDocument dynamic_cast<::Vivy::ScriptDocument *>(vivyApp->getCurrentDocument()) +#define currentVivyDocument dynamic_cast<VivyDocument *>(vivyApp->getCurrentDocument()) +#define currentScriptDocument dynamic_cast<ScriptDocument *>(vivyApp->getCurrentDocument()) // Only support dark theme for now #define VIVY_ICON_APP ":icons/vivy.png" @@ -49,6 +49,7 @@ class ScriptStore; class VivyDocumentStore; class AbstractDocument; class ScriptDocument; +class VivyDocument; // Vivy application class class VivyApplication : public QApplication { @@ -87,7 +88,8 @@ private: ApplicationType selectedType{ ApplicationType::GUI }; // ApplicationType::CLI Only! - std::shared_ptr<ScriptDocument> selectedDoc{ nullptr }; + std::shared_ptr<ScriptDocument> selectedScriptDoc{ nullptr }; + std::shared_ptr<VivyDocument> selectedVivyDoc{ nullptr }; public: VivyApplication(int &argc, char **argv);