Age | Commit message (Collapse) | Author |
|
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()`.
|
|
|
|
|
|
|
|
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.
|
|
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.
|
|
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.
|
|
|
|
Lua scripts floater
|
|
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.
|
|
|
|
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.
|
|
|
|
|
|
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.
|
|
|
|
|
|
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.
|
|
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().
|
|
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>.
|
|
|
|
|
|
|