summaryrefslogtreecommitdiff
path: root/indra
AgeCommit message (Collapse)Author
2024-06-28Work around MSVC limitation: explicitly call fsyspath::string().Nat Goodspeed
2024-06-28Give our fsyspath an operator std::string() conversion method.Nat Goodspeed
This is redundant (but harmless) on a Posix system, but it fills a missing puzzle piece on Windows. The point of fsyspath is to be able to interchange freely between fsyspath and std::string. Existing fsyspath could be constructed and assigned from std::string, and we could explicitly call its string() method to get a std::string, but an implicit fsyspath-to-string conversion that worked on Posix would trip us up on Windows. Fix that.
2024-06-27Work around VS refusal to initialize a stringNat Goodspeed
2024-06-27Introduce TypeTag<T> template whose int value differs for each T.Nat Goodspeed
This replaces type_tag<T>(), which searched and possibly extended the type_tags unordered_map at runtime. If we called lua_emplace<T>() from different threads, that would require locking type_tags. In contrast, the compiler must instantiate a distinct TypeTag<T> for every distinct T passed to lua_emplace<T>(), so each gets a distinct value at static initialization time. No locking is required; no lookup; no allocations. Add a test to llluamanager_test.cpp to verify that each distinct T passed to lua_emplace<T>() gets its own TypeTag<T>::value, and that each gets its own destructor -- but that different lua_emplace<T>() calls with the same T share the same TypeTag<T>::value and the same destructor.
2024-06-27Make lua_emplace<T>() use Luau userdata tags with destructors.Nat Goodspeed
It turns out that Luau does not honor PUC-Rio Lua's __gc metafunction, so despite elaborate measures, the previous lua_emplace<T>() implementation would not have destroyed the contained C++ T object when the resulting userdata object was garbage-collected. Moreover, using LL.atexit() as the mechanism to destroy lua_emplace<T>() userdata objects (e.g. LuaListener) would have been slightly fragile because we also want to use LL.atexit() to make the final fiber.run() call, when appropriate. Introducing an order dependency between fiber.run() and the LuaListener destructor would not be robust. Both of those problems are addressed by leveraging one of Luau's extensions over PUC-Rio Lua. A Luau userdata object can have an int tag; and a tag can have an associated C++ destructor function. When any userdata object bearing that tag is garbage-collected, Luau will call that destructor; and Luau's lua_close() function destroys all userdata objects. The resulting lua_emplace<T>() and lua_toclass<T>() code is far simpler. It only remains to generate a distinct int tag value for each different C++ type passed to the lua_emplace<T>() template. unordered_map<std::type_index, int> addresses that need.
2024-06-27Make test.cpp test driver recognize LOGTEST_testname.Nat Goodspeed
Setting LOGTEST=DEBUG, when many unit/integration tests must be rebuilt and run, can result in lots of unnecessary output. When we only want DEBUG log output from a specific test program, make test.cpp recognize an environment variable LOGTEST_testname, where 'testname' might be the full basename of the executable, or part of INTEGRATION_TEST_testname or PROJECT_foo_TEST_testname. When test.cpp notices a non-empty variable by that name, it behaves as if LOGTEST were set to that value.
2024-06-21Exercise the simple popup.lua APIsNat Goodspeed
2024-06-21Remove pre-Floater.lua versions of the floater test scripts.Nat Goodspeed
2024-06-21login.lua works now, update test_login.lua accordingly.Nat Goodspeed
2024-06-21Introduce require/logout.lua and test_logout.lua.Nat Goodspeed
Add "userQuit" operation to LLAppViewerListener to engage LLAppViewer::userQuit(), which pops up "Are you sure?" prompt unless suppressed.
2024-06-21Multiple LL.atexit(function) calls run functions in reverse order.Nat Goodspeed
2024-06-21Use util.classctor(LLChatListener).Nat Goodspeed
2024-06-21Move newer Lua modules to scripts/lua/require subdirectory.Nat Goodspeed
2024-06-21Merge branch 'release/luau-scripting' into lua-loginNat Goodspeed
2024-06-20Merge branch 'release/luau-scripting' into lua-chat-listenerNat Goodspeed
2024-06-20Use new popup.lua, which supersedes LLNotification.lua.Nat Goodspeed
Use ClassName(ctor args) for classes using util.classctor().
2024-06-20Merge branch 'release/luau-scripting' into lua-loginNat Goodspeed
2024-06-20Revert LLLuaFloater "idle" events in favor of Lua timers.Timer().nat-goodspeed
2024-06-20Merge branch 'release/luau-scripting' into lua-speedometer-demoNat Goodspeed
2024-06-20Give popup() the ability to not wait; add popup:tip(message).Nat Goodspeed
popup:tip() engages 'SystemMessageTip'.
2024-06-20Use LLLeapListener to listen to LLNearbyChat pumpMnikolenko Productengine
2024-06-19Move popup.lua to require subdir with the rest of the modules.Nat Goodspeed
2024-06-19Improve LL.help() function.Nat Goodspeed
The help string for each lua_function() must restate the function name and its arguments. The help string is all that's shown; unless it restates the function name, LL.help() output lists terse explanations for functions whose names are not shown. Make help() prepend "LL." to help output, because these functions must be accessed via the "builtin" LL table instead of directly populating the global Lua namespace. Similarly, before string name lookup, remove "LL." prefix if specified.
2024-06-19Try harder to keep Luau's lua_getinfo() from crashing.Nat Goodspeed
2024-06-18Merge branch 'lua-login' of github.com:secondlife/viewer into lua-loginNat Goodspeed
2024-06-18Initialize lua_Debug lluau::source_path() passes to lua_getinfo().Nat Goodspeed
On Mac it doesn't seem to matter, but on Windows, leaving it uninitialized can produce garbage results and even crash the coroutine. This seems strange, since we've been assuming lua_getinfo() treats its lua_Debug* as output-only.
2024-06-18Use LL_DEBUGS("Lua") for LuaLog.Nat Goodspeed
We might decide to leave some of them in place.
2024-06-18Improve diagnostic output from running 'require' module.Nat Goodspeed
2024-06-18Make ~LuaState() walk Registry.atexit table backwardsNat Goodspeed
so cleanup happens in reverse order, as is conventional. Streamline LL.atexit() function: luaL_newmetatable() performs all the find-or-create named Registry table logic.
2024-06-18lua_emplace<T>() should permit GC despite LL.atexit() safety net.Nat Goodspeed
lua_emplace<T>() was passing LL.atexit() a closure binding the new userdata with a cleanup function. The trouble with that was that a strong reference to the new userdata would prevent it ever being garbage collected, even if that was the only remaining reference. Instead, create a new weak table referencing the userdata, and bind that into the cleanup function's closure. Then if the only remaining reference to the userdata is from the weak table, the userdata can be collected. Make lua_emplace_call_gc<T>() check the bound weak table in case the userdata has in fact been collected. Also, in lua_toclass<T>(), use luaL_checkudata() to synopsize comparing the putative userdata's metatable against the one synthesized by lua_emplace<T>(). This saves several explicit steps.
2024-06-18Make lluau::source_path() report top-level script path.Nat Goodspeed
source_path() previously reported the path of the module containing the current (lowest-level) Lua function. The effect was that the Floater.lua module would always try to look up the XUI file relative to scripts/lua/require. It makes more intuitive sense to make source_path() return the path containing the top-level script, so that a script engaging the Floater.lua module looks for the XUI file relative to the script.
2024-06-17Remove useless 'coro_name' infoMnikolenko Productengine
2024-06-17Store script's LuaListener in userdata in lua_State's Registry.Nat Goodspeed
Instead of deriving LuaListener from LLInstanceTracker with an int key, generating a unique int key and storing that key in the Registry, use new lua_emplace<LuaState>() to store the LuaListener directly in a Lua userdata object in the Lua Registry. Because lua_emplace<T>() uses LL.atexit() to guarantee that ~LuaState will destroy the T object, we no longer need ~LuaState() to make a special call specifically to destroy the LuaListener, if any. So we no longer need LuaState::getListener() separate from obtainListener(). Since LuaListener is no longer an LLInstanceTracker subclass, make LuaState::obtainListener() return LuaListener& rather than LuaListener::ptr_t.
2024-06-14Introduce LL.atexit(), internal lua_emplace<T>(), lua_toclass<T>().Nat Goodspeed
Publish new LL.atexit() function that accepts a Lua function (or C++ closure) and saves it (in Registry["atexit"] table) to call later. Make ~LuaState() walk the Registry["atexit"] table, if it exists, calling each function appended to that table. (Consider using that mechanism to clean up a LuaListener, if one was instantiated. Possibly also use for p.s. leap.run()? But that's run after every expr() call, instead of only at ~LuaState() time. Pragmatically, though, the distinction only matters for a LUA Debug Console LUA string with "clean lua_State" unchecked.) For use by future lua_function() entry points, lua_emplace<T>(ctor args...) pushes a Lua userdata object containing a newly-constructed T instance -- actually a std::optional<T> to avoid double destruction. lua_emplace<T>() is specifically intended to be usable even for T with a nontrivial destructor: it gives the userdata a metatable with a __gc function that destroys the contained T instance when the userdata is garbage collected. But since garbage collection doesn't guarantee to clean up global variables with __gc methods, lua_emplace<T>() also uses LL.atexit() to ensure that ~T() will run when the LuaState is destroyed. The companion to lua_emplace<T>() is lua_toclass<T>(), which returns a non-nullptr T* if the referenced index is in fact a userdata created by lua_emplace<T>() for the same T, that has not yet been destroyed. This lets C++ code access a T previously embedded in Lua userdata.
2024-06-14Move Lua modules for 'require' to indra/newview/scripts/lua/require.Nat Goodspeed
Make viewer_manifest.py copy them into the viewer install image. Make the require() function look for them there.
2024-06-14Add nearby chat listenerMnikolenko Productengine
2024-06-12Avoid messing up Lua's global namespace in 'require' modules.Nat Goodspeed
2024-06-12Add LL_DEBUGS("LLCoros") start/end messages.Nat Goodspeed
We have log messages when a coroutine terminates abnormally, but we don't report either when it starts or when it terminates normally. Address that.
2024-06-12Provide LUA Debug Console feedback for user typing LUA string.Nat Goodspeed
When the user explicitly types 'return expression[, expression]...' we convert the result of the expressions to LLSD and format them into the LUA Debug Console, which serves as a useful acknowledgment. But until now, if the user neither invoked print() nor ran a 'return' statement, the LUA Debug Console output remained empty. This could be a little disconcerting: you click Execute, or press Enter, and apparently nothing happens. You must either monitor viewer log output, or simply trust that the Lua snippet ran. When there are no 'return' results, at least emit 'ok'. But when the user is entering a series of no-output commands, vary the 'ok' output by appending a counter: 'ok 1', 'ok 2' etc.
2024-06-12Defend LLFloaterLUADebug against recursive calls to handlers.Nat Goodspeed
The special case of a Lua snippet that indirectly invokes the "LLNotifications" listener can result in a recursive call to LLFloaterLUADebug's handler methods. Defend against that case.
2024-06-12LuaState::expr() has log messages for ending, add for starting.Nat Goodspeed
It's helpful to see when expr() is actually going to start running a particular Lua chunk. We already report not only when it's done, but also if/when we start and finish a p.s. fiber.run() call.
2024-06-12For a single string concatenation, use operator+().Nat Goodspeed
stringize() constructs, populates and destroys a std::ostringstream, which is actually less efficient than directly allocating a std::string big enough for the result of operator+(). Maybe someday we'll specialize stringize(p0, p1) for the case in which they're both string-like, and invoke operator+() for that situation...
2024-06-12Make popup() directly pass payload.Nat Goodspeed
The expression (payload or {}) is unnecessary, since that value will be converted to LLSD -- and both Lua nil and empty table convert to LLSD::isUndefined().
2024-06-12Extract TempSet from llcallbacklist.cpp into its own tempset.h.Nat Goodspeed
2024-06-12Merge 'release/luau-scripting' of secondlife/viewer into lua-loginNat Goodspeed
2024-06-11Add popup.lua, a preliminary API for viewer notifications.Nat Goodspeed
WIP: This is known not to work yet.
2024-06-11Add login.lua module with login() function.Nat Goodspeed
The nullary login() call (login with saved credentials) has been tested, but the binary login(username, password) call is known not to work yet.
2024-06-11Add to UI.lua a set of 'LLWindow' listener operations.Nat Goodspeed
Add listviews(), viewinfo(), click(), doubleclick(), drag(), keypress() and type(). WIP: These are ported from Python LEAP equivalents, but the Lua implementation has only been partially tested.
2024-06-11Fix a couple bugs in startup.lua.Nat Goodspeed
The 'startup' table, the module's namespace, must be defined near the top because its local waitfor:process() override references startup. The byname table's metatable's __index() function wants to raise an error if you try to access an undefined entry, but it referenced t[k] to check that, producing infinite recursion. Use rawget(t, k) instead. Also use new leap.WaitFor(args) syntax instead of leap.WaitFor:new(args).
2024-06-11Allow Python-like 'object = ClassName(ctor args)' constructor calls.Nat Goodspeed
The discussions we've read about Lua classes conventionally use ClassName:new() as the constructor, and so far we've followed that convention. But setting metaclass(ClassName).__call = ClassName.new permits Lua to respond to calls of the form ClassName(ctor args) by implicitly calling ClassName:new(ctor args). Introduce util.classctor(). Calling util.classctor(ClassName) sets ClassName's metaclass's __call to ClassName's constructor method. If the constructor method is named something other than new(), pass ClassName.method as the second arg. Use util.classctor() on each of our classes that defines a new() method. Replace ClassName:new(args) calls with ClassName(args) calls throughout.