summaryrefslogtreecommitdiff
path: root/indra/newview/scripts/lua
diff options
context:
space:
mode:
Diffstat (limited to 'indra/newview/scripts/lua')
-rw-r--r--indra/newview/scripts/lua/require/LLInventory.lua41
-rw-r--r--indra/newview/scripts/lua/require/UI.lua5
-rw-r--r--indra/newview/scripts/lua/require/result_view.lua98
-rw-r--r--indra/newview/scripts/lua/test_LLInventory.lua15
-rw-r--r--indra/newview/scripts/lua/test_inv_resultset.lua18
-rw-r--r--indra/newview/scripts/lua/test_result_view.lua55
-rw-r--r--indra/newview/scripts/lua/test_setdtor.lua91
7 files changed, 305 insertions, 18 deletions
diff --git a/indra/newview/scripts/lua/require/LLInventory.lua b/indra/newview/scripts/lua/require/LLInventory.lua
index dd1b910250..2c80a8602b 100644
--- a/indra/newview/scripts/lua/require/LLInventory.lua
+++ b/indra/newview/scripts/lua/require/LLInventory.lua
@@ -1,12 +1,28 @@
local leap = require 'leap'
local mapargs = require 'mapargs'
+local result_view = require 'result_view'
+
+local function result(keys)
+ -- capture result_view() instances for both categories and items
+ local result_table = {
+ categories=result_view(keys.categories),
+ items=result_view(keys.items),
+ -- call result_table:close() to release result sets before garbage
+ -- collection or script completion
+ close = function(self)
+ result_view.close(keys.categories[1], keys.items[1])
+ end
+ }
+ -- When the result_table is destroyed, close its result_views.
+ return LL.setdtor('LLInventory result', result_table, result_table.close)
+end
local LLInventory = {}
-- Get the items/folders info by provided IDs,
-- reply will contain "items" and "categories" tables accordingly
function LLInventory.getItemsInfo(item_ids)
- return leap.request('LLInventory', {op = 'getItemsInfo', item_ids=item_ids})
+ return result(leap.request('LLInventory', {op = 'getItemsInfo', item_ids=item_ids}))
end
-- Get the table of folder type names, which can be later used to get the ID of the basic folders
@@ -19,30 +35,33 @@ function LLInventory.getBasicFolderID(ft_name)
return leap.request('LLInventory', {op = 'getBasicFolderID', ft_name=ft_name}).id
end
--- Get the table of asset type names, which can be later used to get the specific items via LLInventory.collectDescendentsIf(...)
+-- Get the table of asset type names, which can be later used to get the specific items via LLInventory.collectDescendantsIf(...)
function LLInventory.getAssetTypeNames()
return leap.request('LLInventory', {op = 'getAssetTypeNames'}).names
end
--- Get the direct descendents of the 'folder_id' provided,
+-- Get the direct descendants of the 'folder_id' provided,
-- reply will contain "items" and "categories" tables accordingly
-function LLInventory.getDirectDescendents(folder_id)
- return leap.request('LLInventory', {op = 'getDirectDescendents', folder_id=folder_id})
+function LLInventory.getDirectDescendants(folder_id)
+ return result(leap.request('LLInventory', {op = 'getDirectDescendants', folder_id=folder_id}))
end
+-- backwards compatibility
+LLInventory.getDirectDescendents = LLInventory.getDirectDescendants
--- Get the descendents of the 'folder_id' provided, which pass specified filters
+-- Get the descendants of the 'folder_id' provided, which pass specified filters
-- reply will contain "items" and "categories" tables accordingly
--- LLInventory.collectDescendentsIf{ folder_id -- parent folder ID
+-- LLInventory.collectDescendantsIf{ folder_id -- parent folder ID
-- [, name] -- name (substring)
-- [, desc] -- description (substring)
-- [, type] -- asset type
-- [, limit] -- item count limit in reply, maximum and default is 100
-- [, filter_links]} -- EXCLUDE_LINKS - don't show links, ONLY_LINKS - only show links, INCLUDE_LINKS - show links too (default)
-function LLInventory.collectDescendentsIf(...)
+function LLInventory.collectDescendantsIf(...)
local args = mapargs('folder_id,name,desc,type,filter_links,limit', ...)
- args.op = 'collectDescendentsIf'
- return leap.request('LLInventory', args)
+ args.op = 'collectDescendantsIf'
+ return result(leap.request('LLInventory', args))
end
-
+-- backwards compatibility
+LLInventory.collectDescendentsIf = LLInventory.collectDescendantsIf
return LLInventory
diff --git a/indra/newview/scripts/lua/require/UI.lua b/indra/newview/scripts/lua/require/UI.lua
index bbcae3514a..73a76fa6b8 100644
--- a/indra/newview/scripts/lua/require/UI.lua
+++ b/indra/newview/scripts/lua/require/UI.lua
@@ -2,6 +2,7 @@
local leap = require 'leap'
local mapargs = require 'mapargs'
+local result_view = require 'result_view'
local Timer = (require 'timers').Timer
local util = require 'util'
@@ -234,7 +235,9 @@ function UI.closeAllFloaters()
end
function UI.getFloaterNames()
- return leap.request("LLFloaterReg", {op = "getFloaterNames"}).floaters
+ local key_length = leap.request("LLFloaterReg", {op = "getFloaterNames"}).floaters
+ local view = result_view(key_length)
+ return LL.setdtor('registered floater names', view, view.close)
end
return UI
diff --git a/indra/newview/scripts/lua/require/result_view.lua b/indra/newview/scripts/lua/require/result_view.lua
new file mode 100644
index 0000000000..5301d7838c
--- /dev/null
+++ b/indra/newview/scripts/lua/require/result_view.lua
@@ -0,0 +1,98 @@
+local leap = require 'leap'
+
+-- metatable for every result_view() table
+local mt = {
+ __len = function(self)
+ return self.length
+ end,
+ __index = function(self, i)
+ -- right away, convert to 0-relative indexing
+ i -= 1
+ -- can we find this index within the current slice?
+ local reli = i - self.start
+ if 0 <= reli and reli < #self.slice then
+ -- Lua 1-relative indexing
+ return self.slice[reli + 1]
+ end
+ -- is this index outside the overall result set?
+ if not (0 <= i and i < self.length) then
+ return nil
+ end
+ -- fetch a new slice starting at i, using provided fetch()
+ local start
+ self.slice, start = self.fetch(self.key, i)
+ -- It's possible that caller-provided fetch() function forgot
+ -- to return the adjusted start index of the new slice. In
+ -- Lua, 0 tests as true, so if fetch() returned (slice, 0),
+ -- we'll duly reset self.start to 0. Otherwise, assume the
+ -- requested index was not adjusted: that the returned slice
+ -- really does start at i.
+ self.start = start or i
+ -- Hopefully this slice contains the desired i.
+ -- Back to 1-relative indexing.
+ return self.slice[i - self.start + 1]
+ end,
+ -- We purposely avoid putting any array entries (int keys) into
+ -- our table so that access to any int key will always call our
+ -- __index() metamethod. Moreover, we want any table iteration to
+ -- call __index(table, i) however many times; we do NOT want it to
+ -- retrieve key, length, start, slice.
+ -- So turn 'for k, v in result' into 'for k, v in ipairs(result)'.
+ __iter = ipairs,
+ -- This result set provides read-only access.
+ -- We do not support pushing updates to individual items back to
+ -- C++; for the intended use cases, that makes no sense.
+ __newindex = function(self, i, value)
+ error("result_view is a read-only data structure", 2)
+ end
+}
+
+-- result_view(key_length, fetch) returns a table which stores only a slice
+-- of a result set plus some control values, yet presents read-only virtual
+-- access to the entire result set.
+-- key_length: {result set key, total result set length}
+-- fetch: function(key, start) that returns (slice, adjusted start)
+local result_view = setmetatable(
+ {
+ -- generic fetch() function
+ fetch = function(key, start)
+ local fetched = leap.request(
+ 'LLInventory',
+ {op='getSlice', result=key, index=start})
+ return fetched.slice, fetched.start
+ end,
+ -- generic close() function accepting variadic result-set keys
+ close = function(...)
+ local keys = table.pack(...)
+ -- table.pack() produces a table with an array entry for every
+ -- parameter, PLUS an 'n' key with the count. Unfortunately that
+ -- 'n' key bollixes our conversion to LLSD, which requires either
+ -- all int keys (for an array) or all string keys (for a map).
+ keys.n = nil
+ leap.send('LLInventory', {op='closeResult', result=keys})
+ end
+ },
+ {
+ -- result_view(key_length, fetch) calls this
+ __call = function(class, key_length, fetch)
+ return setmetatable(
+ {
+ key=key_length[1],
+ length=key_length[2],
+ -- C++ result sets use 0-based indexing, so internally we do too
+ start=0,
+ -- start with a dummy array with length 0
+ slice={},
+ -- if caller didn't pass fetch() function, use generic
+ fetch=fetch or class.fetch,
+ -- returned view:close() will close result set with passed key
+ close=function(self) class.close(key_length[1]) end
+ },
+ -- use our special metatable
+ mt
+ )
+ end
+ }
+)
+
+return result_view
diff --git a/indra/newview/scripts/lua/test_LLInventory.lua b/indra/newview/scripts/lua/test_LLInventory.lua
index 107b0791d4..de57484bcd 100644
--- a/indra/newview/scripts/lua/test_LLInventory.lua
+++ b/indra/newview/scripts/lua/test_LLInventory.lua
@@ -5,7 +5,9 @@ LLInventory = require 'LLInventory'
my_landmarks_id = LLInventory.getBasicFolderID('landmark')
-- Get 3 landmarks from the 'My Landmarks' folder (you can see all folder types via LLInventory.getAssetTypeNames())
landmarks = LLInventory.collectDescendentsIf{folder_id=my_landmarks_id, type="landmark", limit=3}
-print(inspect(landmarks))
+for _, landmark in pairs(landmarks.items) do
+ print(landmark.name)
+end
-- Get 'Calling Cards' folder id
calling_cards_id = LLInventory.getBasicFolderID('callcard')
@@ -13,9 +15,10 @@ calling_cards_id = LLInventory.getBasicFolderID('callcard')
calling_cards = LLInventory.getDirectDescendents(calling_cards_id).items
-- Print a random calling card name from 'Calling Cards' folder
-local card_names = {}
-for _, value in pairs(calling_cards) do
- table.insert(card_names, value.name)
-end
+-- (because getDirectDescendents().items is a Lua result set, selecting
+-- a random entry only fetches one slice containing that entry)
math.randomseed(os.time())
-print("Random calling card: " .. inspect(card_names[math.random(#card_names)]))
+for i = 1, 5 do
+ pick = math.random(#calling_cards)
+ print(`Random calling card (#{pick} of {#calling_cards}): {calling_cards[pick].name}`)
+end
diff --git a/indra/newview/scripts/lua/test_inv_resultset.lua b/indra/newview/scripts/lua/test_inv_resultset.lua
new file mode 100644
index 0000000000..c31cfe3c67
--- /dev/null
+++ b/indra/newview/scripts/lua/test_inv_resultset.lua
@@ -0,0 +1,18 @@
+local LLInventory = require 'LLInventory'
+local inspect = require 'inspect'
+
+print('basic folders:')
+print(inspect(LLInventory.getFolderTypeNames()))
+
+local folder = LLInventory.getBasicFolderID('my_otfts')
+print(`folder = {folder}`)
+local result = LLInventory.getDirectDescendants(folder)
+print(`type(result) = {type(result)}`)
+print(#result.categories, 'categories:')
+for i, cat in pairs(result.categories) do
+ print(`{i}: {cat.name}`)
+end
+print(#result.items, 'items')
+for i, item in pairs(result.items) do
+ print(`{i}: {item.name}`)
+end
diff --git a/indra/newview/scripts/lua/test_result_view.lua b/indra/newview/scripts/lua/test_result_view.lua
new file mode 100644
index 0000000000..304633a472
--- /dev/null
+++ b/indra/newview/scripts/lua/test_result_view.lua
@@ -0,0 +1,55 @@
+-- Verify the functionality of result_view.
+result_view = require 'result_view'
+
+print('alphabet')
+alphabet = "abcdefghijklmnopqrstuvwxyz"
+assert(#alphabet == 26)
+alphabits = string.split(alphabet, '')
+
+print('function slice()')
+function slice(t, index, count)
+ return table.move(t, index, index + count - 1, 1, {})
+end
+
+print('verify slice()')
+-- verify that slice() does what we expect
+assert(table.concat(slice(alphabits, 4, 3)) == "def")
+assert(table.concat(slice(alphabits, 14, 3)) == "nop")
+assert(table.concat(slice(alphabits, 25, 3)) == "yz")
+
+print('function fetch()')
+function fetch(key, index)
+ -- fetch function is defined to be 0-relative: fix for Lua data
+ -- constrain view of alphabits to slices of at most 3 elements
+ return slice(alphabits, index+1, 3), index
+end
+
+print('result_view()')
+-- for test purposes, key is irrelevant, so just 'key'
+view = result_view({'key', #alphabits}, fetch)
+
+print('function check_iter()')
+function check_iter(...)
+ result = {}
+ for k, v in ... do
+ table.insert(result, v)
+ end
+ assert(table.concat(result) == alphabet)
+end
+
+print('check_iter(pairs(view))')
+check_iter(pairs(view))
+print('check_iter(ipairs(view))')
+check_iter(ipairs(view))
+print('check_iter(view)')
+check_iter(view)
+
+print('raw index access')
+assert(view[5] == 'e')
+assert(view[10] == 'j')
+assert(view[15] == 'o')
+assert(view[20] == 't')
+assert(view[25] == 'y')
+
+print('Success!')
+
diff --git a/indra/newview/scripts/lua/test_setdtor.lua b/indra/newview/scripts/lua/test_setdtor.lua
new file mode 100644
index 0000000000..ec5cd47e93
--- /dev/null
+++ b/indra/newview/scripts/lua/test_setdtor.lua
@@ -0,0 +1,91 @@
+inspect = require 'inspect'
+
+print('initial setdtor')
+bye = LL.setdtor('initial setdtor', 'Goodbye world!', print)
+
+print('arithmetic')
+n = LL.setdtor('arithmetic', 11, print)
+print("n =", n)
+print("n._target =", n._target)
+print(pcall(function() n._target = 12 end))
+print("getmetatable(n) =", inspect(getmetatable(n)))
+print("-n =", -n)
+for i = 10, 12 do
+ -- Comparison metamethods are only called if both operands have the same
+ -- metamethod.
+ tempi = LL.setdtor('tempi', i, function(n) print('temp', i) end)
+ print(`n < {i}`, n < tempi)
+ print(`n <= {i}`, n <= tempi)
+ print(`n == {i}`, n == tempi)
+ print(`n ~= {i}`, n ~= tempi)
+ print(`n >= {i}`, n >= tempi)
+ print(`n > {i}`, n > tempi)
+end
+i = 2
+print(`n + {i} =`, n + i)
+print(`{i} + n =`, i + n)
+print(`n - {i} =`, n - i)
+print(`{i} - n =`, i - n)
+print(`n * {i} =`, n * i)
+print(`{i} * n =`, i * n)
+print(`n / {i} =`, n / i)
+print(`{i} / n =`, i / n)
+print(`n // {i} =`, n // i)
+print(`{i} // n =`, i // n)
+print(`n % {i} =`, n % i)
+print(`{i} % n =`, i % n)
+print(`n ^ {i} =`, n ^ i)
+print(`{i} ^ n =`, i ^ n)
+
+print('string')
+s = LL.setdtor('string', 'hello', print)
+print('s =', s)
+print('#s =', #s)
+print('s .. " world" =', s .. " world")
+print('"world " .. s =', "world " .. s)
+
+print('table')
+t = LL.setdtor('table', {'[1]', '[2]', abc='.abc', def='.def'},
+ function(t) print(inspect(t)) end)
+print('t =', inspect(t))
+print('t._target =', inspect(t._target))
+print('#t =', #t)
+print('next(t) =', next(t))
+print('next(t, 1) =', next(t, 1))
+print('t[2] =', t[2])
+print('t.def =', t.def)
+t[1] = 'new [1]'
+print('t[1] =', t[1])
+print('for k, v in pairs(t) do')
+for k, v in pairs(t) do
+ print(`{k}: {v}`)
+end
+print('for k, v in ipairs(t) do')
+for k, v in ipairs(t) do
+ print(`{k}: {v}`)
+end
+print('for k, v in t do')
+for k, v in t do
+ print(`{k}: {v}`)
+end
+-- and now for something completely different
+setmetatable(
+ t._target,
+ {
+ __iter = function(arg)
+ return next, {'alternate', '__iter'}
+ end
+ }
+)
+print('for k, v in t with __iter() metamethod do')
+for k, v in t do
+ print(`{k}: {v}`)
+end
+
+print('function')
+f = LL.setdtor('function', function(a, b) return (a .. b) end, print)
+print('f =', f)
+print('f._target =', f._target)
+print('f("Hello", " world") =', f("Hello", " world"))
+
+print('cleanup')