summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--indra/llcommon/lua_function.cpp17
-rw-r--r--indra/llcommon/lua_function.h162
-rw-r--r--indra/newview/lluilistener.cpp43
-rw-r--r--indra/newview/lluilistener.h1
-rw-r--r--indra/newview/scripts/lua/require/UI.lua6
-rw-r--r--indra/newview/scripts/lua/test_callables.lua6
6 files changed, 224 insertions, 11 deletions
diff --git a/indra/llcommon/lua_function.cpp b/indra/llcommon/lua_function.cpp
index 42bba80ed5..b173d17ede 100644
--- a/indra/llcommon/lua_function.cpp
+++ b/indra/llcommon/lua_function.cpp
@@ -32,6 +32,8 @@
#include "lualistener.h"
#include "stringize.h"
+using namespace std::literals; // e.g. std::string_view literals: "this"sv
+
const S32 INTERRUPTS_MAX_LIMIT = 20000;
const S32 INTERRUPTS_SUSPEND_LIMIT = 100;
@@ -41,7 +43,7 @@ const S32 INTERRUPTS_SUSPEND_LIMIT = 100;
int DistinctInt::mValues{0};
/*****************************************************************************
-* luau namespace
+* lluau namespace
*****************************************************************************/
namespace
{
@@ -93,21 +95,14 @@ fsyspath lluau::source_path(lua_State* L)
void lluau::set_interrupts_counter(lua_State *L, S32 counter)
{
- luaL_checkstack(L, 2, nullptr);
- lua_pushstring(L, "_INTERRUPTS");
- lua_pushinteger(L, counter);
- lua_rawset(L, LUA_REGISTRYINDEX);
+ lua_rawsetfield(L, LUA_REGISTRYINDEX, "_INTERRUPTS"sv, lua_Integer(counter));
}
void lluau::check_interrupts_counter(lua_State* L)
{
- luaL_checkstack(L, 1, nullptr);
- lua_pushstring(L, "_INTERRUPTS");
- lua_rawget(L, LUA_REGISTRYINDEX);
- S32 counter = lua_tointeger(L, -1);
- lua_pop(L, 1);
+ auto counter = lua_rawgetfield<lua_Integer>(L, LUA_REGISTRYINDEX, "_INTERRUPTS"sv);
- lluau::set_interrupts_counter(L, ++counter);
+ set_interrupts_counter(L, ++counter);
if (counter > INTERRUPTS_MAX_LIMIT)
{
lluau::error(L, "Possible infinite loop, terminated.");
diff --git a/indra/llcommon/lua_function.h b/indra/llcommon/lua_function.h
index 7f7a7566f3..7b59af30f5 100644
--- a/indra/llcommon/lua_function.h
+++ b/indra/llcommon/lua_function.h
@@ -18,6 +18,7 @@
#include "luau/lualib.h"
#include "fsyspath.h"
#include "llerror.h"
+#include "llsd.h"
#include "stringize.h"
#include <exception> // std::uncaught_exceptions()
#include <memory> // std::shared_ptr
@@ -169,6 +170,167 @@ private:
};
/*****************************************************************************
+* lua_push() wrappers for generic code
+*****************************************************************************/
+inline
+void lua_push(lua_State* L, bool b)
+{
+ lua_pushboolean(L, int(b));
+}
+
+inline
+void lua_push(lua_State* L, lua_CFunction fn)
+{
+ lua_pushcfunction(L, fn, "");
+}
+
+inline
+void lua_push(lua_State* L, lua_Integer n)
+{
+ lua_pushinteger(L, n);
+}
+
+inline
+void lua_push(lua_State* L, void* p)
+{
+ lua_pushlightuserdata(L, p);
+}
+
+inline
+void lua_push(lua_State* L, const LLSD& data)
+{
+ lua_pushllsd(L, data);
+}
+
+inline
+void lua_push(lua_State* L, const char* s, size_t len)
+{
+ lua_pushlstring(L, s, len);
+}
+
+inline
+void lua_push(lua_State* L)
+{
+ lua_pushnil(L);
+}
+
+inline
+void lua_push(lua_State* L, lua_Number n)
+{
+ lua_pushnumber(L, n);
+}
+
+inline
+void lua_push(lua_State* L, const std::string& s)
+{
+ lua_pushstdstring(L, s);
+}
+
+inline
+void lua_push(lua_State* L, const char* s)
+{
+ lua_pushstring(L, s);
+}
+
+/*****************************************************************************
+* lua_to() wrappers for generic code
+*****************************************************************************/
+template <typename T>
+auto lua_to(lua_State* L, int index);
+
+template <>
+inline
+auto lua_to<bool>(lua_State* L, int index)
+{
+ return lua_toboolean(L, index);
+}
+
+template <>
+inline
+auto lua_to<lua_CFunction>(lua_State* L, int index)
+{
+ return lua_tocfunction(L, index);
+}
+
+template <>
+inline
+auto lua_to<lua_Integer>(lua_State* L, int index)
+{
+ return lua_tointeger(L, index);
+}
+
+template <>
+inline
+auto lua_to<LLSD>(lua_State* L, int index)
+{
+ return lua_tollsd(L, index);
+}
+
+template <>
+inline
+auto lua_to<lua_Number>(lua_State* L, int index)
+{
+ return lua_tonumber(L, index);
+}
+
+template <>
+inline
+auto lua_to<std::string>(lua_State* L, int index)
+{
+ return lua_tostdstring(L, index);
+}
+
+template <>
+inline
+auto lua_to<void*>(lua_State* L, int index)
+{
+ return lua_touserdata(L, index);
+}
+
+/*****************************************************************************
+* field operations
+*****************************************************************************/
+// return to C++, from table at index, the value of field k
+template <typename T>
+auto lua_getfieldv(lua_State* L, int index, const char* k)
+{
+ luaL_checkstack(L, 1, nullptr);
+ lua_getfield(L, index, k);
+ LuaPopper pop(L, 1);
+ return lua_to<T>(L, -1);
+}
+
+// set in table at index, as field k, the specified C++ value
+template <typename T>
+auto lua_setfieldv(lua_State* L, int index, const char* k, const T& value)
+{
+ luaL_checkstack(L, 1, nullptr);
+ lua_push(L, value);
+ lua_setfield(L, index, k);
+}
+
+// return to C++, from table at index, the value of field k (without metamethods)
+template <typename T>
+auto lua_rawgetfield(lua_State* L, int index, const std::string_view& k)
+{
+ luaL_checkstack(L, 1, nullptr);
+ lua_pushlstring(L, k.data(), k.length());
+ lua_rawget(L, index);
+ LuaPopper pop(L, 1);
+ return lua_to<T>(L, -1);
+}
+
+// set in table at index, as field k, the specified C++ value (without metamethods)
+template <typename T>
+void lua_rawsetfield(lua_State* L, int index, const std::string_view& k, const T& value)
+{
+ luaL_checkstack(L, 2, nullptr);
+ lua_pushlstring(L, k.data(), k.length());
+ lua_push(L, value);
+ lua_rawset(L, index);
+}
+
+/*****************************************************************************
* lua_function (and helper class LuaFunction)
*****************************************************************************/
/**
diff --git a/indra/newview/lluilistener.cpp b/indra/newview/lluilistener.cpp
index c73c93859a..2b2187a73b 100644
--- a/indra/newview/lluilistener.cpp
+++ b/indra/newview/lluilistener.cpp
@@ -55,6 +55,13 @@ LLUIListener::LLUIListener():
&LLUIListener::call,
llsd::map("function", LLSD(), "reply", LLSD()));
+ add("callables",
+ "Return a list [\"callables\"] of dicts {name, access} of functions registered to\n"
+ "invoke with \"call\".\n"
+ "access has values \"allow\", \"block\" or \"throttle\".",
+ &LLUIListener::callables,
+ llsd::map("reply", LLSD::String()));
+
add("getValue",
"For the UI control identified by the path in [\"path\"], return the control's\n"
"current value as [\"value\"] reply.",
@@ -131,6 +138,42 @@ void LLUIListener::call(const LLSD& event)
(info->callback_func)(NULL, event["parameter"]);
}
+void LLUIListener::callables(const LLSD& event) const
+{
+ Response response(LLSD(), event);
+
+ using Registry = LLUICtrl::CommitCallbackRegistry;
+ using Method = Registry::Registrar& (*)();
+ static Method registrars[] =
+ {
+ &Registry::defaultRegistrar,
+ &Registry::currentRegistrar,
+ };
+ LLSD list;
+ for (auto method : registrars)
+ {
+ auto& registrar{ (*method)() };
+ for (auto it = registrar.beginItems(), end = registrar.endItems(); it != end; ++it)
+ {
+ LLSD entry{ llsd::map("name", it->first) };
+ switch (it->second.handle_untrusted)
+ {
+ case LLUICtrl::CommitCallbackInfo::UNTRUSTED_ALLOW:
+ entry["access"] = "allow";
+ break;
+ case LLUICtrl::CommitCallbackInfo::UNTRUSTED_BLOCK:
+ entry["access"] = "block";
+ break;
+ case LLUICtrl::CommitCallbackInfo::UNTRUSTED_THROTTLE:
+ entry["access"] = "throttle";
+ break;
+ }
+ list.append(entry);
+ }
+ }
+ response["callables"] = list;
+}
+
void LLUIListener::getValue(const LLSD&event) const
{
Response response(LLSD(), event);
diff --git a/indra/newview/lluilistener.h b/indra/newview/lluilistener.h
index cbb5014300..c90253ab59 100644
--- a/indra/newview/lluilistener.h
+++ b/indra/newview/lluilistener.h
@@ -41,6 +41,7 @@ public:
private:
void call(const LLSD& event);
+ void callables(const LLSD& event) const;
void getValue(const LLSD&event) const;
void addMenu(const LLSD&event) const;
diff --git a/indra/newview/scripts/lua/require/UI.lua b/indra/newview/scripts/lua/require/UI.lua
index 28488ff3e1..06b49c6269 100644
--- a/indra/newview/scripts/lua/require/UI.lua
+++ b/indra/newview/scripts/lua/require/UI.lua
@@ -14,6 +14,10 @@ function UI.call(func, parameter)
leap.request('UI', {op='call', ['function']=func, parameter=parameter})
end
+function UI.callables()
+ return leap.request('UI', {op='callables'}).callables
+end
+
function UI.getValue(path)
return leap.request('UI', {op='getValue', path=path})['value']
end
@@ -152,6 +156,7 @@ function UI.addMenuBranch(...)
return leap.request('UI', args)
end
+-- see UI.callables() for valid values of 'func'
function UI.addMenuItem(...)
local args = mapargs('name,label,parent_menu,func,param', ...)
args.op = 'addMenuItem'
@@ -163,4 +168,5 @@ function UI.addMenuSeparator(...)
args.op = 'addMenuSeparator'
return leap.request('UI', args)
end
+
return UI
diff --git a/indra/newview/scripts/lua/test_callables.lua b/indra/newview/scripts/lua/test_callables.lua
new file mode 100644
index 0000000000..1bee062db8
--- /dev/null
+++ b/indra/newview/scripts/lua/test_callables.lua
@@ -0,0 +1,6 @@
+startup=require 'startup'
+UI=require 'UI'
+startup.wait('STATE_LOGIN_WAIT')
+for _, cbl in pairs(UI.callables()) do
+ print(`{cbl.name} ({cbl.access})`)
+end