summaryrefslogtreecommitdiff
path: root/indra/newview/llluamanager.h
AgeCommit message (Collapse)Author
2024-09-20Add ability to pass command-line arguments to a Lua script.Nat Goodspeed
Introduce `ScriptCommand` class that parses a command line into a script name and optional args, using bash-like quoting and escaping. `ScriptCommand` searches for a file with that script name on a passed list of directories; the directories may be specified relative to a particular base directory. `ScriptCommand` supports the special case of a script name containing unescaped spaces. It guarantees that either the returned script file exists, or its `error()` string is non-empty. Replace `LLLeap::create()` logic, from which `ScriptCommand` was partly derived, with a `ScriptCommand` instance. Make `LLLUAmanager::runScriptFile()` use a `ScriptCommand` instance to parse the passed command line. Subsume `LLAppViewer::init()` script-path-searching logic for `--luafile` into `ScriptCommand`. In fact that lambda now simply calls `LLLUAmanager::runScriptFile()`. Make `lluau::dostring()` accept an optional vector of script argument strings. Following PUC-Rio Lua convention, pass these arguments into a Lua script as the predefined global `arg`, and also as the script's `...` argument. `LuaState::expr()` also accepts and passes through script argument strings. Change the log tag for the Lua script interruption message: if we want it, we can still enable it, but we don't necessarily want it along with all other "Lua" DEBUG messages. Remove `LuaState::script_finished_fn`, which isn't used any more. Also remove the corresponding `LLLUAmanager::script_finished_fn`. This allows us to simplify `~LuaState()` slightly, as well as the parameter signatures for `LLLUAmanager::runScriptFile()` and `runScriptLine()`.
2024-09-04Merge branch 'release/luau-scripting' into lua-mergeNat Goodspeed
2024-08-29Add simple metrics of Lua usageMaxim Nikolenko
2024-08-28Ditch trailing spaces.Nat Goodspeed
2024-07-10Remove ability to reuse a LuaState between LLLUAmanager functions.Nat Goodspeed
Remove LLLUAmanager::mumbleScriptLine() LuaState& parameters. Make startScriptLine(), waitScriptLine() and runScriptLine() exactly parallel to startScriptFile(), waitScriptFile() and runScriptFile(). That means that runScriptLine()'s C++ coroutine instantiates and destroys its own LuaState, which means that LL.atexit() functions will run on the Lua-specific C++ coroutine rather than (say) the viewer's main coroutine. Introduce LLLUAmanager::script_result typedef for std::pair<int, LLSD> and use in method returns. Remove LuaState::initLuaState(); move its logic back into the constructor. Remove initLuaState() calls in the expr() error cases: they're moot now that we won't get subsequent expr() calls on the same LuaState instance. Remove LLFloaterLUADebug "Use clean lua_State" checkbox and the cleanLuaState() method. Remove mState member. Remove explicit LuaState declarations from LLLUAmanager tests. Adapt one test for implicit LuaState: it was directly calling LuaState::obtainListener() to discover the LuaListener's reply-pump name. But since that test also captures two leap.request() calls from the Lua script, it can just look at the "reply" key in either of those requests.
2024-06-28Add LuaAutorunPath, LuaCommandPath and LuaRequirePath settings.Nat Goodspeed
Remove AutorunLuaScriptFile and the LLLUAmanager::runScriptOnLogin() method that checked it. Instead, iterate over LuaAutorunPath directories at viewer startup, iterate over *.lua files in each and implicitly run those. LuaCommandPath and LuaRequirePath are not yet implemented.
2024-04-17Reintroduce LLCoros::killreq() to request killing a named coroutine.Nat Goodspeed
Make LLCoros constructor echo "LLApp" status-change events on new "LLCoros" event pump. Rename LLCoros::kill() to killreq() because this operation only registers a request for the named coroutine to terminate next time it calls checkStop(). Add a new CoroData member to record the name of the coroutine requesting termination. killreq() sets that and also posts "killreq" to "LLCoros". Add an optional final-cleanup callback to LLCoros::checkStop(). Make checkStop() check for a pending killreq() request as well as viewer termination. Introduce new LLCoros::Killed exception for that case. Introduce LLCoros::getStopListener(), with two overloads, to encapsulate some of the messy logic to listen (perhaps temporarily) for viewer shutdown. Both overloads are for use by code at the source end of a queue or promise or other resource for which coroutines might still be waiting at viewer shutdown time. One overload is specifically for when the caller knows the name of the one and only coroutine that will wait on the resource (e.g. because the caller IS that coroutine). That overload honors killreq(). Use getStopListener() to simplify the four existing places where we set up such a listener. Add a fifth: also make WorkQueue listen for viewer shutdown (resolving a TODO comment). Remove LLLUAmanager::terminateScript(), getTerminationList() and the static sTerminationList. In the Lua interrupt callback, instead of checking sTerminationList, call LLCoros::checkStop(). Change LLFloaterLUAScripts terminate-script logic to call LLCoros::killreq() instead of posting on "LLLua" and calling LLLUAmanager::terminateScript(). Drop LLApp::setStatus() posting to "LLLua" LLEventPump: the above makes that moot.
2024-04-08Add script termination option to 'Lua Scripts' floaterMnikolenko Productengine
2024-04-03Merge pull request #1101 from secondlife/lua-scripts-floaternat-goodspeed
Lua scripts floater
2024-04-03Introduce fsyspath subclass of std::filesystem::path.Nat Goodspeed
Our std::strings are UTF-8 encoded, so conversion from std::string to std::filesystem::path must use UTF-8 decoding. The native Windows std::filesystem::path constructor and assignment operator accepting std::string use "native narrow encoding," which mangles path strings containing UTF-8 encoded non-ASCII characters. fsyspath's std::string constructor and assignment operator explicitly engage std::filesystem::u8path() to handle encoding. u8path() is deprecated in C++20, but once we adapt fsyspath's conversion to C++20 conventions, consuming code need not be modified.
2024-04-03Add RAII class for adding/erasing script entries; code clean upMnikolenko Productengine
2024-04-02Streamline std::filesystem::path conversions in LLRequireResolver.Nat Goodspeed
Make LLRequireResolver capture std::filesystem::path instances, instead of std::strings, for the path to resolve and the source directory. Store the running script's containing directory instead of calling parent_path() over and over. Demote Lua LL.post_on() logging to DEBUG level instead of INFO.
2024-04-01Add 'Lua Scripts' floaterMnikolenko Productengine
2024-03-27Run each script file with new LuaStateMnikolenko Productengine
2024-02-29Refactor require() to make it easier to reason about Lua stack usage.Nat Goodspeed
Push throwing Lua errors down into LLRequireResolver::findModule() and findModuleImpl() so their callers don't have to handle the error case. That eliminates finishrequire(). require() itself now only retrieves (and pops) the passed module name and calls LLRequireResolver::resolveRequire() to do the actual work. resolveRequire() is now void. It only instantiates LLRequireResolver and calls its findModule(). findModule() is now also void. It's guaranteed to either push the loaded Lua module or throw a Lua error. In particular, when findPathImpl() cannot find the specified module, findModule() throws an error. That replaces ModuleStatus::NotFound. Since std::filesystem::path::append() aka operator/() detects when its right operand is absolute and, in that case, discards the left operand, we no longer need resolveAndStoreDefaultPaths(): we can just invoke that operation inline. When findModule() pushes _MODULES on the Lua stack, it uses LuaRemover (below) to ensure that _MODULES is removed again no matter how findModules() exits. findModuleImpl() now accepts the candidate pathname as its argument. That eliminates mAbsolutePath. findModuleImpl() now returns only bool: true means the module was found and loaded and pushed on the Lua stack, false means not found and nothing was pushed; no return means an error was reported. Push running a newly found module's source file down into findModuleImpl(). That eliminates the distinction between Cached and FileRead, which obviates ModuleStatus: a bool return means either "previously cached" or "we read it, compiled it, loaded it and ran it." That also eliminates the need to store the module's textual content in mSourceCode. Similarly, once loading the module succeeds, findModuleImpl() caches it in _MODULES right away. That eliminates ResolvedRequire since we need not pass the full pathname of the found module (or its contents) back up through the call chain. Move require() code that runs the new module into private runModule() method, called by findModuleImpl() in the not-cached case. runModule() is the only remaining method that can push either a string error message or the desired module, because of its funny stack manipulations. That means the check for a string error message on the stack top can move down to findModuleImpl(). Add LuaRemover class to ensure that on exit from some particular C++ block, the specified Lua stack entry will definitely be removed. This is different from LuaPopper in that it engages lua_remove() rather than lua_pop(). Also ditch obsolete await_event() Lua entry point.
2024-02-23require() code clean-upMnikolenko Productengine
2024-02-20Initial require implementationMnikolenko Productengine
2024-02-07Add LLLUAmanager::startScriptFile(), startScriptLine() functions.Nat Goodspeed
Break out for LLLUAmanager consumers the promise/future semantics of waitScriptFile() and waitScriptLine(). startScriptMumble() uses runScriptMumble() to launch a coroutine to run the specified Lua script or chunk, providing an internal adapter callback to set a promise on completion. It then returns to its caller the future obtained from that promise. This allows a caller to call startScriptMumble(), run in parallel with the Lua coroutine for a while and then call get() on the returned future to wait for results. waitScriptMumble() is then trivially implemented using startScriptMumble(). Fix runScriptLine()'s logic to abbreviate the passed Lua chunk for use as the description. We were erroneously assigning back through a string_view of the parameter, which overwrote a temporary string in the argument list. With Lua 5.4, listen_events() tried to discover the main "thread" (Lua coroutine) associated with the current lua_State so we could call async callbacks on that thread. Luau doesn't seem to provide that feature, so run callbacks on whichever thread calls listen_events(). Reinstate original multi-argument lua_print_msg(), tweaked to avoid the Lua 5.4 lua_rotate() function, which is missing from Luau.
2024-02-07Add machinery to capture result of running a Lua script or snippet.Nat Goodspeed
Add LuaState::expr() that evaluates a Lua snippet and reports back any result (or error) left on the stack. Add LLLUAmanager::runScriptFile() and runScriptLine() overloads that accept a callback with an (int count, LLSD result) signature. The count disambiguates (error, no result, one result, array of results). Also add overloads that accept an existing LuaState instance. Also add waitScriptFile() and waitScriptLine() methods that pause the calling coroutine until the Lua script completes, and return its results. Instead of giving LuaState a description to use for all subsequent checkLua() calls, remove description from its constructor and data members. Move to expr() and checkLua() parameters: we want a description specific to each operation, rather than for the LuaState as a whole. This prepares for persistent LuaState instances. For now, the existing script_finished_fn semantics remain: the callback will be called only when the LuaState is destroyed. This may need to change as we migrate towards longer-lasting LuaState instances. Make lua_function(name) macro append suffixes to the name for both the LuaFunction subclass declaration and the instance declaration. This allows publishing a lua_function() name such as sleep(), which already has a different C++ declaration. Move the Lua sleep() entry point to a standalone lua_function(sleep), instead of a lambda in the body of runScriptFile().
2023-10-02DRTVWR-589: Add initial integration test for LLLUAmanager.Nat Goodspeed
The first test runs a Lua script that calls post_on(), listen_events() and await_event() to engage in LLEventPump handshakes with the test program. Make llluamanager.cpp testable by putting LL_TEST conditionals around lots of viewer-internals headers and the lua_function definitions that engage them. Since LuaListener::connect() is called by its constructor, make it a static method that explicitly accepts the lua_State* (instead of finding it as mState). Add that parameter to its two existing calls. Add a debug log message when LuaListener is destroyed. This surfaced the need to pass a no-op deleter when listen_events() constructs a LuaListener::ptr_t. When compiled for LL_TEST, make LuaListener::mReplyPump an LLEventLogProxyFor<LLEventStream> instead of a plain LLEventStream. For debugging purposes, add a type string "LLEventLogProxy" for LLEventPumps::make(). A make() call with this type will return an LLEventLogProxyFor<LLEventStream>.
2023-09-13autorun selected script after loginMnikolenko Productengine
2023-09-06addcallback to display error msgMnikolenko Productengine
2023-09-05Initial prototype of embedded LUAMnikolenko Productengine